[DTrace-devel] [PATCH v3] USDT, phase 1
Kris Van Hees
kris.van.hees at oracle.com
Thu Sep 15 15:54:26 UTC 2022
One overarching problem: when testing with Debian unstable I see the issue that
various trigger executables with USDT probes cannot be linked.
Debian unstable has: GNU ld (GNU Binutils for Debian) 2.38.90.20220713
The error is:
LINK: usdt-tst-argmap
/usr/bin/ld: /scratch/dtrace-bpf-user/build/test-triggers--usdt-tst-argmap.o: relocation R_X86_64_NONE against absolute symbol `__dtrace_test_prov___place' in section `.text.startup' is disallowed
collect2: error: ld returned 1 exit status
So, I anticipate that there will be issues once systems start moving to a newer
binutils. We should be ahead of the curve and see why this problem occurs and
either do something to avoid it or (if warranted) submit a patch to fix
binutils.
On Thu, Sep 08, 2022 at 01:26:29PM +0100, Nick Alcock via DTrace-devel wrote:
> This reroll fixes usdt probes with multiple loci
> (test/unittest/usdt/tst.multiple.sh), pid probes with multiple clauses
> (test/unittest/pid/tst.{arg*,ret*}.d), and return pid probes that share a
> locus with entry probes (test/unittest/pid/tst.float.d and others).
>
> We do *not* remove the somewhat strange thing where we add even probes with
> no trampoline to the enabled list, because as far as I can see we have to
> add them because it's only by virtue of (overlying) probes with no
> trampoline getting enabled that the underlying probes get enabled at all!
> So if we don't enable them, nothing is ever enabled and nothing works. No
> code is generated for trampolineless probes, so everything *looks* fine to
> me. You're welcome to find another way, of course :)
>
> All pid and usdt tests passing except usdt/tst.entryreturn.sh, which has
> some as-yet-undiagnosed problem. Full tests still running (the syscall
> provider triggering kernel crashes is not helping, but is likely unrelated).
>
> Patches 12 and 16 have actually changed: patch 20 is merely context.
>
> Full range diff from last set of postings:
>
> 1: 8638d1fada45 = 1: 8638d1fada45 Revert "Remove drti.o and related support code."
> 2: 51adb978a84e = 2: 51adb978a84e drti: emit into a subdirectory
> 3: 4e049adf837e = 3: 4e049adf837e drti: reference first loaded segment of object containing dtrace_dof_init
> 4: 41e02c5a9778 = 4: 41e02c5a9778 pid: drop dpp_stret
> 5: 04d7f8ac9fd8 = 5: 04d7f8ac9fd8 runtest: make ZAPTHESE an array
> 6: 34631890f964 = 6: 34631890f964 uapi headers: include <sys/dtrace_types> as needed
> 7: 0452527b7b24 = 7: 0452527b7b24 dt_link: finish backing out varint, fixing dt_link-generated object files
> 8: aaf630166e62 = 8: aaf630166e62 providers: allow providers with no trampoline
> 9: 996ce3c5429c = 9: 996ce3c5429c port: add daemonization support code
> 10: 096aa7db4af2 = 10: 096aa7db4af2 libproc: add Pinode_to_map()
> 11: 05a389f7bb6c = 11: 05a389f7bb6c libproc: fix double-free on error path
> 12: ac0d0931b565 ! 12: f859a10b8556 usdt: daemon
> @@ dtprobed/uprobes.c (new)
> + char *name, *final_name;
> +
> + if (usdt_probe_name == NULL) {
> -+ if (asprintf(&name, "dt_pid_%llx_%llx_%llx",
> ++ if (asprintf(&name, "dt_pid_%s%llx_%llx_%llx",
> ++ isret ? "ret_" : "",
> + (unsigned long long) dev,
> + (unsigned long long) ino,
> + (unsigned long long) addr) < 0)
> @@ dtprobed/uprobes.c (new)
> + if (!encoded_name)
> + return NULL;
> +
> -+ if (asprintf(&name, "dt_pid_%llx_%llx_%llx_%s",
> ++ if (asprintf(&name, "dt_pid_%s%llx_%llx_%llx_%s",
> ++ isret ? "ret_" : "",
> + (unsigned long long) dev,
> + (unsigned long long) ino,
> + (unsigned long long) addr, encoded_name) < 0) {
> 13: a96414cdc455 = 13: 2ec8eaaa947c drti: use /proc/self/maps
> 14: a1824dc560c8 = 14: 1090c63feec7 fbt, syscall: use getline(), not fgets()
> 15: da5df66da59e = 15: 91606778a81c dof: don't emit providers with no probes
> 16: 150064f83602 ! 16: b8a00c7ada78 usdt: DTrace userspace side
> @@ Commit message
> probes can be associated with more than one underlying probe (if the
> probe appears repeatedly in a program), so if it is repeatedly
> provide_pid'ed with different offsets, we spot this and chain it into
> - all the necessary underlying probes. (This means a bit of flailing
> - about, since we suddenly need a new tiny structure whose sole purpose
> - is to be in this list and point at the real probe.)
> + all the necessary underlying probes, and also keep track of all the
> + underlying probes associated with an overlying probe so we can enable
> + them all (see next item).
>
> - enabling gets a little more complex. We can no longer get away with
> just enabling the underlying probe, because things not in the
> enablings list don't get entries in the probename strtab, and their
> - probename is liable to be empty. So we intern both the overlying
> - *and* the underlying probe, and arrange for the overlying probe to
> - have no trampoline: in conjunction with a prior commit in this series
> - this causes only the underlying probe to have any BPF code generated
> - for it.
> + probename is liable to be empty: in any case, the underlying probes
> + aren't going to get ->enable called for them because the user never
> + named them (only their overlying probe). So we intern both the
> + overlying *and* the underlying probe in enablings (by getting
> + ->enable for the overlying probe to walk its list of underlying
> + probes and enable all of them), and arrange for the overlying probe
> + to have no trampoline: in conjunction with a prior commit in this
> + series this causes only the underlying probe to have any BPF code
> + generated for it.
>
> - Trampoline generation has to adapt to this, but also has to use a
> less kludgy way of figuring out the pids the trampoline applies to:
> @@ libdtrace/dt_pid.c: dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl
> + */
> + if (dpr && dpr->dpr_proc) {
> + assert(MUTEX_HELD(&dpr->dpr_lock));
> -+ if (Pinode_to_map(dpr->dpr_proc, dev, inum) == NULL) {
> -+ dt_dprintf("inode -> map for %i %lx:%lx failed\n", dpr->dpr_pid, dev, inum);
> ++ if (Pinode_to_map(dpr->dpr_proc, dev, inum) == NULL)
> + goto next;
> -+ }
> + }
> +
> + /*
> @@ libdtrace/dt_pid.c: dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl
> + if (pvp->impl->provide_pid(dtp, &psp) < 0 && pdp) {
> + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT,
> + "failed to instantiate probe %s for pid %d: %s",
> -+ pdp->prb, dpr->dpr_pid, strerror(errno));
> ++ pdp->prb, dpr->dpr_pid,
> ++ dtrace_errmsg(dtp, dtrace_errno(dtp)));
> + ret = -1;
> + }
> +
> @@ libdtrace/dt_prov_pid.c
> dt_list_t probes;
> + char *uprobe_name;
> + int dtrace_created;
> ++ int is_return;
> } pid_probe_t;
>
> -+typedef struct pid_overlying_probe {
> ++typedef struct pid_probe_list {
> + dt_list_t list; /* forward/back pointers */
> + dt_probe_t *probe; /* the probe in question */
> -+} pid_overlying_probe_t;
> ++} pid_probe_list_t;
> +
> static const dtrace_pattr_t pattr = {
> { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> return 0;
> }
>
> - static void probe_destroy(dtrace_hdl_t *dtp, void *datap)
> +-static void probe_destroy(dtrace_hdl_t *dtp, void *datap)
> ++/*
> ++ * Destroy an underlying probe.
> ++ */
> ++
> ++static void probe_udestroy(dtrace_hdl_t *dtp, void *datap)
> {
> - pid_probe_t *pp = datap;
> - tp_probe_t *tpp = pp->tp;
> + pid_probe_t *pp = datap;
> + tp_probe_t *tpp = pp->tp;
> -+ pid_overlying_probe_t *pop, *pop_next;
> ++ pid_probe_list_t *pop, *pop_next;
>
> dt_tp_destroy(dtp, tpp);
> dt_free(dtp, pp->fn);
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> dt_free(dtp, pp);
> }
>
> ++/*
> ++ * Destroy an overlying probe.
> ++ */
> ++static void probe_destroy(dtrace_hdl_t *dtp, void *datap)
> ++{
> ++ pid_probe_list_t *pup = datap, *pup_next;
> ++
> ++ for (pup = datap; pup != NULL; pup = pup_next) {
> ++ pup_next = dt_list_next(pup);
> ++ dt_free(dtp, pup);
> ++ }
> ++}
> ++
> ++
> +/*
> + * Look up or create an underlying (real) probe, corresponding directly to a
> + * uprobe. Since multiple pid and USDT probes may all map onto the same
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> +
> + /*
> + * The module for these probes is the mapping inode number, in hex
> -+ * (filled in by the caller): the function is unset, and the probe name
> -+ * is the offset. (This is amenable to change if it turns out to be
> -+ * inconvenient: but it's more or less arbitrary anyway. It just needs
> -+ * to be something that is determinable both for pid and USDT probes.)
> ++ * (filled in by the caller): the function is "underlying", and the
> ++ * probe name is the offset. (This is amenable to change if it turns
> ++ * out to be inconvenient: but it's more or less arbitrary anyway. It
> ++ * just needs to be something that is determinable both for pid and USDT
> ++ * probes.)
> ++ *
> ++ * Return probes get more info from the overlying probe, since they are
> ++ * in a different namespace to other uprobes and don't need to worry
> ++ * about colocation with usdt probes.
> + *
> + * XXX does this mean we lump together all probes with a given offset
> + * when doing wildcarding? This is hardly ideal. Do we want underlying
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> + pd.id = DTRACE_IDNONE;
> + pd.prv = prvname;
> + pd.mod = psp->pps_mod;
> -+ pd.fun = "";
> + pd.prb = psp->pps_prb;
> ++
> ++ if (psp && overlying && overlying->pps_type == DTPPT_RETURN)
> ++ pd.fun = psp->pps_fun;
> ++ else
> ++ pd.fun = "underlying";
> ++
> + prp = dt_probe_lookup(dtp, &pd);
> + if (prp == NULL) {
> + dt_provider_t *pvp;
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> + if (psp->pps_uprobe_name) {
> + pp->uprobe_name = strdup(psp->pps_uprobe_name);
> + if (pp->uprobe_name == NULL)
> -+ goto fail;
> ++ goto fail_errno;
> + }
> +
> + pp->dev = psp->pps_dev;
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> + if (pp->tp == NULL)
> + goto fail;
> +
> -+ prp = dt_probe_insert(dtp, pvp, prvname, pd.mod, pp->fn,
> -+ pd.prb, pp);
> ++ prp = dt_probe_insert(dtp, pvp, pd.prv, pd.mod, pd.fun, pd.prb,
> ++ pp);
> + if (prp == NULL)
> + goto fail;
> ++
> ++ if (overlying && overlying->pps_type == DTPPT_RETURN)
> ++ pp->is_return = 1;
> + }
> ++ else
> ++ pp = prp->prv_data;
> +
> + return prp;
> ++fail_errno:
> ++ dt_set_errno(dtp, errno);
> +fail:
> + probe_destroy(dtp, pp);
> + free(pp->uprobe_name);
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> static int provide_pid(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
> {
> char prv[DTRACE_PROVNAMELEN];
> - char mod[DTRACE_MODNAMELEN];
> - char prb[DTRACE_NAMELEN];
> +- char mod[DTRACE_MODNAMELEN];
> +- char prb[DTRACE_NAMELEN];
> - dt_provider_t *pidpvp;
> ++ const char *mod;
> ++ const char *prb;
> ++ char underlying_mod[DTRACE_MODNAMELEN];
> + char underlying_prb[DTRACE_NAMELEN];
> dt_provider_t *pvp;
> dtrace_probedesc_t pd;
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
> + dt_probe_t *prp, *uprp;
> + uint64_t off = psp->pps_addr;
> + pid_probespec_t pp_psp;
> -+ pid_overlying_probe_t *pop;
> ++ pid_probe_list_t *pop, *pup;
> +
> + if (psp->pps_type == DTPPT_UNDERLYING) {
> + if (provide_pid_underlying(dtp, psp))
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid_proc;
>
> + snprintf(underlying_prb, sizeof(underlying_prb), "%lx", off);
> +
> -+ strcpy(mod, psp->pps_mod);
> ++ mod = psp->pps_mod;
> switch (psp->pps_type) {
> case DTPPT_ENTRY:
> - strncpy(prb, "entry", sizeof(prb));
> -@@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
> - strncpy(prb, "return", sizeof(prb));
> +- strncpy(prb, "entry", sizeof(prb));
> ++ prb = "entry";
> + break;
> + case DTPPT_RETURN:
> +- strncpy(prb, "return", sizeof(prb));
> ++ prb = "return";
> ++ /*
> ++ * Return probes are in their own namespace and cannot collide
> ++ * with other probes: so we can give them a name that reflects
> ++ * their nature, since their nature is known (while other
> ++ * underlying probes might serve both USDT and pid probes at the
> ++ * same time, or pid and glob-offset, etc).
> ++ */
> ++ sprintf(underlying_prb, "return");
> break;
> case DTPPT_OFFSETS:
> - snprintf(prb, sizeof(prb), "%lx", off);
> -+ strcpy(prb, underlying_prb);
> ++ prb = underlying_prb;
> + break;
> + case DTPPT_USDT:
> -+ strcpy(prb, psp->pps_usdt_prb);
> -+ strcpy(mod, psp->pps_usdt_mod);
> ++ prb = psp->pps_usdt_prb;
> ++ mod = psp->pps_usdt_mod;
> break;
> default:
> - return 0;
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_pro
> - * "return", or the offset into the function (in hex).
> - */
> - snprintf(mod, sizeof(mod), "%lx", psp->pps_ino);
> -+ snprintf(mod, sizeof(mod), "%lx", psp->pps_inum);
> ++ snprintf(underlying_mod, sizeof(underlying_mod), "%lx", psp->pps_inum);
> +
> + /* Get (or create) the underlying probe. */
> + memcpy(&pp_psp, psp, sizeof(pid_probespec_t));
> + pp_psp.pps_type = DTPPT_UNDERLYING;
> -+ pp_psp.pps_mod = mod;
> ++ pp_psp.pps_mod = underlying_mod;
> + pp_psp.pps_prb = underlying_prb;
> + uprp = provide_pid_underlying(dtp, &pp_psp);
> +
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_pro
> - pp->tp = dt_tp_alloc(dtp);
> - if (pp->tp == NULL)
> - goto fail;
> -+ pop = dt_zalloc(dtp, sizeof(pid_overlying_probe_t));
> ++ /*
> ++ * Underlying and overlying probe list entries.
> ++ */
> ++ pop = dt_zalloc(dtp, sizeof(pid_probe_list_t));
> + if (pop == NULL)
> + return -1;
> ++
> ++ pup = dt_zalloc(dtp, sizeof(pid_probe_list_t));
> ++ if (pup == NULL) {
> ++ dt_free(dtp, pop);
> ++ return -1;
> ++ }
>
> - prp = dt_probe_insert(dtp, pidpvp, prvname, mod, psp->pps_fun,
> - prb, pp);
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_pro
> - /* Try to add the pid probe. */
> - prp = dt_probe_insert(dtp, pvp, prv, psp->pps_mod, psp->pps_fun, prb,
> - prp);
> -- if (prp == NULL)
> ++ pup->probe = uprp;
> + if (prp == NULL)
> - goto fail;
> -+ if (prp == NULL)
> -+ prp = dt_probe_insert(dtp, pvp, prv, psp->pps_mod, psp->pps_fun,
> -+ prb, uprp);
> ++ prp = dt_probe_insert(dtp, pvp, pd.prv, pd.mod, pd.fun, pd.prb,
> ++ pup);
> ++ else
> ++ dt_list_append((dt_list_t *) prp->prv_data, pup);
>
> - /* Add the pid probe to the list of probes for the main (real) probe. */
> - dt_list_append(&pp->probes, prp);
> + if (prp == NULL) {
> + dt_free(dtp, pop);
> ++ dt_free(dtp, pup);
> + return -1;
> + }
>
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_pro
> return 0;
> }
>
> -@@ libdtrace/dt_prov_pid.c: static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
> + static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
> {
> ++ const pid_probe_list_t *pup;
> assert(prp->prov->impl == &dt_pid_proc);
>
> - /* We need to enable the main (real) probe (if not enabled yet). */
> +- dt_probe_enable(dtp, (dt_probe_t *)prp->prv_data);
> + /*
> -+ * We need to enable the main (real) probe (if not enabled yet).
> ++ * We need to enable the underlying probes (if not enabled yet).
> + */
> - dt_probe_enable(dtp, (dt_probe_t *)prp->prv_data);
> -+
> ++ for (pup = prp->prv_data; pup != NULL; pup = dt_list_next(pup)) {
> ++ dt_probe_t *uprp = pup->probe;
> ++ dt_probe_enable(dtp, uprp);
> ++ }
> +
> + /*
> + * Finally, ensure we're in the list of enablings as well.
> @@ libdtrace/dt_prov_pid.c: static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
> + dt_irlist_t *dlp = &pcb->pcb_ir;
> + const dt_probe_t *prp = pcb->pcb_probe;
> + const pid_probe_t *pp = prp->prv_data;
> -+ const pid_overlying_probe_t *pop;
> ++ const pid_probe_list_t *pop;
> + uint_t lbl_exit = pcb->pcb_exitlbl;
>
> dt_cg_tramp_prologue(pcb);
>
> +@@ libdtrace/dt_prov_pid.c: static void trampoline(dt_pcb_t *pcb)
> + */
> +
> + dt_cg_tramp_copy_regs(pcb, BPF_REG_8);
> +- if (strcmp(pcb->pcb_probe->desc->prb, "return") == 0)
> ++ if (pp->is_return)
> + dt_cg_tramp_copy_rval_from_regs(pcb, BPF_REG_8);
> + else
> + dt_cg_tramp_copy_args_from_regs(pcb, BPF_REG_8);
> @@ libdtrace/dt_prov_pid.c: static void trampoline(dt_pcb_t *pcb)
> * are no assignments to %r0 possible in between the conditional
> * statements.
> @@ libdtrace/dt_prov_pid.c: static int attach(dtrace_hdl_t *dtp, const dt_probe_t *
> + return -ENOENT;
> +
> + prb = uprobe_create(pp->dev, pp->inum, pp->off, spec, NULL,
> -+ prp->desc->prb[0] == 'r');
> ++ pp->is_return);
> + free(spec);
> + if (prb == NULL)
> + return -ENOENT;
> @@ libdtrace/dt_prov_pid.c: static void detach(dtrace_hdl_t *dtp, const dt_probe_t
> .name = prvname,
> .prog_type = BPF_PROG_TYPE_KPROBE,
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid = {
> - .probe_destroy = &probe_destroy,
> + .attach = &attach,
> + .probe_info = &probe_info,
> + .detach = &detach,
> +- .probe_destroy = &probe_destroy,
> ++ .probe_destroy = &probe_udestroy,
> };
>
> +/*
> @@ libdtrace/dt_prov_pid.c: dt_provimpl_t dt_pid = {
> .name = prvname,
> .prog_type = BPF_PROG_TYPE_KPROBE,
> .provide_pid = &provide_pid,
> -- .enable = &enable,
> + .enable = &enable,
> - .trampoline = &trampoline,
> -+ .enable = &enable
> ++ .probe_destroy = &probe_destroy,
> };
> 17: b9c0adc1c3c8 = 17: 15c0acee80b0 usdt: testsuite updates
> 18: 88a895fe7844 = 18: 34606d200a69 test, usdt, pid: remove arg count check
> 19: e63129c83f3a = 19: 206b038b63b9 test: Signal an error if trigger does not exist
> 20: 5f634879aad5 ! 20: 6758bc71ad66 usdt: fix stack args on PT_REGS_ARGSTKBASE > 0 platforms
> @@ libdtrace/dt_prov_fbt.c: static void trampoline(dt_pcb_t *pcb)
>
> ## libdtrace/dt_prov_pid.c ##
> @@ libdtrace/dt_prov_pid.c: typedef struct pid_probe {
> - dt_list_t probes;
> char *uprobe_name;
> int dtrace_created;
> + int is_return;
> + int arg_setup;
> } pid_probe_t;
>
> - typedef struct pid_overlying_probe {
> + typedef struct pid_probe_list {
> @@ libdtrace/dt_prov_pid.c: static void probe_destroy(dtrace_hdl_t *dtp, void *datap)
> * If not found, we create a new probe.
> */
> @@ libdtrace/dt_prov_pid.c: static void probe_destroy(dtrace_hdl_t *dtp, void *data
> dtrace_probedesc_t pd;
> dt_probe_t *prp;
> @@ libdtrace/dt_prov_pid.c: static dt_probe_t *provide_pid_underlying(dtrace_hdl_t *dtp,
> - if (prp == NULL)
> - goto fail;
> - }
> -+ else
> -+ pp = prp->prv_data;
> -+
> + else
> + pp = prp->prv_data;
> +
> + /*
> + * USDT probes are positioned after argument setup for a function that
> + * is never actually called, so the stack is slightly different from the
> @@ libdtrace/dt_prov_pid.c: static dt_probe_t *provide_pid_underlying(dtrace_hdl_t
> + */
> + if (overlying && overlying->pps_type == DTPPT_USDT)
> + pp->arg_setup = 1;
> -
> ++
> return prp;
> - fail:
> + fail_errno:
> + dt_set_errno(dtp, errno);
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
> - pid_overlying_probe_t *pop;
> + pid_probe_list_t *pop, *pup;
>
> if (psp->pps_type == DTPPT_UNDERLYING) {
> - if (provide_pid_underlying(dtp, psp))
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_pro
> return -1;
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
> pp_psp.pps_type = DTPPT_UNDERLYING;
> - pp_psp.pps_mod = mod;
> + pp_psp.pps_mod = underlying_mod;
> pp_psp.pps_prb = underlying_prb;
> - uprp = provide_pid_underlying(dtp, &pp_psp);
> + uprp = provide_pid_underlying(dtp, &pp_psp, psp);
> @@ libdtrace/dt_prov_pid.c: static int provide_pid(dtrace_hdl_t *dtp, const pid_pro
> if (uprp == NULL)
> return -1;
> @@ libdtrace/dt_prov_pid.c: static void trampoline(dt_pcb_t *pcb)
> - if (strcmp(pcb->pcb_probe->desc->prb, "return") == 0)
> + if (pp->is_return)
> dt_cg_tramp_copy_rval_from_regs(pcb, BPF_REG_8);
> else
> - dt_cg_tramp_copy_args_from_regs(pcb, BPF_REG_8);
>
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel
More information about the DTrace-devel
mailing list