Re: [DTrace-devel] [PATCH 4/6] dtrace: Add uresolve(symbol_name[, optional_fallback]) for symbol lookup
Kris Van Hees <[email protected]> Fri, 5 Jun 2026 21:08:20 -0400
| Newsgroups | dev.linux.lists.dtrace |
|---|---|
| Message-ID | <[email protected]> |
A few initial comments: - How is this different from what ``symbol or object``symbol would provide? (Yes, as far as I know it never got fully implemented but I think this might be similar to what you are doing, and perhaps it would be better to use the already documented syntax, and actually implement it more fully.) - I think it is problematic that the cg code is making calls to a function in a particular provider. THe architecture has been quite careful at avoiding breaking through that boundary. I'm still digging a bit more through the code to determine exactly why that call is truly needed - it should not be necessary as far as I can see. Resolution of a userspace symbol should essentially be a simple matter of: object-base-addr + symbol-offset where the object is a particular mapping within the address space of the current user process. On Fri, Jun 05, 2026 at 11:12:15PM +0100, Alan Maguire via DTrace-devel wrote: > Add uresolve(symbol[, fallback]) to resolve user-space symbols from D > scripts. uresolve() resolves a symbol to an object-relative offset at > compile time, then computes the process-specific runtime address at probe > fire time as: > > current uprobe IP - probe offset + symbol offset > > For pid$target probes, use the target process and its /proc/<pid>/maps state > to find the symbol and translate it to the same object-relative coordinate > used by uprobes. For system-wide uprobes, resolve the offset from the probed > object file. In both cases, address generation is shared and remains dynamic; > the presence of a target process does not bake in an absolute address. > > Use bpf_get_func_ip() when available so system-wide uprobes use the actual > probed instruction address rather than a saved pt_regs IP that may contain > the resume address. Retain the saved-IP path as a fallback. > > This allows scripts to locate process-local data such as > _PyThreadState_Current across ASLR and across system-wide probes firing in > different processes. The optional fallback argument is returned when the > symbol cannot be resolved; without it, resolution failure remains a > compile-time error. > > Signed-off-by: Alan Maguire <[email protected]> > Assisted-by: OpenAI Codex (GPT-5) <[email protected]> > --- > include/dtrace/dif_defines.h | 3 +- > libdtrace/dt_bpf.c | 1 + > libdtrace/dt_cg.c | 456 +++++++++++++++++++++++++++++++++++ > libdtrace/dt_open.c | 2 + > libdtrace/dt_probe.h | 1 + > libdtrace/dt_prov_uprobe.c | 58 ++++- > 6 files changed, 516 insertions(+), 5 deletions(-) > > diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h > index edb98f06..63b8c293 100644 > --- a/include/dtrace/dif_defines.h > +++ b/include/dtrace/dif_defines.h > @@ -213,8 +213,9 @@ > #define DIF_SUBR_LINK_NTOP 45 > #define DIF_SUBR_STACK 46 > #define DIF_SUBR_USTACK 47 > +#define DIF_SUBR_URESOLVE 48 > > -#define DIF_SUBR_MAX 47 > +#define DIF_SUBR_MAX 48 > > typedef uint32_t dif_instr_t; > > diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c > index 146a66e3..aecd71d9 100644 > --- a/libdtrace/dt_bpf.c > +++ b/libdtrace/dt_bpf.c > @@ -470,6 +470,7 @@ dt_bpf_init_helpers(dtrace_hdl_t *dtp) > BPF_HELPER_MAP(probe_read_user_str, probe_read_str); > BPF_HELPER_MAP(probe_read_kernel, probe_read); > BPF_HELPER_MAP(probe_read_kernel_str, probe_read_str); > + BPF_HELPER_MAP(get_func_ip, unspec); > BPF_HELPER_MAP(get_current_task_btf, unspec); > BPF_HELPER_MAP(task_pt_regs, unspec); > #undef BPF_HELPER_MAP > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c > index 1bd73e11..16c58e35 100644 > --- a/libdtrace/dt_cg.c > +++ b/libdtrace/dt_cg.c > @@ -11,6 +11,9 @@ > #include <setjmp.h> > #include <assert.h> > #include <errno.h> > +#include <ctype.h> > +#include <fcntl.h> > +#include <unistd.h> > > #include <sys/socket.h> /* needed for if_arp.h on OL7/x86 */ > #include <linux/if_arp.h> /* ARPHRD_ETHER ARPHRD_INFINIBAND */ > @@ -6988,6 +6991,458 @@ dt_cg_subr_link_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > dt_regset_free(drp, type->dn_reg); > } > > +static const char * > +dt_cg_basename(const char *path) > +{ > + const char *p; > + > + p = strrchr(path, '/'); > + return p != NULL ? p + 1 : path; > +} > + > +static int > +dt_cg_parse_objname(const char *mod, Lmid_t *lmidp, const char **objp) > +{ > + char *end; > + > + if (mod == NULL || mod[0] == '\0' || strisglob(mod)) > + return -1; > + > + if (strncmp(mod, "LM", 2) == 0 && isdigit((unsigned char)mod[2])) { > + *lmidp = strtoul(mod + 2, &end, 16); > + if (*end != '`' || end[1] == '\0' || strchr(end + 1, '`')) > + return -1; > + > + *objp = end + 1; > + return 0; > + } > + > + *lmidp = PR_LMID_EVERY; > + *objp = mod; > + return 0; > +} > + > +static int > +dt_cg_probe_objname(const dt_probe_t *prp, Lmid_t *lmidp, const char **objp) > +{ > + if (prp == NULL || prp->desc == NULL) > + return -1; > + > + return dt_cg_parse_objname(prp->desc->mod, lmidp, objp); > +} > + > +static int > +dt_cg_obj_matches_path(const char *obj, const char *path) > +{ > + const char *base; > + Lmid_t lmid; > + > + if (obj == NULL || path == NULL) > + return 0; > + > + if (dt_cg_parse_objname(obj, &lmid, &obj) == -1) > + return 0; > + > + base = dt_cg_basename(path); > + return strcmp(obj, path) == 0 || strcmp(obj, base) == 0; > +} > + > +static int > +dt_cg_elf_sym_to_offset(Elf *elf, const GElf_Sym *sym, uint64_t *offp) > +{ > + GElf_Ehdr ehdr; > + size_t i, phnum; > + uint64_t base = 0; > + > + if (sym->st_shndx == SHN_UNDEF || > + gelf_getehdr(elf, &ehdr) == NULL || > + elf_getphdrnum(elf, &phnum) != 0) > + return -1; > + > + /* > + * Match the object-relative coordinate used by uprobe offsets. For > + * ET_DYN, libproc computes file_dyn_base from the first PT_LOAD > + * segment's page offset. For ET_EXEC, the load bias is zero and the > + * first segment's vaddr remains part of the object-relative offset. > + */ > + for (i = 0; i < phnum; i++) { > + GElf_Phdr phdr; > + > + if (gelf_getphdr(elf, i, &phdr) == NULL || > + phdr.p_type != PT_LOAD) > + continue; > + > + if (ehdr.e_type == ET_EXEC) > + base = phdr.p_vaddr; > + else if (ehdr.e_type == ET_DYN && phdr.p_align != 0) > + base = phdr.p_vaddr & (phdr.p_align - 1); > + > + break; > + } > + > + if (i == phnum || sym->st_value < base) > + return -1; > + > + *offp = sym->st_value - base; > + return 0; > +} > + > +static int > +dt_cg_elf_lookup_symtab(Elf *elf, int type, const char *name, GElf_Sym *symp) > +{ > + Elf_Scn *scn = NULL; > + > + while ((scn = elf_nextscn(elf, scn)) != NULL) { > + GElf_Shdr shdr; > + Elf_Data *data; > + size_t i, nsyms; > + > + if (gelf_getshdr(scn, &shdr) == NULL || > + shdr.sh_type != type || > + shdr.sh_entsize == 0) > + continue; > + > + data = elf_getdata(scn, NULL); > + if (data == NULL) > + continue; > + > + nsyms = shdr.sh_size / shdr.sh_entsize; > + for (i = 0; i < nsyms; i++) { > + GElf_Sym sym; > + const char *s; > + uchar_t stype; > + > + if (gelf_getsym(data, i, &sym) == NULL || > + sym.st_name == 0 || > + sym.st_shndx == SHN_UNDEF) > + continue; > + > + stype = GELF_ST_TYPE(sym.st_info); > + if (stype == STT_FILE || stype == STT_SECTION) > + continue; > + > + s = elf_strptr(elf, shdr.sh_link, sym.st_name); > + if (s != NULL && strcmp(s, name) == 0) { > + *symp = sym; > + return 0; > + } > + } > + } > + > + return -1; > +} > + > +static int > +dt_cg_elf_lookup_offset(const char *path, const char *name, uint64_t *offp) > +{ > + GElf_Sym sym; > + Elf *elf = NULL; > + int fd, rc = -1; > + > + fd = open(path, O_RDONLY); > + if (fd < 0) > + return -1; > + > + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); > + if (elf == NULL || elf_kind(elf) != ELF_K_ELF) > + goto out; > + > + if (dt_cg_elf_lookup_symtab(elf, SHT_SYMTAB, name, &sym) == -1 && > + dt_cg_elf_lookup_symtab(elf, SHT_DYNSYM, name, &sym) == -1) > + goto out; > + > + rc = dt_cg_elf_sym_to_offset(elf, &sym, offp); > + > +out: > + if (elf != NULL) > + elf_end(elf); > + close(fd); > + return rc; > +} > + > +typedef struct dt_cg_uresolve_arg { > + const char *name; > + const char *obj; > + int explicit_obj; > + int nmatches; > + int no_path; > + int no_symbol; > + int bad_object; > + int different_offset; > + uint64_t off; > +} dt_cg_uresolve_arg_t; > + > +static int > +dt_cg_uresolve_probe(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg) > +{ > + dt_cg_uresolve_arg_t *uap = arg; > + const char *path; > + uint64_t off; > + > + path = dt_probe_uprobe_path(prp); > + if (path == NULL) { > + uap->no_path = 1; > + return 1; > + } > + > + if (uap->explicit_obj && !dt_cg_obj_matches_path(uap->obj, path)) { > + uap->bad_object = 1; > + return 1; > + } > + > + if (dt_cg_elf_lookup_offset(path, uap->name, &off) != 0) { > + uap->no_symbol = 1; > + return 1; > + } > + > + if (uap->nmatches++ == 0) { > + uap->off = off; > + return 0; > + } > + > + if (uap->off != off) { > + uap->different_offset = 1; > + return 1; > + } > + > + return 0; > +} > + > +static int > +dt_cg_uresolve_from_probe_file(dt_node_t *dnp, dt_node_t *arg, > + const char *name, const char *obj, > + int explicit_obj, int allow_fallback, > + uint64_t *offp) > +{ > + dt_cg_uresolve_arg_t uarg = { 0 }; > + dtrace_hdl_t *dtp = yypcb->pcb_hdl; > + > + uarg.name = name; > + uarg.obj = obj; > + uarg.explicit_obj = explicit_obj; > + > + if (yypcb->pcb_pdesc != NULL) > + dt_probe_iter(dtp, yypcb->pcb_pdesc, dt_cg_uresolve_probe, > + NULL, &uarg); > + else if (yypcb->pcb_probe != NULL) > + dt_cg_uresolve_probe(dtp, yypcb->pcb_probe, &uarg); > + > + if (uarg.bad_object) > + dnerror(arg, D_PROC_NAME, "uresolve( ) object %s does not " > + "match the current uprobe object\n", obj); > + if (uarg.no_path) > + dnerror(dnp, D_PROC_NAME, "uresolve( ) requires a unique " > + "uprobe object path for this probe\n"); > + if (uarg.no_symbol) { > + if (allow_fallback) > + return -1; > + > + dnerror(arg, D_PROC_FUNC, "failed to resolve user symbol %s " > + "in the current uprobe object\n", arg->dn_string); > + } > + > + if (uarg.nmatches == 0) { > + dnerror(dnp, D_PROC_NAME, "uresolve( ) cannot determine the " > + "current uprobe object\n"); > + } > + > + if (uarg.different_offset) > + dnerror(arg, D_PROC_FUNC, "uresolve( ) matched multiple " > + "uprobe objects with different offsets for symbol %s\n", > + arg->dn_string); > + > + *offp = uarg.off; > + return 0; > +} > + > +static int > +dt_cg_uresolve_from_target(dt_node_t *dnp, dt_node_t *arg, pid_t pid, > + Lmid_t lmid, const char *obj, const char *name, > + int allow_fallback, uint64_t *offp) > +{ > + dtrace_hdl_t *dtp = yypcb->pcb_hdl; > + const prmap_t *mapp, *first; > + GElf_Sym sym; > + pid_t gpid; > + int err = 0; > + > + gpid = dt_proc_grab_lock(dtp, pid, > + DTRACE_PROC_WAITING | DTRACE_PROC_SHORTLIVED); > + if (gpid <= 0) > + dnerror(dnp, D_PROC_GRAB, "failed to grab target process %d " > + "for uresolve( )\n", pid); > + > + if (dt_Pxlookup_by_name(dtp, gpid, lmid, obj, name, > + &sym, NULL) != 0) { > + err = 1; > + } else if ((mapp = dt_Paddr_to_map(dtp, gpid, sym.st_value)) == NULL || > + mapp->pr_file == NULL || > + (first = mapp->pr_file->first_segment) == NULL || > + sym.st_value < first->pr_vaddr) { > + err = 1; > + } else { > + *offp = sym.st_value - first->pr_vaddr; > + } > + > + dt_proc_release_unlock(dtp, gpid); > + > + if (err == 0) > + return 0; > + > + if (allow_fallback) > + return -1; > + > + dnerror(arg, D_PROC_FUNC, "failed to resolve target user symbol %s\n", > + arg->dn_string); > +} > + > +static void > +dt_cg_uresolve_emit_offset_addr(dt_node_t *dnp, dt_irlist_t *dlp, > + dt_regset_t *drp, uint64_t symoff) > +{ > + dtrace_hdl_t *dtp = yypcb->pcb_hdl; > + int treg; > + > + /* > + * Compute the current object base from the saved user PC and the > + * uprobe offset, then add the compile-time-resolved symbol offset. > + * When available, use the kernel's current uprobe IP directly because > + * the saved register block may not reliably carry the breakpoint > + * address for system-wide uprobes across different processes. > + */ > + if (dtp->dt_bpfhelper[BPF_FUNC_get_func_ip] != BPF_FUNC_unspec) { > + if (dt_regset_xalloc_args(drp) == -1) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > + if (dt_regset_xalloc(drp, BPF_REG_0) == -1) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > + > + dt_cg_access_dctx(BPF_REG_1, dlp, drp, DCTX_CTX); > + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_get_func_ip])); > + dt_regset_free_args(drp); > + > + if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > + > + emit(dlp, BPF_MOV_REG(dnp->dn_reg, BPF_REG_0)); > + dt_regset_free(drp, BPF_REG_0); > + } else { > + if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > + > + if ((treg = dt_regset_alloc(drp)) == -1) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > + > + dt_cg_access_dctx(treg, dlp, drp, DCTX_MST); > + emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, treg, > + DMST_REGS + PT_REGS_IP)); > + dt_regset_free(drp, treg); > + } > + > + if ((treg = dt_regset_alloc(drp)) == -1) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > + > + dt_cg_access_dctx(treg, dlp, drp, DCTX_MST); > + emit(dlp, BPF_LOAD(BPF_DW, treg, treg, DMST_PROFF)); > + emit(dlp, BPF_ALU64_REG(BPF_SUB, dnp->dn_reg, treg)); > + dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, treg, symoff); > + emit(dlp, BPF_ALU64_REG(BPF_ADD, dnp->dn_reg, treg)); > + > + dt_regset_free(drp, treg); > +} > + > +static void > +dt_cg_subr_uresolve(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > +{ > + dtrace_hdl_t *dtp = yypcb->pcb_hdl; > + dt_node_t *arg = dnp->dn_args; > + dt_node_t *fallback; > + dt_ident_t *tidp; > + pid_t pid = 0; > + char *spec, *tick; > + const char *obj = NULL; > + const char *name; > + Lmid_t lmid = PR_LMID_EVERY; > + uint64_t off = 0; > + int err = 0, explicit_obj = 0; > + int use_fallback = 0; > + > + if (arg == NULL || (arg->dn_list != NULL && > + arg->dn_list->dn_list != NULL)) > + dnerror(dnp, D_PROTO_LEN, "uresolve( ) prototype mismatch: " > + "expected 1 or 2 arguments\n"); > + > + if (arg->dn_kind != DT_NODE_STRING) > + dnerror(arg, D_PROTO_ARG, "uresolve( ) argument #1 must be " > + "a string constant\n"); > + > + fallback = arg->dn_list; > + tidp = dt_idhash_lookup(dtp->dt_macros, "target"); > + if (tidp != NULL) > + pid = tidp->di_id; > + > + spec = strdup(arg->dn_string); > + if (spec == NULL) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); > + > + tick = strrchr(spec, '`'); > + if (tick != NULL) { > + *tick = '\0'; > + obj = spec; > + name = tick + 1; > + explicit_obj = 1; > + > + if (*obj == '\0' || *name == '\0') > + err = 1; > + } else { > + name = spec; > + } > + > + if (err != 0) { > + free(spec); > + dnerror(arg, D_PROC_NAME, "uresolve( ) argument must be " > + "\"symbol\" or \"object`symbol\"\n"); > + } > + > + if (pid == 0) { > + if (dt_cg_uresolve_from_probe_file(dnp, arg, name, obj, > + explicit_obj, fallback != NULL, &off) != 0) > + use_fallback = 1; > + goto done; > + } > + > + if (explicit_obj) { > + if (dt_cg_parse_objname(obj, &lmid, &obj) != 0) { > + free(spec); > + dnerror(arg, D_PROC_NAME, "uresolve( ) object %s is " > + "not a valid user object name\n", arg->dn_string); > + } > + } else if (dt_cg_probe_objname(yypcb->pcb_probe, &lmid, &obj) != 0) { > + const char *path = dt_probe_uprobe_path(yypcb->pcb_probe); > + > + if (path != NULL) { > + obj = path; > + lmid = PR_LMID_EVERY; > + } else { > + free(spec); > + dnerror(arg, D_PROC_NAME, "unqualified uresolve( ) " > + "requires a concrete probe module\n"); > + } > + } > + > + if (dt_cg_uresolve_from_target(dnp, arg, pid, lmid, obj, name, > + fallback != NULL, &off) != 0) > + use_fallback = 1; > + > +done: > + free(spec); > + > + if (use_fallback) { > + dt_cg_node(fallback, dlp, drp); > + dnp->dn_reg = fallback->dn_reg; > + } else > + dt_cg_uresolve_emit_offset_addr(dnp, dlp, drp, off); > +} > + > typedef void dt_cg_subr_f(dt_node_t *, dt_irlist_t *, dt_regset_t *); > > static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { > @@ -7039,6 +7494,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { > [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, > [DIF_SUBR_STACK] = &dt_cg_subr_stack, > [DIF_SUBR_USTACK] = &dt_cg_subr_ustack, > + [DIF_SUBR_URESOLVE] = &dt_cg_subr_uresolve, > }; > > static void > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c > index ca00788a..0505e2ff 100644 > --- a/libdtrace/dt_open.c > +++ b/libdtrace/dt_open.c > @@ -330,6 +330,8 @@ static const dt_ident_t _dtrace_globals[] = { > DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, > { "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0, > &dt_idops_regs, NULL }, > +{ "uresolve", DT_IDENT_FUNC, 0, DIF_SUBR_URESOLVE, DT_ATTR_STABCMN, > + DT_VERS_2_0, &dt_idops_func, "uintptr_t(string, [uintptr_t])" }, > { "ustack", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_USTACK, DT_ATTR_STABCMN, > DT_VERS_1_0, &dt_idops_func, "dt_stack_t([uint32_t], [uint32_t])" }, > { "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH, > diff --git a/libdtrace/dt_probe.h b/libdtrace/dt_probe.h > index 54053cd3..bff47055 100644 > --- a/libdtrace/dt_probe.h > +++ b/libdtrace/dt_probe.h > @@ -102,6 +102,7 @@ typedef int dt_dependent_f(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg); > extern int dt_probe_dependent_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp, > dt_dependent_f *func, void *arg); > > +extern const char *dt_probe_uprobe_path(const dt_probe_t *prp); > > extern void dt_probe_init(dtrace_hdl_t *dtp); > extern void dt_probe_detach_all(dtrace_hdl_t *dtp); > diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c > index d53b1e43..9a481f59 100644 > --- a/libdtrace/dt_prov_uprobe.c > +++ b/libdtrace/dt_prov_uprobe.c > @@ -307,6 +307,47 @@ typedef struct uprobe_data { > int ref_shift; > } uprobe_data_t; > > +dt_provimpl_t dt_pid; > +dt_provimpl_t dt_usdt; > +dt_provimpl_t dt_stapsdt; > + > +const char * > +dt_probe_uprobe_path(const dt_probe_t *prp) > +{ > + const dt_uprobe_t *upp; > + const list_probe_t *pup; > + const char *path = NULL; > + > + if (prp == NULL || prp->prov == NULL) > + return NULL; > + > + if (prp->prov->impl == &dt_uprobe) { > + upp = prp->prv_data; > + return upp != NULL ? upp->fn : NULL; > + } > + > + if (prp->prov->impl != &dt_pid && > + prp->prov->impl != &dt_usdt && > + prp->prov->impl != &dt_stapsdt) > + return NULL; > + > + for (pup = prp->prv_data; pup != NULL; pup = dt_list_next(pup)) { > + if (pup->probe == NULL || pup->probe->prv_data == NULL) > + return NULL; > + > + upp = pup->probe->prv_data; > + if (upp->fn == NULL) > + return NULL; > + > + if (path == NULL) > + path = upp->fn; > + else if (strcmp(path, upp->fn) != 0) > + return NULL; > + } > + > + return path; > +} > + > static const dtrace_pattr_t pattr = { > { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, > { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, > @@ -315,10 +356,6 @@ static const dtrace_pattr_t pattr = { > { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, > }; > > -dt_provimpl_t dt_pid; > -dt_provimpl_t dt_usdt; > -dt_provimpl_t dt_stapsdt; > - > #define UPROBE_CONFIG "/sys/bus/event_source/devices/uprobe/" > #define PERF_TYPE_FILE (UPROBE_CONFIG "type") > #define RET_FLAG_FILE (UPROBE_CONFIG "format/retprobe") > @@ -1392,6 +1429,19 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) > */ > dt_cg_tramp_copy_regs(pcb); > > + /* > + * On some architectures the saved user IP in the uprobe pt_regs is the > + * resume address rather than the probed instruction address. Normalize > + * the saved IP to the actual uprobe address when the kernel can provide > + * it so consumers such as uresolve() can derive the correct object base. > + */ > + if (dtp->dt_bpfhelper[BPF_FUNC_get_func_ip] != BPF_FUNC_unspec) { > + emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_8)); > + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_get_func_ip])); > + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, > + DMST_REGS + PT_REGS_IP, BPF_REG_0)); > + } > + > /* > * Record the uprobe instrumentation offset in the probe context. > * This is the same object-relative offset passed to perf_event_open() > -- > 2.43.5 > > > _______________________________________________ > DTrace-devel mailing list > [email protected] > https://oss.oracle.com/mailman/listinfo/dtrace-devel