[DTrace-devel] [PATCH 1/2] usdt: is-enabled probe support
Kris Van Hees
kris.van.hees at oracle.com
Sat May 13 03:36:46 UTC 2023
On Wed, Apr 19, 2023 at 04:44:12PM +0100, Nick Alcock via DTrace-devel wrote:
> This implementation is in many ways similar to v1's, but contains one
> significant simplification: rather than is-enabled probes appearing to
> the user as a function that returns a 1 or 0, they appear as a function
> that returns void and takes the address of a local variable: the
> _IS_ENABLED macros use the GCC statement-expression extension
> to declare and initialize a distinct local for each use of the
> is-enabled probe:
>
> ({ uint32_t enabled = 0; \
> __dtraceenabled_foo___bar(&enabled); \
> enabled; })
>
> The is-enabled trampoline writes a 1 into this local variable. This
> allows the dt_link code to discard all the architecture-dependent code
> dealing with return value handling and treat is-enabled probes just like
> other USDT probes: it still tracks whether is-enabled probes are used,
> but barely uses the info for anything but DOF-version validation.
The last part of this paragraph is confusing. When you say "barely" it
makes me wonder what it uses the info for aside from DOF validation.
> The downside of this approach, of course, is that users need the
> statement-expression extension to work, and that old is-enabled probes
> from DTrace v1 aren't going to work without regeneration with dtrace
> -G. Neither of these seem likely to be serious problems in practice. (An
> upcoming commit will prevent v1 is-enabled probes from being mistaken
> for v2 probes.)
This needs to change in iew of the v1 prevention patch going in before this
one.
> We use #pragma system_header to suppress -pedantic warnings about
> use of the extension.
>
> Internally, there are tiny changes in the dtprobed and dt_pid
> uprobe-registration-and-creation layers to put is-enabled probes in a
> different uprobe group to prevent their names clashing with USDT probes
> with the same name (dt_pid_is_enabled/ rather than dt_pid/). Normal USDT
> probes enable the correspondinng is-enabled probe, if any, when they are
> enabled: those probes have custom trampoline that copy a 64-bit-wide 1
> into the first function parameter (and have truncated paramter-copying
> code that avoids preserving any parameter but the first, because there
> will never be any more).
>
paramter -> parameter
> Unanswered questions:
> - is any of the stuff in dt_prov_usdt unnecessary? There's quite a lot
> of boilerplate I am unsure of the need for.
> - the is-enabled probes somehow get enabled even if I forget to
> fix up the provider name to prvname_is_enabled in enable().
> I have no idea how, but it makes me wonder if the special "USDT
> enabling auto-enables the corresponding is-enabled probe" code is
> actually needed.
This is a bit of a problem. These issues should be resolved one way or another
before this goes in.
> Please ignore the code duplication between trampoline() and
> trampoline_is_enabled(): this is temporary to make it easier to make
> changes for getting globbed systemwide probing working later on.
>
> Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
> ---
> dtprobed/dtprobed.c | 8 +-
> libcommon/uprobes.c | 27 ++--
> libcommon/uprobes.h | 22 +--
> libdtrace/dt_cg.c | 34 ++++-
> libdtrace/dt_cg.h | 3 +-
> libdtrace/dt_link.c | 188 +++++++------------------
> libdtrace/dt_pid.c | 31 ++--
> libdtrace/dt_program.c | 28 ++--
> libdtrace/dt_prov_fbt.c | 4 +-
> libdtrace/dt_prov_uprobe.c | 178 ++++++++++++++++++++---
> test/unittest/usdt/tst.enable.d | 3 +-
> test/unittest/usdt/tst.enable_and.d | 3 +-
> test/unittest/usdt/tst.enable_and_2.d | 3 +-
> test/unittest/usdt/tst.enable_or_2.d | 3 +-
> test/unittest/usdt/tst.enable_return.d | 3 +-
> test/unittest/usdt/tst.enable_stmt.d | 3 +-
> test/unittest/usdt/tst.enabled.sh | 3 +-
> 17 files changed, 326 insertions(+), 218 deletions(-)
>
> diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c
> index af647d92d3355..3725dba2fe1c6 100644
> --- a/dtprobed/dtprobed.c
> +++ b/dtprobed/dtprobed.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace; DOF-consumption and USDT-probe-creation daemon.
> - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -323,15 +323,13 @@ create_probe(pid_t pid, dof_parsed_t *provider, dof_parsed_t *probe,
> {
> const char *mod, *fun, *prb;
>
> - if (tp->tracepoint.is_enabled)
> - return; /* Not yet implemented. */
> -
> mod = probe->probe.name;
> fun = mod + strlen(mod) + 1;
> prb = fun + strlen(fun) + 1;
>
> free(uprobe_create_from_addr(pid, tp->tracepoint.addr,
> - provider->provider.name, mod, fun, prb));
> + tp->tracepoint.is_enabled, provider->provider.name,
> + mod, fun, prb));
> }
>
> /*
> diff --git a/libcommon/uprobes.c b/libcommon/uprobes.c
> index 8a45a1f2a2b9c..8c3cc6280e9a1 100644
> --- a/libcommon/uprobes.c
> +++ b/libcommon/uprobes.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -209,13 +209,13 @@ uprobe_decode_name(const char *name)
> }
>
> char *
> -uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret)
> +uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret, int is_enabled)
> {
> char *name;
>
> - if (asprintf(&name, "dt_pid/%c_%llx_%llx_%lx", isret ? 'r' : 'p',
> - (unsigned long long)dev, (unsigned long long)ino,
> - (unsigned long)addr) < 0)
> + if (asprintf(&name, "dt_pid%s/%c_%llx_%llx_%lx", is_enabled?"_is_enabled":"",
> + isret ? 'r' : 'p', (unsigned long long)dev,
> + (unsigned long long)ino, (unsigned long)addr) < 0)
> return NULL;
>
> return name;
> @@ -229,7 +229,7 @@ uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret)
> */
> char *
> uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret,
> - const char *prv, const char *mod, const char *fun,
> + int is_enabled, const char *prv, const char *mod, const char *fun,
> const char *prb)
> {
> int fd = -1;
> @@ -261,7 +261,7 @@ uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int i
> return NULL;
> }
>
> - name = uprobe_name(dev, ino, addr, isret);
> + name = uprobe_name(dev, ino, addr, isret, is_enabled);
> if (!name)
> goto out;
>
> @@ -292,9 +292,10 @@ out:
> * systemwide uprobe list.)
> */
> char *
> -uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret)
> +uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret,
> + int is_enabled)
> {
> - return uprobe_create_named(dev, ino, addr, spec, isret,
> + return uprobe_create_named(dev, ino, addr, spec, isret, is_enabled,
> NULL, NULL, NULL, NULL);
> }
>
> @@ -304,7 +305,7 @@ uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret)
> * are set, they are passed down as the name of the corresponding DTrace probe.
> */
> char *
> -uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
> +uprobe_create_from_addr(pid_t pid, uint64_t addr, int is_enabled, const char *prv,
> const char *mod, const char *fun, const char *prb)
> {
> char *spec;
> @@ -316,7 +317,7 @@ uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
> return NULL;
>
> name = uprobe_create_named(mapp.pr_dev, mapp.pr_inum, addr, spec, 0,
> - prv, mod, fun, prb);
> + is_enabled, prv, mod, fun, prb);
> free(spec);
> return name;
> }
> @@ -325,13 +326,13 @@ uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
> * Destroy a uprobe for a given device, address, and spec.
> */
> int
> -uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret)
> +uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret, int is_enabled)
> {
> int fd = -1;
> int rc = -1;
> char *name;
>
> - name = uprobe_name(dev, ino, addr, isret);
> + name = uprobe_name(dev, ino, addr, isret, is_enabled);
> if (!name)
> goto out;
>
> diff --git a/libcommon/uprobes.h b/libcommon/uprobes.h
> index fde6ba40235a2..bd5f79d1cc9b9 100644
> --- a/libcommon/uprobes.h
> +++ b/libcommon/uprobes.h
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace; simple uprobe helper functions
> - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -15,17 +15,19 @@
>
> extern char *uprobe_spec_by_addr(pid_t pid, ps_prochandle *P, uint64_t addr,
> prmap_t *mapp);
> -extern char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret);
> +extern char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret,
> + int is_enabled);
> extern char *uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr,
> - const char *spec, int isret, const char *prv,
> - const char *mod, const char *fun,
> - const char *prb);
> + const char *spec, int isret, int is_enabled,
> + const char *prv, const char *mod,
> + const char *fun, const char *prb);
> extern char *uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec,
> - int isret);
> -extern char *uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
> - const char *mod, const char *fun,
> - const char *prb);
> -extern int uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret);
> + int isret, int is_enabled);
> +extern char *uprobe_create_from_addr(pid_t pid, uint64_t addr, int is_enabled,
> + const char *prv, const char *mod,
> + const char *fun, const char *prb);
> +extern int uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret,
> + int is_enabled);
> extern char *uprobe_encode_name(const char *);
> extern char *uprobe_decode_name(const char *);
>
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index 14ae21f764f59..27ca56438afac 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -314,11 +314,13 @@ dt_cg_tramp_copy_regs(dt_pcb_t *pcb)
> * function: if zero, they are laid out as at the call instruction, before the
> * function is called (as is done for e.g. usdt).
> *
> + * if one_arg is set, copy only one arg.
I don't think this is a good idea. Since this is a special case, you might
as well just do the load/store conbination for arg0 in the trampoline, rather
than changing this function for a very special case.
> + *
> * The caller must ensure that %r7 and %r8 contain the values set by the
> * dt_cg_tramp_prologue*() functions.
> */
> void
> -dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called)
> +dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called, int one_arg)
> {
> dtrace_hdl_t *dtp = pcb->pcb_hdl;
> dt_irlist_t *dlp = &pcb->pcb_ir;
> @@ -332,6 +334,10 @@ dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called)
> */
> emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, PT_REGS_ARG0));
> emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0));
> +
> + if (one_arg)
> + return;
> +
> emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, PT_REGS_ARG1));
> emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_0));
> emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, PT_REGS_ARG2));
> @@ -1014,6 +1020,32 @@ dt_cg_memcpy(dt_irlist_t *dlp, dt_regset_t *drp, int dst, int src, size_t size)
> dt_regset_free(drp, BPF_REG_0);
> }
>
> +/*
> + * Copy the given immediate value into the address given by the specified probe
> + * argument.
> + */
> +void
> +dt_cg_tramp_copyout_val(dt_pcb_t *pcb, uint32_t val, int arg)
> +{
> + dt_regset_t *drp = pcb->pcb_regs;
> + dt_irlist_t *dlp = &pcb->pcb_ir;
> +
> + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), val));
> +
> + if (dt_regset_xalloc_args(drp) == -1)
> + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(arg)));
> + emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP));
> + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0)));
> + emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t)));
> + dt_regset_xalloc(drp, BPF_REG_0);
> + emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_write_user));
> +
> + /* XXX any point error-checking here? What can we possibly do? */
> + dt_regset_free(drp, BPF_REG_0);
> + dt_regset_free_args(drp);
> +}
I'd rather see this be in the trampoline code of the provider. There is no
other code using this so there is no need to have a generic function. And it
is very much tied to the implementation details of is-enabled probes.
> static void
> dt_cg_spill_store(int reg)
> {
> diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h
> index 95bf507ff7fb1..320862682cb43 100644
> --- a/libdtrace/dt_cg.h
> +++ b/libdtrace/dt_cg.h
> @@ -24,9 +24,10 @@ extern void dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act);
> extern void dt_cg_tramp_prologue(dt_pcb_t *pcb);
> extern void dt_cg_tramp_clear_regs(dt_pcb_t *pcb);
> extern void dt_cg_tramp_copy_regs(dt_pcb_t *pcb);
> -extern void dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called);
> +extern void dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called, int one_arg);
See above - should not be needed.
> extern void dt_cg_tramp_copy_pc_from_regs(dt_pcb_t *pcb);
> extern void dt_cg_tramp_copy_rval_from_regs(dt_pcb_t *pcb);
> +extern void dt_cg_tramp_copyout_val(dt_pcb_t *pcb, uint32_t val, int arg);
See above - should not be needed.
> extern void dt_cg_tramp_save_args(dt_pcb_t *pcb);
> extern void dt_cg_tramp_restore_args(dt_pcb_t *pcb);
> extern void dt_cg_tramp_call_clauses(dt_pcb_t *pcb, const dt_probe_t *prp,
> diff --git a/libdtrace/dt_link.c b/libdtrace/dt_link.c
> index 5daaf2b02212a..e6059e9840cde 100644
> --- a/libdtrace/dt_link.c
> +++ b/libdtrace/dt_link.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -775,8 +775,7 @@ dt_elf_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn,
>
> /*ARGSUSED*/
> static int
> -dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> - uint32_t *off)
> +dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off)
> {
> uint32_t *ip;
>
> @@ -801,25 +800,18 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> * invocation. Check to see if the present instruction sequence matches
> * the one we would install below.
> */
> - if (isenabled) {
> - if (ip[0] == DT_OP_NOP) {
> + if (DT_IS_RESTORE(ip[1])) {
> + if (ip[0] == DT_OP_RET) {
> (*off) += sizeof(ip[0]);
> return 0;
> }
> + } else if (DT_IS_MOV_O7(ip[1])) {
> + if (DT_IS_RETL(ip[0]))
> + return 0;
> } else {
> - if (DT_IS_RESTORE(ip[1])) {
> - if (ip[0] == DT_OP_RET) {
> - (*off) += sizeof(ip[0]);
> - return 0;
> - }
> - } else if (DT_IS_MOV_O7(ip[1])) {
> - if (DT_IS_RETL(ip[0]))
> - return 0;
> - } else {
> - if (ip[0] == DT_OP_NOP) {
> - (*off) += sizeof(ip[0]);
> - return 0;
> - }
> + if (ip[0] == DT_OP_NOP) {
> + (*off) += sizeof(ip[0]);
> + return 0;
> }
> }
>
> @@ -832,58 +824,32 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> return -1;
> }
>
> - if (isenabled) {
> - /*
> - * It would necessarily indicate incorrect usage if an is-
> - * enabled probe were tail-called so flag that as an error.
> - * It's also potentially (very) tricky to handle gracefully,
> - * but could be done if this were a desired use scenario.
> - */
> - if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) {
> - dt_dprintf("tail call to is-enabled probe at %llx\n",
> - (unsigned long long)rela->r_offset);
> - return -1;
> - }
> -
> -
> - /*
> - * On SPARC, we take advantage of the fact that the first
> - * argument shares the same register as for the return value.
> - * The macro handles the work of zeroing that register so we
> - * don't need to do anything special here. We instrument the
> - * instruction in the delay slot as we'll need to modify the
> - * return register after that instruction has been emulated.
> - */
> - ip[0] = DT_OP_NOP;
> + /*
> + * If the call is followed by a restore, it's a tail call so
> + * change the call to a ret. If the call if followed by a mov
> + * of a register into %o7, it's a tail call in leaf context
> + * so change the call to a retl-like instruction that returns
> + * to that register value + 8 (rather than the typical %o7 +
> + * 8); the delay slot instruction is left, but should have no
> + * effect. Otherwise we change the call to be a nop. We
> + * identify the subsequent instruction as the probe point in
> + * all but the leaf tail-call case to ensure that arguments to
> + * the probe are complete and consistent. An astute, though
> + * largely hypothetical, observer would note that there is the
> + * possibility of a false-positive probe firing if the function
> + * contained a branch to the instruction in the delay slot of
> + * the call. Fixing this would require significant in-kernel
> + * modifications, and isn't worth doing until we see it in the
> + * wild.
> + */
> + if (DT_IS_RESTORE(ip[1])) {
> + ip[0] = DT_OP_RET;
> (*off) += sizeof(ip[0]);
> + } else if (DT_IS_MOV_O7(ip[1])) {
> + ip[0] = DT_MAKE_RETL(DT_RS2(ip[1]));
> } else {
> - /*
> - * If the call is followed by a restore, it's a tail call so
> - * change the call to a ret. If the call if followed by a mov
> - * of a register into %o7, it's a tail call in leaf context
> - * so change the call to a retl-like instruction that returns
> - * to that register value + 8 (rather than the typical %o7 +
> - * 8); the delay slot instruction is left, but should have no
> - * effect. Otherwise we change the call to be a nop. We
> - * identify the subsequent instruction as the probe point in
> - * all but the leaf tail-call case to ensure that arguments to
> - * the probe are complete and consistent. An astute, though
> - * largely hypothetical, observer would note that there is the
> - * possibility of a false-positive probe firing if the function
> - * contained a branch to the instruction in the delay slot of
> - * the call. Fixing this would require significant in-kernel
> - * modifications, and isn't worth doing until we see it in the
> - * wild.
> - */
> - if (DT_IS_RESTORE(ip[1])) {
> - ip[0] = DT_OP_RET;
> - (*off) += sizeof(ip[0]);
> - } else if (DT_IS_MOV_O7(ip[1])) {
> - ip[0] = DT_MAKE_RETL(DT_RS2(ip[1]));
> - } else {
> - ip[0] = DT_OP_NOP;
> - (*off) += sizeof(ip[0]);
> - }
> + ip[0] = DT_OP_NOP;
> + (*off) += sizeof(ip[0]);
> }
>
> return 0;
> @@ -895,13 +861,9 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> #define DT_OP_RET 0xc3
> #define DT_OP_CALL 0xe8
> #define DT_OP_JMP32 0xe9
> -#define DT_OP_REX_RAX 0x48
> -#define DT_OP_XOR_EAX_0 0x33
> -#define DT_OP_XOR_EAX_1 0xc0
>
> static int
> -dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> - uint32_t *off)
> +dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off)
> {
> uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1);
> uint8_t ret;
> @@ -924,37 +886,20 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> */
> if (GELF_R_TYPE(rela->r_info) != R_386_PC32 &&
> GELF_R_TYPE(rela->r_info) != R_386_PLT32 &&
> - GELF_R_TYPE(rela->r_info) != R_386_NONE)
> + GELF_R_TYPE(rela->r_info) != R_386_NONE) {
> + dt_dprintf("unexpected reloc type %li\n", GELF_R_TYPE(rela->r_info));
> return -1;
> + }
>
> /*
> * We may have already processed this object file in an earlier linker
> * invocation. Check to see if the present instruction sequence matches
> - * the one we would install. For is-enabled probes, we advance the
> - * offset to the first nop instruction in the sequence to match the
> - * text modification code below.
> + * the one we would install.
> */
> - if (!isenabled) {
> - if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) &&
> - ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP &&
> - ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP)
> - return 0;
> - } else if (dtp->dt_oflags & DTRACE_O_ILP32) {
> - if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 &&
> - (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) &&
> - ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) {
> - (*off) += 2;
> - return 0;
> - }
> - } else {
> - if (ip[0] == DT_OP_REX_RAX &&
> - ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 &&
> - (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) &&
> - ip[4] == DT_OP_NOP) {
> - (*off) += 3;
> - return 0;
> - }
> - }
> + if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) &&
> + ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP &&
> + ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP)
> + return 0;
>
> /*
> * We expect either a call instrution with a 32-bit displacement or a
> @@ -969,33 +914,13 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP;
>
> /*
> - * Establish the instruction sequence -- all nops for probes, and an
> - * instruction to clear the return value register (%eax/%rax) followed
> - * by nops for is-enabled probes. For is-enabled probes, we advance
> - * the offset to the first nop. This isn't stricly necessary but makes
> - * for more readable disassembly when the probe is enabled.
> + * Establish the instruction sequence: all nops.
> */
> - if (!isenabled) {
> - ip[0] = ret;
> - ip[1] = DT_OP_NOP;
> - ip[2] = DT_OP_NOP;
> - ip[3] = DT_OP_NOP;
> - ip[4] = DT_OP_NOP;
> - } else if (dtp->dt_oflags & DTRACE_O_ILP32) {
> - ip[0] = DT_OP_XOR_EAX_0;
> - ip[1] = DT_OP_XOR_EAX_1;
> - ip[2] = ret;
> - ip[3] = DT_OP_NOP;
> - ip[4] = DT_OP_NOP;
> - (*off) += 2;
> - } else {
> - ip[0] = DT_OP_REX_RAX;
> - ip[1] = DT_OP_XOR_EAX_0;
> - ip[2] = DT_OP_XOR_EAX_1;
> - ip[3] = ret;
> - ip[4] = DT_OP_NOP;
> - (*off) += 3;
> - }
> + ip[0] = ret;
> + ip[1] = DT_OP_NOP;
> + ip[2] = DT_OP_NOP;
> + ip[3] = DT_OP_NOP;
> + ip[4] = DT_OP_NOP;
>
> return 0;
> }
> @@ -1008,8 +933,7 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> #define DT_OP_JUMP26 0x14000000
>
> static int
> -dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> - uint32_t *off)
> +dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off)
> {
> uint32_t *ip;
>
> @@ -1050,11 +974,9 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
> }
>
> /*
> - * On arm64, we do not have to differentiate between regular probes and
> - * is-enabled probes. Both cases are encoded as a regular branch for
> - * non-tail call locations, and a jump for tail call locations. Calls
> - * are to be converted into a no-op whereas jumps should become a
> - * return.
> + * On arm64, we encode all probes as a regular branch for non-tail call
> + * locations, and a jump for tail call locations. Calls are to be
> + * converted into a no-op whereas jumps should become a return.
> */
> if (ip[0] == DT_OP_CALL26)
> ip[0] = DT_OP_NOP;
> @@ -1502,10 +1424,8 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
> assert(fsym.st_value <= rela.r_offset);
>
> off = rela.r_offset - fsym.st_value;
> - if (dt_modtext(dtp, data_tgt->d_buf, eprobe,
> - &rela, &off) != 0) {
> + if (dt_modtext(dtp, data_tgt->d_buf, &rela, &off) != 0)
> goto err;
> - }
>
> if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0)
> return dt_link_error(dtp, elf, fd, bufs,
> diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
> index fd9e0d1da62dd..06bd7a4dd24aa 100644
> --- a/libdtrace/dt_pid.c
> +++ b/libdtrace/dt_pid.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -626,6 +626,8 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
> dev_t dev;
> ino_t inum;
> uint64_t off;
> + int is_enabled;
> + const char *fmt;
> unsigned long long dev_ll, inum_ll;
> char *inum_str = NULL;
> char *spec = NULL;
> @@ -634,11 +636,23 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
> pid_probespec_t psp;
>
> #define UPROBE_PREFIX "p:dt_pid/p_"
> - if (strncmp(buf, UPROBE_PREFIX, strlen(UPROBE_PREFIX)) != 0)
> +#define UPROBE_IS_ENABLED_PREFIX "p:dt_pid_is_enabled/p_"
> +#define UPROBE_PROBE_FMT "%llx_%llx_%lx %ms P%m[^= ]=\\1 M%m[^= ]=\\2 F%m[^= ]=\\3 N%m[^= ]=\\4"
> +#define UPROBE_FMT UPROBE_PREFIX UPROBE_PROBE_FMT
> +#define UPROBE_IS_ENABLED_FMT UPROBE_IS_ENABLED_PREFIX UPROBE_PROBE_FMT
> +
> + if (strncmp(buf, UPROBE_PREFIX, strlen(UPROBE_PREFIX)) == 0) {
> + is_enabled = 0;
> + fmt = UPROBE_FMT;
> + } else if (strncmp(buf, UPROBE_IS_ENABLED_PREFIX,
> + strlen(UPROBE_IS_ENABLED_PREFIX)) == 0) {
> + is_enabled = 1;
> + fmt = UPROBE_IS_ENABLED_FMT;
> + }
> + else /* Not a DTrace uprobe. */
> continue;
>
> - switch (sscanf(buf, "p:dt_pid/p_%llx_%llx_%lx %ms "
> - "P%m[^= ]=\\1 M%m[^= ]=\\2 F%m[^= ]=\\3 N%m[^= ]=\\4", &dev_ll, &inum_ll,
> + switch (sscanf(buf, fmt, &dev_ll, &inum_ll,
> &off, &spec, &eprv, &emod, &efun, &eprb)) {
> case 8: /* Includes dtrace probe names: decode them. */
> prv = uprobe_decode_name(eprv);
> @@ -664,9 +678,7 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
> * Make the underlying probe, if not already present.
> */
> memset(&psp, 0, sizeof(pid_probespec_t));
> -
> - /* FIXME: DTPPT_IS_ENABLED needs to be supported also. */
> - psp.pps_type = DTPPT_OFFSETS;
> + psp.pps_type = is_enabled ? DTPPT_IS_ENABLED : DTPPT_OFFSETS;
>
> /*
> * These components are only used for creation of an underlying
> @@ -732,8 +744,9 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr,
>
> if (pvp->impl->provide_probe(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,
> + "failed to instantiate %sprobe %s for pid %d: %s",
> + is_enabled ? "is-enabled ": "", pdp->prb,
> + dpr->dpr_pid,
> dtrace_errmsg(dtp, dtrace_errno(dtp)));
> ret = -1;
> }
> diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
> index a95d0eefdb1a2..a4b052fc47603 100644
> --- a/libdtrace/dt_program.c
> +++ b/libdtrace/dt_program.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -368,12 +368,8 @@ dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
> return dt_set_errno(dtp, errno);
>
> if (fprintf(infop->dthi_out,
> - "#if !defined(__aarch64__) && !defined(__sparc)\n"
> - "extern int __dtraceenabled_%s___%s(void);\n"
> - "#else\n"
> - "extern int __dtraceenabled_%s___%s(long);\n"
> - "#endif\n",
> - infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
> + "extern void __dtraceenabled_%s___%s(uint32_t *flag);\n",
> + infop->dthi_pfname, fname) < 0)
> return dt_set_errno(dtp, errno);
>
> return 0;
> @@ -436,17 +432,18 @@ dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
>
> if (!infop->dthi_empty) {
> if (fprintf(infop->dthi_out,
> - "#if !defined(__aarch64__) && !defined(__sparc)\n"
> + "#ifdef __GNUC__\n"
> "#define\t%s_%s_ENABLED() \\\n"
> - "\t__dtraceenabled_%s___%s()\n"
> + "\t({ uint32_t enabled = 0; \\\n"
> + "\t__dtraceenabled_%s___%s(&enabled); \\\n"
> + "\t enabled; })\n"
> "#else\n"
> - "#define\t%s_%s_ENABLED() \\\n"
> - "\t__dtraceenabled_%s___%s(0)\n"
> + "#define\t%s_%s_ENABLED() (1)\\n"
This seems to be a bit problematic. If the code is not compiled with GCC then
we silently turn is-enabled probes into a true value? We should preferably
have an alternative that does not depend on GCC extension syntax, or worst case
at least issue a warning that we do not support is-enabled probes on whatever
compiler people are using.
> + "#endif\n"
> "#endif\n",
> infop->dthi_pmname, mname,
> infop->dthi_pfname, fname,
> - infop->dthi_pmname, mname,
> - infop->dthi_pfname, fname) < 0)
> + infop->dthi_pmname, mname) < 0)
> return dt_set_errno(dtp, errno);
>
> } else {
> @@ -536,6 +533,11 @@ dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
> if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
> return -1;
>
> + if (fprintf(out, "#ifdef\t__GNUC__\n"
> + "#pragma GCC system_header\n"
> + "#endif\n\n") < 0)
> + return -1;
> +
> while ((pvp = dt_htab_next(dtp->dt_provs, &it)) != NULL) {
> if (dt_header_provider(dtp, pvp, out) != 0) {
> dt_htab_next_destroy(it);
> diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
> index add76c55f3ae8..be0e6248e6ac0 100644
> --- a/libdtrace/dt_prov_fbt.c
> +++ b/libdtrace/dt_prov_fbt.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> *
> @@ -175,7 +175,7 @@ static void trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, BPF_REG_0, -1);
> emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0));
> } else
> - dt_cg_tramp_copy_args_from_regs(pcb, 1);
> + dt_cg_tramp_copy_args_from_regs(pcb, 1, 0);
See above - not needed.
> dt_cg_tramp_epilogue(pcb);
> }
>
> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> index f85d15297e910..d3bd2097ac0ae 100644
> --- a/libdtrace/dt_prov_uprobe.c
> +++ b/libdtrace/dt_prov_uprobe.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> *
> @@ -23,13 +23,15 @@
> #include "uprobes.h"
>
> /* Provider name for the underlying probes. */
> -static const char prvname[] = "uprobe";
> +static const char prvname[] = "uprobe";
> +static const char prvname_is_enabled[] = "uprobe__is_enabled";
>
> -#define UPROBE_EVENTS TRACEFS "uprobe_events"
> +#define UPROBE_EVENTS TRACEFS "uprobe_events"
>
> #define PP_IS_MINE 1
> #define PP_IS_RETURN 2
> #define PP_IS_FUNCALL 4
> +#define PP_IS_ENABLED 8
>
> typedef struct dt_uprobe {
> dev_t dev;
> @@ -54,12 +56,15 @@ static const dtrace_pattr_t pattr = {
> { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
> };
>
> +dt_provimpl_t dt_uprobe_is_enabled;
> dt_provimpl_t dt_pid;
> dt_provimpl_t dt_usdt;
>
> static int populate(dtrace_hdl_t *dtp)
> {
> dt_provider_create(dtp, dt_uprobe.name, &dt_uprobe, &pattr);
> + dt_provider_create(dtp, dt_uprobe_is_enabled.name,
> + &dt_uprobe_is_enabled, &pattr);
> dt_provider_create(dtp, dt_pid.name, &dt_pid, &pattr);
> dt_provider_create(dtp, dt_usdt.name, &dt_usdt, &pattr);
>
> @@ -115,6 +120,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> dtrace_probedesc_t pd;
> dt_probe_t *prp;
> dt_uprobe_t *upp;
> + int is_enabled = 0;
>
> /*
> * The underlying probes (uprobes) represent the tracepoints that pid
> @@ -136,6 +142,9 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> case DTPPT_RETURN:
> strcpy(prb, "return");
> break;
> + case DTPPT_IS_ENABLED:
> + is_enabled = 1;
> + /* Fallthrough. */
> case DTPPT_ENTRY:
> case DTPPT_OFFSETS:
> snprintf(prb, sizeof(prb), "%lx", psp->pps_off);
> @@ -146,7 +155,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> }
>
> pd.id = DTRACE_IDNONE;
> - pd.prv = prvname;
> + pd.prv = is_enabled ? prvname_is_enabled : prvname;
> pd.mod = mod;
> pd.fun = psp->pps_fun;
> pd.prb = prb;
> @@ -156,7 +165,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> dt_provider_t *pvp;
>
> /* Get the provider for underlying probes. */
> - pvp = dt_provider_lookup(dtp, prvname);
> + pvp = dt_provider_lookup(dtp, pd.prv);
> if (pvp == NULL)
> return NULL;
>
> @@ -181,8 +190,18 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> } else
> upp = prp->prv_data;
>
> - if (psp->pps_type == DTPPT_RETURN)
> - upp->flags |= PP_IS_RETURN;
> + switch (psp->pps_type) {
> + case DTPPT_RETURN:
> + upp->flags |= PP_IS_RETURN;
> + break;
> + case DTPPT_IS_ENABLED:
> + upp->flags |= PP_IS_ENABLED;
> + break;
> + default: ;
> + /*
> + * No flags needed for other types.
> + */
> + }
>
> return prp;
>
> @@ -302,7 +321,8 @@ static int provide_pid_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
>
> static int provide_usdt_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
> {
> - if (psp->pps_type != DTPPT_OFFSETS) {
> + if (psp->pps_type != DTPPT_OFFSETS &&
> + psp->pps_type != DTPPT_IS_ENABLED) {
> dt_dprintf("pid: unknown USDT probe type %i\n", psp->pps_type);
> return -1;
> }
> @@ -310,7 +330,7 @@ static int provide_usdt_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp)
> return provide_probe(dtp, psp, psp->pps_prb, &dt_usdt, PP_IS_FUNCALL);
> }
>
> -static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
> +static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp, int is_enabled)
This seems a bit confusing to me. THe is_enabled argument seems to indicate
whether we're trying to enable an is-enabled probe but if I read this correctly
it actually enabled both the USDT probe and its related is-enabled probes.
Perhaps is_usdt might be a better name? Or can we determine the type of probe
based on the passed in prp (e.g. look at what the provider is)?
> {
> const list_probe_t *pup;
>
> @@ -318,12 +338,26 @@ static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
>
> /*
> * We need to enable the underlying probes (if not enabled yet).
> + *
> + * If necessary, we need to enable is-enabled probes too (if they
> + * exist).
> */
> for (pup = prp->prv_data; pup != NULL; pup = dt_list_next(pup)) {
> dt_probe_t *uprp = pup->probe;
> dt_probe_enable(dtp, uprp);
> }
>
> + if (is_enabled) {
> + dtrace_probedesc_t pd;
> + dt_probe_t *iep;
> +
> + memcpy(&pd, &prp->desc, sizeof(pd));
> + pd.prv = prvname_is_enabled;
> + iep = dt_probe_lookup(dtp, &pd);
> + if (iep != NULL)
> + dt_probe_enable(dtp, iep);
> + }
> +
> /*
> * Finally, ensure we're in the list of enablings as well.
> * (This ensures that, among other things, the probes map
> @@ -333,6 +367,19 @@ static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
> dt_list_append(&dtp->dt_enablings, prp);
> }
>
> +static void enable_plain(dtrace_hdl_t *dtp, dt_probe_t *prp)
Surely enable_pid would be better?
> +{
> + enable(dtp, prp, 0);
> +}
> +
> +/*
> + * USDT enabling has to enable any is-enabled probes as well.
> + */
> +static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp)
> +{
> + enable(dtp, prp, 1);
> +}
> +
> /*
> * Generate a BPF trampoline for a pid probe.
> *
> @@ -365,7 +412,8 @@ static void trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> dt_cg_tramp_copy_rval_from_regs(pcb);
> else
> dt_cg_tramp_copy_args_from_regs(pcb,
> - !(upp->flags & PP_IS_FUNCALL));
> + !(upp->flags & PP_IS_FUNCALL),
> + 0);
See above - not needed.
> /*
> * Retrieve the PID of the process that caused the probe to fire.
> @@ -420,6 +468,88 @@ static void trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> dt_cg_tramp_return(pcb);
> }
>
> +/*
> + * Generate a BPF trampoline for an is-enabled probe. The is-enabled probe
> + * prototype looks like:
> + *
> + * int is_enabled(int *arg)
> + *
> + * The trampoline dereferences the passed-in arg and writes 1 into it if this is
> + * one of the processes for which the probe is enabled.
> + */
> +static void trampoline_is_enabled(dt_pcb_t *pcb, uint_t exitlbl)
> +{
> + dt_irlist_t *dlp = &pcb->pcb_ir;
> + const dt_probe_t *prp = pcb->pcb_probe;
> + const dt_uprobe_t *upp = prp->prv_data;
> + const list_probe_t *pop;
> + uint_t lbl_exit = pcb->pcb_exitlbl;
> +
> + dt_cg_tramp_prologue(pcb);
> +
> + /*
> + * After the dt_cg_tramp_prologue() call, we have:
> + * // (%r7 = dctx->mst)
> + * // (%r8 = dctx->ctx)
> + */
> +
> + dt_cg_tramp_copy_regs(pcb);
> + dt_cg_tramp_copy_args_from_regs(pcb,
> + !(upp->flags & PP_IS_FUNCALL), 1);
See above - just inline the copying of the one argument.
> + /*
> + * Retrieve the PID of the process that caused the probe to fire.
> + */
> + emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> + emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
> +
> + /*
> + * Generate a composite conditional clause, as above, except that rather
> + * than emitting call_clauses, we emit copyouts instead, using
> + * dt_cg_copyout_reg().
> + *
> + * if (pid == PID1) {
> + * *arg0 = 1;
> + * goto exit;
> + * } else if (pid == PID2) {
> + * *arg0 = 1;
> + * goto exit;
> + * } else if (pid == ...) {
> + * < ... >
> + * }
Can't this be rendered in code where the *arg0 = 1 occurs just once, and any
matching case jumps to that code?
> + *
> + * It is valid and safe to use %r0 to hold the pid value because there
> + * are no assignments to %r0 possible in between the conditional
> + * statements.
> + */
> + for (pop = dt_list_next(&upp->probes); pop != NULL;
> + pop = dt_list_next(pop)) {
> + const dt_probe_t *pprp = pop->probe;
> + uint_t lbl_next = dt_irlist_label(dlp);
> + pid_t pid;
> + dt_ident_t *idp;
> +
> + pid = dt_pid_get_pid(pprp->desc, pcb->pcb_hdl, pcb, NULL);
> + assert(pid != -1);
> +
> + idp = dt_dlib_add_probe_var(pcb->pcb_hdl, pprp);
> + assert(idp != NULL);
> +
> + /*
> + * Check whether this pid-provider probe serves the current
> + * process, and copy out a 1 into arg 0 if so.
> + */
> + emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, pid, lbl_next));
> + dt_cg_tramp_copyout_val(pcb, 1, 0);
Just inline it.
> + emit(dlp, BPF_JUMP(lbl_exit));
> + emitl(dlp, lbl_next,
> + BPF_NOP());
> + }
> +
> + dt_cg_tramp_return(pcb);
> +}
> +
> +
> static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
> {
> dt_uprobe_t *upp = prp->prv_data;
> @@ -441,7 +571,7 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
> return -ENOENT;
>
> prb = uprobe_create(upp->dev, upp->inum, upp->off, spec,
> - upp->flags & PP_IS_RETURN);
> + upp->flags & PP_IS_RETURN, 0);
> free(spec);
>
> /*
> @@ -453,7 +583,8 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
>
> if (prb == NULL)
> prb = uprobe_name(upp->dev, upp->inum, upp->off,
> - upp->flags & PP_IS_RETURN);
> + upp->flags & PP_IS_RETURN,
> + upp->flags & PP_IS_ENABLED);
>
> /* open format file */
> rc = asprintf(&fn, "%s%s/format", EVENTSFS, prb);
> @@ -509,8 +640,9 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
> if (!(upp->flags & PP_IS_MINE))
> return;
>
> - uprobe_delete(upp->dev, upp->inum, upp->off, upp->flags & PP_IS_RETURN);
> -}
> + uprobe_delete(upp->dev, upp->inum, upp->off, upp->flags & PP_IS_RETURN,
> + upp->flags & PP_IS_ENABLED);
> + }
>
> /*
> * Used for underlying probes (uprobes).
> @@ -526,6 +658,20 @@ dt_provimpl_t dt_uprobe = {
> .probe_destroy = &probe_destroy_underlying,
> };
>
> +/*
> + * Used for underlying is-enabled uprobes.
> + */
> +dt_provimpl_t dt_uprobe_is_enabled = {
> + .name = prvname_is_enabled,
> + .prog_type = BPF_PROG_TYPE_KPROBE,
> + .populate = &populate,
> + .trampoline = &trampoline_is_enabled,
> + .attach = &attach,
> + .probe_info = &probe_info,
> + .detach = &detach,
> + .probe_destroy = &probe_destroy_underlying,
> +};
> +
> /*
> * Used for pid probes.
> */
> @@ -533,7 +679,7 @@ dt_provimpl_t dt_pid = {
> .name = "pid",
> .prog_type = BPF_PROG_TYPE_UNSPEC,
> .provide_probe = &provide_pid_probe,
> - .enable = &enable,
> + .enable = &enable_plain,
> .probe_destroy = &probe_destroy,
> };
>
> @@ -544,6 +690,6 @@ dt_provimpl_t dt_usdt = {
> .name = "usdt",
> .prog_type = BPF_PROG_TYPE_UNSPEC,
> .provide_probe = &provide_usdt_probe,
> - .enable = &enable,
> + .enable = &enable_usdt,
> .probe_destroy = &probe_destroy,
> };
> diff --git a/test/unittest/usdt/tst.enable.d b/test/unittest/usdt/tst.enable.d
> index 1211af97290ad..a95eee2009174 100644
> --- a/test/unittest/usdt/tst.enable.d
> +++ b/test/unittest/usdt/tst.enable.d
> @@ -1,11 +1,10 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
>
> -/* @@xfail: dtv2, no is-enabled probes yet */
> /* @@trigger: usdt-tst-special 2 */
>
> #pragma D option quiet
> diff --git a/test/unittest/usdt/tst.enable_and.d b/test/unittest/usdt/tst.enable_and.d
> index 94a053ef43bbb..9715c9c11eaa4 100644
> --- a/test/unittest/usdt/tst.enable_and.d
> +++ b/test/unittest/usdt/tst.enable_and.d
> @@ -1,11 +1,10 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
>
> -/* @@xfail: dtv2, no is-enabled probes yet */
> /* @@trigger: usdt-tst-special 5 */
>
> #pragma D option quiet
> diff --git a/test/unittest/usdt/tst.enable_and_2.d b/test/unittest/usdt/tst.enable_and_2.d
> index 3b2963f4330bc..47e8feb59825f 100644
> --- a/test/unittest/usdt/tst.enable_and_2.d
> +++ b/test/unittest/usdt/tst.enable_and_2.d
> @@ -1,11 +1,10 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
>
> -/* @@xfail: dtv2, no is-enabled probes yet */
> /* @@trigger: usdt-tst-special 6 */
>
> #pragma D option quiet
> diff --git a/test/unittest/usdt/tst.enable_or_2.d b/test/unittest/usdt/tst.enable_or_2.d
> index 6b599544fe9f4..c384cddfb8db4 100644
> --- a/test/unittest/usdt/tst.enable_or_2.d
> +++ b/test/unittest/usdt/tst.enable_or_2.d
> @@ -1,11 +1,10 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
>
> -/* @@xfail: dtv2, no is-enabled probes yet */
> /* @@trigger: usdt-tst-special 4 */
>
> #pragma D option quiet
> diff --git a/test/unittest/usdt/tst.enable_return.d b/test/unittest/usdt/tst.enable_return.d
> index 0d727b8a6d0c9..2e7b41f91c7b9 100644
> --- a/test/unittest/usdt/tst.enable_return.d
> +++ b/test/unittest/usdt/tst.enable_return.d
> @@ -1,11 +1,10 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
>
> -/* @@xfail: dtv2, no is-enabled probes yet */
> /* @@trigger: usdt-tst-special 8 */
>
> #pragma D option quiet
> diff --git a/test/unittest/usdt/tst.enable_stmt.d b/test/unittest/usdt/tst.enable_stmt.d
> index 5c26919f764d6..37e106bf6d1d1 100644
> --- a/test/unittest/usdt/tst.enable_stmt.d
> +++ b/test/unittest/usdt/tst.enable_stmt.d
> @@ -1,11 +1,10 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
>
> -/* @@xfail: dtv2, no is-enabled probes yet */
> /* @@trigger: usdt-tst-special 7 */
>
> #pragma D option quiet
> diff --git a/test/unittest/usdt/tst.enabled.sh b/test/unittest/usdt/tst.enabled.sh
> index 5363172fd8b4b..2c0a5b405e7a5 100755
> --- a/test/unittest/usdt/tst.enabled.sh
> +++ b/test/unittest/usdt/tst.enabled.sh
> @@ -1,7 +1,7 @@
> #!/bin/bash
> #
> # Oracle Linux DTrace.
> -# Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
> +# Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
> # Licensed under the Universal Permissive License v 1.0 as shown at
> # http://oss.oracle.com/licenses/upl.
> #
> @@ -9,7 +9,6 @@ if [ $# != 1 ]; then
> echo expected one argument: '<'dtrace-path'>'
> exit 2
> fi
> -# @@xfail: dtv2, no is-enabled probes yet
>
> dtrace=$1
> CC=/usr/bin/gcc
>
> base-commit: f543fa6706c0b31364356c01bf3de63e3cce8ad1
> prerequisite-patch-id: fa667248b7b02e92ee6b3807123ebcf2ac0acc38
> prerequisite-patch-id: 0cec5f1a31d528a493d6143644c1e6b78c7f403b
> prerequisite-patch-id: 756ad5b8f08d5595c32dd113d742218991107746
> prerequisite-patch-id: eb290f098e38981181d85240150e1713979dc505
> prerequisite-patch-id: c25b38ab68e815a63f064aff7496408684f94a36
> prerequisite-patch-id: b86eb7e00b5883a586bd4dc7143ab25094912288
> --
> 2.39.1.268.g9de2f9a303
>
>
> _______________________________________________
> 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