[DTrace-devel] [PATCH RFC POC 1/2] drti: re-register DOF after fork

Nick Alcock nick.alcock at oracle.com
Fri Aug 11 14:44:44 UTC 2023


DTrace v2 doesn't automatically copy tracing sessions across fork boundaries
the way v1 used to (in the kernel).  Instead. re-register DOF in the forked
child just like it was registered for the original process at ELF
constructor invocation time.

(Despite using pthread_atfork, this works fine in single-threaded processes
too, and does not require linking with -lpthread -- which has, in any case,
gone away in recent glibc.)

In the process, clean up some messes: moving the device file I/O into a
separate function means we no longer need to close it on error in a dozen
places; don't mess around with temporary variables just to open
/proc/self/maps, which is a literal string (back in the day it used to be
/proc/%i/maps where %i was getpid(), but not for years).

(Technically, calling ioctl() from a pthread_atfork() handler is dodgy as it
is not async-signal-safe. In practice, in this implementation, it's fine.
The use of dprintf() in error messages is more likely to be problematic.)

Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
 libdtrace/drti.c | 52 ++++++++++++++++++++++++++++--------------------
 1 file changed, 30 insertions(+), 22 deletions(-)

This is a bit academic and a proof-of-concept to show it can be done.
Until DTrace userspace can pick up on the new forked child, all this
does is keeps the DOF stash accurate (and tracers started *after* the
fork could pick up on probes in the forked child).

No tests are affected by this, but it *is* a correctness fix, assuming
that pthread_atfoork()ing so promiscuously is fine (which it probably
is, I mean glibc itself does it).

The next commit is a correctness fix to this correctnesss fix :)

diff --git a/libdtrace/drti.c b/libdtrace/drti.c
index e1252b4fe02b7..c3e4d4e5898b8 100644
--- a/libdtrace/drti.c
+++ b/libdtrace/drti.c
@@ -12,6 +12,7 @@
 #include <sys/dtrace.h>
 #include <sys/compiler.h>
 #include <sys/ioctl.h>
+#include <pthread.h>
 
 #include <gelf.h>
 
@@ -37,6 +38,9 @@ static const char *modname;	/* Name of this load object */
 static int gen;			/* DOF helper generation */
 extern dof_hdr_t __SUNW_dof;	/* DOF defined in the .SUNW_dof section */
 static boolean_t dof_init_debug = B_FALSE;	/* From DTRACE_DOF_INIT_DEBUG */
+static dof_helper_t dh;
+
+static void dtrace_dof_register(void);
 
 _dt_constructor_(dtrace_dof_init)
 static void
@@ -48,12 +52,9 @@ dtrace_dof_init(void)
 #else
 	Elf32_Ehdr *elf;
 #endif
-	dof_helper_t dh;
 	struct link_map *lmp = NULL;
 	Lmid_t lmid = -1;
-	int fd;
 	const char *p;
-	char mfn[PATH_MAX];		/* "/proc/<pid>/maps" */
 	char str[4096];			/* read buffer */
 	char *enm = NULL;		/* pointer to target executable name */
 	FILE *fp;
@@ -68,30 +69,22 @@ dtrace_dof_init(void)
 	if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
 		devname = p;
 
-	if ((fd = open(devname, O_RDWR)) < 0) {
-		if (dof_init_debug)
-			dprintf(2, "DRTI: Failed to open helper device %s\n",
-				devname);
-		return;
-	}
-
 #if 0
 	if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1) {
 		dprintf(2, "DRTI: Couldn't discover module name or address.\n");
-                goto out;
+		return;
 	}
 
 	if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
 		dprintf(2, "DRTI: Couldn't discover link map ID.\n");
-                goto out;
+		return;
 	}
 #else
 	lmid = 0;			/* We need a way to determine this. */
 
-	snprintf(mfn, sizeof(mfn), "/proc/self/maps");
-	if ((fp = fopen(mfn, "re")) == NULL) {
+	if ((fp = fopen("/proc/self/maps", "re")) == NULL) {
 		dprintf(2, "DRTI: Failed to open maps file.\n");
-                goto out;
+		return;
 	}
 	while (fgets(str, sizeof(str), fp) != NULL) {
 		uintptr_t	start, end;
@@ -119,7 +112,7 @@ dtrace_dof_init(void)
 	if (_dt_unlikely_(enm == NULL)) {
 		fclose(fp);
 		dprintf(2, "DRTI: Couldn't discover module name or address.\n");
-		goto out;
+		return;
 	}
 
 	/* Now start at the beginning & look for 1st segment of the target */
@@ -150,7 +143,7 @@ dtrace_dof_init(void)
 #endif
 	if (_dt_unlikely_(lmp == NULL)) {
 		dprintf(2, "DRTI: Couldn't discover module name or address.\n");
-                goto out;
+		return;
 	}
 
 	if ((modname = strrchr(lmp->l_name, '/')) == NULL)
@@ -164,7 +157,7 @@ dtrace_dof_init(void)
 	    dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
 		dprintf(2, "DRTI: .SUNW_dof section corrupt in %s.\n",
 			lmp->l_name);
-                goto out;
+		return;
 	}
 
 	elf = (void *)lmp->l_addr;
@@ -179,14 +172,29 @@ dtrace_dof_init(void)
 		(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
 		    "LM%lu`%s", lmid, modname);
 	}
+	dtrace_dof_register();
+	pthread_atfork(NULL, NULL, dtrace_dof_register);
+}
+
+static void
+dtrace_dof_register(void)
+{
+	int fd;
+
+	if ((fd = open(devname, O_RDWR, O_CLOEXEC)) < 0) {
+		if (dof_init_debug)
+			dprintf(2, "DRTI: Failed to open helper device %s\n",
+				devname);
+		return;
+	}
 
 	if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
-		dprintf(2, "DRTI: Ioctl failed for DOF at %p\n", (void *)dof);
+		dprintf(2, "DRTI: Ioctl failed for DOF at %llx\n",
+			(long long unsigned) dh.dofhp_addr);
 	else if (dof_init_debug)
-		dprintf(2, "DRTI: Ioctl OK for DOF at %p (gen %d)\n",
-			(void *)dof, gen);
+		dprintf(2, "DRTI: Ioctl OK for DOF at %llx (gen %d)\n",
+			(long long unsigned) dh.dofhp_addr, gen);
 
- out:
 	close(fd);
 }
 

base-commit: 42f15d3235bcf816ed814b88d64492a63fc5f0f0
prerequisite-patch-id: 52ce11c079ec2f65353146f18303b24fa9ff62e2
prerequisite-patch-id: 9bc8cfafabd7ab0579f0a27e30a87b3587bb5f9f
prerequisite-patch-id: 36029942b8e0fb4863721accb514d53199c3cc15
prerequisite-patch-id: 311784758ab15c7f1bb41ad1c054b9b28aa7f8a3
prerequisite-patch-id: 6dae9b2a704bdf47b0c5fe33419c6192a90022e6
prerequisite-patch-id: 1955f24b076143dd23ce6891c8d9b967100eeb3a
prerequisite-patch-id: 93b2d575d476e1161dd8e78a785a8b7d47c51c63
prerequisite-patch-id: 9fa5e3f8bbb20bae6e94ed1aec4006b561d5200e
prerequisite-patch-id: 79a97c0ecde13efa67ccd9a0bd468bee62ad6545
prerequisite-patch-id: 4761cfcb57543dcfee1e527a4050ac073f895694
prerequisite-patch-id: a1b67b863ae8524ea6a2eeb17dfad937b3f36efd
prerequisite-patch-id: 3b8d1d4ac33178ee30df262a8e97ea8ddcfe8d08
prerequisite-patch-id: bb04bcb898ee1a3a2cba63230c87e7719fae7f85
prerequisite-patch-id: 241757982119cc76f1b11d13d496f931ed794d6f
prerequisite-patch-id: b70b16fd155514aab31448a67679bf8f6cfa80ba
prerequisite-patch-id: ae96e31c0192a1a7262589a3d02ed582a3589db2
prerequisite-patch-id: fcef3ab1a97aea6b58859bd20dcb0e886d23e878
prerequisite-patch-id: 48178546b9ce81d9a2e8f608a389c99ff7f40586
prerequisite-patch-id: 89677db3750346d140dfcb662111fc8e1a1a8248
prerequisite-patch-id: 55b66c9176784232ea41f23f01b927a6ba8c020a
-- 
2.41.0.270.g68fa1d84b5




More information about the DTrace-devel mailing list