summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjb <jb@FreeBSD.org>2007-10-22 04:12:57 +0000
committerjb <jb@FreeBSD.org>2007-10-22 04:12:57 +0000
commit9dec415fef268455335c088626d24f3cd5dd26fc (patch)
treeca90169fbd250bbc580b712e8482c755895ffc8f
parent9392728ba026a7e54d585f8efec5f232146d34a2 (diff)
downloadFreeBSD-src-9dec415fef268455335c088626d24f3cd5dd26fc.zip
FreeBSD-src-9dec415fef268455335c088626d24f3cd5dd26fc.tar.gz
Add the full module path name to the kld_file_stat structure
for kldstat(2). This allows libdtrace to determine the exact file from which a kernel module was loaded without having to guess. The kldstat(2) API is versioned with the size of the kld_file_stat structure, so this change creates version 2. Add the pathname to the verbose output of kldstat(8) too. MFC: 3 days
-rw-r--r--lib/libc/sys/kldstat.25
-rw-r--r--sbin/kldstat/kldstat.c4
-rw-r--r--sys/kern/kern_linker.c45
-rw-r--r--sys/sys/linker.h26
4 files changed, 71 insertions, 9 deletions
diff --git a/lib/libc/sys/kldstat.2 b/lib/libc/sys/kldstat.2
index 946417a..f2ca2a6 100644
--- a/lib/libc/sys/kldstat.2
+++ b/lib/libc/sys/kldstat.2
@@ -53,6 +53,7 @@ struct kld_file_stat {
int id;
caddr_t address; /* load address */
size_t size; /* size in bytes */
+ char pathname[MAXPATHLEN];
};
.Ed
.Pp
@@ -77,6 +78,10 @@ The id of the file specified in
The load address of the kld file.
.It size
The size of the file.
+.It pathname
+The full name of the file referred to by
+.Fa fileid ,
+including the path.
.El
.Sh RETURN VALUES
.Rv -std kldstat
diff --git a/sbin/kldstat/kldstat.c b/sbin/kldstat/kldstat.c
index 74f375e..4f4e786 100644
--- a/sbin/kldstat/kldstat.c
+++ b/sbin/kldstat/kldstat.c
@@ -60,9 +60,9 @@ static void printfile(int fileid, int verbose)
if (kldstat(fileid, &stat) < 0)
warn("can't stat file id %d", fileid);
else
- printf("%2d %4d %p %-8jx %s\n",
+ printf("%2d %4d %p %-8jx %s (%s)\n",
stat.id, stat.refs, stat.address, (uintmax_t)stat.size,
- stat.name);
+ stat.name, stat.pathname);
if (verbose) {
printf("\tContains modules:\n");
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index 7640334..324d349 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -97,6 +97,12 @@ linker_file_t linker_kernel_file;
static struct sx kld_sx; /* kernel linker lock */
+/*
+ * Load counter used by clients to determine if a linker file has been
+ * re-loaded. This counter is incremented for each file load.
+ */
+static int loadcnt;
+
static linker_class_list_t classes;
static linker_file_list_t linker_files;
static int next_file_id = 1;
@@ -534,7 +540,7 @@ linker_make_file(const char *pathname, linker_class_t lc)
KLD_LOCK_ASSERT();
filename = linker_basename(pathname);
- KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
+ KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname));
lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK);
if (lf == NULL)
return (NULL);
@@ -542,9 +548,13 @@ linker_make_file(const char *pathname, linker_class_t lc)
lf->userrefs = 0;
lf->flags = 0;
lf->filename = linker_strdup(filename);
+ lf->pathname = linker_strdup(pathname);
LINKER_GET_NEXT_FILE_ID(lf->id);
lf->ndeps = 0;
lf->deps = NULL;
+ lf->loadcnt = ++loadcnt;
+ lf->sdt_probes = NULL;
+ lf->sdt_nprobes = 0;
STAILQ_INIT(&lf->common);
TAILQ_INIT(&lf->modules);
TAILQ_INSERT_TAIL(&linker_files, lf, link);
@@ -629,6 +639,10 @@ linker_file_unload(linker_file_t file, int flags)
free(file->filename, M_LINKER);
file->filename = NULL;
}
+ if (file->pathname) {
+ free(file->pathname, M_LINKER);
+ file->pathname = NULL;
+ }
kobj_delete((kobj_t) file, M_LINKER);
return (0);
}
@@ -920,7 +934,13 @@ kern_kldunload(struct thread *td, int fileid, int flags)
lf = linker_find_file_by_id(fileid);
if (lf) {
KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
- if (lf->userrefs == 0) {
+
+ /* Check if there are DTrace probes enabled on this file. */
+ if (lf->nenabled > 0) {
+ printf("kldunload: attempt to unload file that has"
+ " DTrace probes enabled\n");
+ error = EBUSY;
+ } else if (lf->userrefs == 0) {
/*
* XXX: maybe LINKER_UNLOAD_FORCE should override ?
*/
@@ -1041,15 +1061,18 @@ kldstat(struct thread *td, struct kldstat_args *uap)
{
struct kld_file_stat stat;
linker_file_t lf;
- int error, namelen;
+ int error, namelen, version, version_num;
/*
* Check the version of the user's structure.
*/
- error = copyin(uap->stat, &stat, sizeof(struct kld_file_stat));
- if (error)
+ if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0)
return (error);
- if (stat.version != sizeof(struct kld_file_stat))
+ if (version == sizeof(struct kld_file_stat_1))
+ version_num = 1;
+ else if (version == sizeof(struct kld_file_stat))
+ version_num = 2;
+ else
return (EINVAL);
#ifdef MAC
@@ -1065,6 +1088,7 @@ kldstat(struct thread *td, struct kldstat_args *uap)
return (ENOENT);
}
+ /* Version 1 fields: */
namelen = strlen(lf->filename) + 1;
if (namelen > MAXPATHLEN)
namelen = MAXPATHLEN;
@@ -1073,11 +1097,18 @@ kldstat(struct thread *td, struct kldstat_args *uap)
stat.id = lf->id;
stat.address = lf->address;
stat.size = lf->size;
+ if (version_num > 1) {
+ /* Version 2 fields: */
+ namelen = strlen(lf->pathname) + 1;
+ if (namelen > MAXPATHLEN)
+ namelen = MAXPATHLEN;
+ bcopy(lf->pathname, &stat.pathname[0], namelen);
+ }
KLD_UNLOCK();
td->td_retval[0] = 0;
- return (copyout(&stat, uap->stat, sizeof(struct kld_file_stat)));
+ return (copyout(&stat, uap->stat, version));
}
int
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
index e35180a..83774e6 100644
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -73,6 +73,7 @@ struct linker_file {
#define LINKER_FILE_LINKED 0x1 /* file has been fully linked */
TAILQ_ENTRY(linker_file) link; /* list of all loaded files */
char* filename; /* file which was loaded */
+ char* pathname; /* file name with full path */
int id; /* unique id */
caddr_t address; /* load address */
size_t size; /* size of file */
@@ -81,6 +82,18 @@ struct linker_file {
STAILQ_HEAD(, common_symbol) common; /* list of common symbols */
TAILQ_HEAD(, module) modules; /* modules in this file */
TAILQ_ENTRY(linker_file) loaded; /* preload dependency support */
+ int loadcnt; /* load counter value */
+
+ /*
+ * Function Boundary Tracing (FBT) or Statically Defined Tracing (SDT)
+ * fields.
+ */
+ int nenabled; /* number of enabled probes. */
+ int fbt_nentries; /* number of fbt entries created. */
+ void *sdt_probes;
+ int sdt_nentries;
+ size_t sdt_nprobes;
+ size_t sdt_size;
};
/*
@@ -245,6 +258,18 @@ int elf_cpu_unload_file(linker_file_t);
#define ELF_RELOC_REL 1
#define ELF_RELOC_RELA 2
+/*
+ * This is version 1 of the KLD file status structure. It is identified
+ * by it's _size_ in the version field.
+ */
+struct kld_file_stat_1 {
+ int version; /* set to sizeof(linker_file_stat) */
+ char name[MAXPATHLEN];
+ int refs;
+ int id;
+ caddr_t address; /* load address */
+ size_t size; /* size in bytes */
+};
#endif /* _KERNEL */
struct kld_file_stat {
@@ -254,6 +279,7 @@ struct kld_file_stat {
int id;
caddr_t address; /* load address */
size_t size; /* size in bytes */
+ char pathname[MAXPATHLEN];
};
struct kld_sym_lookup {
OpenPOWER on IntegriCloud