[DTrace-devel] [PATCH REVIEW] work: run under valgrind

Nick Alcock nick.alcock at oracle.com
Thu Sep 9 04:14:04 PDT 2021


Running BEGIN/END probes under valgrind failed because these probes work
by dropping uprobes on DTrace itself, and uprobes fail if the uprobed
process is being valgrinded: the breakpoint instruction inserted by
uprobes is translated into VEX IR and then emulated by valgrind, and the
emulation is located at a different address than the address originally
used by the kernel: so the kernel has no idea it was a uprobe, and
passes the breakpoint through to dtrace itself, killing it with a
SIGTRAP.

The solution is to use the bizarrely-named VALGRIND_NON_SIMD_CALL0
request to call the probes when valgrind is in use.  This asks valgrind
to invoke a function on the real CPU rather than the emulated one, which
invokes it from the right address, so the kernel spots the uprobe for
what it is. VALGRIND_NON_SIMD_CALL* has harsh and barely-documented
requirements on what it can be used to call, but our probe functions are
entirely empty, so we can be pretty sure it'll always work for us.

Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
Orabug: 32760574
---
 dtrace.spec         |  2 +-
 libdtrace/dt_work.c | 11 +++++++++--
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/dtrace.spec b/dtrace.spec
index 9098570f849d..a4c0e097f7ee 100644
--- a/dtrace.spec
+++ b/dtrace.spec
@@ -46,7 +46,7 @@ License:      Universal Permissive License (UPL), Version 1.0
 Group:        Development/Tools
 Requires:     cpp elfutils-libelf zlib libpcap
 BuildRequires: glibc-headers bison flex zlib-devel elfutils-libelf-devel
-BuildRequires: glibc-static %{glibc32} wireshark libpcap-devel
+BuildRequires: glibc-static %{glibc32} wireshark libpcap-devel valgrind-devel
 BuildRequires: kernel%{variant}-devel = %{build_kernel}
 BuildRequires: gcc-bpf-unknown-none
 BuildRequires: binutils-bpf-unknown-none
diff --git a/libdtrace/dt_work.c b/libdtrace/dt_work.c
index 108eef9ac6f4..ff2a2458ad57 100644
--- a/libdtrace/dt_work.c
+++ b/libdtrace/dt_work.c
@@ -18,6 +18,7 @@
 #include <port.h>
 #include <linux/perf_event.h>
 #include <sys/epoll.h>
+#include <valgrind/valgrind.h>
 
 void
 BEGIN_probe(void)
@@ -109,7 +110,10 @@ dtrace_go(dtrace_hdl_t *dtp, uint_t cflags)
 	if (err)
 		return err;
 
-	BEGIN_probe();
+	if (RUNNING_ON_VALGRIND)
+		VALGRIND_NON_SIMD_CALL0(BEGIN_probe);
+	else
+		BEGIN_probe();
 
 	dtp->dt_active = 1;
 	dtp->dt_beganon = dt_state_get_beganon(dtp);
@@ -141,7 +145,10 @@ dtrace_stop(dtrace_hdl_t *dtp)
 	if (dt_state_get_activity(dtp) < DT_ACTIVITY_DRAINING)
 		dt_state_set_activity(dtp, DT_ACTIVITY_DRAINING);
 
-	END_probe();
+	if (RUNNING_ON_VALGRIND)
+		VALGRIND_NON_SIMD_CALL0(END_probe);
+	else
+		END_probe();
 
 	dtp->dt_stopped = 1;
 	dtp->dt_endedon = dt_state_get_endedon(dtp);
-- 
2.33.0.256.gb827f06fa9




More information about the DTrace-devel mailing list