[DTrace-devel] [PATCH v3] cg: allow providers to specify a skip count for stack retrieval

Kris Van Hees kris.van.hees at oracle.com
Wed May 1 20:52:20 UTC 2024


Some probes cause extra frames to be reported with bpf_get_stack() that
need to be skipped to ensure we report the correct stack trace to the
consumer.  FBT probes based on fentry/fexit probes need this.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 bpf/get_bvar.c          | 13 +++++++++----
 libdtrace/dt_bpf.h      |  1 +
 libdtrace/dt_cc.c       |  3 +++
 libdtrace/dt_cg.c       | 11 +++++++++--
 libdtrace/dt_dlibs.c    |  1 +
 libdtrace/dt_prov_fbt.c |  1 +
 libdtrace/dt_provider.h |  1 +
 7 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
index 71eef277..ea5dc6b1 100644
--- a/bpf/get_bvar.c
+++ b/bpf/get_bvar.c
@@ -28,6 +28,7 @@ extern uint64_t STBSZ;
 extern uint64_t STKSIZ;
 extern uint64_t BOOTTM;
 extern uint64_t STACK_OFF;
+extern uint64_t STACK_SKIP;
 
 #define error(dctx, fault, illval) \
 	({ \
@@ -64,12 +65,14 @@ noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx)
 	case DIF_VAR_STACKDEPTH:
 	case DIF_VAR_USTACKDEPTH: {
 		uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ);
-		uint64_t flags = 0 & BPF_F_SKIP_FIELD_MASK;
+		uint64_t flags;
 		char *buf = dctx->mem + (uint64_t)(&STACK_OFF);
 		uint64_t stacksize;
 
 		if (id == DIF_VAR_USTACKDEPTH)
-			flags |= BPF_F_USER_STACK;
+			flags = BPF_F_USER_STACK;
+		else
+			flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK;
 
 		stacksize = bpf_get_stack(dctx->ctx, buf, bufsiz, flags);
 		if (stacksize < 0)
@@ -89,11 +92,13 @@ noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx)
 	}
 	case DIF_VAR_CALLER:
 	case DIF_VAR_UCALLER: {
-		uint64_t flags = 0 & BPF_F_SKIP_FIELD_MASK;
+		uint64_t flags;
 		uint64_t buf[2] = { 0, };
 
 		if (id == DIF_VAR_UCALLER)
-			flags |= BPF_F_USER_STACK;
+			flags = BPF_F_USER_STACK;
+		else
+			flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK;
 
 		if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), flags) < 0)
 			return 0;
diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
index 3b9fc633..5b2df264 100644
--- a/libdtrace/dt_bpf.h
+++ b/libdtrace/dt_bpf.h
@@ -55,6 +55,7 @@ extern "C" {
 #define DT_CONST_RODATA_SIZE		21
 #define DT_CONST_ZERO_OFF		22
 #define DT_CONST_STACK_OFF		23
+#define DT_CONST_STACK_SKIP		24
 
 #define DT_BPF_LOG_SIZE_DEFAULT	(UINT32_MAX >> 8)
 #define DT_BPF_LOG_SIZE_SMALL	4096
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index cb07b8d6..d1ee3843 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -1193,6 +1193,9 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
 			case DT_CONST_STACK_OFF:
 				nrp->dofr_data = DMEM_STACK(dtp);
 				continue;
+			case DT_CONST_STACK_SKIP:
+				nrp->dofr_data = prp->prov->impl->stack_skip;
+				continue;
 			default:
 				/* probe name -> value is probe id */
 				if (strchr(idp->di_name, ':') != NULL)
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 27246a40..a1c24e37 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -2597,6 +2597,9 @@ dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, dtrace_actk
 	uint64_t	arg;
 	int		nframes, stacksize, prefsz, align = sizeof(uint64_t);
 	uint_t		lbl_valid = dt_irlist_label(dlp);
+	dt_ident_t	*skip = dt_dlib_get_var(dtp, "STACK_SKIP");
+
+	assert(skip != NULL);
 
 	/* Get sizing information from dnp->dn_arg. */
 	arg = dt_cg_stack_arg(dtp, dnp, kind);
@@ -2644,8 +2647,12 @@ dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, dtrace_actk
 		emit(dlp,  BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, off + prefsz));
 	}
 	emit(dlp,  BPF_MOV_IMM(BPF_REG_3, stacksize));
-	emit(dlp,  BPF_MOV_IMM(BPF_REG_4, (0 & BPF_F_SKIP_FIELD_MASK)
-					  | (kind == DTRACEACT_USTACK ? BPF_F_USER_STACK : 0)));
+	if (kind == DTRACEACT_USTACK)
+		emit(dlp,  BPF_MOV_IMM(BPF_REG_4, BPF_F_USER_STACK));
+	else {
+		emite(dlp, BPF_MOV_IMM(BPF_REG_4, -1), skip);
+		emit(dlp,  BPF_ALU64_IMM(BPF_AND, BPF_REG_4, BPF_F_SKIP_FIELD_MASK));
+	}
 	dt_regset_xalloc(drp, BPF_REG_0);
 	emit(dlp,  BPF_CALL_HELPER(BPF_FUNC_get_stack));
 	dt_regset_free_args(drp);
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index fe22616a..bc883e11 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -96,6 +96,7 @@ static const dt_ident_t		dt_bpf_symbols[] = {
 	DT_BPF_SYMBOL_ID(RODATA_SIZE, DT_IDENT_SCALAR, DT_CONST_RODATA_SIZE),
 	DT_BPF_SYMBOL_ID(ZERO_OFF, DT_IDENT_SCALAR, DT_CONST_ZERO_OFF),
 	DT_BPF_SYMBOL_ID(STACK_OFF, DT_IDENT_SCALAR, DT_CONST_STACK_OFF),
+	DT_BPF_SYMBOL_ID(STACK_SKIP, DT_IDENT_SCALAR, DT_CONST_STACK_SKIP),
 
 	/* End-of-list marker */
 	{ NULL, }
diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
index 0ddffa20..fa888ed8 100644
--- a/libdtrace/dt_prov_fbt.c
+++ b/libdtrace/dt_prov_fbt.c
@@ -431,6 +431,7 @@ static void kprobe_detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
 dt_provimpl_t	dt_fbt_fprobe = {
 	.name		= prvname,
 	.prog_type	= BPF_PROG_TYPE_TRACING,
+	.stack_skip	= 4,
 	.populate	= &populate,
 	.load_prog	= &fprobe_prog_load,
 	.trampoline	= &fprobe_trampoline,
diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h
index a24b1d00..17b1844c 100644
--- a/libdtrace/dt_provider.h
+++ b/libdtrace/dt_provider.h
@@ -44,6 +44,7 @@ typedef struct dt_argdesc {
 typedef struct dt_provimpl {
 	const char *name;			/* provider generic name */
 	int prog_type;				/* BPF program type */
+	uint32_t stack_skip;			/* # of stack frames to skip */
 	int (*populate)(dtrace_hdl_t *dtp);	/* register probes */
 	int (*provide)(dtrace_hdl_t *dtp,	/* provide probes */
 		       const dtrace_probedesc_t *pdp);
-- 
2.42.0




More information about the DTrace-devel mailing list