[DTrace-devel] [PATCH v3 1/2] print() action: identify ctf object used for print

Alan Maguire alan.maguire at oracle.com
Fri Apr 26 13:33:26 UTC 2024


when generating code for print() action we need to identify source
of CTF; is it shared CTF, cdefs or ddefs or another module?
Introduce a module id scheme where the module id can be stored
at cg time for later retrieval at print time; this allows us
to later look up the module and its associated CTF without relying
on possibly freed pointers.

Under the hood, the id scheme uses a monotonic counter coupled
with the hash of the modules name; the latter allows us to quickly
look up the right bucket via dt_htab_find_hval().

This fixes an issue encountered when using a shared kernel type
with alloca()ed memory; DTrace assumed the type was in ddefs
and it wasn't so it wasn't displayed.  This change fixes that and
all tests continue to pass.  Also tested that it works with
kernel module-defined types now:

dtrace: description 'fbt::ieee80211_rx_napi:entry ' matched 1 probe
CPU     ID                    FUNCTION:NAME
  7 123161          ieee80211_rx_napi:entry 0xffff9f8980fa08e0 = *
                                            (struct ieee80211_hw) {
                                             .conf = (struct ieee80211_conf) {
                                              .listen_interval = (u16)10,
                                              .long_frame_max_tx_count = (u8)4,
                                              .short_frame_max_tx_count = (u8)7,
                                             },

Signed-off-by: Alan Maguire <alan.maguire at oracle.com>
---
 libdtrace/dt_cg.c      |  7 ++++++-
 libdtrace/dt_consume.c |  7 +++++--
 libdtrace/dt_htab.c    | 17 +++++++++++++++++
 libdtrace/dt_htab.h    |  2 ++
 libdtrace/dt_impl.h    |  1 +
 libdtrace/dt_module.c  | 30 ++++++++++++++++++++++++++++++
 libdtrace/dt_module.h  |  1 +
 libdtrace/dt_printf.c  | 12 +++++++++---
 libdtrace/dt_printf.h  |  2 +-
 9 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 27246a40..30cccdaf 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -20,6 +20,7 @@
 #include <dt_dctx.h>
 #include <dt_cg.h>
 #include <dt_grammar.h>
+#include <dt_module.h>
 #include <dt_parser.h>
 #include <dt_printf.h>
 #include <dt_provider.h>
@@ -2832,7 +2833,9 @@ dt_cg_act_print(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 	ctf_id_t	type = addr->dn_type;
 	char		n[DT_TYPE_NAMELEN];
 	size_t		size;
+	dt_module_t	*dmp;
 
+	dmp = dt_module_lookup_by_ctf(dtp, fp);
 	type = ctf_type_reference(fp, type);
 	if (type == CTF_ERR)
 		longjmp(yypcb->pcb_jmpbuf, EDT_CTF);
@@ -2842,9 +2845,11 @@ dt_cg_act_print(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 			"print( ) argument #1 reference has type '%s' with size 0; cannot print( ) it.\n",
 			ctf_type_name(fp, type, n, sizeof(n)));
 
-	/* reserve space for addr/type, data/size */
+	/* reserve space for addr/type, module identification, data/size */
 	addr_off = dt_rec_add(dtp, dt_cg_fill_gap, DTRACEACT_PRINT,
 			      sizeof(uint64_t), 8, NULL, type);
+	dt_rec_add(dtp, dt_cg_fill_gap, DTRACEACT_PRINT,
+		   sizeof(uint64_t), 8, NULL, (uint64_t)dmp->dm_id);
 	data_off = dt_rec_add(dtp, dt_cg_fill_gap, DTRACEACT_PRINT,
 			      size, 8, NULL, size);
 
diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
index dec2314b..432b4e12 100644
--- a/libdtrace/dt_consume.c
+++ b/libdtrace/dt_consume.c
@@ -1987,9 +1987,11 @@ static int
 dt_print_print(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
 	       const caddr_t buf)
 {
-	dtrace_recdesc_t *data_rec = rec + 1;
+	dtrace_recdesc_t *ctf_rec = rec + 1;
+	dtrace_recdesc_t *data_rec = rec + 2;
 	size_t max_size = dtp->dt_options[DTRACEOPT_PRINTSIZE];
 	size_t size = (size_t)data_rec->dtrd_arg;
+	unsigned long dm_id = (unsigned long)ctf_rec->dtrd_arg;
 	uint64_t printaddr;
 
 	if (size > max_size)
@@ -1998,7 +2000,8 @@ dt_print_print(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
 	if (dt_read_scalar(buf, rec, &printaddr) < 0)
 		return dt_set_errno(dtp, EDT_PRINT);
 
-	return dt_print_type(dtp, fp, printaddr, (ctf_id_t)rec->dtrd_arg,
+	return dt_print_type(dtp, fp, printaddr, dm_id,
+			     (ctf_id_t)rec->dtrd_arg,
 			     (caddr_t)buf + data_rec->dtrd_offset, size);
 }
 
diff --git a/libdtrace/dt_htab.c b/libdtrace/dt_htab.c
index 478c728a..3c167cb5 100644
--- a/libdtrace/dt_htab.c
+++ b/libdtrace/dt_htab.c
@@ -229,6 +229,23 @@ void *dt_htab_find(const dt_htab_t *htab, const void *entry,
 	return ent;
 }
 
+/* Find an entry in the hashtable, using the provided callback function as a
+ * secondary comparison function to differentiate between entries in a bucket.
+ * A pre-computed hash value is passed in.
+ */
+void *dt_htab_find_hval(const dt_htab_t *htab, uint32_t hval,
+			dt_htab_ecmp_fn *cmpf, void *arg)
+{
+	int		idx = hval & htab->mask;
+	dt_hbucket_t	*bucket;
+
+	for (bucket = htab->tab[idx]; bucket; bucket = bucket->next) {
+		if (cmpf(bucket->head, arg))
+			return bucket->head;
+	}
+	return NULL;
+}
+
 /*
  * Remove an entry from the hashtable.  If we are deleting the last entry in a
  * bucket, get rid of the bucket.
diff --git a/libdtrace/dt_htab.h b/libdtrace/dt_htab.h
index d39ae65e..1ce5a80d 100644
--- a/libdtrace/dt_htab.h
+++ b/libdtrace/dt_htab.h
@@ -100,6 +100,8 @@ extern void *dt_htab_lookup(const dt_htab_t *htab, const void *entry);
 typedef int dt_htab_ecmp_fn(const void *entry, void *arg);
 extern void *dt_htab_find(const dt_htab_t *htab, const void *entry,
 			  dt_htab_ecmp_fn *cmpf, void *arg);
+extern void *dt_htab_find_hval(const dt_htab_t *htab, uint32_t hval,
+			       dt_htab_ecmp_fn *cmpf, void *arg);
 extern size_t dt_htab_entries(const dt_htab_t *htab);
 extern int dt_htab_delete(dt_htab_t *htab, void *entry);
 extern void *dt_htab_next(const dt_htab_t *htab, dt_htab_next_t **it);
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 2dfb64d6..2bd1dafe 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -136,6 +136,7 @@ typedef struct dt_module {
 	dt_list_t dm_list;	/* list forward/back pointers */
 	char dm_name[DTRACE_MODNAMELEN]; /* string name of module */
 	char dm_file[PATH_MAX]; /* file path of module */
+	unsigned long dm_id;	/* id of module */
 	uint_t dm_flags;	/* module flags (see below) */
 	struct dt_hentry dm_he;	/* htab links */
 	dtrace_hdl_t *dm_dtp;	/* backpointer to the dtrace instance */
diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c
index 1e730426..7697f73b 100644
--- a/libdtrace/dt_module.c
+++ b/libdtrace/dt_module.c
@@ -35,6 +35,8 @@
 #define KSYM_NAME_MAX 128		    /* from kernel/scripts/kallsyms.c */
 #define GZCHUNKSIZE (1024*512)		    /* gzip uncompression chunk size */
 
+unsigned int module_idx = 0;
+
 static void
 dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp);
 
@@ -50,6 +52,12 @@ dt_module_hval(const dt_module_t *mod)
 	return str2hval(mod->dm_name, 0);
 }
 
+/* id is combination of hash and index */
+static void dt_module_init_id(dt_module_t *dmp)
+{
+	dmp->dm_id = ((unsigned long)dt_module_hval(dmp)) << 32 | module_idx++;
+}
+
 static int
 dt_module_cmp(const dt_module_t *p, const dt_module_t *q)
 {
@@ -150,6 +158,7 @@ dt_module_create(dtrace_hdl_t *dtp, const char *name)
 
 	memset(dmp, 0, sizeof(dt_module_t));
 	strlcpy(dmp->dm_name, name, sizeof(dmp->dm_name));
+	dt_module_init_id(dmp);
 	if (dt_htab_insert(dtp->dt_mods, dmp) < 0) {
 		free(dmp);
 		return NULL;
@@ -193,6 +202,27 @@ dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp)
 	return ctfp ? ctf_getspecific(ctfp) : NULL;
 }
 
+static int
+dt_module_idmatch(const dt_module_t *m1, dt_module_t *m2)
+{
+	return m1->dm_id == m2->dm_id;
+}
+
+/* High-order 32 bits of id are hash value, low order the module index.
+ * This allows us to limit cost of search based on bucket size.
+ */
+dt_module_t *
+dt_module_lookup_by_id(dtrace_hdl_t *dtp, unsigned long id)
+{
+	uint32_t hval = id >> 32;
+	dt_module_t tmpl;
+
+	tmpl.dm_id = id;
+
+	return dt_htab_find_hval(dtp->dt_mods, hval, (dt_htab_ecmp_fn *)dt_module_idmatch,
+				 &tmpl);
+}
+
 static int
 dt_module_init_elf(dtrace_hdl_t *dtp, dt_module_t *dmp)
 {
diff --git a/libdtrace/dt_module.h b/libdtrace/dt_module.h
index 56df17a6..68dadfc6 100644
--- a/libdtrace/dt_module.h
+++ b/libdtrace/dt_module.h
@@ -18,6 +18,7 @@ extern dt_module_t *dt_module_create(dtrace_hdl_t *, const char *);
 
 extern dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *, const char *);
 extern dt_module_t *dt_module_lookup_by_ctf(dtrace_hdl_t *, ctf_file_t *);
+extern dt_module_t *dt_module_lookup_by_id(dtrace_hdl_t *, unsigned long);
 
 extern ctf_file_t *dt_module_getctf(dtrace_hdl_t *, dt_module_t *);
 extern dt_ident_t *dt_module_extern(dtrace_hdl_t *, dt_module_t *,
diff --git a/libdtrace/dt_printf.c b/libdtrace/dt_printf.c
index 50842216..108adc23 100644
--- a/libdtrace/dt_printf.c
+++ b/libdtrace/dt_printf.c
@@ -14,6 +14,7 @@
 #include <limits.h>
 #include <port.h>
 
+#include <dt_module.h>
 #include <dt_printf.h>
 #include <dt_string.h>
 #include <dt_impl.h>
@@ -2236,13 +2237,18 @@ err:
 
 int
 dt_print_type(dtrace_hdl_t *dtp, FILE *fp, uint64_t printaddr,
-	      ctf_id_t type, caddr_t data, size_t size)
+	      unsigned long dm_id, ctf_id_t type, caddr_t data, size_t size)
 {
 	struct dt_visit_arg dva;
+	dt_module_t *dmp = dt_module_lookup_by_id(dtp, dm_id);
 
+	if (!dmp) {
+		dt_dprintf("error retrieving CTF for print() action\n");
+		return dt_set_errno(dtp, EDT_CTF);
+	}
+	dva.dv_ctfp = dt_module_getctf(dtp, dmp);
 	dva.dv_dtp = dtp;
 	dva.dv_fp = fp;
-	dva.dv_ctfp = dtp->dt_ddefs->dm_ctfp;
 	dva.dv_data = data;
 	dva.dv_size = size;
 	dva.dv_last_depth = 0;
@@ -2260,5 +2266,5 @@ dt_print_type(dtrace_hdl_t *dtp, FILE *fp, uint64_t printaddr,
 	if (dt_print_close_parens(&dva, 0) < 0)
 		return -1;
 
-	return 2;
+	return 3;
 }
diff --git a/libdtrace/dt_printf.h b/libdtrace/dt_printf.h
index 9771c4a8..8d55d82b 100644
--- a/libdtrace/dt_printf.h
+++ b/libdtrace/dt_printf.h
@@ -108,7 +108,7 @@ extern int dt_print_ustack(dtrace_hdl_t *, FILE *,
     const char *, caddr_t, uint64_t);
 extern int dt_print_mod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
 extern int dt_print_umod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
-extern int dt_print_type(dtrace_hdl_t *, FILE *, uint64_t, ctf_id_t,
+extern int dt_print_type(dtrace_hdl_t *, FILE *, uint64_t, unsigned long, ctf_id_t,
 			 caddr_t, size_t);
 
 #ifdef	__cplusplus
-- 
2.39.3




More information about the DTrace-devel mailing list