Index: usr.sbin/pmcstat/pmcstat.h =================================================================== --- usr.sbin/pmcstat/pmcstat.h +++ usr.sbin/pmcstat/pmcstat.h @@ -127,6 +127,11 @@ pid_t pt_pid; }; +struct pmcstat_path { + STAILQ_ENTRY(pmcstat_path) pp_next; + char *pp_path; /* pathname */ +}; + struct pmcstat_args { int pa_flags; /* argument flags */ int pa_required; /* required features */ @@ -140,6 +145,7 @@ void *pa_logparser; /* log file parser */ const char *pa_fsroot; /* FS root where executables reside */ char *pa_kernel; /* pathname of the kernel */ + char *pa_module_path; /* pathnames of the kernel modules */ const char *pa_samplesdir; /* directory for profile files */ const char *pa_mapfilename;/* mapfile name */ FILE *pa_graphfile; /* where to send the callgraph */ @@ -156,6 +162,7 @@ char **pa_argv; STAILQ_HEAD(, pmcstat_ev) pa_events; SLIST_HEAD(, pmcstat_target) pa_targets; + STAILQ_HEAD(, pmcstat_path) pa_modules; }; extern int pmcstat_displayheight; /* current terminal height */ Index: usr.sbin/pmcstat/pmcstat.8 =================================================================== --- usr.sbin/pmcstat/pmcstat.8 +++ usr.sbin/pmcstat/pmcstat.8 @@ -38,6 +38,7 @@ .Op Fl E .Op Fl F Ar pathname .Op Fl G Ar pathname +.Op Fl K Ar moduledirs .Op Fl M Ar mapfilename .Op Fl N .Op Fl O Ar logfilename @@ -155,6 +156,18 @@ this information is sent to the output file specified by the .Fl o option. +.It Fl K Ar moduledirs +Set the list of pathnames of the kernel module directories to argument +.Ar moduledirs . +This directory list specifies where +.Nm +should look for the kernel modules. +Argument +.Ar dir-list +is a colon separated list of paths to use in searching for modules. +The default is to use the module path of the running kernel obtained from the +.Va kern.module_path +sysctl. .It Fl M Ar mapfilename Write the mapping between executable objects encountered in the event log and the abbreviated pathnames used for Index: usr.sbin/pmcstat/pmcstat.c =================================================================== --- usr.sbin/pmcstat/pmcstat.c +++ usr.sbin/pmcstat/pmcstat.c @@ -497,6 +497,7 @@ "\t -F file\t write a system-wide callgraph (Kcachegrind format)" " to \"file\"\n" "\t -G file\t write a system-wide callgraph to \"file\"\n" + "\t -K dir-list\t set the paths to check for kernel modules\n" "\t -M file\t print executable/gmon file map to \"file\"\n" "\t -N\t\t (toggle) capture callchains\n" "\t -O file\t send log output to \"file\"\n" @@ -565,11 +566,12 @@ int pipefd[2], rfd; int use_cumulative_counts; short cf, cb; - char *end, *tmp; + char *end, *modpath, *mp, *tmp; const char *errmsg, *graphfilename; enum pmcstat_state runstate; struct pmc_driverstats ds_start, ds_end; struct pmcstat_ev *ev; + struct pmcstat_path *pp; struct sigaction sa; struct kevent kev; struct winsize ws; @@ -607,6 +609,7 @@ args.pa_duration = 0.0; STAILQ_INIT(&args.pa_events); SLIST_INIT(&args.pa_targets); + STAILQ_INIT(&args.pa_modules); bzero(&ds_start, sizeof(ds_start)); bzero(&ds_end, sizeof(ds_end)); ev = NULL; @@ -622,6 +625,18 @@ if (sysctlbyname("kern.bootfile", args.pa_kernel, &len, NULL, 0) == -1) err(EX_OSERR, "ERROR: Cannot determine path of running kernel"); + len = 0; + if (sysctlbyname("kern.module_path", NULL, &len, NULL, 0) == -1) + err(EX_OSERR, + "ERROR: Cannot determine running kernel module paths"); + args.pa_module_path = malloc(len); + if (args.pa_module_path == NULL) + errx(EX_SOFTWARE, "ERROR: Out of memory."); + if (sysctlbyname("kern.module_path", args.pa_module_path, &len, NULL, + 0) == -1) + err(EX_OSERR, + "ERROR: Cannot determine running kernel module paths"); + /* * The initial CPU mask specifies the root mask of this process * which is usually all CPUs in the system. @@ -632,7 +647,7 @@ CPU_COPY(&rootmask, &cpumask); while ((option = getopt(argc, argv, - "CD:EF:G:M:NO:P:R:S:TWa:c:def:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1) + "CD:EF:G:K:M:NO:P:R:S:TWa:c:def:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1) switch (option) { case 'a': /* Annotate + callgraph */ args.pa_flags |= FLAG_DO_ANNOTATE; @@ -710,6 +725,13 @@ args.pa_flags |= FLAG_HAS_KERNELPATH; break; + case 'K': /* paths to kernel modules */ + free(args.pa_module_path); + args.pa_module_path = strdup(optarg); + if (args.pa_module_path == NULL) + errx(EX_SOFTWARE, "ERROR: Out of memory"); + break; + case 'l': /* time duration in seconds */ duration = strtod(optarg, &end); if (*end != '\0' || duration <= 0) @@ -1111,6 +1133,20 @@ } /* + * Build the kernel modules pathname list + */ + mp = args.pa_module_path; + while ((modpath = strsep(&mp, ":;")) != NULL) { + if (*modpath == '\0') + continue; + pp = malloc(sizeof(*pp)); + if (pp == NULL) + errx(EX_SOFTWARE, "ERROR: Out of memory."); + pp->pp_path = modpath; + STAILQ_INSERT_TAIL(&args.pa_modules, pp, pp_next); + } + + /* * If we have a callgraph be created, select the outputfile. */ if (args.pa_flags & FLAG_DO_CALLGRAPHS) { Index: usr.sbin/pmcstat/pmcstat_log.c =================================================================== --- usr.sbin/pmcstat/pmcstat_log.c +++ usr.sbin/pmcstat/pmcstat_log.c @@ -608,6 +608,27 @@ symptr->ps_end = (symptr+1)->ps_start; } +static int +pmcstat_find_module(const char *path, char *buffer, size_t len) +{ + struct pmcstat_path *pp; + + /* Try the module list */ + STAILQ_FOREACH(pp, &args.pa_modules, pp_next) { + snprintf(buffer, len, "%s%s/%s", args.pa_fsroot, pp->pp_path, + path); + if (access(buffer, R_OK) != -1) + return (1); + } + + /* Try the kernel path */ + snprintf(buffer, len, "%s%s/%s", args.pa_fsroot, args.pa_kernel, path); + if (access(buffer, R_OK) != -1) + return (1); + + return (0); +} + /* * Examine an ELF file to determine the size of its text segment. * Sets image->pi_type if anything conclusive can be determined about @@ -646,10 +667,11 @@ * Look for kernel modules under FSROOT/KERNELPATH/NAME, * and user mode executable objects under FSROOT/PATHNAME. */ - if (image->pi_iskernelmodule) - (void) snprintf(buffer, sizeof(buffer), "%s%s/%s", - args.pa_fsroot, args.pa_kernel, path); - else + if (image->pi_iskernelmodule) { + if (pmcstat_find_module(path, buffer, sizeof(buffer)) == 0) + warnx("WARNING: Cannot find kernel module \"%s\".", + path); + } else (void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot, path);