[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