[DTrace-devel] [PATCH 16/20] module: add support for wildcard matching for user modules

Kris Van Hees kris.van.hees at oracle.com
Fri Oct 30 19:36:57 UTC 2026


Tests for this new support are provided by the uprobe provider.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_module.c | 134 +++++++++++++++++++++++++++++++-----------
 libdtrace/dt_module.h |   3 +
 2 files changed, 103 insertions(+), 34 deletions(-)

diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c
index 2b91f1e6..06bd55d9 100644
--- a/libdtrace/dt_module.c
+++ b/libdtrace/dt_module.c
@@ -19,6 +19,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <ctype.h>
+#include <dirent.h>
 #include <port.h>
 
 #include <zlib.h>
@@ -412,6 +413,50 @@ dt_module_create(dtrace_hdl_t *dtp, const char *name)
 	return dmp;
 }
 
+/* Create a userspace module using an already resolved pathname. */
+static dt_module_t *
+dt_module_create_user_file(dtrace_hdl_t *dtp, const char *name, const char *file)
+{
+	dt_module_t	*dmp;
+	const char	*p;
+
+	/*
+	 * Use the resolved pathname as the object location, but name it based
+	 * on just the filename.
+	 */
+	p = strrchr(name, '/');
+	if (p != NULL)
+		name = p + 1;
+
+	if (strcmp(name, "shared_ctf") == 0) {
+		dt_set_errno(dtp, EEXIST);
+		return NULL;
+	}
+
+	if (strlen(name) >= DTRACE_MODNAMELEN ||
+	    strlen(file) >= sizeof(dmp->dm_file)) {
+		dt_set_errno(dtp, ENAMETOOLONG);
+		return NULL;
+	}
+
+	dmp = dt_module_lookup_by_name(dtp, name);
+	if (dmp != NULL) {
+		/* Do not turn a kernel or built-in type module into a user module. */
+		if (dmp->dm_flags & DT_DM_KERNEL || dmp == dtp->dt_cdefs ||
+		    dmp == dtp->dt_ddefs ||
+		    (dmp->dm_file[0] != '\0' && strcmp(dmp->dm_file, file) != 0)) {
+			dt_set_errno(dtp, EEXIST);
+			return NULL;
+		}
+	} else if ((dmp = dt_module_create(dtp, name)) == NULL) {
+		dt_set_errno(dtp, EDT_NOMEM);
+		return NULL;
+	}
+
+	strlcpy(dmp->dm_file, file, sizeof(dmp->dm_file));
+	return dmp;
+}
+
 /*
  * Create a userspace module for an ELF object.  Userspace module names are
  * resolved based on the LD_LIBRARY_PATH, ld.so.cache entries, and PATH.
@@ -422,7 +467,6 @@ dt_module_create_user(dtrace_hdl_t *dtp, const char *name)
 {
 	dt_module_t	*dmp;
 	char		*file = NULL;
-	char		*p;
 
 	if (name == NULL || name[0] == '\0') {
 		dt_set_errno(dtp, EINVAL);
@@ -454,46 +498,68 @@ dt_module_create_user(dtrace_hdl_t *dtp, const char *name)
 		}
 	}
 
-	/*
-	 * Use the resolved pathname as the object location, but name it based
-	 * on just the filename.
-	 */
-	p = strrchr(name, '/');
-	if (p != NULL)
-		name = p + 1;
+	dmp = dt_module_create_user_file(dtp, name, file);
+	free(file);
+	return dmp;
+}
 
-	if (strcmp(name, "shared_ctf") == 0) {
-		dt_set_errno(dtp, EEXIST);
-		goto fail;
-	}
+/*
+ * Discover user modules matching a pattern and call func once for each match,
+ * including modules already known to the handle.  A nonzero callback result
+ * stops iteration and is returned to the caller.  The callback may remove the
+ * current module (for example, if loading it finds an invalid ELF object).
+ */
+int
+dt_module_user_iter(dtrace_hdl_t *dtp, const char *pattern, dt_module_f *func,
+    void *arg)
+{
+	dt_path_t	*path;
+	dt_module_t	*dmp, *next;
+	int		rc;
 
-	if (strlen(name) >= DTRACE_MODNAMELEN ||
-	    strlen(file) >= sizeof(dmp->dm_file)) {
-		dt_set_errno(dtp, ENAMETOOLONG);
-		goto fail;
-	}
+	if (dt_list_empty(&dtp->dt_user_path) && dt_user_path_init(dtp) == -1)
+		return -1;
 
-	dmp = dt_module_lookup_by_name(dtp, name);
-	if (dmp != NULL) {
-		/* Do not turn a kernel or built-in type module into a user module. */
-		if (dmp->dm_flags & DT_DM_KERNEL || dmp == dtp->dt_cdefs ||
-		    dmp == dtp->dt_ddefs ||
-		    (dmp->dm_file[0] != '\0' && strcmp(dmp->dm_file, file) != 0)) {
-			dt_set_errno(dtp, EEXIST);
-			goto fail;
+	for (path = dt_list_next(&dtp->dt_user_path); path != NULL;
+	     path = dt_list_next(path)) {
+		DIR		*dir = opendir(path->str);
+		struct dirent	*ent;
+
+		if (dir == NULL)
+			continue;
+
+		while ((ent = readdir(dir)) != NULL) {
+			char	*file;
+
+			if (strcmp(ent->d_name, ".") == 0 ||
+			    strcmp(ent->d_name, "..") == 0 ||
+			    !dt_gmatch(ent->d_name, pattern) ||
+			    dt_module_lookup_by_name(dtp, ent->d_name) != NULL)
+				continue;
+
+			if (asprintf(&file, "%s/%s", path->str, ent->d_name) == -1) {
+				closedir(dir);
+				return dt_set_errno(dtp, ENOMEM);
+			}
+
+			if (access(file, R_OK) == 0)
+				dt_module_create_user_file(dtp, ent->d_name, file);
+			free(file);
 		}
-	} else if ((dmp = dt_module_create(dtp, name)) == NULL) {
-		dt_set_errno(dtp, EDT_NOMEM);
-		goto fail;
+		closedir(dir);
 	}
 
-	strlcpy(dmp->dm_file, file, sizeof(dmp->dm_file));
-	free(file);
-	return dmp;
+	for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; dmp = next) {
+		next = dt_list_next(dmp);
+		if ((dmp->dm_flags & DT_DM_KERNEL) || dmp->dm_file[0] == '\0' ||
+		    !dt_gmatch(dmp->dm_name, pattern))
+			continue;
 
-fail:
-	free(file);
-	return NULL;
+		if ((rc = func(dtp, dmp, arg)) != 0)
+			return rc;
+	}
+
+	return 0;
 }
 
 dt_module_t *
diff --git a/libdtrace/dt_module.h b/libdtrace/dt_module.h
index 73be7144..6857f120 100644
--- a/libdtrace/dt_module.h
+++ b/libdtrace/dt_module.h
@@ -16,6 +16,9 @@ extern "C" {
 
 extern dt_module_t *dt_module_create(dtrace_hdl_t *, const char *);
 extern dt_module_t *dt_module_create_user(dtrace_hdl_t *, const char *);
+typedef int dt_module_f(dtrace_hdl_t *, dt_module_t *, void *);
+extern int dt_module_user_iter(dtrace_hdl_t *, const char *, dt_module_f *,
+    void *);
 extern void dt_user_path_destroy(dtrace_hdl_t *);
 
 extern dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *, const char *);
-- 
2.52.0




More information about the DTrace-devel mailing list