[DTrace-devel] [PATCH] Change stack_skip to 3

eugene.loh at oracle.com eugene.loh at oracle.com
Wed Jan 21 23:51:54 UTC 2026


From: Eugene Loh <eugene.loh at oracle.com>

For most probes, bpf_get_stack() strips off artificial BPF JIT stack
frames.  In a few cases -- like fprobes and rawtp -- we have to skip
the first few frames manually.  Typically, we should skip 3 frames
(trampoline, clause, and the bpf_get_stack call itself).  Further,
our BPF functions like
    get_bvar_caller()
    get_bvar_stackdepth()
    get_bvar_ucaller()
    get_bvar_ustackdepth()
skip an additional frame to account for that call.

Change stack_skip to 3 for the dt_fbt_fprobe and dt_rawtp providers.

This raises the thorny question of testing.  Until recently, the
stack_skip value we had been using -- 4, not 3 -- worked since it was
chosen empirically:  there was a bug in the kernel that added an extra
frame.  But now, the kernel situation is muddled.  The bug has been
fixed in recent kernels, but only for x86.  See

https://github.com/torvalds/linux/commit/6d08340d1e354787d6c65a8c3cdd4d41ffb8a5ed
Revert "perf/x86: Always store regs->ip in perf_callchain_kernel()"

A broader fix, for non-x86, is also expected.  See the thread that
starts at:
https://lore.kernel.org/all/a38fed68-67bc-98ce-8e12-743342121ae3@oracle.com/

So, for now, XFAIL tests on "unfixed" (older) kernels.

Orabug: 38776929
Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_prov_fbt.c                   |  2 +-
 libdtrace/dt_prov_rawtp.c                 |  2 +-
 test/unittest/funcs/stack/tst.asgn_dvar.x |  1 +
 test/unittest/funcs/stack/tst.asgn_gvar.x |  1 +
 test/unittest/funcs/stack/tst.asgn_lvar.x |  1 +
 test/unittest/funcs/stack/tst.asgn_tvar.x |  1 +
 test/unittest/funcs/stack/tst.ref_addrs.x |  1 +
 test/unittest/printf/tst.stack.x          |  1 +
 test/unittest/stack/tst.stack.x           |  1 +
 test/utils/stack_skip_test.sh             | 33 +++++++++++++++++++++++
 10 files changed, 42 insertions(+), 2 deletions(-)
 create mode 120000 test/unittest/funcs/stack/tst.asgn_dvar.x
 create mode 120000 test/unittest/funcs/stack/tst.asgn_gvar.x
 create mode 120000 test/unittest/funcs/stack/tst.asgn_lvar.x
 create mode 120000 test/unittest/funcs/stack/tst.asgn_tvar.x
 create mode 120000 test/unittest/funcs/stack/tst.ref_addrs.x
 create mode 120000 test/unittest/printf/tst.stack.x
 create mode 120000 test/unittest/stack/tst.stack.x
 create mode 100755 test/utils/stack_skip_test.sh

diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
index 8dbf9740a..4df621657 100644
--- a/libdtrace/dt_prov_fbt.c
+++ b/libdtrace/dt_prov_fbt.c
@@ -736,7 +736,7 @@ reject:
 dt_provimpl_t	dt_fbt_fprobe = {
 	.name		= prvname,
 	.prog_type	= BPF_PROG_TYPE_TRACING,
-	.stack_skip	= 4,
+	.stack_skip	= 3,
 	.populate	= &populate,
 	.provide	= &provide,
 	.load_prog	= &fprobe_prog_load,
diff --git a/libdtrace/dt_prov_rawtp.c b/libdtrace/dt_prov_rawtp.c
index e3269f4b3..27a992d2e 100644
--- a/libdtrace/dt_prov_rawtp.c
+++ b/libdtrace/dt_prov_rawtp.c
@@ -296,7 +296,7 @@ use_alt:
 dt_provimpl_t	dt_rawtp = {
 	.name		= prvname,
 	.prog_type	= BPF_PROG_TYPE_RAW_TRACEPOINT,
-	.stack_skip	= 4,
+	.stack_skip	= 3,
 	.populate	= &populate,
 	.load_prog	= &dt_bpf_prog_load,
 	.trampoline	= &trampoline,
diff --git a/test/unittest/funcs/stack/tst.asgn_dvar.x b/test/unittest/funcs/stack/tst.asgn_dvar.x
new file mode 120000
index 000000000..0edb412f0
--- /dev/null
+++ b/test/unittest/funcs/stack/tst.asgn_dvar.x
@@ -0,0 +1 @@
+../../../utils/stack_skip_test.sh
\ No newline at end of file
diff --git a/test/unittest/funcs/stack/tst.asgn_gvar.x b/test/unittest/funcs/stack/tst.asgn_gvar.x
new file mode 120000
index 000000000..0edb412f0
--- /dev/null
+++ b/test/unittest/funcs/stack/tst.asgn_gvar.x
@@ -0,0 +1 @@
+../../../utils/stack_skip_test.sh
\ No newline at end of file
diff --git a/test/unittest/funcs/stack/tst.asgn_lvar.x b/test/unittest/funcs/stack/tst.asgn_lvar.x
new file mode 120000
index 000000000..0edb412f0
--- /dev/null
+++ b/test/unittest/funcs/stack/tst.asgn_lvar.x
@@ -0,0 +1 @@
+../../../utils/stack_skip_test.sh
\ No newline at end of file
diff --git a/test/unittest/funcs/stack/tst.asgn_tvar.x b/test/unittest/funcs/stack/tst.asgn_tvar.x
new file mode 120000
index 000000000..0edb412f0
--- /dev/null
+++ b/test/unittest/funcs/stack/tst.asgn_tvar.x
@@ -0,0 +1 @@
+../../../utils/stack_skip_test.sh
\ No newline at end of file
diff --git a/test/unittest/funcs/stack/tst.ref_addrs.x b/test/unittest/funcs/stack/tst.ref_addrs.x
new file mode 120000
index 000000000..0edb412f0
--- /dev/null
+++ b/test/unittest/funcs/stack/tst.ref_addrs.x
@@ -0,0 +1 @@
+../../../utils/stack_skip_test.sh
\ No newline at end of file
diff --git a/test/unittest/printf/tst.stack.x b/test/unittest/printf/tst.stack.x
new file mode 120000
index 000000000..b5ac46b84
--- /dev/null
+++ b/test/unittest/printf/tst.stack.x
@@ -0,0 +1 @@
+../../utils/stack_skip_test.sh
\ No newline at end of file
diff --git a/test/unittest/stack/tst.stack.x b/test/unittest/stack/tst.stack.x
new file mode 120000
index 000000000..b5ac46b84
--- /dev/null
+++ b/test/unittest/stack/tst.stack.x
@@ -0,0 +1 @@
+../../utils/stack_skip_test.sh
\ No newline at end of file
diff --git a/test/utils/stack_skip_test.sh b/test/utils/stack_skip_test.sh
new file mode 100755
index 000000000..8ebfd29ff
--- /dev/null
+++ b/test/utils/stack_skip_test.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# Older kernels had a bug in which the leaf frame was replicated.
+#
+# This bug was fixed on x86_64.  See
+#   https://github.com/torvalds/linux/commit/6d08340d1e354787d6c65a8c3cdd4d41ffb8a5ed
+#   Revert "perf/x86: Always store regs->ip in perf_callchain_kernel()"
+#
+# A broader fix, for non-x86, is also expected.  See the thread that starts at:
+#   https://lore.kernel.org/all/a38fed68-67bc-98ce-8e12-743342121ae3@oracle.com/
+#
+# Use this as a .x file to mark tests as "XFAIL" for older kernels with the
+# superfluous frame (and therefore exposing a BPF JIT frame, appearing as an
+# untranslated 0xffff address).  On older kernels, it is also possible for fbt
+# to be implemented with kprobes rather than fprobes;  in this case, the .x
+# issues no concerns and the tests are expected to PASS.
+
+$dtrace -c test/triggers/periodic_output -qn '
+fbt::hrtimer_nanosleep:entry
+{
+        stack(1);
+        exit(0);
+}
+
+ERROR
+{
+        exit(1);
+}' | grep -q 0xffff
+if [ $? -eq 0 ]; then
+	echo stack appears to have superfluous frame
+	exit 1
+fi
+exit 0
-- 
2.47.3




More information about the DTrace-devel mailing list