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
This commit is contained in:
Mark Johnston 2015-06-06 16:47:45 +00:00
parent 3981a55d9d
commit 8436cb81cd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=284085
5 changed files with 100 additions and 0 deletions

View File

@ -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 */

View File

@ -37,6 +37,7 @@
#else
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/module.h>
#include <sys/stat.h>
#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);
}

View File

@ -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 *,

View File

@ -1178,6 +1178,9 @@ dt_vopen(int version, int flags, int *errp,
#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 @@ dt_vopen(int version, int flags, int *errp,
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);
}

View File

@ -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);