pmc: Provide full path to modules from kernel linker
This unifies the user object and kernel module paths in libpmcstat, allows modules loaded from non-standard locations (e.g. from a user's home directory when testing) to be found and, since buffer is what all the warnings here use (they were never updated when buffer_modules were added to pick based on where the file was found) has the side-effect of ensuring the messages are correct. This includes obsoleting the now-superfluous -k option in pmcstat. This change breaks the hwpmc ABI and will be followed by a bump to the pmc major version. Reviewed by: jhb, jkoshy, mhorne Differential Revision: https://reviews.freebsd.org/D40048
This commit is contained in:
parent
8e63e787ab
commit
53d0b9e438
@ -98,7 +98,7 @@ struct pmcstat_args {
|
||||
#define FLAG_READ_LOGFILE 0x00000200 /* -R file */
|
||||
#define FLAG_DO_GPROF 0x00000400 /* -g */
|
||||
#define FLAG_HAS_SAMPLESDIR 0x00000800 /* -D dir */
|
||||
#define FLAG_HAS_KERNELPATH 0x00001000 /* -k kernel */
|
||||
/* was FLAG_HAS_KERNELPATH 0x00001000 */
|
||||
#define FLAG_DO_PRINT 0x00002000 /* -o */
|
||||
#define FLAG_DO_CALLGRAPHS 0x00004000 /* -G or -F */
|
||||
#define FLAG_DO_ANNOTATE 0x00008000 /* -m */
|
||||
@ -121,7 +121,6 @@ struct pmcstat_args {
|
||||
char *pa_outputpath; /* path to output log */
|
||||
void *pa_logparser; /* log file parser */
|
||||
const char *pa_fsroot; /* FS root where executables reside */
|
||||
char *pa_kernel; /* pathname of the kernel */
|
||||
const char *pa_samplesdir; /* directory for profile files */
|
||||
const char *pa_mapfilename;/* mapfile name */
|
||||
FILE *pa_graphfile; /* where to send the callgraph */
|
||||
|
@ -315,7 +315,6 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
|
||||
GElf_Shdr sh;
|
||||
enum pmcstat_image_type image_type;
|
||||
char buffer[PATH_MAX];
|
||||
char buffer_modules[PATH_MAX];
|
||||
|
||||
assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
|
||||
|
||||
@ -330,32 +329,19 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
|
||||
assert(path != NULL);
|
||||
|
||||
/*
|
||||
* Look for kernel modules under FSROOT/KERNELPATH/NAME and
|
||||
* FSROOT/boot/modules/NAME, and user mode executable objects
|
||||
* under FSROOT/PATHNAME.
|
||||
* Look for files under FSROOT/PATHNAME.
|
||||
*/
|
||||
if (image->pi_iskernelmodule) {
|
||||
(void) snprintf(buffer, sizeof(buffer), "%s%s/%s",
|
||||
args->pa_fsroot, args->pa_kernel, path);
|
||||
(void) snprintf(buffer_modules, sizeof(buffer_modules),
|
||||
"%s/boot/modules/%s", args->pa_fsroot, path);
|
||||
} else {
|
||||
(void) snprintf(buffer, sizeof(buffer), "%s%s",
|
||||
args->pa_fsroot, path);
|
||||
}
|
||||
(void) snprintf(buffer, sizeof(buffer), "%s%s",
|
||||
args->pa_fsroot, path);
|
||||
|
||||
e = NULL;
|
||||
fd = open(buffer, O_RDONLY, 0);
|
||||
if (fd < 0 && !image->pi_iskernelmodule) {
|
||||
if (fd < 0) {
|
||||
warnx("WARNING: Cannot open \"%s\".",
|
||||
buffer);
|
||||
goto done;
|
||||
}
|
||||
if (fd < 0 && (fd = open(buffer_modules, O_RDONLY, 0)) < 0) {
|
||||
warnx("WARNING: Cannot open \"%s\" or \"%s\".",
|
||||
buffer, buffer_modules);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE) {
|
||||
warnx("WARNING: failed to init elf\n");
|
||||
goto done;
|
||||
|
@ -5402,7 +5402,7 @@ pmc_kld_load(void *arg __unused, linker_file_t lf)
|
||||
CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
|
||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE)
|
||||
pmclog_process_map_in(po, (pid_t) -1,
|
||||
(uintfptr_t) lf->address, lf->filename);
|
||||
(uintfptr_t) lf->address, lf->pathname);
|
||||
PMC_EPOCH_EXIT();
|
||||
|
||||
/*
|
||||
|
@ -2119,7 +2119,7 @@ linker_hwpmc_list_objects(void)
|
||||
i = 0;
|
||||
TAILQ_FOREACH(lf, &linker_files, link) {
|
||||
/* Save the info for this linker file. */
|
||||
kobase[i].pm_file = lf->filename;
|
||||
kobase[i].pm_file = lf->pathname;
|
||||
kobase[i].pm_address = (uintptr_t)lf->address;
|
||||
i++;
|
||||
}
|
||||
|
@ -57,7 +57,6 @@
|
||||
.Op Fl f Ar pluginopt
|
||||
.Op Fl g
|
||||
.Op Fl i Ar lwp
|
||||
.Op Fl k Ar kerneldir
|
||||
.Op Fl l Ar secs
|
||||
.Op Fl m Ar pathname
|
||||
.Op Fl n Ar rate
|
||||
@ -336,17 +335,6 @@ which you can get from
|
||||
.Xr ps 1
|
||||
.Fl o
|
||||
.Li lwp .
|
||||
.It Fl k Ar kerneldir
|
||||
Set the pathname of the kernel directory to argument
|
||||
.Ar kerneldir .
|
||||
This directory specifies where
|
||||
.Nm
|
||||
should look for the kernel and its modules.
|
||||
The default is to use the path of the running kernel obtained from the
|
||||
.Va kern.bootfile
|
||||
sysctl.
|
||||
Modules will also be searched for in /boot/modules if not found in
|
||||
.Ar kerneldir .
|
||||
.It Fl l Ar secs
|
||||
Set system-wide performance measurement duration for
|
||||
.Ar secs
|
||||
|
@ -383,7 +383,6 @@ pmcstat_show_usage(void)
|
||||
"\t -f spec\t pass \"spec\" to as plugin option\n"
|
||||
"\t -g\t\t produce gprof(1) compatible profiles\n"
|
||||
"\t -i lwp\t\t filter on thread id \"lwp\" in post-processing\n"
|
||||
"\t -k dir\t\t set the path to the kernel\n"
|
||||
"\t -l secs\t set duration time\n"
|
||||
"\t -m file\t print sampled PCs to \"file\"\n"
|
||||
"\t -n rate\t set sampling rate\n"
|
||||
@ -456,7 +455,7 @@ main(int argc, char **argv)
|
||||
int use_cumulative_counts;
|
||||
short cf, cb;
|
||||
uint64_t current_sampling_count;
|
||||
char *end, *tmp, *event;
|
||||
char *end, *event;
|
||||
const char *errmsg, *graphfilename;
|
||||
enum pmcstat_state runstate;
|
||||
struct pmc_driverstats ds_start, ds_end;
|
||||
@ -465,7 +464,6 @@ main(int argc, char **argv)
|
||||
struct kevent kev;
|
||||
struct winsize ws;
|
||||
struct stat sb;
|
||||
char buffer[PATH_MAX];
|
||||
uint32_t caps;
|
||||
|
||||
check_driver_stats = 0;
|
||||
@ -510,16 +508,6 @@ main(int argc, char **argv)
|
||||
caps = 0;
|
||||
CPU_ZERO(&cpumask);
|
||||
|
||||
|
||||
/* Default to using the running system kernel. */
|
||||
len = 0;
|
||||
if (sysctlbyname("kern.bootfile", NULL, &len, NULL, 0) == -1)
|
||||
err(EX_OSERR, "ERROR: Cannot determine path of running kernel");
|
||||
args.pa_kernel = malloc(len);
|
||||
if (args.pa_kernel == NULL)
|
||||
errx(EX_SOFTWARE, "ERROR: Out of memory.");
|
||||
if (sysctlbyname("kern.bootfile", args.pa_kernel, &len, NULL, 0) == -1)
|
||||
err(EX_OSERR, "ERROR: Cannot determine path of running kernel");
|
||||
len = sizeof(domains);
|
||||
if (sysctlbyname("vm.ndomains", &domains, &len, NULL, 0) == -1)
|
||||
err(EX_OSERR, "ERROR: Cannot get number of domains");
|
||||
@ -623,12 +611,8 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'k': /* pathname to the kernel */
|
||||
free(args.pa_kernel);
|
||||
args.pa_kernel = strdup(optarg);
|
||||
if (args.pa_kernel == NULL)
|
||||
errx(EX_SOFTWARE, "ERROR: Out of memory");
|
||||
args.pa_required |= FLAG_DO_ANALYSIS;
|
||||
args.pa_flags |= FLAG_HAS_KERNELPATH;
|
||||
warnx("WARNING: -k is obsolete, has no effect "
|
||||
"and will be removed in FreeBSD 15.");
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
@ -1029,12 +1013,6 @@ main(int argc, char **argv)
|
||||
"ERROR: option -O is used only with options -E, -P, -S and -W."
|
||||
);
|
||||
|
||||
/* -k kernel path require -g/-G/-m/-T or -R */
|
||||
if ((args.pa_flags & FLAG_HAS_KERNELPATH) &&
|
||||
(args.pa_flags & FLAG_DO_ANALYSIS) == 0 &&
|
||||
(args.pa_flags & FLAG_READ_LOGFILE) == 0)
|
||||
errx(EX_USAGE, "ERROR: option -k is only used with -g/-R/-m/-T.");
|
||||
|
||||
/* -D only applies to gprof output mode (-g) */
|
||||
if ((args.pa_flags & FLAG_HAS_SAMPLESDIR) &&
|
||||
(args.pa_flags & FLAG_DO_GPROF) == 0)
|
||||
@ -1058,36 +1036,6 @@ main(int argc, char **argv)
|
||||
"ERROR: option -O is required if counting and sampling PMCs are specified together."
|
||||
);
|
||||
|
||||
/*
|
||||
* Check if 'kerneldir' refers to a file rather than a
|
||||
* directory. If so, use `dirname path` to determine the
|
||||
* kernel directory.
|
||||
*/
|
||||
(void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot,
|
||||
args.pa_kernel);
|
||||
if (stat(buffer, &sb) < 0)
|
||||
err(EX_OSERR, "ERROR: Cannot locate kernel \"%s\"",
|
||||
buffer);
|
||||
if (!S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode))
|
||||
errx(EX_USAGE, "ERROR: \"%s\": Unsupported file type.",
|
||||
buffer);
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
tmp = args.pa_kernel;
|
||||
args.pa_kernel = strdup(dirname(args.pa_kernel));
|
||||
if (args.pa_kernel == NULL)
|
||||
errx(EX_SOFTWARE, "ERROR: Out of memory");
|
||||
free(tmp);
|
||||
(void) snprintf(buffer, sizeof(buffer), "%s%s",
|
||||
args.pa_fsroot, args.pa_kernel);
|
||||
if (stat(buffer, &sb) < 0)
|
||||
err(EX_OSERR, "ERROR: Cannot stat \"%s\"",
|
||||
buffer);
|
||||
if (!S_ISDIR(sb.st_mode))
|
||||
errx(EX_USAGE,
|
||||
"ERROR: \"%s\" is not a directory.",
|
||||
buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a callgraph be created, select the outputfile.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user