perf symbols: Add symfs option for off-box analysis using specified tree
authorDavid Ahern <daahern@cisco.com>
Thu, 9 Dec 2010 20:27:07 +0000 (13:27 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 21 Dec 2010 22:17:51 +0000 (20:17 -0200)
The symfs argument allows analysis of perf.data file using a locally accessible
filesystem tree with debug symbols - e.g., tree created during image builds,
sshfs mount, loop mounted KVM disk images, USB keys, initrds, etc. Anything
with an OS tree can be analyzed from anywhere without the need to populate a
local data store with build-ids.

Commiter notes:

o Fixed up symfs="/" variants handling.

o prefixed DSO__ORIG_GUEST_KMODULE case with symfs too, avoiding use of files
  outside the symfs directory.

LKML-Reference: <1291926427-28846-1-git-send-email-daahern@cisco.com>
Signed-off-by: David Ahern <daahern@cisco.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-diff.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-timechart.txt
tools/perf/builtin-diff.c
tools/perf/builtin-report.c
tools/perf/builtin-timechart.c
tools/perf/util/hist.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h

index 6a9ec2b353103e4460c2477e34b84e6ecb5a02d6..74d7481ed7a6916f8797ed67b91b5c5d80382edc 100644 (file)
@@ -66,6 +66,8 @@ OPTIONS
 --force::
        Don't complain, do it.
 
+--symfs=<directory>::
+        Look for files with symbols relative to this directory.
 
 SEE ALSO
 --------
index fefea77ec6e9c33276b4c53647b6c550d1138e28..8ba03d6e5398d8387b11f9caf183bed81a0eb5a2 100644 (file)
@@ -116,6 +116,9 @@ OPTIONS
 --force::
         Don't complain, do it.
 
+--symfs=<directory>::
+        Look for files with symbols relative to this directory.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1]
index 4b1788355ecac3d305bf72e6f58d5a477e08ba7b..d7b79e2ba2adbe2cc0cb6468a9d84d6b73b8ed0f 100644 (file)
@@ -38,6 +38,8 @@ OPTIONS
 --process::
         Select the processes to display, by name or PID
 
+--symfs=<directory>::
+        Look for files with symbols relative to this directory.
 
 SEE ALSO
 --------
index 97846dcafc63dd9c32d7928128426594149d417a..3153e492dbcc29e1593b6df29357424dd012da99 100644 (file)
@@ -194,6 +194,8 @@ static const struct option options[] = {
        OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
                   "separator for columns, no spaces will be added between "
                   "columns '.' is reserved."),
+       OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
+                   "Look for files with symbols relative to this directory"),
        OPT_END()
 };
 
index 4af7ce6e155546ac3ec4dabcb2d01cbf35440fcc..75183a4518e60d23db05e36e585fc178df731a19 100644 (file)
@@ -483,6 +483,8 @@ static const struct option options[] = {
                   "columns '.' is reserved."),
        OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
                    "Only display entries resolved to a symbol"),
+       OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
+                   "Look for files with symbols relative to this directory"),
        OPT_END()
 };
 
index 459b5e3db267a556ebc8b3b83dbebe4b9b0514ec..d75084bccdb79d4402bd8066212d26e4a4571c74 100644 (file)
@@ -1022,6 +1022,8 @@ static const struct option options[] = {
        OPT_CALLBACK('p', "process", NULL, "process",
                      "process selector. Pass a pid or process name.",
                       parse_process),
+       OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
+                   "Look for files with symbols relative to this directory"),
        OPT_END()
 };
 
index a3b84160c42eb0ff56fa258ce29f0b26d9290c5d..d5036700a4359ba640e6e9c953e7b0861c443382 100644 (file)
@@ -1092,6 +1092,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
        FILE *file;
        int err = 0;
        u64 len;
+       char symfs_filename[PATH_MAX];
+
+       if (filename) {
+               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
+                        symbol_conf.symfs, filename);
+       }
 
        if (filename == NULL) {
                if (dso->has_build_id) {
@@ -1100,9 +1106,9 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
                        return -ENOMEM;
                }
                goto fallback;
-       } else if (readlink(filename, command, sizeof(command)) < 0 ||
+       } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
                   strstr(command, "[kernel.kallsyms]") ||
-                  access(filename, R_OK)) {
+                  access(symfs_filename, R_OK)) {
                free(filename);
 fallback:
                /*
@@ -1111,6 +1117,8 @@ fallback:
                 * DSO is the same as when 'perf record' ran.
                 */
                filename = dso->long_name;
+               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
+                        symbol_conf.symfs, filename);
                free_filename = false;
        }
 
@@ -1137,7 +1145,7 @@ fallback:
                 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
                 map__rip_2objdump(map, sym->start),
                 map__rip_2objdump(map, sym->end),
-                filename, filename);
+                symfs_filename, filename);
 
        pr_debug("Executing: %s\n", command);
 
index ceefa6568def788d4495b815a953b3b2d8dd1fe9..561db6361f57a3f42e1af978f8006ae7657469bc 100644 (file)
@@ -41,6 +41,7 @@ struct symbol_conf symbol_conf = {
        .exclude_other    = true,
        .use_modules      = true,
        .try_vmlinux_path = true,
+       .symfs            = "",
 };
 
 int dso__name_len(const struct dso *self)
@@ -839,8 +840,11 @@ static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
        char sympltname[1024];
        Elf *elf;
        int nr = 0, symidx, fd, err = 0;
+       char name[PATH_MAX];
 
-       fd = open(self->long_name, O_RDONLY);
+       snprintf(name, sizeof(name), "%s%s",
+                symbol_conf.symfs, self->long_name);
+       fd = open(name, O_RDONLY);
        if (fd < 0)
                goto out;
 
@@ -1452,16 +1456,19 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
             self->origin++) {
                switch (self->origin) {
                case DSO__ORIG_BUILD_ID_CACHE:
-                       if (dso__build_id_filename(self, name, size) == NULL)
+                       /* skip the locally configured cache if a symfs is given */
+                       if (symbol_conf.symfs[0] ||
+                           (dso__build_id_filename(self, name, size) == NULL)) {
                                continue;
+                       }
                        break;
                case DSO__ORIG_FEDORA:
-                       snprintf(name, size, "/usr/lib/debug%s.debug",
-                                self->long_name);
+                       snprintf(name, size, "%s/usr/lib/debug%s.debug",
+                                symbol_conf.symfs, self->long_name);
                        break;
                case DSO__ORIG_UBUNTU:
-                       snprintf(name, size, "/usr/lib/debug%s",
-                                self->long_name);
+                       snprintf(name, size, "%s/usr/lib/debug%s",
+                                symbol_conf.symfs, self->long_name);
                        break;
                case DSO__ORIG_BUILDID: {
                        char build_id_hex[BUILD_ID_SIZE * 2 + 1];
@@ -1473,19 +1480,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
                                          sizeof(self->build_id),
                                          build_id_hex);
                        snprintf(name, size,
-                                "/usr/lib/debug/.build-id/%.2s/%s.debug",
-                                build_id_hex, build_id_hex + 2);
+                                "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
+                                symbol_conf.symfs, build_id_hex, build_id_hex + 2);
                        }
                        break;
                case DSO__ORIG_DSO:
-                       snprintf(name, size, "%s", self->long_name);
+                       snprintf(name, size, "%s%s",
+                            symbol_conf.symfs, self->long_name);
                        break;
                case DSO__ORIG_GUEST_KMODULE:
                        if (map->groups && map->groups->machine)
                                root_dir = map->groups->machine->root_dir;
                        else
                                root_dir = "";
-                       snprintf(name, size, "%s%s", root_dir, self->long_name);
+                       snprintf(name, size, "%s%s%s", symbol_conf.symfs,
+                                root_dir, self->long_name);
+                       break;
+
+               case DSO__ORIG_KMODULE:
+                       snprintf(name, size, "%s%s", symbol_conf.symfs,
+                                self->long_name);
                        break;
 
                default:
@@ -1784,17 +1798,20 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
                             const char *vmlinux, symbol_filter_t filter)
 {
        int err = -1, fd;
+       char symfs_vmlinux[PATH_MAX];
 
-       fd = open(vmlinux, O_RDONLY);
+       snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
+                symbol_conf.symfs, vmlinux);
+       fd = open(symfs_vmlinux, O_RDONLY);
        if (fd < 0)
                return -1;
 
        dso__set_loaded(self, map->type);
-       err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
+       err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
        close(fd);
 
        if (err > 0)
-               pr_debug("Using %s for symbols\n", vmlinux);
+               pr_debug("Using %s for symbols\n", symfs_vmlinux);
 
        return err;
 }
@@ -1872,6 +1889,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
                        goto out_fixup;
        }
 
+       /* do not try local files if a symfs was given */
+       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,
@@ -2262,9 +2283,6 @@ 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;
@@ -2277,6 +2295,14 @@ static int vmlinux_path__init(void)
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
        ++vmlinux_path__nr_entries;
+
+       /* only try running kernel version if no symfs was given */
+       if (symbol_conf.symfs[0] != 0)
+               return 0;
+
+       if (uname(&uts) < 0)
+               return -1;
+
        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)
@@ -2336,6 +2362,8 @@ static int setup_list(struct strlist **list, const char *list_str,
 
 int symbol__init(void)
 {
+       const char *symfs;
+
        if (symbol_conf.initialized)
                return 0;
 
@@ -2364,6 +2392,18 @@ int symbol__init(void)
                       symbol_conf.sym_list_str, "symbol") < 0)
                goto out_free_comm_list;
 
+       /*
+        * A path to symbols of "/" is identical to ""
+        * reset here for simplicity.
+        */
+       symfs = realpath(symbol_conf.symfs, NULL);
+       if (symfs == NULL)
+               symfs = symbol_conf.symfs;
+       if (strcmp(symfs, "/") == 0)
+               symbol_conf.symfs = "";
+       if (symfs != symbol_conf.symfs)
+               free((void *)symfs);
+
        symbol_conf.initialized = true;
        return 0;
 
index 12defbe18c13fe858c4d9fccd55db7f90f8b0b2e..bcd2f986927e491504c828aed5fbc803edaef60a 100644 (file)
@@ -86,6 +86,7 @@ struct symbol_conf {
        struct strlist  *dso_list,
                        *comm_list,
                        *sym_list;
+       const char      *symfs;
 };
 
 extern struct symbol_conf symbol_conf;