diff options
author | green <green@FreeBSD.org> | 2001-10-30 15:54:09 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2001-10-30 15:54:09 +0000 |
commit | 85a9f299f9ff18dd7fee037e0aee7e70d3971e7e (patch) | |
tree | 3af54369ee3af34acc584ccf59baf1a0dc95e078 /usr.bin/gprof | |
parent | 0bacb7acb24b620b0199d06b1a081160742a8cd5 (diff) | |
download | FreeBSD-src-85a9f299f9ff18dd7fee037e0aee7e70d3971e7e.zip FreeBSD-src-85a9f299f9ff18dd7fee037e0aee7e70d3971e7e.tar.gz |
Add -K support to gprof(1), which enables dynamic symbol resolution from
the currently-running kernel (and supercedes an executable file argument
given). With this change, properly-compiled KLD modules are now
able to be profiled.
Obtained from: NAI Labs CBOSS project
Funded by: DARPA
Diffstat (limited to 'usr.bin/gprof')
-rw-r--r-- | usr.bin/gprof/Makefile | 3 | ||||
-rw-r--r-- | usr.bin/gprof/gprof.1 | 11 | ||||
-rw-r--r-- | usr.bin/gprof/gprof.c | 8 | ||||
-rw-r--r-- | usr.bin/gprof/gprof.h | 4 | ||||
-rw-r--r-- | usr.bin/gprof/kernel.c | 64 |
5 files changed, 87 insertions, 3 deletions
diff --git a/usr.bin/gprof/Makefile b/usr.bin/gprof/Makefile index 29291cc..cc5a276 100644 --- a/usr.bin/gprof/Makefile +++ b/usr.bin/gprof/Makefile @@ -1,8 +1,9 @@ # @(#)Makefile 8.1 (Berkeley) 6/29/93 +# $FreeBSD$ PROG= gprof SRCS= gprof.c aout.c arcs.c dfn.c elf.c lookup.c ${MACHINE_ARCH}.c hertz.c \ - printgprof.c printlist.c + printgprof.c printlist.c kernel.c beforeinstall: ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 \ diff --git a/usr.bin/gprof/gprof.1 b/usr.bin/gprof/gprof.1 index f421221..fa45baa 100644 --- a/usr.bin/gprof/gprof.1 +++ b/usr.bin/gprof/gprof.1 @@ -208,6 +208,17 @@ option may be given. Only one pair of routine names may be given with each .Fl k option. +.It Fl K +Gather information about symbols from the currently-running kernel using the +.Xr sysctl 3 +and +.Xr kldsym 2 +interfaces. +This forces the +.Pa a.out +argument to be ignored, and allows for symbols in +.Xr kld 4 +modules to be used. .It Fl l Suppresses the printing of the call-graph profile. .It Fl L diff --git a/usr.bin/gprof/gprof.c b/usr.bin/gprof/gprof.c index dfb1e2c..79dafc7 100644 --- a/usr.bin/gprof/gprof.c +++ b/usr.bin/gprof/gprof.c @@ -125,6 +125,9 @@ main(argc, argv) addlist( ktolist , *++argv ); kflag = TRUE; break; + case 'K': + Kflag = TRUE; + break; case 'l': lflag = 1; Lflag = 0; @@ -162,8 +165,9 @@ main(argc, argv) /* * get information from the executable file. */ - if (elf_getnfile(a_outname, &defaultEs) == -1 && - aout_getnfile(a_outname, &defaultEs) == -1) + if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || + (elf_getnfile(a_outname, &defaultEs) == -1 && + aout_getnfile(a_outname, &defaultEs) == -1)) errx(1, "%s: bad format", a_outname); /* * sort symbol table. diff --git a/usr.bin/gprof/gprof.h b/usr.bin/gprof/gprof.h index 3a7c54b..ee0976e 100644 --- a/usr.bin/gprof/gprof.h +++ b/usr.bin/gprof/gprof.h @@ -238,6 +238,7 @@ bool Eflag; /* functions excluded with time */ bool fflag; /* specific functions requested */ bool Fflag; /* functions requested with time */ bool kflag; /* arcs to be deleted */ +bool Kflag; /* use the running kernel for symbols */ bool sflag; /* sum multiple gmon.out files */ bool uflag; /* suppress symbols hidden from C */ bool zflag; /* zero time/called functions, too */ @@ -295,6 +296,9 @@ int elf_getnfile(const char *, char ***); getpfile(); gprofheader(); gprofline(); +*/ +int kernel_getnfile(const char *, char ***); +/* main(); */ unsigned long max(); diff --git a/usr.bin/gprof/kernel.c b/usr.bin/gprof/kernel.c new file mode 100644 index 0000000..c8df0d0 --- /dev/null +++ b/usr.bin/gprof/kernel.c @@ -0,0 +1,64 @@ +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/linker.h> +#include <sys/sysctl.h> +#include <sys/errno.h> + +#include <err.h> +#include <stdlib.h> + +#include "gprof.h" + +/* Things which get -E excluded by default. */ +static char *excludes[] = { ".mcount", "_mcleanup", NULL }; + +int +kernel_getnfile(const char *unused, char ***defaultEs) +{ + char *namelist; + size_t len; + char *name; + + if (sysctlbyname("kern.function_list", NULL, &len, NULL, 0) == -1) + err(1, "sysctlbyname: function_list size"); + for (;;) { + namelist = malloc(len); + if (namelist == NULL) + err(1, "malloc"); + if (sysctlbyname("kern.function_list", namelist, &len, NULL, + 0) == 0) + break; + if (errno == ENOMEM) + free(namelist); + else + err(1, "sysctlbyname: function_list"); + } + nname = 0; + for (name = namelist; *name != '\0'; name += strlen(name) + 1) + nname++; + /* Allocate memory for them, plus a terminating entry. */ + if ((nl = (nltype *)calloc(nname + 1, sizeof(nltype))) == NULL) + errx(1, "Insufficient memory for symbol table"); + npe = nl; + for (name = namelist; *name != '\0'; name += strlen(name) + 1) { + struct kld_sym_lookup ksl; + + ksl.version = sizeof(ksl); + ksl.symname = name; + if (kldsym(0, KLDSYM_LOOKUP, &ksl)) + err(1, "kldsym(%s)", name); + /* aflag not supported */ + if (uflag && strchr(name, '.') != NULL) + continue; + npe->value = ksl.symvalue; + npe->name = name; + npe++; + } + npe->value = -1; + + *defaultEs = excludes; +} |