[DTrace-devel] [PATCH 14/17] usdt: implement tracing USDT probes specified in ELF notes
Kris Van Hees
kris.van.hees at oracle.com
Sat Jun 7 06:15:05 UTC 2025
---
include/dtrace/pid.h | 1 +
libdtrace/dt_cg.c | 4 +-
libdtrace/dt_cg.h | 3 +-
libdtrace/dt_pid.c | 3 +
libdtrace/dt_prov_uprobe.c | 590 +++++++++++++++++++++++++++++++++++--
5 files changed, 573 insertions(+), 28 deletions(-)
diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h
index 12934500..8d4b6432 100644
--- a/include/dtrace/pid.h
+++ b/include/dtrace/pid.h
@@ -44,6 +44,7 @@ typedef struct pid_probespec {
char *pps_xargv; /* array of xlated args */
size_t pps_xargvlen; /* (high estimate of) length of array */
int8_t *pps_argmap; /* mapped arg indexes */
+ char *pps_sargv; /* list of arg sources */
/*
* Fields below this point do not apply to underlying probes.
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index c68a5d45..bd0763d6 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -1597,7 +1597,7 @@ dt_cg_check_ptr_arg(dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dnp,
dt_cg_check_notnull(dlp, drp, dnp->dn_reg);
}
-static void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x);
+void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x);
static int
dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind,
@@ -3006,7 +3006,7 @@ dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x)
emit(dlp, instr[1]);
}
-static void
+void
dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x)
{
dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x);
diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h
index fb26c125..81b79399 100644
--- a/libdtrace/dt_cg.h
+++ b/libdtrace/dt_cg.h
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2025, 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.
*/
@@ -18,6 +18,7 @@ extern "C" {
#endif
extern void dt_cg(dt_pcb_t *, dt_node_t *);
+extern void dt_cg_setx(dt_irlist_t *, int, uint64_t);
extern void dt_cg_xsetx(dt_irlist_t *, dt_ident_t *, uint_t, int, uint64_t);
extern dt_irnode_t *dt_cg_node_alloc(uint_t, struct bpf_insn);
extern void dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act);
diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
index 9b1a2278..d12b7919 100644
--- a/libdtrace/dt_pid.c
+++ b/libdtrace/dt_pid.c
@@ -1077,6 +1077,9 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
if (argmap)
psp.pps_argmap = argmap;
+ if (tp->tracepoint.args[0] != 0)
+ psp.pps_sargv = tp->tracepoint.args;
+
dt_dprintf("providing %s:%s:%s:%s for pid %d\n", psp.pps_prv,
psp.pps_mod, psp.pps_fun, psp.pps_prb, psp.pps_pid);
if (pvp->impl->provide_probe(dtp, &psp) < 0) {
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index 28762eb3..cf5cfd43 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -46,6 +46,231 @@
/* Provider name for the underlying probes. */
static const char prvname[] = "uprobe";
+typedef struct asm_reg {
+ const char *name; /* register name */
+ const char *mname; /* *pt_regs member name */
+ size_t moff; /* offset in member */
+ uint64_t mask; /* value mask (after shift) */
+ uint8_t shift; /* value shift */
+ int off; /* *pt_regs value offset */
+ dt_hentry_t he;
+} asm_reg_t;
+
+static uint32_t
+reg_hval(const asm_reg_t *reg)
+{
+ return str2hval(reg->name, 0);
+}
+
+static int
+reg_cmp(const asm_reg_t *p, const asm_reg_t *q)
+{
+ return strcmp(p->name, q->name);
+}
+
+DEFINE_HE_STD_LINK_FUNCS(reg, asm_reg_t, he)
+DEFINE_HTAB_STD_OPS(reg)
+
+static asm_reg_t asm_regs[] = {
+#if defined(__amd64)
+# define REG_R(n, m) { (n), (m), 0, (-1LL), 0, 0, }
+# define REG_E(n, m) { (n), (m), 0, ((1ULL << 32) - 1), 0, 0, }
+# define REG_X(n, m) { (n), (m), 0, ((1ULL << 16) - 1), 0, 0, }
+# define REG_L(n, m) { (n), (m), 0, ((1ULL << 8) - 1), 0, 0, }
+# define REG_H(n, m) { (n), (m), 0, ((1ULL << 8) - 1), 8, 0, }
+
+ REG_R("rax", "ax"),
+ REG_E("eax", "ax"),
+ REG_X("ax", "ax"),
+ REG_L("al", "ax"),
+ REG_H("ah", "ax"),
+ REG_R("rbx", "bx"),
+ REG_E("ebx", "bx"),
+ REG_X("bx", "bx"),
+ REG_L("bl", "bx"),
+ REG_H("bh", "bx"),
+ REG_R("rcx", "cx"),
+ REG_E("ecx", "cx"),
+ REG_X("cx", "cx"),
+ REG_L("cl", "cx"),
+ REG_H("ch", "cx"),
+ REG_R("rdx", "dx"),
+ REG_E("edx", "dx"),
+ REG_X("dx", "dx"),
+ REG_L("dl", "dx"),
+ REG_H("dh", "dx"),
+
+ REG_R("rsi", "si"),
+ REG_E("esi", "si"),
+ REG_X("si", "si"),
+ REG_L("sil", "si"),
+ REG_R("rdi", "di"),
+ REG_E("edi", "di"),
+ REG_X("di", "di"),
+ REG_L("dil", "di"),
+ REG_R("rsp", "sp"),
+ REG_E("esp", "sp"),
+ REG_X("sp", "sp"),
+ REG_L("spl", "sp"),
+ REG_R("rbp", "bp"),
+ REG_E("ebp", "bp"),
+ REG_X("bp", "bp"),
+ REG_L("bpl", "bp"),
+
+ REG_R("r8", "r8"),
+ REG_E("r8d", "r8"),
+ REG_X("r8w", "r8"),
+ REG_L("r8b", "r8"),
+ REG_R("r9", "r9"),
+ REG_E("r9d", "r9"),
+ REG_X("r9w", "r9"),
+ REG_L("r9b", "r9"),
+ REG_R("r10", "r10"),
+ REG_E("r10d", "r10"),
+ REG_X("r10w", "r10"),
+ REG_L("r10b", "r10"),
+ REG_R("r11", "r11"),
+ REG_E("r11d", "r11"),
+ REG_X("r11w", "r11"),
+ REG_L("r11b", "r11"),
+ REG_R("r12", "r12"),
+ REG_E("r12d", "r12"),
+ REG_X("r12w", "r12"),
+ REG_L("r12b", "r12"),
+ REG_R("r13", "r13"),
+ REG_E("r13d", "r13"),
+ REG_X("r13w", "r13"),
+ REG_L("r13b", "r13"),
+ REG_R("r14", "r14"),
+ REG_E("r14d", "r14"),
+ REG_X("r14w", "r14"),
+ REG_L("r14b", "r14"),
+ REG_R("r15", "r15"),
+ REG_E("r15d", "r15"),
+ REG_X("r15w", "r15"),
+ REG_L("r15b", "r15"),
+
+ REG_R("rip", "ip"),
+ REG_E("eip", "ip"),
+ REG_X("ip", "ip"),
+#elif defined(__aarch64__)
+# define REG_X(n, m, i) { (n), (m), (i) * sizeof(uint64_t), (-1LL), 0, 0, }
+# define REG_W(n, m, i) { (n), (m), (i) * sizeof(uint64_t), ((1ULL << 32) - 1), 0, 0, }
+
+ REG_X("x0", "regs", 0),
+ REG_X("x1", "regs", 1),
+ REG_X("x2", "regs", 2),
+ REG_X("x3", "regs", 3),
+ REG_X("x4", "regs", 4),
+ REG_X("x5", "regs", 5),
+ REG_X("x6", "regs", 6),
+ REG_X("x7", "regs", 7),
+ REG_X("x8", "regs", 8),
+ REG_X("x9", "regs", 9),
+ REG_X("x10", "regs", 10),
+ REG_X("x11", "regs", 11),
+ REG_X("x12", "regs", 12),
+ REG_X("x13", "regs", 13),
+ REG_X("x14", "regs", 14),
+ REG_X("x15", "regs", 15),
+ REG_X("x16", "regs", 16),
+ REG_X("x17", "regs", 17),
+ REG_X("x18", "regs", 18),
+ REG_X("x19", "regs", 19),
+ REG_X("x20", "regs", 20),
+ REG_X("x21", "regs", 21),
+ REG_X("x22", "regs", 22),
+ REG_X("x23", "regs", 23),
+ REG_X("x24", "regs", 24),
+ REG_X("x25", "regs", 25),
+ REG_X("x26", "regs", 26),
+ REG_X("x27", "regs", 27),
+ REG_X("x28", "regs", 28),
+ REG_X("x29", "regs", 29),
+ REG_X("x30", "regs", 30),
+
+ REG_W("w0", "regs", 0),
+ REG_W("w1", "regs", 1),
+ REG_W("w2", "regs", 2),
+ REG_W("w3", "regs", 3),
+ REG_W("w4", "regs", 4),
+ REG_W("w5", "regs", 5),
+ REG_W("w6", "regs", 6),
+ REG_W("w7", "regs", 7),
+ REG_W("w8", "regs", 8),
+ REG_W("w9", "regs", 9),
+ REG_W("w10", "regs", 10),
+ REG_W("w11", "regs", 11),
+ REG_W("w12", "regs", 12),
+ REG_W("w13", "regs", 13),
+ REG_W("w14", "regs", 14),
+ REG_W("w15", "regs", 15),
+ REG_W("w16", "regs", 16),
+ REG_W("w17", "regs", 17),
+ REG_W("w18", "regs", 18),
+ REG_W("w19", "regs", 19),
+ REG_W("w20", "regs", 20),
+ REG_W("w21", "regs", 21),
+ REG_W("w22", "regs", 22),
+ REG_W("w23", "regs", 23),
+ REG_W("w24", "regs", 24),
+ REG_W("w25", "regs", 25),
+ REG_W("w26", "regs", 26),
+ REG_W("w27", "regs", 27),
+ REG_W("w28", "regs", 28),
+ REG_W("w29", "regs", 29),
+ REG_W("w30", "regs", 30),
+
+ REG_X("sp", "sp", 0),
+ REG_X("pc", "sp", 0),
+
+ REG_X("lr", "regs", 30),
+#else
+# error ISA not supported
+#endif
+};
+
+static asm_reg_t *
+get_asm_reg(dt_provider_t *pvp, const char *name)
+{
+ dt_htab_t *rtab = pvp->prv_data;
+ asm_reg_t regt;
+
+ if (rtab == NULL) {
+ int i;
+ asm_reg_t *rp, *reg = NULL;
+
+ rtab = dt_htab_create(®_htab_ops);
+ if (rtab == NULL)
+ return NULL;
+
+ pvp->prv_data = rtab;
+
+ for (i = 0, rp = asm_regs; i < ARRAY_SIZE(asm_regs);
+ i++, rp++) {
+#if defined(__amd64)
+ rp->off = dt_cg_ctf_offsetof("struct pt_regs",
+ rp->mname, NULL, 0) +
+ rp->moff;
+#elif defined(__aarch64__)
+ rp->off = dt_cg_ctf_offsetof("struct user_pt_regs",
+ rp->mname, NULL, 0) +
+ rp->moff;
+#endif
+
+ if (dt_htab_insert(rtab, rp) < 0)
+ return NULL;
+ if (strcmp(rp->name, name) == 0)
+ reg = rp;
+ }
+
+ return reg;
+ }
+
+ regt.name = name;
+ return dt_htab_lookup(rtab, ®t);
+}
+
#define PP_IS_RETURN 0x1
#define PP_IS_FUNCALL 0x2
#define PP_IS_ENABLED 0x4
@@ -55,15 +280,17 @@ static const char prvname[] = "uprobe";
typedef struct dt_uprobe {
dev_t dev;
ino_t inum;
- char *fn; /* object full file name */
- char *func; /* function */
+ char *fn; /* object full file name */
+ char *func; /* function */
uint64_t off;
int flags;
tp_probe_t *tp;
- int argc; /* number of args */
- dt_argdesc_t *args; /* args array (points into argvbuf) */
- char *argvbuf; /* arg strtab */
- dt_list_t probes; /* pid/USDT probes triggered by it */
+ int argc; /* number of args */
+ dt_argdesc_t *args; /* args array (points into argvbuf) */
+ char *argvbuf; /* arg strtab */
+ int sargc; /* number of arg source specs */
+ char *sargv; /* arg source specs */
+ dt_list_t probes; /* pid/USDT probes triggered by it */
} dt_uprobe_t;
typedef struct list_probe {
@@ -132,6 +359,7 @@ static void probe_destroy_underlying(dtrace_hdl_t *dtp, void *datap)
dt_free(dtp, upp->func);
dt_free(dtp, upp->args);
dt_free(dtp, upp->argvbuf);
+ dt_free(dtp, upp->sargv);
dt_free(dtp, upp);
}
@@ -290,15 +518,19 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp)
* status in the clause flags for dt_stmts[n].
*/
if (dt_stmt_clsflag_test(stp, DT_CLSFLAG_USDT_INCLUDE | DT_CLSFLAG_USDT_EXCLUDE) == 0) {
- char lastchar = pdp->prv[strlen(pdp->prv) - 1];
+ size_t len = strlen(pdp->prv);
/*
* If the last char in the provider description is
* neither '*' nor a digit, it cannot be a USDT probe.
*/
- if (lastchar != '*' && !isdigit(lastchar)) {
- dt_stmt_clsflag_set(stp, DT_CLSFLAG_USDT_EXCLUDE);
- return 1;
+ if (len > 1) {
+ char lastchar = pdp->prv[len - 1];
+
+ if (lastchar != '*' && !isdigit(lastchar)) {
+ dt_stmt_clsflag_set(stp, DT_CLSFLAG_USDT_EXCLUDE);
+ return 1;
+ }
}
/*
@@ -340,6 +572,17 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp)
return 0;
}
+static void usdt_error(dt_pcb_t *pcb, const char *fmt, ...)
+{
+ dtrace_hdl_t *dtp = pcb->pcb_hdl;
+ va_list ap;
+
+ va_start(ap, fmt);
+ dt_set_errmsg(dtp, NULL, NULL, NULL, 0, fmt, ap);
+ va_end(ap);
+ longjmp(pcb->pcb_jmpbuf, EDT_COMPILER);
+}
+
static int add_probe_uprobe(dtrace_hdl_t *dtp, dt_probe_t *prp)
{
dtrace_difo_t *dp;
@@ -539,6 +782,18 @@ static int populate_args(dtrace_hdl_t *dtp, const pid_probespec_t *psp,
upp->argc = psp->pps_xargc;
+ /* Copy argument value source string data (if any). */
+ if (psp->pps_sargv) {
+ /*
+ * Is-enabled probes have one (internal use only) argument.
+ * They retain the narg/xarg data from the probe they are
+ * associated with, for consistency, but that data will not be
+ * used.
+ */
+ upp->sargc = (upp->flags & PP_IS_ENABLED) ? 1 : psp->pps_nargc;
+ upp->sargv = strdup(psp->pps_sargv);
+ }
+
/*
* If we have a nonzero number of args, we always have at least one narg
* and at least one xarg. Double-check to be sure. (These are not
@@ -700,9 +955,6 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
assert(strcmp(upp->func, psp->pps_fun) == 0);
}
- if (populate_args(dtp, psp, upp) < 0)
- goto fail;
-
switch (psp->pps_type) {
case DTPPT_RETURN:
upp->flags |= PP_IS_RETURN;
@@ -719,6 +971,9 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
*/
}
+ if (populate_args(dtp, psp, upp) < 0)
+ goto fail;
+
return uprp;
fail:
@@ -889,6 +1144,289 @@ static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp)
enable(dtp, prp, 1);
}
+/*
+ * Generate code that populates the probe arguments.
+ */
+static void copy_args(dt_pcb_t *pcb, const dt_uprobe_t *upp)
+{
+ dtrace_hdl_t *dtp = pcb->pcb_hdl;
+ dt_irlist_t *dlp = &pcb->pcb_ir;
+ dt_provider_t *pvp = dt_provider_lookup(dtp, dt_usdt.name);
+ asm_reg_t *areg;
+ int i;
+ char *p = upp->sargv;
+
+ assert(pvp != NULL);
+
+ for (i = 0; i < upp->sargc; i++) {
+ int ssize, disp, len;
+ char *reg = NULL;
+ int64_t val = 0;
+
+ /*
+ * Get sign/size. Missing sign/size is an error.
+ * Also, float is not supported.
+ */
+ ssize = 0;
+ len = -1;
+ if (sscanf(p, " %d @ %n", &ssize, &len) <= 0 || len == -1)
+ usdt_error(pcb, "Missing sign/size in arg%d spec", i);
+
+ p += len;
+
+ /* Look for dereference (with optional displacement). */
+ disp = 0;
+ len = -1;
+#ifdef __aarch64__
+ if (sscanf(p, "[ %m[^],] %n", ®, &len) > 0 && len > 0) {
+ char *ireg = NULL;
+
+ p += len;
+
+ if (*p != ']') {
+ /* Expect a displacement or index register. */
+ if (sscanf(p, ", %n", &len) < 0)
+ usdt_error(pcb, "Expected , in arg%d spec", i);
+
+ p += len;
+
+ if (sscanf(p, "%d ] %n", &disp, &len) != 1 &&
+ sscanf(p, "%m[^],] , %d ] %n", &ireg, &disp,
+ &len) != 2 &&
+ sscanf(p, "%m[^]] ] %n", &ireg, &len) != 1)
+ usdt_error(pcb, "Missing displacement and/or index register in arg%d spec", i);
+ } else
+ sscanf(p, "] %n", &len);
+
+ p += len;
+
+ /*
+ * If there is an index register, put its value in %r1
+ * (after applying the scale if specified).
+ */
+ if (ireg != NULL) {
+ areg = get_asm_reg(pvp, ireg);
+ if (areg == NULL)
+ usdt_error(pcb, "Unknown index register %s in arg%d spec", ireg, i);
+
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, areg->off));
+ }
+
+ /* If there is a base register, get its value. */
+ if (reg != NULL) {
+ int neg = 0;
+ int shift;
+
+ if (ssize < 0) {
+ neg = 1;
+ ssize = -ssize;
+ }
+
+ shift = 64 - ssize * 8;
+
+ areg = get_asm_reg(pvp, reg);
+ if (areg == NULL)
+ usdt_error(pcb, "Unknown base register %s in arg%d spec", reg, i);
+
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, areg->off));
+
+ if (ireg != NULL)
+ emit(dlp, BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1));
+
+ if (disp != 0)
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, disp));
+
+ /* Load value from the pointer. */
+ emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_7));
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DMST_ARG(i)));
+ emit(dlp, BPF_MOV_IMM(BPF_REG_2, ssize));
+ emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0));
+ emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user]));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(i)));
+ if (shift) {
+ emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift));
+ emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift));
+ }
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0));
+ } else {
+ if (disp != 0)
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, disp));
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_1));
+ }
+
+ free(reg);
+ free(ireg);
+ } else if (sscanf(p, "%ld %n", &val, &len) > 0) {
+ /* Handle constant value. */
+ p += len;
+
+ if (val > (1ULL << 32) - 1ULL) {
+ dt_cg_setx(dlp, BPF_REG_0, val);
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0));
+ } else
+ emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), val));
+ } else if (sscanf(p, "%m[a-z0-9] %n", ®, &len) > 0) {
+ /* Handle simple register. */
+ int neg = 0;
+ int shift;
+ uint_t sz;
+
+ if (ssize < 0) {
+ neg = 1;
+ ssize = -ssize;
+ }
+
+ shift = 64 - ssize * 8;
+ sz = bpf_ldst_size(ssize, 1);
+
+ areg = get_asm_reg(pvp, reg);
+ if (areg == NULL)
+ usdt_error(pcb, "Unknown register %s in arg%d spec", reg, i);
+
+ emit(dlp, BPF_LOAD(sz, BPF_REG_0, BPF_REG_8, areg->off));
+ if (shift) {
+ emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift));
+ emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift));
+ }
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0));
+
+ free(reg);
+ p += len;
+ } else
+ usdt_error(pcb, "Unknown format in arg%d spec", i);
+#else
+ if ((sscanf(p, "%d ( %n", &disp, &len) == 1 ||
+ sscanf(p, "( %n", &len) == 0) && len >= 0) {
+ char *ireg = NULL;
+ int scale = -1;
+
+ p += len;
+
+ if (*p != ',') {
+ /* Expect a base register. */
+ if (sscanf(p, "%%%m[^,)] %n", ®, &len) <= 0)
+ usdt_error(pcb, "Missing base register in arg%d spec", i);
+
+ p += len;
+ }
+
+ if (*p != ')') {
+ /* Expect an index register. */
+ if (sscanf(p, ", %%%m[^,)] %n", &ireg, &len) <= 0)
+ usdt_error(pcb, "Missing index register in arg%d spec", i);
+
+ p += len;
+
+ /* Expect scale or closing parenthesis. */
+ len = 0;
+ if (sscanf(p, ", %d ) %n", &scale, &len) <= 0 &&
+ sscanf(p, ") %n", &len) < 0)
+ usdt_error(pcb, "Missing scale or ) in arg%d spec", i);
+ } else
+ sscanf(p, ") %n", &len);
+
+ p += len;
+
+ /*
+ * If there is an index register, put its value in %r1
+ * (after applying the scale if specified).
+ */
+ if (ireg != NULL) {
+ areg = get_asm_reg(pvp, ireg);
+ if (areg == NULL)
+ usdt_error(pcb, "Unknown index register %s in arg%d spec", ireg, i);
+
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, areg->off));
+ if (scale > 0)
+ emit(dlp, BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, scale));
+ }
+
+ /* If there is a base register, get its value. */
+ if (reg != NULL) {
+ int neg = 0;
+ int shift;
+
+ if (ssize < 0) {
+ neg = 1;
+ ssize = -ssize;
+ }
+
+ shift = 64 - ssize * 8;
+
+ areg = get_asm_reg(pvp, reg);
+ if (areg == NULL)
+ usdt_error(pcb, "Unknown base register %s in arg%d spec", reg, i);
+
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, areg->off));
+
+ if (ireg != NULL)
+ emit(dlp, BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1));
+
+ if (disp != 0)
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, disp));
+
+ /* Load value from the pointer. */
+ emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_7));
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DMST_ARG(i)));
+ emit(dlp, BPF_MOV_IMM(BPF_REG_2, ssize));
+ emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0));
+ emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user]));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(i)));
+ if (shift) {
+ emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift));
+ emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift));
+ }
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0));
+ } else {
+ if (disp != 0)
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, disp));
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_1));
+ }
+
+ free(reg);
+ free(ireg);
+ } else if (sscanf(p, "%%%ms %n", ®, &len) > 0) {
+ /* Handle simple register. */
+ int neg = 0;
+ int shift;
+ uint_t sz;
+
+ if (ssize < 0) {
+ neg = 1;
+ ssize = -ssize;
+ }
+
+ shift = 64 - ssize * 8;
+ sz = bpf_ldst_size(ssize, 1);
+
+ areg = get_asm_reg(pvp, reg);
+ if (areg == NULL)
+ usdt_error(pcb, "Unknown register %s in arg%d spec", reg, i);
+
+ emit(dlp, BPF_LOAD(sz, BPF_REG_0, BPF_REG_8, areg->off));
+ if (shift) {
+ emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift));
+ emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift));
+ }
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0));
+
+ free(reg);
+ p += len;
+ } else if (sscanf(p, "$%ld %n", &val, &len) > 0) {
+ /* Handle constant value. */
+ p += len;
+
+ if (val > (1ULL << 32) - 1ULL) {
+ dt_cg_setx(dlp, BPF_REG_0, val);
+ emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0));
+ } else
+ emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), val));
+ } else
+ usdt_error(pcb, "Unknown format in arg%d spec", i);
+#endif
+ }
+}
+
/*
* Generate a BPF trampoline for a pid or USDT probe.
*
@@ -981,17 +1519,10 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
if (upp->flags & PP_IS_RETURN)
goto out;
- dt_cg_tramp_copy_args_from_regs(pcb, 0);
-
- /*
- * Apply arg mappings, if needed.
- */
- if (upp->flags & PP_IS_MAPPED) {
-
- /* dt_cg_tramp_map_args() works from the saved args. */
- dt_cg_tramp_save_args(pcb);
- dt_cg_tramp_map_args(pcb, upp->args, upp->argc);
- }
+ if (upp->sargc)
+ copy_args(pcb, upp);
+ else
+ dt_cg_tramp_copy_args_from_regs(pcb, 0);
/*
* Retrieve the PID of the process that caused the probe to fire.
@@ -1022,7 +1553,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
* The trampoline writes 1 into the location pointed to by the passed-in arg.
*/
emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), 1));
- emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, PT_REGS_ARG0));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(0)));
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)));
@@ -1042,6 +1573,15 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
/* Read the bit mask from the table lookup in %r6. */ // FIXME someday, extend this past 64 bits
emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_0, offsetof(usdt_prids_map_val_t, mask)));
+ /*
+ * Apply arg mappings, if needed.
+ */
+ if (upp->flags & PP_IS_MAPPED) {
+ /* dt_cg_tramp_map_args() works from the saved args. */
+ dt_cg_tramp_save_args(pcb);
+ dt_cg_tramp_map_args(pcb, upp->args, upp->argc);
+ }
+
/*
* Hold the bit mask in %r6 between clause calls.
*/
--
2.45.2
More information about the DTrace-devel
mailing list