summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/asf/Makefile6
-rw-r--r--usr.sbin/asf/asf.892
-rw-r--r--usr.sbin/asf/asf.c524
-rw-r--r--usr.sbin/asf/asf.h40
-rw-r--r--usr.sbin/asf/asf_kld.c59
-rw-r--r--usr.sbin/asf/asf_kvm.c128
-rw-r--r--usr.sbin/asf/asf_prog.c73
7 files changed, 685 insertions, 237 deletions
diff --git a/usr.sbin/asf/Makefile b/usr.sbin/asf/Makefile
index b8e7e4b..b4b7af3 100644
--- a/usr.sbin/asf/Makefile
+++ b/usr.sbin/asf/Makefile
@@ -1,6 +1,12 @@
# $FreeBSD$
PROG= asf
+SRCS= asf.c asf_kld.c asf_kvm.c asf_prog.c
MAN= asf.8
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+
+WARNS?= 4
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/asf/asf.8 b/usr.sbin/asf/asf.8
index 65d8762..649fac1 100644
--- a/usr.sbin/asf/asf.8
+++ b/usr.sbin/asf/asf.8
@@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 8, 2003
+.Dd June 18, 2006
.Os
.Dt ASF 8
.Sh NAME
@@ -31,14 +31,20 @@
.Nd add symbol files
.Sh SYNOPSIS
.Nm
-.Op Fl afksx
+.Op Fl afKksVx
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Op Fl o Ar outfile
+.Op Fl X Ar suffix
.Op Ar modules-path Op Ar outfile
.Sh DESCRIPTION
By default,
.Nm
reads
.Xr kldstat 8
-output from standard input and writes to standard output a list of
+output from standard input and writes to the
+.Pa \&.asf
+file a list of
.Xr gdb 1
commands to add symbol files from KLDs in subdirectories of the subdirectory
.Pa modules
@@ -62,7 +68,13 @@ If
.Ar outfile
is specified,
.Nm
-writes to it instead of standard output.
+writes to it instead of
+.Pa .asf .
+If
+.Ar outfile
+is a single dash
+.Pq Sq \&- ,
+the standard output is used.
.Sh OPTIONS
The following options modify the function of
.Nm :
@@ -78,26 +90,72 @@ a traversal in the same way that
does to locate an exact path for each module, no matter where in
.Ar modules-path
it is located.
+.It Fl K
+Instead of reading from standard input, use the conventional
+system interface to get the list of modules currently loaded.
.It Fl k
Instead of reading from standard input, start a
.Xr kldstat 8
and read the information from it.
+.It Fl M
+Specify the core file for
+.Xr kvm 3 .
+Impiles
+.Fl V .
+.It Fl N
+Specify the system file for
+.Xr kvm 3 .
+Implies
+.Fl V .
+.It Fl o
+Specify the file for
+.Nm
+to write or append its output to.
+If
+.Ar outfile
+is a single dash
+.Pq Sq \&- ,
+the standard output is used.
.It Fl s
Do not prepend a (guessed) subdirectory of the module path.
-.It Fl x
-Normally
-.Nm
-looks for KLDs with names of the form
-.Ao Ar module Ac Ns Pa .ko.debug .
+.It Fl V
+Instead of reading from standard input, use the
+.Xr kvm 3
+interface to get the list of modules.
+This interface allows for inspecting system crash dumps,
+as well as the live system.
The
-.Fl x
-option tells
+.Fl M
+and
+.Fl N
+options will be of use if inspecting a crash dump.
+Elevated privileges, e.g., those of a superuser,
+may be needed to use this option.
+.It Fl X
+Add
+.Ar suffix
+to the list of suffixes
.Nm
-to look for KLDs with names of the form
-.Ao Ar module Ac Ns Pa .ko .
+tries to append to KLD file names.
+The default list consists of
+.Pa .debug ,
+.Pa .symbols ,
+and the null suffix.
+The null suffix always stays at the list tail, after the suffix added.
+Should it be needed in the middle of the list,
+a blank suffix can be specified to
+.Fl X
+instead.
+.It Fl x
+Clear the list of suffixes
+.Nm
+tries to append to KLD file names.
+Only the null suffix is left in the list.
.El
.Sh SEE ALSO
.Xr gdb 1 ,
+.Xr kvm 3 ,
+.Xr kld 4 ,
.Xr kldstat 8
.Sh HISTORY
The
@@ -107,6 +165,8 @@ utility first appeared in
.Sh AUTHORS
.An Greg Lehey Aq grog@FreeBSD.org
.Sh BUGS
-It should be possible to write to an
-.Ar outfile
-without specifying a module path.
+Module paths are guessed in a rather naive way by default.
+It is likely to lag behind the changes to the build tree layout.
+Using
+.Fl f
+is recommended.
diff --git a/usr.sbin/asf/asf.c b/usr.sbin/asf/asf.c
index 2539011..7a30386 100644
--- a/usr.sbin/asf/asf.c
+++ b/usr.sbin/asf/asf.c
@@ -1,4 +1,4 @@
-/*
+/*-
* Copyright (c) 2002, 2003 Greg Lehey
* All rights reserved.
*
@@ -24,26 +24,77 @@
* software, even if advised of the possibility of such damage.
*/
/* $Id: asf.c,v 1.4 2003/05/04 02:55:20 grog Exp grog $ */
-/* $FreeBSD$ */
-#define MAXLINE 1024
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
#include <ctype.h>
+#include <err.h>
#include <errno.h>
+#include <fts.h>
+#include <inttypes.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/file.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <fts.h>
#include <unistd.h>
-#define MAXTOKEN 10
-const char *modules_path; /* path relative to kernel
- * build directory */
-const char *outfile; /* and where to write the output */
+#include "asf.h"
+
+struct kfile {
+ char *name;
+ caddr_t addr;
+ int seen;
+ STAILQ_ENTRY(kfile) link;
+};
+
+static STAILQ_HEAD(,kfile) kfile_head = STAILQ_HEAD_INITIALIZER(kfile_head);
+
+void
+kfile_add(const char *name, caddr_t addr)
+{
+ struct kfile *kfp;
+
+ if ((kfp = malloc(sizeof(*kfp))) == NULL ||
+ (kfp->name = strdup(name)) == NULL)
+ errx(2, "out of memory");
+ kfp->addr = addr;
+ kfp->seen = 0;
+ STAILQ_INSERT_TAIL(&kfile_head, kfp, link);
+}
+
+static struct kfile *
+kfile_find(const char *name)
+{
+ struct kfile *kfp;
+
+ STAILQ_FOREACH(kfp, &kfile_head, link)
+ if (strcmp(kfp->name, name) == 0)
+ return (kfp); /* found */
+
+ return (NULL); /* not found */
+}
+
+static int
+kfile_allseen(void)
+{
+ struct kfile *kfp;
+
+ STAILQ_FOREACH(kfp, &kfile_head, link)
+ if (!kfp->seen)
+ return (0); /* at least one unseen */
+
+ return (1); /* all seen */
+}
+
+static int
+kfile_empty(void)
+{
+ return (STAILQ_EMPTY(&kfile_head));
+}
/*
* Take a blank separated list of tokens and turn it into a list of
@@ -52,7 +103,7 @@ const char *outfile; /* and where to write the output */
* number of tokens, or -1 on error (typically a missing string
* delimiter).
*/
-static int
+int
tokenize(char *cptr, char *token[], int maxtoken)
{
char delim; /* delimiter to search for */
@@ -92,70 +143,109 @@ tokenize(char *cptr, char *token[], int maxtoken)
return maxtoken; /* can't get here */
}
-static char *
-findmodule(char *modules_path, const char *module_name)
+static void
+doobj(const char *path, caddr_t addr, FILE *out)
{
- char *const path_argv[2] = { modules_path, NULL };
- char *module_path = NULL;
- int module_name_len = strlen(module_name);
- FTS *fts;
- FTSENT *ftsent;
-
- if (modules_path == NULL) {
- fprintf(stderr,
- "Can't allocate memory to traverse a path: %s (%d)\n",
- strerror(errno),
- errno);
- exit(1);
+ uintmax_t base = (uintptr_t)addr;
+ uintmax_t textaddr = 0;
+ uintmax_t dataaddr = 0;
+ uintmax_t bssaddr = 0;
+ uintmax_t *up;
+ int octokens;
+ char *octoken[MAXTOKEN];
+ char ocbuf[LINE_MAX + PATH_MAX];
+ FILE *objcopy;
+
+ snprintf(ocbuf, sizeof(ocbuf),
+ "/usr/bin/objdump --section-headers %s", path);
+ if ((objcopy = popen(ocbuf, "r")) == NULL)
+ err(2, "can't start %s", ocbuf);
+ while (fgets(ocbuf, sizeof(ocbuf), objcopy)) {
+ octokens = tokenize(ocbuf, octoken, MAXTOKEN);
+ if (octokens <= 1)
+ continue;
+ up = NULL;
+ if (strcmp(octoken[1], ".text") == 0)
+ up = &textaddr;
+ else if (strcmp(octoken[1], ".data") == 0)
+ up = &dataaddr;
+ else if (strcmp(octoken[1], ".bss") == 0)
+ up = &bssaddr;
+ if (up == NULL)
+ continue;
+ *up = strtoumax(octoken[3], NULL, 16) + base;
}
- fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
- if (fts == NULL) {
- fprintf(stderr,
- "Can't begin traversing path %s: %s (%d)\n",
- modules_path,
- strerror(errno),
- errno);
- exit(1);
+ if (textaddr) { /* we must have a text address */
+ fprintf(out, "add-symbol-file %s 0x%jx", path, textaddr);
+ if (dataaddr)
+ fprintf(out, " -s .data 0x%jx", dataaddr);
+ if (bssaddr)
+ fprintf(out, " -s .bss 0x%jx", bssaddr);
+ fprintf(out, "\n");
}
- while ((ftsent = fts_read(fts)) != NULL) {
- if (ftsent->fts_info == FTS_DNR ||
- ftsent->fts_info == FTS_ERR ||
- ftsent->fts_info == FTS_NS) {
- fprintf(stderr,
- "Error while traversing path %s: %s (%d)\n",
- modules_path,
- strerror(errno),
- errno);
- exit(1);
- }
- if (ftsent->fts_info != FTS_F ||
- ftsent->fts_namelen != module_name_len ||
- memcmp(module_name, ftsent->fts_name, module_name_len) != 0)
- continue;
- if (asprintf(&module_path,
- "%.*s",
- ftsent->fts_pathlen,
- ftsent->fts_path) == -1) {
- fprintf(stderr,
- "Can't allocate memory traversing path %s: %s (%d)\n",
- modules_path,
- strerror(errno),
- errno);
- exit(1);
+}
+
+static void
+findmodules(const char *modules_path, const char *sfx[], FILE *out)
+{
+ char *path_argv[2];
+ char *p;
+ FTS *fts;
+ FTSENT *ftsent;
+ struct kfile *kfp;
+ int i;
+ int sl;
+
+ /* Have to copy modules_path here because it's const */
+ if ((path_argv[0] = strdup(modules_path)) == NULL)
+ errx(2, "out of memory");
+ path_argv[1] = NULL;
+
+ /* Have to fts once per suffix to find preferred suffixes first */
+ do {
+ sl = *sfx ? strlen(*sfx) : 0; /* current suffix length */
+ fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
+ if (fts == NULL)
+ err(2, "can't begin traversing path %s", modules_path);
+ while ((ftsent = fts_read(fts)) != NULL) {
+ if (ftsent->fts_info == FTS_DNR ||
+ ftsent->fts_info == FTS_ERR ||
+ ftsent->fts_info == FTS_NS) {
+ errno = ftsent->fts_errno;
+ err(2, "error while traversing path %s", ftsent->fts_path);
+ }
+ if (ftsent->fts_info != FTS_F)
+ continue; /* not a plain file */
+
+ if (sl > 0) {
+ /* non-blank suffix; see if file name has it */
+ i = ftsent->fts_namelen - sl;
+ if (i <= 0 || strcmp(ftsent->fts_name + i, *sfx) != 0)
+ continue; /* no such suffix */
+ if ((p = strdup(ftsent->fts_name)) == NULL)
+ errx(2, "out of memory");
+ p[i] = '\0'; /* remove suffix in the copy */
+ kfp = kfile_find(p);
+ free(p);
+ } else
+ kfp = kfile_find(ftsent->fts_name);
+
+ if (kfp && !kfp->seen) {
+ doobj(ftsent->fts_path, kfp->addr, out);
+ kfp->seen = 1;
+ /* Optimization: stop fts as soon as seen all loaded modules */
+ if (kfile_allseen()) {
+ fts_close(fts);
+ goto done;
+ }
+ }
}
- break;
- }
- if (ftsent == NULL && errno != 0) {
- fprintf(stderr,
- "Couldn't complete traversing path %s: %s (%d)\n",
- modules_path,
- strerror(errno),
- errno);
- exit(1);
- }
- fts_close(fts);
- free(modules_path);
- return (module_path);
+ if (ftsent == NULL && errno != 0)
+ err(2, "couldn't complete traversing path %s", modules_path);
+ fts_close(fts);
+ } while (*sfx++);
+done:
+ free(path_argv[0]);
}
static void
@@ -163,169 +253,161 @@ usage(const char *myname)
{
fprintf(stderr,
"Usage:\n"
- "%s [-a] [-f] [-k] [-s] [-x] [modules-path [outfile]]\n\n"
- "\t-a\tappend to outfile)\n"
- "\t-f\tfind the module in any subdirectory of module-path\n"
+ "%s [-afKksVx] [-M core] [-N system ] [-o outfile] [-X suffix]\n"
+ "%*s [modules-path [outfile]]\n\n"
+ "\t-a\tappend to outfile\n"
+ "\t-f\tfind the module in any subdirectory of modules-path\n"
+ "\t-K\tuse kld(2) to get the list of modules\n"
"\t-k\ttake input from kldstat(8)\n"
+ "\t-M\tspecify core name for kvm(3)\n"
+ "\t-N\tspecify system name for kvm(3)\n"
+ "\t-o\tuse outfile instead of \".asf\"\n"
"\t-s\tdon't prepend subdir for module path\n"
- "\t-x\tdon't append \".debug\" to module name\n",
- myname);
+ "\t-V\tuse kvm(3) to get the list of modules\n"
+ "\t-X\tappend suffix to list of possible module file name suffixes\n"
+ "\t-x\tclear list of possible module file name suffixes\n",
+ myname, strlen(myname), "");
+ exit(2);
}
+#define MAXSUFFIXES 15
+
+/* KLD file names end in this */
+static int nsuffixes = 2;
+static const char *suffixes[MAXSUFFIXES + 1] = {
+ ".debug",
+ ".symbols",
+ NULL
+};
+
int
main(int argc, char *argv[])
{
- char buf[MAXLINE];
- FILE *kldstat;
- FILE *objcopy;
- FILE *out; /* output file */
- char ocbuf[MAXLINE];
- int tokens; /* number of tokens on line */
- char basetoken[MAXLINE];
- int i;
+ char basename[PATH_MAX];
+ char path[PATH_MAX];
const char *filemode = "w"; /* mode for outfile */
- char cwd[MAXPATHLEN]; /* current directory */
- const char *debugname = ".debug"; /* some file names end in this */
- char *token[MAXTOKEN];
- int nosubdir = 0;
+ const char *modules_path = "modules"; /* path to kernel build directory */
+ const char *outfile = ".asf"; /* and where to write the output */
+ const char *corefile = NULL; /* for kvm(3) */
+ const char *sysfile = NULL; /* for kvm(3) */
+ const char **sfx;
+ struct kfile *kfp;
+ struct stat st;
+ FILE *out; /* output file */
int dofind = 0;
+ int dokld = 0;
+ int dokvm = 0;
+ int nosubdir = 0;
+ int runprog = 0;
+ int i;
+ const int sl = strlen(KLDSUFFIX);
- getcwd(cwd, MAXPATHLEN); /* find where we are */
- kldstat = stdin;
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- if (strcmp(argv[i], "-k") == 0) { /* get input from kldstat(8) */
- if (!(kldstat = popen("kldstat", "r"))) {
- perror("Can't start kldstat");
- return 1;
- }
- } else if (strcmp(argv[i], "-a") == 0) /* append to outfile */
- filemode = "a";
- else if (strcmp(argv[i], "-x") == 0) /* no .debug extension */
- debugname = ""; /* nothing */
- else if (strcmp(argv[i], "-s") == 0) /* no subdir */
- nosubdir = 1; /* nothing */
- else if (strcmp(argv[i], "-f") == 0) /* find .ko (recursively) */
- dofind = 1;
- else {
- fprintf(stderr,
- "Invalid option: %s, aborting\n",
- argv[i]);
- usage(argv[0]);
- return 1;
- }
- } else if (modules_path == NULL)
- modules_path = argv[i];
- else if (outfile == NULL)
- outfile = argv[i];
- else {
- fprintf(stderr,
- "Extraneous startup information: \"%s\", aborting\n",
- argv[i]);
+ while ((i = getopt(argc, argv, "afKkM:N:o:sVX:x")) != -1)
+ switch (i) {
+ case 'a':
+ filemode = "a"; /* append to outfile */
+ break;
+ case 'f':
+ dofind = 1; /* find .ko (recursively) */
+ break;
+ case 'K':
+ dokld = 1; /* use kld(2) interface */
+ break;
+ case 'k':
+ runprog = 1; /* get input from kldstat(8) */
+ break;
+ case 'M':
+ corefile = optarg; /* core file for kvm(3) */
+ break;
+ case 'N':
+ sysfile = optarg; /* system file (kernel) for kvm(3) */
+ break;
+ case 'o':
+ outfile = optarg; /* output file name */
+ break;
+ case 's':
+ nosubdir = 1; /* don't descend into subdirs */
+ break;
+ case 'V':
+ dokvm = 1; /* use kvm(3) interface */
+ break;
+ case 'X':
+ if (nsuffixes >= MAXSUFFIXES)
+ errx(2, "only %d suffixes can be specified", MAXSUFFIXES);
+ suffixes[nsuffixes++] = optarg;
+ suffixes[nsuffixes] = NULL;
+ break;
+ case 'x':
+ nsuffixes = 0;
+ suffixes[0] = NULL;
+ break;
+ default:
usage(argv[0]);
- return 1;
}
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ modules_path = argv[0];
+ argc--, argv++;
}
- if (modules_path == NULL)
- modules_path = "modules";
- if (outfile == NULL)
- outfile = ".asf";
- if ((out = fopen(outfile, filemode)) == NULL) {
- fprintf(stderr,
- "Can't open output file %s: %s (%d)\n",
- outfile,
- strerror(errno),
- errno);
- return 1;
+ if (argc > 0) {
+ outfile = argv[0];
+ argc--, argv++;
}
- while (fgets(buf, MAXLINE, kldstat)) {
- if ((!(strstr(buf, "kernel")))
- && buf[0] != 'I') {
- quad_t base;
- quad_t textaddr = 0;
- quad_t dataaddr = 0;
- quad_t bssaddr = 0;
-
- tokens = tokenize(buf, token, MAXTOKEN);
- if (tokens < 4)
- continue;
- base = strtoll(token[2], NULL, 16);
- if (!dofind) {
- strcpy(basetoken, token[4]);
- basetoken[strlen(basetoken) - 3] = '/';
- basetoken[strlen(basetoken) - 2] = '\0'; /* cut off the .ko */
- snprintf(ocbuf,
- MAXLINE,
- "/usr/bin/objdump --section-headers %s/%s%s%s",
- modules_path,
- nosubdir ? "" : basetoken,
- token[4],
- debugname);
- } else {
- char *modpath;
-
- modpath = findmodule(strdup(modules_path), token[4]);
- if (modpath == NULL)
- continue;
- snprintf(ocbuf,
- MAXLINE,
- "/usr/bin/objdump --section-headers %s%s",
- modpath,
- debugname);
- free(modpath);
- }
- if (!(objcopy = popen(ocbuf, "r"))) {
- fprintf(stderr,
- "Can't start %s: %s (%d)\n",
- ocbuf,
- strerror(errno),
- errno);
- return 1;
- }
- while (fgets(ocbuf, MAXLINE, objcopy)) {
- int octokens;
- char *octoken[MAXTOKEN];
-
- octokens = tokenize(ocbuf, octoken, MAXTOKEN);
- if (octokens > 1) {
- if (!strcmp(octoken[1], ".text"))
- textaddr = strtoll(octoken[3], NULL, 16) + base;
- else if (!strcmp(octoken[1], ".data"))
- dataaddr = strtoll(octoken[3], NULL, 16) + base;
- else if (!strcmp(octoken[1], ".bss"))
- bssaddr = strtoll(octoken[3], NULL, 16) + base;
- }
+ if (argc > 0)
+ usage(argv[0]);
+
+ if (strcmp(outfile, "-") == 0)
+ out = stdout;
+ else
+ if ((out = fopen(outfile, filemode)) == NULL)
+ err(2, "can't open output file %s", outfile);
+
+ if (dokvm || corefile || sysfile) {
+ if (dokld || runprog)
+ warnx("using kvm(3) instead");
+ asf_kvm(sysfile, corefile);
+ } else if (dokld) {
+ if (runprog)
+ warnx("using kld(2) instead");
+ asf_kld();
+ } else
+ asf_prog(runprog);
+
+ /* Avoid long operations like module tree traversal when nothing to do */
+ if (kfile_empty()) {
+ warnx("no kernel modules loaded");
+ return (0);
+ }
+
+ if (!dofind)
+ STAILQ_FOREACH(kfp, &kfile_head, link) {
+ if (!nosubdir) {
+ /* prepare basename of KLD, w/o suffix */
+ strlcpy(basename, kfp->name, sizeof(basename) - 1);
+ i = strlen(basename);
+ if (i > sl && strcmp(basename + i - sl, KLDSUFFIX) == 0)
+ i -= sl;
+ basename[i] = '/';
+ basename[i + 1] = '\0';
}
- if (textaddr) { /* we must have a text address */
- if (!dofind) {
- fprintf(out,
- "add-symbol-file %s/%s/%s%s%s 0x%llx",
- cwd,
- modules_path,
- nosubdir ? "" : basetoken,
- token[4],
- debugname,
- textaddr);
- } else {
- char *modpath;
-
- modpath = findmodule(strdup(modules_path), token[4]);
- if (modpath == NULL)
- continue;
- fprintf(out,
- "add-symbol-file %s%s 0x%llx",
- modpath,
- debugname,
- textaddr);
- free(modpath);
+ for (sfx = suffixes;; sfx++) {
+ snprintf(path, sizeof(path),
+ "%s/%s%s%s",
+ modules_path,
+ nosubdir ? "" : basename,
+ kfp->name,
+ *sfx ? *sfx : "");
+ if (*sfx == NULL || stat(path, &st) == 0) {
+ doobj(path, kfp->addr, out);
+ break;
}
- if (dataaddr)
- fprintf(out, " -s .data 0x%llx", dataaddr);
- if (bssaddr)
- fprintf(out, " -s .bss 0x%llx", bssaddr);
- fprintf(out, "\n");
}
}
- }
- return 0;
+ else
+ findmodules(modules_path, suffixes, out);
+
+ return (0);
}
diff --git a/usr.sbin/asf/asf.h b/usr.sbin/asf/asf.h
new file mode 100644
index 0000000..d034936
--- /dev/null
+++ b/usr.sbin/asf/asf.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define KERNFILE "kernel"
+#define KLDSUFFIX ".ko"
+
+#define MAXTOKEN 10
+
+int tokenize(char *cptr, char *token[], int maxtoken);
+
+void kfile_add(const char *name, caddr_t addr);
+
+void asf_kld(void);
+void asf_kvm(const char *kernfile, const char *corefile);
+void asf_prog(int run);
diff --git a/usr.sbin/asf/asf_kld.c b/usr.sbin/asf/asf_kld.c
new file mode 100644
index 0000000..1d6a2b7
--- /dev/null
+++ b/usr.sbin/asf/asf_kld.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <err.h>
+#include <string.h>
+
+#include "asf.h"
+
+/*
+ * Get the linker file list using the kld interface.
+ * Works with a live kernel only.
+ */
+void
+asf_kld()
+{
+ struct kld_file_stat kfs;
+ int fid = 0; /* indicates the beginning of the linker file list */
+
+ while ((fid = kldnext(fid)) != 0) {
+ if (fid == -1)
+ err(2, "kldnext");
+ kfs.version = sizeof(kfs); /* must be set for kldstat(2) */
+ /* Get info on this linker file */
+ if (kldstat(fid, &kfs) == -1)
+ err(2, "kldstat");
+ if (strcmp(kfs.name, KERNFILE) == 0)
+ continue;
+ /* Add to our list of linker files */
+ kfile_add(kfs.name, kfs.address);
+ }
+}
diff --git a/usr.sbin/asf/asf_kvm.c b/usr.sbin/asf/asf_kvm.c
new file mode 100644
index 0000000..aa4effe
--- /dev/null
+++ b/usr.sbin/asf/asf_kvm.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h> /* for <sys/linker.h> with _KERNEL defined */
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _KERNEL
+#include <sys/linker.h>
+#undef _KERNEL
+
+#include "asf.h"
+
+/* Name of the head of the linker file list in /sys/kern/kern_linker.c */
+#define LINKER_HEAD "linker_files"
+
+/*
+ * Get the list of linker files using kvm(3).
+ * Can work with a live kernel as well as with a crash dump.
+ */
+void
+asf_kvm(const char *kernfile, const char *corefile)
+{
+ char errbuf[LINE_MAX];
+ char name[PATH_MAX];
+ kvm_t *kd;
+ struct nlist nl[2];
+ struct linker_file lf;
+ linker_file_list_t linker_files;
+ ssize_t n;
+ void *kp;
+
+ kd = kvm_openfiles(kernfile, corefile, NULL, O_RDONLY, errbuf);
+ if (kd == NULL)
+ errx(2, "open kernel memory: %s", errbuf);
+
+ /*
+ * Locate the head of the linker file list using kernel symbols.
+ */
+ strcpy(name, LINKER_HEAD);
+ nl[0].n_name = name; /* can't use LINKER_HEAD here because it's const */
+ nl[1].n_name = NULL; /* terminate the array for kvm_nlist() */
+ switch (kvm_nlist(kd, nl)) {
+ case 0:
+ break;
+ case -1:
+ warnx("%s: %s", LINKER_HEAD, kvm_geterr(kd));
+ kvm_close(kd);
+ exit(2);
+ default:
+ kvm_close(kd);
+ errx(2, "%s: symbol not found", LINKER_HEAD);
+ }
+
+ /*
+ * Read the head of the linker file list from kernel memory.
+ */
+ n = kvm_read(kd, nl[0].n_value, &linker_files, sizeof(linker_files));
+ if (n == -1)
+ goto read_err;
+ if (n != sizeof(linker_files)) {
+ kvm_close(kd);
+ errx(2, "%s: short read", LINKER_HEAD);
+ }
+
+ /*
+ * Traverse the linker file list starting at its head.
+ */
+ for (kp = linker_files.tqh_first; kp; kp = lf.link.tqe_next) {
+ /* Read a linker file structure */
+ n = kvm_read(kd, (u_long)kp, &lf, sizeof(lf));
+ if (n == -1)
+ goto read_err;
+ if (n != sizeof(lf)) {
+ kvm_close(kd);
+ errx(2, "kvm: short read");
+ }
+ /* Read the name of the file stored separately */
+ bzero(name, sizeof(name));
+ n = kvm_read(kd, (u_long)lf.filename, name, sizeof(name) - 1);
+ if (n == -1)
+ goto read_err;
+ if (strcmp(name, KERNFILE) == 0)
+ continue;
+ /* Add this file to our list of linker files */
+ kfile_add(name, lf.address);
+ }
+ kvm_close(kd);
+ return;
+
+read_err: /* A common error case */
+ warnx("read kernel memory: %s", kvm_geterr(kd));
+ kvm_close(kd);
+ exit(2);
+}
diff --git a/usr.sbin/asf/asf_prog.c b/usr.sbin/asf/asf_prog.c
new file mode 100644
index 0000000..9a13cd6
--- /dev/null
+++ b/usr.sbin/asf/asf_prog.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2002, 2003 Greg Lehey
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * This software is provided by the author ``as is'' and any express
+ * or implied warranties, including, but not limited to, the implied
+ * warranties of merchantability and fitness for a particular purpose
+ * are disclaimed. In no event shall the author be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability,
+ * whether in contract, strict liability, or tort (including
+ * negligence or otherwise) arising in any way out of the use of this
+ * software, even if advised of the possibility of such damage.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <err.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "asf.h"
+
+/*
+ * Get the linker file list from kldstat(8) output.
+ * The "run" flag tells if kldstat(8) should run now.
+ * Of course, kldstat(1) can run in a live system only, but its output
+ * can be saved beforehand and fed to this function later via stdin.
+ */
+void
+asf_prog(int run)
+{
+ char buf[LINE_MAX];
+ char *token[MAXTOKEN];
+ char *endp;
+ FILE *kldstat;
+ caddr_t base;
+ int tokens;
+
+ if (run) {
+ if ((kldstat = popen("kldstat", "r")) == NULL)
+ err(2, "can't start kldstat");
+ } else
+ kldstat = stdin;
+
+ while (fgets(buf, sizeof(buf), kldstat)) {
+ /* Skip header line and main kernel file */
+ if (buf[0] == 'I' || strstr(buf, KERNFILE))
+ continue;
+ tokens = tokenize(buf, token, MAXTOKEN);
+ if (tokens < 4)
+ continue;
+ base = (caddr_t)(uintptr_t)strtoumax(token[2], &endp, 16);
+ if (endp == NULL || *endp != '\0')
+ continue;
+ kfile_add(token[4], base);
+ }
+}
OpenPOWER on IntegriCloud