[PATCH 38/38] Systemwide USDT WIP

eugene.loh
2024-06-27T05:39:57Z

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

need to:
- review tests
- handle globs in dt_pid_create_probes_module()
- add process monitoring / inotify
- deal with FIXMEs

Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_cc.c | 3 +-
libdtrace/dt_pid.c | 133 +++++++++++++++---
.../dtrace-util/tst.ListProbesNameUSDT.sh | 1 -
.../dtrace-util/tst.ListProbesProviderUSDT.sh | 1 -
test/unittest/usdt/tst.forker.sh | 1 -
5 files changed, 119 insertions(+), 20 deletions(-)

diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index d09a9775..3f316775 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -278,7 +278,8 @@ dt_setcontext(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
* and tag -- we just have to longjmp() out of here.
*/
if (pdp->prv && pdp->prv[0] &&
- isdigit(pdp->prv[strlen(pdp->prv) - 1]) &&
+ (isdigit(pdp->prv[strlen(pdp->prv) - 1]) ||
+ pdp->prv[strlen(pdp->prv) - 1] == '*') &&
((pvp = dt_provider_lookup(dtp, pdp->prv)) == NULL ||
pvp->pv_flags & DT_PROVIDER_PID) &&
dt_pid_create_probes((dtrace_probedesc_t *)pdp, dtp, yypcb) != 0) {
diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
index 996543b1..079377ec 100644
--- a/libdtrace/dt_pid.c
+++ b/libdtrace/dt_pid.c
@@ -605,6 +605,9 @@ dt_pid_fix_mod(dt_pid_probe_t *pp, dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
return pmp;
}

+/*
+ * Create pid probes for the specified process.
+ */
static int
dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
dt_pcb_t *pcb, dt_proc_t *dpr)
@@ -702,6 +705,7 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,

return ret;
}
+
/*
* Read a file into a buffer and return it.
*/
@@ -780,8 +784,8 @@ validate_dof_record(const char *path, const dof_parsed_t *parsed,
/*
* Create underlying probes relating to the probespec passed on input.
*
- * If dpr is set, just set up probes relating to mappings found in that one
- * process. (dpr must in this case be locked.)
+ * dpr must be set and locked. Just set up probes relating to mappings found
+ * in this one process.
*
* Return 0 on success or -1 on error. (Failure to create specific underlying
* probes is not an error.)
@@ -795,9 +799,6 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr, dtrace_probedesc_t
char *probepath = NULL;
glob_t probeglob = {0};

- /*
- * Systemwide probing: not yet implemented.
- */
assert(dpr != NULL && dpr->dpr_proc);
assert(MUTEX_HELD(&dpr->dpr_lock));

@@ -1094,22 +1095,99 @@ dt_pid_get_pid(const dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
return pid;
}

+static const char *
+convert_pidglob(const char *s)
+{
+ /*
+ * Convert a glob for "pid[1-9][0-9]*" into one for just the numerical
+ * portion. It will always be a subset of the input string. A NULL
+ * pointer is returned if there is no such string -- e.g., if the input
+ * string is "foo1234".
+ *
+ * There is no need to check the entire string for legality. E.g., if
+ * the input string is "pid*q*", we can simply return "*q*". Then, this
+ * string will not match any "[1-9][0-9]*"; we do not need to intervene.
+ */
+ const char *p;
+ int nchars = 0; /* number of chars of "pid" we have seen so far */
+
+ for (p = s; ; p++) {
+ switch (*p) {
+ case 'p':
+ if (nchars > 0)
+ return NULL;
+ nchars = 1;
+ break;
+ case 'i':
+ if (nchars > 1)
+ return NULL;
+ if (nchars < 1 && p[-1] != '*')
+ return NULL;
+ nchars = 2;
+ break;
+ case 'd':
+ if (nchars > 2)
+ return NULL;
+ if (nchars < 2 && p[-1] != '*')
+ return NULL;
+ nchars = 3;
+ break;
+ case '*':
+ break;
+ case '\0':
+ if (p == s)
+ return NULL;
+ if (p[-1] != '*')
+ return p;
+ return p - 1;
+ default:
+ if (*p < '0' || *p > '9')
+ return NULL;
+ if (p == s)
+ return NULL;
+ if (p[-1] != '*')
+ return p;
+ return p - 1;
+ }
+ }
+}
+
int
dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
{
- char provname[DTRACE_PROVNAMELEN];
dt_proc_t *dpr;
pid_t pid;
- int err = 0;
+ int err = 0, i, nmatches = 0;
+ glob_t globbuf;
+ char *globpat;

assert(pcb != NULL);

- if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1)
+ /* Exclude pid0 from being specifically requested. */
+ if (strcmp(pdp->prv, "pid0") == 0) {
+ dt_pid_error(dtp, pcb, NULL, D_PROC_BADPID,
+ "pid0 does not contain a valid pid");
return -1;
+ }
+
+ /*
+ * Try pid probes.
+ */
+ asprintf(&globpat, "/proc/%s/map_files", convert_pidglob(pdp->prv));
+ nmatches = glob(globpat, 0, NULL, &globbuf) ? 0 : globbuf.gl_pathc;
+ for (i = 0; i < nmatches; i++) {
+ if (strncmp(globbuf.gl_pathv[i], "/proc/self", 10) == 0)
+ continue;
+
+ pid = strtol(globbuf.gl_pathv[i] + strlen("/proc/"), NULL, 10);

- snprintf(provname, sizeof(provname), "pid%d", (int)pid);
+#if 1
+ // FIXME: omit this check once we have confidence in convert_pidglob()
+ char provname[DTRACE_PROVNAMELEN];
+ snprintf(provname, sizeof(provname), "pid%d", (int)pid);
+ assert(gmatch(provname, pdp->prv) != 0);
+#endif

- if (gmatch(provname, pdp->prv) != 0) {
if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING) < 0) {
dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB,
"failed to grab process %d", (int)pid);
@@ -1119,14 +1197,36 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
dpr = dt_proc_lookup(dtp, pid);
assert(dpr != NULL);

+ // FIXME How should err be handled?
err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr);
dt_proc_release_unlock(dtp, pid);
}
+ free(globpat);
+ globfree(&globbuf);

/*
- * If it's not strictly a pid provider, we might match a USDT provider.
+ * Try USDT probes.
*/
- if (strcmp(provname, pdp->prv) != 0) {
+ asprintf(&globpat, "%s/probes/*/%s", dtp->dt_dofstash_path, pdp->prv);
+ nmatches = glob(globpat, 0, NULL, &globbuf) ? 0 : globbuf.gl_pathc;
+ for (i = 0; i < nmatches; i++) {
+ char *s = globbuf.gl_pathv[i]
+ + strlen(dtp->dt_dofstash_path)
+ + strlen("/probes/");
+ dtrace_probedesc_t pdptmp;
+
+ pdptmp.prv = strchr(s, '/');
+ pdptmp.mod = pdp->mod[0] == '\0' ? "*" : pdp->mod;
+ pdptmp.fun = pdp->fun[0] == '\0' ? "*" : pdp->fun;
+ pdptmp.prb = pdp->prb[0] == '\0' ? "*" : pdp->prb;
+
+ pid = atoll(s);
+
+ // Check, since dtprobed takes a while to clean up dead processes.
+ if (!Pexists(pid))
+ continue;
+// FIXME should also check dof_version, though that doesn't do much yet
+
if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING |
DTRACE_PROC_SHORTLIVED) < 0) {
dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB,
@@ -1137,17 +1237,18 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
dpr = dt_proc_lookup(dtp, pid);
assert(dpr != NULL);

- err = dt_pid_create_usdt_probes(dtp, dpr, pdp, pcb);
+ // FIXME: How should err be handled?
+ err = dt_pid_create_usdt_probes(dtp, dpr, &pdptmp, pcb);

/*
* Put the module name in its canonical form.
*/
- dt_pid_fix_mod(NULL, pdp, dtp, dpr->dpr_pid);
+ dt_pid_fix_mod(NULL, &pdptmp, dtp, dpr->dpr_pid);

dt_proc_release_unlock(dtp, pid);
}
-
- /* (USDT systemwide probing goes here.) */
+ free(globpat);
+ globfree(&globbuf);

return err ? -1 : 0;
}
diff --git a/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh
index c5dfc72b..9d8f06e9 100755
--- a/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh
+++ b/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh
@@ -5,7 +5,6 @@
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.
#
-# @@xfail: dtv2

##
#
diff --git a/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh
index 644da2ac..6eae82ed 100755
--- a/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh
+++ b/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh
@@ -5,7 +5,6 @@
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.
#
-# @@xfail: dtv2

##
#
diff --git a/test/unittest/usdt/tst.forker.sh b/test/unittest/usdt/tst.forker.sh
index 7cfa9eb5..92513eb5 100755
--- a/test/unittest/usdt/tst.forker.sh
+++ b/test/unittest/usdt/tst.forker.sh
@@ -7,7 +7,6 @@
#
#
# @@timeout: 120
-# @@xfail: dtv2 USDT wildcard

if [ $# != 1 ]; then
echo expected one argument: '<'dtrace-path'>'
--
2.18.4