[DTrace-devel] [PATCH v4] Add support for uregs[]

Eugene Loh eugene.loh at oracle.com
Mon Feb 27 00:46:45 UTC 2023


On 2/26/23 02:23, Kris Van Hees wrote:
> On Sat, Feb 25, 2023 at 02:14:40AM -0500, eugene.loh--- via DTrace-devel wrote:
>> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
>> @@ -3944,6 +3944,107 @@ dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
>>   	TRACE_REGSET("    assoc_op: End  ");
>>   }
>>   
>> +#if defined(__amd64)
>> +static void
>> +dt_cg_uregs(unsigned int idx, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
>> +{
>> +	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
>> +	ctf_file_t *cfp = dtp->dt_shared_ctf;
>> +	ctf_id_t type;
>> +	ctf_membinfo_t ctm;
>> +	int offset, rc;
>> +
>> +	/* look up pt_regs[] */
>> +	if (idx <= 20 /* SS */) {
>> +		if (dtp->dt_bpfhelper[BPF_FUNC_get_current_task_btf] == BPF_FUNC_unspec
>> +		  || dtp->dt_bpfhelper[BPF_FUNC_task_pt_regs] == BPF_FUNC_unspec)
>> +			dnerror(dnp, D_UNKNOWN, "uregs[] is not supported on this kernel\n");
>> +		if (dt_regset_xalloc_args(drp) == -1)
>> +			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
>> +		dt_regset_xalloc(drp, BPF_REG_0);
>> +		emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_task_btf));
>> +		emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_0));
>> +		emit(dlp, BPF_CALL_HELPER(BPF_FUNC_task_pt_regs));
>> +		dt_regset_free_args(drp);
>> +		emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, idx * sizeof(uint64_t)));
>> +		emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_0, 0));
>> +		dt_regset_free(drp, BPF_REG_0);
>> +		return;
>> +	}
>> +
>> +	/* look up task->thread offset */
>> +	if (!cfp)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
>> +
>> +	type = ctf_lookup_by_name(cfp, "struct task_struct");
>> +	if (type == CTF_ERR)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
>> +	if (ctf_member_info(cfp, type, "thread", &ctm) == CTF_ERR)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
>> +	offset = ctm.ctm_offset / NBBY;
>> +
>> +	/* add the thread->member offset */
>> +	type = ctf_lookup_by_name(cfp, "struct thread_struct");
>> +	if (type == CTF_ERR)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
>> +	switch (idx) {
>> +	case 21: rc = ctf_member_info(cfp, type, "ds", &ctm); break;
>> +	case 22: rc = ctf_member_info(cfp, type, "es", &ctm); break;
>> +	case 23: rc = ctf_member_info(cfp, type, "fsbase", &ctm); break;
>> +	case 24: rc = ctf_member_info(cfp, type, "gsbase", &ctm); break;
>> +	case 25: rc = ctf_member_info(cfp, type, "trap_nr", &ctm); break;
>> +	default: dnerror(dnp, D_UNKNOWN, "uregs[]: index out of bounds (%d)\n", idx);
>> +	}
>> +	if (rc == -1)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
>> +	offset += ctm.ctm_offset / NBBY;
>> +
>> +	/* copy task->thread.member onto the stack */
>> +	if (dt_regset_xalloc_args(drp) == -1)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
>> +	dt_regset_xalloc(drp, BPF_REG_0);
>> +	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_task));
>> +	emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0));
>> +	emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, offset));
>> +	emit(dlp, BPF_MOV_IMM(BPF_REG_2, sizeof(uint64_t)));
>> +	emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_SP));
>> +	emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_kernel]));
>> +	dt_regset_free_args(drp);
>> +	emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_FP, DT_STK_SP));
>> +	emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_0, 0));
>> +	dt_regset_free(drp, BPF_REG_0);
>> +}
>> +
>> +#elif defined(__aarch64__)
>> +static void
>> +dt_cg_uregs(unsigned int idx, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
>> +{
>> +	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
>> +
>> +	if (idx >= sizeof(struct user_pt_regs) / sizeof(uint64_t)) {
>> +		dnerror(dnp, D_UNKNOWN, "uregs[]: index out of bounds (%d)\n", idx);
>> +		return;
>> +	}
>> +
>> +	if (dtp->dt_bpfhelper[BPF_FUNC_get_current_task_btf] == BPF_FUNC_unspec
>> +	  || dtp->dt_bpfhelper[BPF_FUNC_task_pt_regs] == BPF_FUNC_unspec)
>> +		dnerror(dnp, D_UNKNOWN, "uregs[] is not supported on this kernel\n");
>> +
>> +	if (dt_regset_xalloc_args(drp) == -1)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
>> +	dt_regset_xalloc(drp, BPF_REG_0);
>> +	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_task_btf));
>> +	emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_0));
>> +	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_task_pt_regs));
>> +	dt_regset_free_args(drp);
>> +	emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, idx * sizeof(uint64_t)));
>> +	emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_0, 0));
>> +	dt_regset_free(drp, BPF_REG_0);
>> +}
>> +#else
>> +#error unknown ISA
>> +#endif
> So, looking at the way this works and the fact that we have a dt_pt_regs type
> (see libdtrace/dt_pt_regs.h), why not actually consolidate this in a single
> function that accesses dt_pt_regs as a uint64_t array indexed by the given
> constant index (after boundary check) and have a special case (ifdef amd64)
> for DS, ES, FS, GS, TRAPNO.  So, something like:
>
> 	If the helpers are not available report error
>
> 	if (idx >= sizeof(dt_pt_regs) / sizeof(uint64_t)) {
> #ifdef __amd64 (or if defined(__amd64)
> 		See if the idx is DS, ES, FS, GS, or TRAPNO, and if so, get
> 		the correct value and return it
> #endif
> 		Report index out of bound error
> 	}
>
> 	return ((uint64_t *)dt_pt_regs)[idx]
>
> That avoids having this big #if .. #elif .. #else .. #endif construct for
> something that really can be done with a generic function with just a special
> case of x86_64 for the 5 index values that are special.

Good idea.  v5 posted.



More information about the DTrace-devel mailing list