From 07f201748f5d0ecfda7b6ede2f3812cb700ba119 Mon Sep 17 00:00:00 2001 From: markj Date: Sat, 6 Jun 2015 16:47:45 +0000 Subject: libdtrace: allow D libraries to declare dependencies on kernel modules The "depends_on module" pragma can be used to declare a dependency on a DTrace module, which for kernel probes corresponds to a KLD. Such dependencies cannot be checked if the KLD is compiled into the kernel. Therefore, allow a module dependency to be satisfied if either a kernel module or a KLD with the specified name is loaded. Differential Revision: https://reviews.freebsd.org/D2653 Reviewed by: gnn, rpaulo Reported by: gnn --- .../opensolaris/lib/libdtrace/common/dt_impl.h | 18 ++++++++ .../opensolaris/lib/libdtrace/common/dt_module.c | 50 ++++++++++++++++++++++ .../opensolaris/lib/libdtrace/common/dt_module.h | 4 ++ .../opensolaris/lib/libdtrace/common/dt_open.c | 20 +++++++++ .../opensolaris/lib/libdtrace/common/dt_pragma.c | 8 ++++ 5 files changed, 100 insertions(+) (limited to 'cddl/contrib/opensolaris/lib') diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h index 51bed72..36cc539 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h @@ -156,6 +156,21 @@ typedef struct dt_module { #define DT_DM_KERNEL 0x2 /* module is associated with a kernel object */ #define DT_DM_PRIMARY 0x4 /* module is a krtld primary kernel object */ +#ifdef __FreeBSD__ +/* + * A representation of a FreeBSD kernel module, used when checking module + * dependencies. This differs from dt_module_t, which refers to a KLD in the + * case of kernel probes. Since modules can be identified regardless of whether + * they've been compiled into the kernel, we use them to identify DTrace + * modules. + */ +typedef struct dt_kmodule { + struct dt_kmodule *dkm_next; /* hash table entry */ + char *dkm_name; /* string name of module */ + dt_module_t *dkm_module; /* corresponding KLD module */ +} dt_kmodule_t; +#endif + typedef struct dt_provmod { char *dp_name; /* name of provider module */ struct dt_provmod *dp_next; /* next module */ @@ -235,6 +250,9 @@ struct dtrace_hdl { dt_idhash_t *dt_tls; /* hash table of thread-local identifiers */ dt_list_t dt_modlist; /* linked list of dt_module_t's */ dt_module_t **dt_mods; /* hash table of dt_module_t's */ +#ifdef __FreeBSD__ + dt_kmodule_t **dt_kmods; /* hash table of dt_kmodule_t's */ +#endif uint_t dt_modbuckets; /* number of module hash buckets */ uint_t dt_nmods; /* number of modules in hash and list */ dt_provmod_t *dt_provmod; /* linked list of provider modules */ diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c index b3fe516..77f9223 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c @@ -37,6 +37,7 @@ #else #include #include +#include #include #endif @@ -542,6 +543,22 @@ dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp) return (ctfp ? ctf_getspecific(ctfp) : NULL); } +#ifdef __FreeBSD__ +dt_kmodule_t * +dt_kmodule_lookup(dtrace_hdl_t *dtp, const char *name) +{ + uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; + dt_kmodule_t *dkmp; + + for (dkmp = dtp->dt_kmods[h]; dkmp != NULL; dkmp = dkmp->dkm_next) { + if (strcmp(dkmp->dkm_name, name) == 0) + return (dkmp); + } + + return (NULL); +} +#endif + static int dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp) { @@ -1124,6 +1141,12 @@ dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat) char fname[MAXPATHLEN]; struct stat64 st; int fd, err, bits; +#ifdef __FreeBSD__ + struct module_stat ms; + dt_kmodule_t *dkmp; + uint_t h; + int modid; +#endif dt_module_t *dmp; const char *s; @@ -1270,6 +1293,33 @@ dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat) if (dmp->dm_info.objfs_info_primary) dmp->dm_flags |= DT_DM_PRIMARY; +#ifdef __FreeBSD__ + ms.version = sizeof(ms); + for (modid = kldfirstmod(k_stat->id); modid > 0; + modid = modnext(modid)) { + if (modstat(modid, &ms) != 0) { + dt_dprintf("modstat failed for id %d in %s: %s\n", + modid, k_stat->name, strerror(errno)); + continue; + } + if (dt_kmodule_lookup(dtp, ms.name) != NULL) + continue; + + dkmp = malloc(sizeof (*dkmp)); + if (dkmp == NULL) { + dt_dprintf("failed to allocate memory\n"); + dt_module_destroy(dtp, dmp); + return; + } + + h = dt_strtab_hash(ms.name, NULL) % dtp->dt_modbuckets; + dkmp->dkm_next = dtp->dt_kmods[h]; + dkmp->dkm_name = strdup(ms.name); + dkmp->dkm_module = dmp; + dtp->dt_kmods[h] = dkmp; + } +#endif + dt_dprintf("opened %d-bit module %s (%s) [%d]\n", bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid); } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h index d103e02..6db16cc 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h @@ -44,6 +44,10 @@ extern void dt_module_destroy(dtrace_hdl_t *, dt_module_t *); 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 *); +#ifdef __FreeBSD__ +extern dt_kmodule_t *dt_kmodule_lookup(dtrace_hdl_t *, const char *); +#endif + extern int dt_module_hasctf(dtrace_hdl_t *, dt_module_t *); 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/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index 80e4be9..ac0524b 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -1178,6 +1178,9 @@ alloc: #endif dtp->dt_modbuckets = _dtrace_strbuckets; dtp->dt_mods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *)); +#ifdef __FreeBSD__ + dtp->dt_kmods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *)); +#endif dtp->dt_provbuckets = _dtrace_strbuckets; dtp->dt_provs = calloc(dtp->dt_provbuckets, sizeof (dt_provider_t *)); dt_proc_hash_create(dtp); @@ -1199,6 +1202,7 @@ alloc: if (dtp->dt_mods == NULL || dtp->dt_provs == NULL || dtp->dt_procs == NULL || dtp->dt_ld_path == NULL || #ifdef __FreeBSD__ + dtp->dt_kmods == NULL || dtp->dt_objcopy_path == NULL || #endif dtp->dt_cpp_path == NULL || dtp->dt_cpp_argv == NULL) @@ -1621,6 +1625,10 @@ dtrace_close(dtrace_hdl_t *dtp) dtrace_prog_t *pgp; dt_xlator_t *dxp; dt_dirpath_t *dirp; +#ifdef __FreeBSD__ + dt_kmodule_t *dkm; + uint_t h; +#endif int i; if (dtp->dt_procs != NULL) @@ -1648,6 +1656,15 @@ dtrace_close(dtrace_hdl_t *dtp) if (dtp->dt_tls != NULL) dt_idhash_destroy(dtp->dt_tls); +#ifdef __FreeBSD__ + for (h = 0; h < dtp->dt_modbuckets; h++) + while ((dkm = dtp->dt_kmods[h]) != NULL) { + dtp->dt_kmods[h] = dkm->dkm_next; + free(dkm->dkm_name); + free(dkm); + } +#endif + while ((dmp = dt_list_next(&dtp->dt_modlist)) != NULL) dt_module_destroy(dtp, dmp); @@ -1697,6 +1714,9 @@ dtrace_close(dtrace_hdl_t *dtp) #endif free(dtp->dt_mods); +#ifdef __FreeBSD__ + free(dtp->dt_kmods); +#endif free(dtp->dt_provs); free(dtp); } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c index bd0d708..550a436 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c @@ -278,6 +278,14 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp) } else if (strcmp(cnp->dn_string, "module") == 0) { dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; +#ifdef __FreeBSD__ + if (!found) { + dt_kmodule_t *dkmp = dt_kmodule_lookup(dtp, + nnp->dn_string); + found = dkmp != NULL && + dt_module_getctf(dtp, dkmp->dkm_module) != NULL; + } +#endif } else if (strcmp(cnp->dn_string, "library") == 0) { if (yypcb->pcb_cflags & DTRACE_C_CTL) { assert(dtp->dt_filetag != NULL); -- cgit v1.1