perf symbols: Look for vmlinux in more places
authorArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 23 Nov 2009 18:39:10 +0000 (16:39 -0200)
committerIngo Molnar <mingo@elte.hu>
Mon, 23 Nov 2009 18:51:48 +0000 (19:51 +0100)
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>
tools/perf/builtin-annotate.c
tools/perf/builtin-kmem.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/util/data_map.c
tools/perf/util/data_map.h
tools/perf/util/header.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h

index 2031527..6b13a1e 100644 (file)
@@ -37,6 +37,7 @@ static bool           use_modules;
 
 static unsigned long   page_size;
 static unsigned long   mmap_window = 32;
+const char             *vmlinux_name;
 
 struct sym_hist {
        u64             sum;
@@ -637,7 +638,7 @@ static int __cmd_annotate(void)
                exit(0);
        }
 
-       if (kernel_maps__init(use_modules) < 0) {
+       if (kernel_maps__init(vmlinux_name, true, use_modules) < 0) {
                pr_err("failed to create kernel maps for symbol resolution\b");
                return -1;
        }
index 4145049..5d8aeae 100644 (file)
@@ -291,7 +291,7 @@ static int read_events(void)
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name, 0, 0,
+       return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0,
                                       &cwdlen, &cwd);
 }
 
index 7e690f7..fe474b7 100644 (file)
@@ -52,6 +52,7 @@ static char           *pretty_printing_style = default_pretty_printing_style;
 static int             exclude_other = 1;
 
 static char            callchain_default_opt[] = "fractal,0.5";
+const char             *vmlinux_name;
 
 static char            *cwd;
 static int             cwdlen;
@@ -925,8 +926,9 @@ static int __cmd_report(void)
 
        register_perf_file_handler(&file_handler);
 
-       ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths,
-                                     &cwdlen, &cwd);
+       ret = mmap_dispatch_perf_file(&header, input_name, vmlinux_name,
+                                     !vmlinux_name, force,
+                                     full_paths, &cwdlen, &cwd);
        if (ret)
                return ret;
 
index df44b75..260f57a 100644 (file)
@@ -1718,7 +1718,8 @@ static int read_events(void)
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd);
+       return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0,
+                                      &cwdlen, &cwd);
 }
 
 static void print_bad_events(void)
index ea49c2e..eef9caa 100644 (file)
@@ -79,6 +79,7 @@ static int                    dump_symtab                     =      0;
 static bool                    hide_kernel_symbols             =  false;
 static bool                    hide_user_symbols               =  false;
 static struct winsize          winsize;
+const char                     *vmlinux_name;
 static const char              *graph_line                     =
        "_____________________________________________________________________"
        "_____________________________________________________________________";
@@ -1341,7 +1342,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        if (delay_secs < 1)
                delay_secs = 1;
 
-       err = kernel_maps__init(true);
+       err = kernel_maps__init(vmlinux_name, !vmlinux_name, true);
        if (err < 0)
                return err;
        parse_source(sym_filter_entry);
index d042d65..b71198e 100644 (file)
@@ -131,7 +131,8 @@ static int __cmd_trace(void)
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd);
+       return mmap_dispatch_perf_file(&header, input_name, NULL, false,
+                                      0, 0, &cwdlen, &cwd);
 }
 
 static const char * const annotate_usage[] = {
index e7b6c2b..f318d19 100644 (file)
@@ -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;
        }
index ae036ec..3f0d21b 100644 (file)
@@ -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,
index ac3410b..1332f8e 100644 (file)
@@ -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);
index 74b5b8a..44d81d5 100644 (file)
@@ -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");
index 7a12904..8c4d026 100644 (file)
@@ -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 */