Skip to content

Commit

Permalink
perf symbols: Add ability to find kcore in build-id cache
Browse files Browse the repository at this point in the history
When no vmlinux is found, tools will use kallsyms and, if possible,
kcore.  Add the ability to find kcore in the build-id cache.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1381747424-3557-7-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Adrian Hunter authored and Arnaldo Carvalho de Melo committed Oct 14, 2013
1 parent 9a17d72 commit 0544d42
Showing 1 changed file with 103 additions and 44 deletions.
147 changes: 103 additions & 44 deletions tools/perf/util/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1401,6 +1401,105 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
return err;
}

static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
{
char kallsyms_filename[PATH_MAX];
struct dirent *dent;
int ret = -1;
DIR *d;

d = opendir(dir);
if (!d)
return -1;

while (1) {
dent = readdir(d);
if (!dent)
break;
if (dent->d_type != DT_DIR)
continue;
scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
"%s/%s/kallsyms", dir, dent->d_name);
if (!validate_kcore_modules(kallsyms_filename, map)) {
strlcpy(dir, kallsyms_filename, dir_sz);
ret = 0;
break;
}
}

closedir(d);

return ret;
}

static char *dso__find_kallsyms(struct dso *dso, struct map *map)
{
u8 host_build_id[BUILD_ID_SIZE];
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
bool is_host = false;
char path[PATH_MAX];

if (!dso->has_build_id) {
/*
* Last resort, if we don't have a build-id and couldn't find
* any vmlinux file, try the running kernel kallsyms table.
*/
goto proc_kallsyms;
}

if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
sizeof(host_build_id)) == 0)
is_host = dso__build_id_equal(dso, host_build_id);

build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);

/* Use /proc/kallsyms if possible */
if (is_host) {
DIR *d;
int fd;

/* If no cached kcore go with /proc/kallsyms */
scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s",
buildid_dir, sbuild_id);
d = opendir(path);
if (!d)
goto proc_kallsyms;
closedir(d);

/*
* Do not check the build-id cache, until we know we cannot use
* /proc/kcore.
*/
fd = open("/proc/kcore", O_RDONLY);
if (fd != -1) {
close(fd);
/* If module maps match go with /proc/kallsyms */
if (!validate_kcore_modules("/proc/kallsyms", map))
goto proc_kallsyms;
}

/* Find kallsyms in build-id cache with kcore */
if (!find_matching_kcore(map, path, sizeof(path)))
return strdup(path);

goto proc_kallsyms;
}

scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
buildid_dir, sbuild_id);

if (access(path, F_OK)) {
pr_err("No kallsyms or vmlinux with build-id %s was found\n",
sbuild_id);
return NULL;
}

return strdup(path);

proc_kallsyms:
return strdup("/proc/kallsyms");
}

static int dso__load_kernel_sym(struct dso *dso, struct map *map,
symbol_filter_t filter)
{
Expand Down Expand Up @@ -1449,51 +1548,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
if (symbol_conf.symfs[0] != 0)
return -1;

/*
* Say the kernel DSO was created when processing the build-id header table,
* we have a build-id, so check if it is the same as the running kernel,
* using it if it is.
*/
if (dso->has_build_id) {
u8 kallsyms_build_id[BUILD_ID_SIZE];
char sbuild_id[BUILD_ID_SIZE * 2 + 1];

if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
sizeof(kallsyms_build_id)) == 0) {
if (dso__build_id_equal(dso, kallsyms_build_id)) {
kallsyms_filename = "/proc/kallsyms";
goto do_kallsyms;
}
}
/*
* Now look if we have it on the build-id cache in
* $HOME/.debug/[kernel.kallsyms].
*/
build_id__sprintf(dso->build_id, sizeof(dso->build_id),
sbuild_id);

if (asprintf(&kallsyms_allocated_filename,
"%s/.debug/[kernel.kallsyms]/%s",
getenv("HOME"), sbuild_id) == -1) {
pr_err("Not enough memory for kallsyms file lookup\n");
return -1;
}

kallsyms_filename = kallsyms_allocated_filename;
kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
if (!kallsyms_allocated_filename)
return -1;

if (access(kallsyms_filename, F_OK)) {
pr_err("No kallsyms or vmlinux with build-id %s "
"was found\n", sbuild_id);
free(kallsyms_allocated_filename);
return -1;
}
} else {
/*
* Last resort, if we don't have a build-id and couldn't find
* any vmlinux file, try the running kernel kallsyms table.
*/
kallsyms_filename = "/proc/kallsyms";
}
kallsyms_filename = kallsyms_allocated_filename;

do_kallsyms:
err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Expand Down

0 comments on commit 0544d42

Please sign in to comment.