* [PATCH 02/20] libdtrace: retain module metadata across incremental discovery
@ 2026-10-30 19:36 Kris Van Hees
0 siblings, 0 replies; only message in thread
From: Kris Van Hees @ 2026-10-30 19:36 UTC (permalink / raw)
To: dtrace, dtrace-devel
Stop unloading cached modules in dtrace_update(), including vmlinux. Keep
discovered symbol tables, ranges, types, and BTF IDs for the handle lifetime
while collecting newly loaded modules. Module disappearance or reloading no
longer replaces cached metadata.
Separate failed ELF-load cleanup from module destruction, retaining the
existing handle ownership of shared CTF and BTF. Document the new lifetime
contract and cover incremental discovery with both kernel symbol formats.
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
---
INCOMPATIBILITIES | 10 ++
libdtrace/dt_btf.c | 2 +-
libdtrace/dt_impl.h | 1 +
libdtrace/dt_module.c | 90 +++++-----
libdtrace/dt_open.c | 1 -
libdtrace/dtrace.h | 8 +-
test/internals/btf/tst.module-discovery.sh | 11 ++
test/triggers/Build | 11 +-
test/triggers/module-discovery.c | 195 +++++++++++++++++++++
9 files changed, 282 insertions(+), 47 deletions(-)
create mode 100755 test/internals/btf/tst.module-discovery.sh
create mode 100644 test/triggers/module-discovery.c
diff --git a/INCOMPATIBILITIES b/INCOMPATIBILITIES
index bf55019e..933c5c86 100644
--- a/INCOMPATIBILITIES
+++ b/INCOMPATIBILITIES
@@ -183,3 +183,13 @@ proc:::signal-discard
expiration should be discarded, no signal-discard probe is fired.
The reason for this behaviour is that SDT probes do not work in
IRQ context.
+
+
+Kernel module metadata lifetime
+--------------------------------
+dtrace_update() discovers new kernel modules and retains previously discovered
+symbols, address ranges, and types, including those for vmlinux. Returned
+metadata remains valid across updates until dtrace_close(). Dynamic kernel
+module unloading and reloading are not supported: a module name continues to
+refer to its first discovered instance, even if it disappears or reappears at
+a different address. Open a new handle to obtain a fresh view of the kernel.
diff --git a/libdtrace/dt_btf.c b/libdtrace/dt_btf.c
index 55b58bf5..54011e4d 100644
--- a/libdtrace/dt_btf.c
+++ b/libdtrace/dt_btf.c
@@ -1002,7 +1002,7 @@ dt_btf_get_module_ids(dtrace_hdl_t *dtp)
return dt_set_errno(dtp, errno);
dmp = dt_module_lookup_by_name(dtp, name);
- if (dmp == NULL)
+ if (dmp == NULL || dmp->dm_btf_id != 0)
continue;
dmp->dm_btf_id = id;
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 243fd2a7..0290e0b4 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -202,6 +202,7 @@ typedef struct dt_kern_path {
#define DT_DM_KERNEL 0x2 /* module is associated with a kernel object */
#define DT_DM_CTF_ARCHIVED 0x4 /* module found in a CTF archive */
#define DT_DM_KERN_UNLOADED 0x8 /* module not loaded into the kernel */
+#define DT_DM_KERN_SYMS 0x40 /* kernel symbols discovered and finalized */
/*
* Why do we need (only) 4 slots? The maximum amount of string arguments to
diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c
index 5d5859a3..c98297e7 100644
--- a/libdtrace/dt_module.c
+++ b/libdtrace/dt_module.c
@@ -34,7 +34,10 @@
#define GZCHUNKSIZE (1024*512) /* gzip uncompression chunk size */
static void
-dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp);
+dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp);
+
+static void
+dt_module_clear_elf(dt_module_t *dmp);
static void
dt_module_shuffle_to_start(dtrace_hdl_t *dtp, const char *name);
@@ -242,7 +245,7 @@ dt_module_del_mod(dt_module_t *head, dt_module_t *dmp)
head = dt_module_del(head, dmp);
dt_list_delete(&dmp->dm_dtp->dt_modlist, dmp);
- dt_module_unload(dmp->dm_dtp, dmp);
+ dt_module_destroy(dmp->dm_dtp, dmp);
free(dmp);
return head;
@@ -799,7 +802,7 @@ dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
*/
if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1) {
- dt_module_unload(dtp, dmp);
+ dt_module_clear_elf(dmp);
return -1; /* dt_errno is set for us */
}
@@ -848,7 +851,7 @@ dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
*/
if (dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 ||
dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) {
- dt_module_unload(dtp, dmp);
+ dt_module_clear_elf(dmp);
return -1; /* dt_errno is set for us */
}
@@ -895,7 +898,7 @@ dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
dmp->dm_flags |= DT_DM_LOADED;
return 0;
oom:
- dt_module_unload(dtp, dmp);
+ dt_module_clear_elf(dmp);
return dt_set_errno(dtp, EDT_NOMEM);
}
@@ -975,18 +978,12 @@ dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
return dmp->dm_ctfp;
}
-/*ARGSUSED*/
+/*
+ * Discard a partial ELF load without invalidating persistent kernel metadata.
+ */
static void
-dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
+dt_module_clear_elf(dt_module_t *dmp)
{
- if (dmp->dm_btf != dtp->dt_shared_btf)
- dt_btf_destroy(dtp, dmp->dm_btf);
- dmp->dm_btf = NULL;
-
- if (dmp->dm_ctfp != dtp->dt_shared_ctf)
- ctf_close(dmp->dm_ctfp);
- dmp->dm_ctfp = NULL;
-
free(dmp->dm_ctdata_data);
dmp->dm_ctdata_data = NULL;
@@ -1003,31 +1000,33 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
free(dmp->dm_asmap);
dmp->dm_asmap = NULL;
- dt_symtab_destroy(dtp, dmp->dm_kernsyms);
- dmp->dm_kernsyms = NULL;
-
dmp->dm_symfree = 0;
dmp->dm_nsymbuckets = 0;
dmp->dm_nsymelems = 0;
dmp->dm_asrsv = 0;
dmp->dm_aslen = 0;
- free(dmp->dm_text_addrs);
- free(dmp->dm_data_addrs);
- dmp->dm_text_addrs = NULL;
- dmp->dm_data_addrs = NULL;
- dmp->dm_text_addrs_size = 0;
- dmp->dm_data_addrs_size = 0;
-
- dt_idhash_destroy(dmp->dm_extern);
- dmp->dm_extern = NULL;
-
elf_end(dmp->dm_elf);
dmp->dm_elf = NULL;
dmp->dm_flags &= ~DT_DM_LOADED;
}
+/* Release module metadata only when its owning module is destroyed. */
+static void
+dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+ if (dmp->dm_btf != dtp->dt_shared_btf)
+ dt_btf_destroy(dtp, dmp->dm_btf);
+ if (dmp->dm_ctfp != dtp->dt_shared_ctf)
+ ctf_close(dmp->dm_ctfp);
+ dt_module_clear_elf(dmp);
+ dt_symtab_destroy(dtp, dmp->dm_kernsyms);
+ free(dmp->dm_text_addrs);
+ free(dmp->dm_data_addrs);
+ dt_idhash_destroy(dmp->dm_extern);
+}
+
/*
* Insert a new external symbol reference into the specified module. The new
* symbol will be marked as undefined and is assigned a symbol index beyond
@@ -1768,8 +1767,7 @@ dt_modsym_addsym(dtrace_hdl_t *dtp, dt_module_t *dmp, dt_kallsym_t *sym,
* ranges as needed, and add the symbol in this line to the module's kernel
* symbol table.
*
- * If we return non-NULL, we might have a changing file, probably due
- * to module unloading during read. Perhaps this case should trigger a retry.
+ * Modules discovered by an earlier update retain their symbols and ranges.
*/
static int
dt_modsym_update(dtrace_hdl_t *dtp, const char *line, dt_kasstate_t *state)
@@ -1877,12 +1875,21 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line, dt_kasstate_t *state)
dmp = dt_module_create(dtp, modname);
if (dmp == NULL)
return EDT_NOMEM;
+ }
+ if (!(dmp->dm_flags & DT_DM_KERNEL)) {
err = dt_kern_module_init(dtp, dmp);
if (err != 0)
return err;
}
+ /* Never replace metadata for a previously discovered module. */
+ if (dmp->dm_flags & DT_DM_KERN_SYMS)
+ continue;
+
+ /* A module previously known only through on-disk types is now live. */
+ dmp->dm_flags &= ~DT_DM_KERN_UNLOADED;
+
err = dt_modsym_addsym(dtp, dmp, &sym, state);
if (err != 0)
return err;
@@ -1895,8 +1902,9 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line, dt_kasstate_t *state)
#undef KERNEL_FLAG_INIT_SCRATCH
/*
- * Unload all the loaded modules and then refresh the module cache with the
- * latest list of loaded modules and their address ranges.
+ * Discover new kernel modules without invalidating existing symbols, address
+ * ranges, or types. Module unloading and reloading are not supported: the first
+ * discovered instance of a module is retained until the handle is closed.
*/
int
dtrace_update(dtrace_hdl_t *dtp)
@@ -1905,10 +1913,6 @@ dtrace_update(dtrace_hdl_t *dtp)
FILE *fd;
dt_kasstate_t *state = NULL;
- for (dmp = dt_list_next(&dtp->dt_modlist);
- dmp != NULL; dmp = dt_list_next(dmp))
- dt_module_unload(dtp, dmp);
-
/*
* Note all the symbols currently loaded into the kernel's address
* space and construct modules with appropriate address ranges from
@@ -1945,13 +1949,21 @@ dtrace_update(dtrace_hdl_t *dtp)
*/
for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
dmp = dt_list_next(dmp)) {
+ if (!(dmp->dm_flags & DT_DM_KERNEL) ||
+ (dmp->dm_flags & (DT_DM_KERN_SYMS | DT_DM_KERN_UNLOADED)))
+ continue;
+
if (dmp->dm_kernsyms != NULL) {
dt_symtab_sort(dmp->dm_kernsyms,
state->kind == DT_MODSYM_KALLSYMS);
dt_symtab_pack(dmp->dm_kernsyms);
}
+ dmp->dm_flags |= DT_DM_KERN_SYMS;
}
+ /* Discover BTF IDs for new modules, retaining IDs already cached. */
+ dt_btf_get_module_ids(dtp);
+
/*
* Look up all the macro identifiers and set di_id to the latest value.
* This code collaborates with dt_lex.l on the use of di_id. We will
@@ -2082,10 +2094,8 @@ dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name,
/*
* Search loaded kernel symbols first, iff searching all kernel symbols
- * is requested. This is only an optimization: there are (obscure)
- * cases in which loaded kernel symbols might not end up in this hash
- * (e.g. if a kernel symbol is duplicated in multiple modules, then one
- * of them is unloaded).
+ * is requested. Fall back to per-module lookup for symbols loaded
+ * from ELF objects rather than the running kernel.
*/
if ((object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS) &&
dtp->dt_kernsyms) {
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 1baf3844..9dd15483 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -1227,7 +1227,6 @@ dtrace_init(dtrace_hdl_t *dtp)
* Initialize the BPF library handling.
*/
dt_bpf_init(dtp);
- dt_btf_get_module_ids(dtp);
dt_dlib_init(dtp);
/*
diff --git a/libdtrace/dtrace.h b/libdtrace/dtrace.h
index 82965fbd..2b4bf583 100644
--- a/libdtrace/dtrace.h
+++ b/libdtrace/dtrace.h
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -480,9 +480,9 @@ extern pid_t dtrace_proc_getpid(dtrace_hdl_t *dtp,
* information cached for each of the program objects in use by DTrace. The
* resulting struct contains pointers to address range arrays and arbitrary-
* length strings, including object, symbol, and type names, that are persistent
- * until the next call to dtrace_update(). Once dtrace_update() is called, any
- * cached values must be flushed and not used subsequently by the client
- * program.
+ * until dtrace_close(). dtrace_update() discovers additional kernel modules
+ * without invalidating existing metadata. Kernel module unloading and reloading
+ * are not supported: metadata for the first discovered instance is retained.
*/
#define DTRACE_OBJ_EXEC ((const char *)0L) /* primary executable file */
diff --git a/test/internals/btf/tst.module-discovery.sh b/test/internals/btf/tst.module-discovery.sh
new file mode 100755
index 00000000..4edff5df
--- /dev/null
+++ b/test/internals/btf/tst.module-discovery.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+# ASSERTION: Module discovery adds new symbols and retains metadata across
+# repeated updates, module disappearance, and module reloading.
+#
+
+test/triggers/module-discovery
diff --git a/test/triggers/Build b/test/triggers/Build
index f8a08d6c..20763860 100644
--- a/test/triggers/Build
+++ b/test/triggers/Build
@@ -24,7 +24,8 @@ EXTERNAL_TRIGGERS = $(EXTERNAL_64BIT_TRIGGERS) $(if $(NATIVE_BITNESS_ONLY),,$(EX
INTERNAL_64BIT_TRIGGERS = libproc-pldd libproc-consistency libproc-sleeper \
libproc-sleeper-pie libproc-dlmadopen libproc-lookup-by-name \
- libproc-lookup-victim libproc-execing-bkpts libproc-execing-bkpts-victim
+ libproc-lookup-victim libproc-execing-bkpts libproc-execing-bkpts-victim \
+ module-discovery
INTERNAL_32BIT_TRIGGERS := libproc-sleeper-32 libproc-sleeper-pie-32
INTERNAL_TRIGGERS = $(INTERNAL_64BIT_TRIGGERS) $(if $(NATIVE_BITNESS_ONLY),,$(INTERNAL_32BIT_TRIGGERS))
@@ -244,3 +245,11 @@ ustack-tst-bigstack-spin_CFLAGS := -O0 -fno-inline -fno-omit-frame-pointer
ustack-tst-spin_CFLAGS := -O0
ustack-tst-mtspin_CFLAGS := -O0
ustack-tst-mtspin_LIBS := -lpthread
+
+module-discovery_CFLAGS := -Ilibproc -Ilibdtrace -Ilibcommon -Wno-pedantic
+module-discovery_LDFLAGS := -Wl,--wrap=fopen64 \
+ -Wl,--wrap=dt_bpf_btf_get_next_id -Wl,--wrap=dt_bpf_btf_get_fd_by_id \
+ -Wl,--wrap=dt_bpf_btf_get_info_by_fd
+module-discovery_DEPS := build-libdtrace.a build-libproc.a libcommon.a libport.a
+module-discovery_LIBS := $(objdir)/build-libdtrace.a $(objdir)/build-libproc.a \
+ $(objdir)/build-libcommon.a $(objdir)/build-libport.a $(libdtrace_LIBS)
diff --git a/test/triggers/module-discovery.c b/test/triggers/module-discovery.c
new file mode 100644
index 00000000..d11b761b
--- /dev/null
+++ b/test/triggers/module-discovery.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <dt_bpf.h>
+#include <dt_module.h>
+#include <dt_symtab.h>
+
+#define CHECK(expr) do { \
+ if (!(expr)) { \
+ fprintf(stderr, "Check failed at line %d: %s\n", __LINE__, #expr); \
+ return 1; \
+ } \
+} while (0)
+
+static const char *symbols;
+static int kallsyms;
+static uint32_t btf_generation, btf_id;
+
+extern FILE *__real_fopen64(const char *, const char *);
+
+/* Supply changing kernel symbol snapshots without loading real modules. */
+FILE *
+__wrap_fopen64(const char *path, const char *mode)
+{
+ if (symbols != NULL) {
+ if (strcmp(path, "/proc/kallmodsyms") == 0) {
+ if (!kallsyms)
+ return fmemopen((void *)symbols, strlen(symbols), "r");
+ errno = ENOENT;
+ return NULL;
+ }
+ if (strcmp(path, "/proc/kallsyms") == 0)
+ return fmemopen((void *)symbols, strlen(symbols), "r");
+ }
+ return __real_fopen64(path, mode);
+}
+
+extern int __real_dt_bpf_btf_get_fd_by_id(uint32_t);
+extern int __real_dt_bpf_btf_get_info_by_fd(int, btf_info_t *, uint32_t *);
+
+int
+__wrap_dt_bpf_btf_get_next_id(uint32_t curr, uint32_t *next)
+{
+ /*
+ * Do not cache real kernel IDs during dtrace_open(): they can collide
+ * with the synthetic IDs used by subsequent discovery snapshots.
+ */
+ if (symbols == NULL || curr == btf_generation + 3) {
+ errno = ENOENT;
+ return -1;
+ }
+ *next = curr == 0 ? btf_generation + 1 : curr + 1;
+ return 0;
+}
+
+int
+__wrap_dt_bpf_btf_get_fd_by_id(uint32_t id)
+{
+ if (symbols == NULL)
+ return __real_dt_bpf_btf_get_fd_by_id(id);
+ btf_id = id;
+ return open("/dev/null", O_RDONLY);
+}
+
+int
+__wrap_dt_bpf_btf_get_info_by_fd(int fd, btf_info_t *info, uint32_t *size)
+{
+ static const char *names[] = {
+ "discovery_first", "discovery_second", "discovery_offline"
+ };
+
+ if (symbols == NULL)
+ return __real_dt_bpf_btf_get_info_by_fd(fd, info, size);
+ snprintf((char *)(uintptr_t)info->name, info->name_len, "%s",
+ names[btf_id - btf_generation - 1]);
+ return 0;
+}
+
+static int
+check_discovery(int fallback)
+{
+ dtrace_hdl_t *dtp;
+ dt_module_t *kernel, *first, *second, *offline;
+ dt_symtab_t *kernel_syms, *first_syms;
+ dt_symbol_t *sym, *entry;
+ int count, found_first, found_second;
+ dtrace_addr_range_t *ranges, *kernel_ranges;
+ ctf_file_t *types;
+ GElf_Sym elf;
+ int err, i;
+
+ CHECK((dtp = dtrace_open(DTRACE_VERSION, DTRACE_O_LP64, &err)) != NULL);
+ kernel = dtp->dt_exec;
+ CHECK(kernel != NULL);
+ kernel_syms = kernel->dm_kernsyms;
+ kernel_ranges = kernel->dm_text_addrs;
+ kallsyms = fallback;
+ btf_generation = 100;
+
+ /* A module can be known through its types before it is discovered live. */
+ CHECK((offline = dt_module_create(dtp, "discovery_offline")) != NULL);
+ CHECK((types = ctf_create(&err)) != NULL);
+ offline->dm_ctfp = types;
+ offline->dm_flags |= DT_DM_KERNEL | DT_DM_KERN_UNLOADED;
+
+ symbols = fallback ?
+ "100 T _end\n"
+ "1000 T discovery_symbol [discovery_first]\n"
+ "1010 T discovery_tail [discovery_first]\n" :
+ "100 1 T _end\n"
+ "1000 10 T discovery_symbol [discovery_first]\n"
+ "1010 10 T discovery_tail [discovery_first]\n";
+ CHECK(dtrace_update(dtp) == 0);
+ CHECK((first = dt_module_lookup_by_name(dtp, "discovery_first")) != NULL);
+ CHECK(first->dm_flags & DT_DM_KERNEL);
+ CHECK(first->dm_btf_id == 101);
+ CHECK((sym = dt_module_symbol_by_name(dtp, first, "discovery_symbol")) != NULL);
+ first_syms = first->dm_kernsyms;
+ ranges = first->dm_text_addrs;
+ CHECK(first->dm_text_addrs_size == 1);
+ CHECK(ranges->dar_va == 0x1000);
+ CHECK(ranges->dar_size == (fallback ? 0x11 : 0x20));
+ CHECK(dt_symbol_by_addr(first_syms, 0x1000) == sym);
+
+ /* Keep the old module while discovering another, including a duplicate name. */
+ btf_generation = 200;
+ symbols = fallback ?
+ "100 T _end\n"
+ "1000 T discovery_symbol [discovery_first]\n"
+ "1010 T discovery_tail [discovery_first]\n"
+ "2000 T discovery_symbol [discovery_second]\n"
+ "3000 T discovery_live [discovery_offline]\n" :
+ "100 1 T _end\n"
+ "1000 10 T discovery_symbol [discovery_first]\n"
+ "1010 10 T discovery_tail [discovery_first]\n"
+ "2000 10 T discovery_symbol [discovery_second]\n"
+ "3000 10 T discovery_live [discovery_offline]\n";
+ CHECK(dtrace_update(dtp) == 0);
+ CHECK((second = dt_module_lookup_by_name(dtp, "discovery_second")) != NULL);
+ CHECK(first->dm_btf_id == 101 && second->dm_btf_id == 202);
+ CHECK(dt_module_symbol_by_name(dtp, second, "discovery_symbol") != NULL);
+ CHECK(dt_module_symbol_by_name(dtp, offline, "discovery_live") != NULL);
+ CHECK(!(offline->dm_flags & DT_DM_KERN_UNLOADED));
+ CHECK(offline->dm_ctfp == types);
+ count = found_first = found_second = 0;
+ for (entry = dt_symbol_by_name(dtp, "discovery_symbol"); entry != NULL;
+ entry = dt_symbol_by_name_next(entry)) {
+ count++;
+ found_first += entry == sym;
+ found_second += dt_symbol_module(entry) == second;
+ }
+ CHECK(count == 2 && found_first == 1 && found_second == 1);
+
+ /* Disappearance and reappearance at a new address do not replace metadata. */
+ for (i = 0; i < 4; i++) {
+ symbols = i % 2 == 0 ? "" : fallback ?
+ "100 T _end\n9000 T discovery_symbol [discovery_first]\n" :
+ "100 1 T _end\n9000 80 T discovery_symbol [discovery_first]\n";
+ CHECK(dtrace_update(dtp) == 0);
+ CHECK(dtp->dt_exec == kernel);
+ CHECK(kernel->dm_kernsyms == kernel_syms);
+ CHECK(kernel->dm_text_addrs == kernel_ranges);
+ CHECK(first->dm_kernsyms == first_syms);
+ CHECK(first->dm_btf_id == 101 && second->dm_btf_id == 202);
+ CHECK(first->dm_text_addrs == ranges);
+ CHECK(first->dm_text_addrs_size == 1);
+ CHECK(ranges->dar_va == 0x1000);
+ CHECK(ranges->dar_size == (fallback ? 0x11 : 0x20));
+ CHECK(dt_module_symbol_by_name(dtp, first, "discovery_symbol") == sym);
+ dt_symbol_to_elfsym(dtp, sym, &elf);
+ CHECK(elf.st_value == 0x1000);
+ CHECK(dt_symbol_by_addr(first_syms, 0x9000) == NULL);
+ CHECK(dt_module_symbol_by_name(dtp, second, "discovery_symbol") != NULL);
+ CHECK(offline->dm_ctfp == types);
+ }
+
+ symbols = NULL;
+ dtrace_close(dtp);
+ return 0;
+}
+
+int
+main(void)
+{
+ CHECK(check_discovery(0) == 0);
+ CHECK(check_discovery(1) == 0);
+ return 0;
+}
--
2.52.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-30 19:38 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30 19:36 [PATCH 02/20] libdtrace: retain module metadata across incremental discovery Kris Van Hees
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox