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
This commit is contained in:
John Birrell 2007-10-22 04:12:57 +00:00
parent a3347b3e74
commit 1676805c18
4 changed files with 71 additions and 9 deletions

View File

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

View File

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

View File

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

View File

@ -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 {