diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-11-23 16:39:10 -0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-23 19:51:48 +0100 |
commit | cc612d8199089413719397c9d92e5823da578eac (patch) | |
tree | aec84294a839bc82b738326ed5f338e6ebc47a30 /tools/perf/util | |
parent | 1b290d670ffa883b7e062177463a8efd00eaa2c1 (diff) |
perf symbols: Look for vmlinux in more places
Now that we can check the buildid to see if it really matches,
this can be done safely:
vmlinux
/boot/vmlinux
/boot/vmlinux-<uts.release>
/lib/modules/<uts.release>/build/vmlinux
/usr/lib/debug/lib/modules/%s/vmlinux
More can be added - if you know about distros that put the
vmlinux somewhere else please let us know.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1259001550-8194-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/data_map.c | 4 | ||||
-rw-r--r-- | tools/perf/util/data_map.h | 2 | ||||
-rw-r--r-- | tools/perf/util/header.c | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 113 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 4 |
5 files changed, 109 insertions, 16 deletions
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index e7b6c2bea3d..f318d19b256 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -101,6 +101,8 @@ out: int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, + const char *vmlinux_name, + bool try_vmlinux_path, int force, int full_paths, int *cwdlen, @@ -171,7 +173,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, goto out_delete; err = -ENOMEM; - if (kernel_maps__init(true) < 0) { + if (kernel_maps__init(vmlinux_name, try_vmlinux_path, true) < 0) { pr_err("failed to setup the kernel maps to resolve symbols\n"); goto out_delete; } diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index ae036ecd762..3f0d21b3819 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h @@ -23,6 +23,8 @@ struct perf_file_handler { void register_perf_file_handler(struct perf_file_handler *handler); int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, + const char *vmlinux_name, + bool try_vmlinux_path, int force, int full_paths, int *cwdlen, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ac3410b8e9e..1332f8ec04a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -257,7 +257,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) * Read the kernel buildid nad the list of loaded modules with * its build_ids: */ - kernel_maps__init(true); + kernel_maps__init(NULL, false, true); /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 74b5b8a1695..44d81d5ae8c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -34,6 +34,8 @@ static void kernel_maps__insert(struct map *map); static int dso__load_kernel_sym(struct dso *self, struct map *map, symbol_filter_t filter); unsigned int symbol__priv_size; +static int vmlinux_path__nr_entries; +static char **vmlinux_path; static struct rb_root kernel_maps; @@ -1386,15 +1388,43 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, static int dso__load_kernel_sym(struct dso *self, struct map *map, symbol_filter_t filter) { - int err = dso__load_vmlinux(self, map, self->name, filter); + int err; + bool is_kallsyms; + + if (vmlinux_path != NULL) { + int i; + pr_debug("Looking at the vmlinux_path (%d entries long)\n", + vmlinux_path__nr_entries); + for (i = 0; i < vmlinux_path__nr_entries; ++i) { + err = dso__load_vmlinux(self, map, vmlinux_path[i], + filter); + if (err > 0) { + pr_debug("Using %s for symbols\n", + vmlinux_path[i]); + dso__set_long_name(self, + strdup(vmlinux_path[i])); + goto out_fixup; + } + } + } + + is_kallsyms = self->long_name[0] == '['; + if (is_kallsyms) + goto do_kallsyms; + err = dso__load_vmlinux(self, map, self->long_name, filter); if (err <= 0) { + pr_info("The file %s cannot be used, " + "trying to use /proc/kallsyms...", self->long_name); + sleep(2); +do_kallsyms: err = kernel_maps__load_kallsyms(filter); - if (err > 0) + if (err > 0 && !is_kallsyms) dso__set_long_name(self, strdup("[kernel.kallsyms]")); } if (err > 0) { +out_fixup: map__fixup_start(map); map__fixup_end(map); } @@ -1403,9 +1433,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } LIST_HEAD(dsos); -struct dso *vdso; - -const char *vmlinux_name = "vmlinux"; +struct dso *vdso; static void dsos__add(struct dso *dso) { @@ -1457,9 +1485,9 @@ size_t dsos__fprintf_buildid(FILE *fp) return ret; } -static int kernel_maps__create_kernel_map(void) +static int kernel_maps__create_kernel_map(const char *vmlinux_name) { - struct dso *kernel = dso__new(vmlinux_name); + struct dso *kernel = dso__new(vmlinux_name ?: "[kernel.kallsyms]"); if (kernel == NULL) return -1; @@ -1468,10 +1496,10 @@ static int kernel_maps__create_kernel_map(void) if (kernel_map == NULL) goto out_delete_kernel_dso; - kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; + kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; + kernel->short_name = "[kernel]"; + kernel->kernel = 1; - kernel->short_name = "[kernel]"; - kernel->kernel = 1; vdso = dso__new("[vdso]"); if (vdso == NULL) goto out_delete_kernel_map; @@ -1494,11 +1522,72 @@ out_delete_kernel_dso: return -1; } -int kernel_maps__init(bool use_modules) +static void vmlinux_path__exit(void) +{ + while (--vmlinux_path__nr_entries >= 0) { + free(vmlinux_path[vmlinux_path__nr_entries]); + vmlinux_path[vmlinux_path__nr_entries] = NULL; + } + + free(vmlinux_path); + vmlinux_path = NULL; +} + +static int vmlinux_path__init(void) +{ + struct utsname uts; + char bf[PATH_MAX]; + + if (uname(&uts) < 0) + return -1; + + vmlinux_path = malloc(sizeof(char *) * 5); + if (vmlinux_path == NULL) + return -1; + + vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); + vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); + vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", + uts.release); + vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + + return 0; + +out_fail: + vmlinux_path__exit(); + return -1; +} + +int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, + bool use_modules) { - if (kernel_maps__create_kernel_map() < 0) + if (try_vmlinux_path && vmlinux_path__init() < 0) return -1; + if (kernel_maps__create_kernel_map(vmlinux_name) < 0) { + vmlinux_path__exit(); + return -1; + } + if (use_modules && kernel_maps__create_module_maps() < 0) pr_debug("Failed to load list of modules in use, " "continuing...\n"); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 7a129047c47..8c4d026e067 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -93,7 +93,8 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); -int kernel_maps__init(bool use_modules); +int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, + bool use_modules); size_t kernel_maps__fprintf(FILE *fp); void symbol__init(unsigned int priv_size); @@ -101,5 +102,4 @@ void symbol__init(unsigned int priv_size); extern struct list_head dsos; extern struct map *kernel_map; extern struct dso *vdso; -extern const char *vmlinux_name; #endif /* __PERF_SYMBOL */ |