[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