diff options
author | David Ahern <daahern@cisco.com> | 2010-12-09 15:27:07 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-12-21 17:17:51 -0500 |
commit | ec5761eab318e50e69fcf8e63e9edaef5949c067 (patch) | |
tree | b81fa986f8c61f3cdcbbf11bc1195db65e8cd036 /tools/perf/util/symbol.c | |
parent | eac23d1c384b55e4bbb89ea9e5a6bb77fb4d1140 (diff) |
perf symbols: Add symfs option for off-box analysis using specified tree
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>
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 72 |
1 files changed, 56 insertions, 16 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ceefa6568def..561db6361f57 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -41,6 +41,7 @@ struct symbol_conf symbol_conf = { | |||
41 | .exclude_other = true, | 41 | .exclude_other = true, |
42 | .use_modules = true, | 42 | .use_modules = true, |
43 | .try_vmlinux_path = true, | 43 | .try_vmlinux_path = true, |
44 | .symfs = "", | ||
44 | }; | 45 | }; |
45 | 46 | ||
46 | int dso__name_len(const struct dso *self) | 47 | int dso__name_len(const struct dso *self) |
@@ -839,8 +840,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
839 | char sympltname[1024]; | 840 | char sympltname[1024]; |
840 | Elf *elf; | 841 | Elf *elf; |
841 | int nr = 0, symidx, fd, err = 0; | 842 | int nr = 0, symidx, fd, err = 0; |
843 | char name[PATH_MAX]; | ||
842 | 844 | ||
843 | fd = open(self->long_name, O_RDONLY); | 845 | snprintf(name, sizeof(name), "%s%s", |
846 | symbol_conf.symfs, self->long_name); | ||
847 | fd = open(name, O_RDONLY); | ||
844 | if (fd < 0) | 848 | if (fd < 0) |
845 | goto out; | 849 | goto out; |
846 | 850 | ||
@@ -1452,16 +1456,19 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1452 | self->origin++) { | 1456 | self->origin++) { |
1453 | switch (self->origin) { | 1457 | switch (self->origin) { |
1454 | case DSO__ORIG_BUILD_ID_CACHE: | 1458 | case DSO__ORIG_BUILD_ID_CACHE: |
1455 | if (dso__build_id_filename(self, name, size) == NULL) | 1459 | /* skip the locally configured cache if a symfs is given */ |
1460 | if (symbol_conf.symfs[0] || | ||
1461 | (dso__build_id_filename(self, name, size) == NULL)) { | ||
1456 | continue; | 1462 | continue; |
1463 | } | ||
1457 | break; | 1464 | break; |
1458 | case DSO__ORIG_FEDORA: | 1465 | case DSO__ORIG_FEDORA: |
1459 | snprintf(name, size, "/usr/lib/debug%s.debug", | 1466 | snprintf(name, size, "%s/usr/lib/debug%s.debug", |
1460 | self->long_name); | 1467 | symbol_conf.symfs, self->long_name); |
1461 | break; | 1468 | break; |
1462 | case DSO__ORIG_UBUNTU: | 1469 | case DSO__ORIG_UBUNTU: |
1463 | snprintf(name, size, "/usr/lib/debug%s", | 1470 | snprintf(name, size, "%s/usr/lib/debug%s", |
1464 | self->long_name); | 1471 | symbol_conf.symfs, self->long_name); |
1465 | break; | 1472 | break; |
1466 | case DSO__ORIG_BUILDID: { | 1473 | case DSO__ORIG_BUILDID: { |
1467 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 1474 | 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) | |||
1473 | sizeof(self->build_id), | 1480 | sizeof(self->build_id), |
1474 | build_id_hex); | 1481 | build_id_hex); |
1475 | snprintf(name, size, | 1482 | snprintf(name, size, |
1476 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | 1483 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", |
1477 | build_id_hex, build_id_hex + 2); | 1484 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); |
1478 | } | 1485 | } |
1479 | break; | 1486 | break; |
1480 | case DSO__ORIG_DSO: | 1487 | case DSO__ORIG_DSO: |
1481 | snprintf(name, size, "%s", self->long_name); | 1488 | snprintf(name, size, "%s%s", |
1489 | symbol_conf.symfs, self->long_name); | ||
1482 | break; | 1490 | break; |
1483 | case DSO__ORIG_GUEST_KMODULE: | 1491 | case DSO__ORIG_GUEST_KMODULE: |
1484 | if (map->groups && map->groups->machine) | 1492 | if (map->groups && map->groups->machine) |
1485 | root_dir = map->groups->machine->root_dir; | 1493 | root_dir = map->groups->machine->root_dir; |
1486 | else | 1494 | else |
1487 | root_dir = ""; | 1495 | root_dir = ""; |
1488 | snprintf(name, size, "%s%s", root_dir, self->long_name); | 1496 | snprintf(name, size, "%s%s%s", symbol_conf.symfs, |
1497 | root_dir, self->long_name); | ||
1498 | break; | ||
1499 | |||
1500 | case DSO__ORIG_KMODULE: | ||
1501 | snprintf(name, size, "%s%s", symbol_conf.symfs, | ||
1502 | self->long_name); | ||
1489 | break; | 1503 | break; |
1490 | 1504 | ||
1491 | default: | 1505 | default: |
@@ -1784,17 +1798,20 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, | |||
1784 | const char *vmlinux, symbol_filter_t filter) | 1798 | const char *vmlinux, symbol_filter_t filter) |
1785 | { | 1799 | { |
1786 | int err = -1, fd; | 1800 | int err = -1, fd; |
1801 | char symfs_vmlinux[PATH_MAX]; | ||
1787 | 1802 | ||
1788 | fd = open(vmlinux, O_RDONLY); | 1803 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", |
1804 | symbol_conf.symfs, vmlinux); | ||
1805 | fd = open(symfs_vmlinux, O_RDONLY); | ||
1789 | if (fd < 0) | 1806 | if (fd < 0) |
1790 | return -1; | 1807 | return -1; |
1791 | 1808 | ||
1792 | dso__set_loaded(self, map->type); | 1809 | dso__set_loaded(self, map->type); |
1793 | err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); | 1810 | err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); |
1794 | close(fd); | 1811 | close(fd); |
1795 | 1812 | ||
1796 | if (err > 0) | 1813 | if (err > 0) |
1797 | pr_debug("Using %s for symbols\n", vmlinux); | 1814 | pr_debug("Using %s for symbols\n", symfs_vmlinux); |
1798 | 1815 | ||
1799 | return err; | 1816 | return err; |
1800 | } | 1817 | } |
@@ -1872,6 +1889,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1872 | goto out_fixup; | 1889 | goto out_fixup; |
1873 | } | 1890 | } |
1874 | 1891 | ||
1892 | /* do not try local files if a symfs was given */ | ||
1893 | if (symbol_conf.symfs[0] != 0) | ||
1894 | return -1; | ||
1895 | |||
1875 | /* | 1896 | /* |
1876 | * Say the kernel DSO was created when processing the build-id header table, | 1897 | * Say the kernel DSO was created when processing the build-id header table, |
1877 | * we have a build-id, so check if it is the same as the running kernel, | 1898 | * 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) | |||
2262 | struct utsname uts; | 2283 | struct utsname uts; |
2263 | char bf[PATH_MAX]; | 2284 | char bf[PATH_MAX]; |
2264 | 2285 | ||
2265 | if (uname(&uts) < 0) | ||
2266 | return -1; | ||
2267 | |||
2268 | vmlinux_path = malloc(sizeof(char *) * 5); | 2286 | vmlinux_path = malloc(sizeof(char *) * 5); |
2269 | if (vmlinux_path == NULL) | 2287 | if (vmlinux_path == NULL) |
2270 | return -1; | 2288 | return -1; |
@@ -2277,6 +2295,14 @@ static int vmlinux_path__init(void) | |||
2277 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | 2295 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) |
2278 | goto out_fail; | 2296 | goto out_fail; |
2279 | ++vmlinux_path__nr_entries; | 2297 | ++vmlinux_path__nr_entries; |
2298 | |||
2299 | /* only try running kernel version if no symfs was given */ | ||
2300 | if (symbol_conf.symfs[0] != 0) | ||
2301 | return 0; | ||
2302 | |||
2303 | if (uname(&uts) < 0) | ||
2304 | return -1; | ||
2305 | |||
2280 | snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); | 2306 | snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); |
2281 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); | 2307 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); |
2282 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | 2308 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) |
@@ -2336,6 +2362,8 @@ static int setup_list(struct strlist **list, const char *list_str, | |||
2336 | 2362 | ||
2337 | int symbol__init(void) | 2363 | int symbol__init(void) |
2338 | { | 2364 | { |
2365 | const char *symfs; | ||
2366 | |||
2339 | if (symbol_conf.initialized) | 2367 | if (symbol_conf.initialized) |
2340 | return 0; | 2368 | return 0; |
2341 | 2369 | ||
@@ -2364,6 +2392,18 @@ int symbol__init(void) | |||
2364 | symbol_conf.sym_list_str, "symbol") < 0) | 2392 | symbol_conf.sym_list_str, "symbol") < 0) |
2365 | goto out_free_comm_list; | 2393 | goto out_free_comm_list; |
2366 | 2394 | ||
2395 | /* | ||
2396 | * A path to symbols of "/" is identical to "" | ||
2397 | * reset here for simplicity. | ||
2398 | */ | ||
2399 | symfs = realpath(symbol_conf.symfs, NULL); | ||
2400 | if (symfs == NULL) | ||
2401 | symfs = symbol_conf.symfs; | ||
2402 | if (strcmp(symfs, "/") == 0) | ||
2403 | symbol_conf.symfs = ""; | ||
2404 | if (symfs != symbol_conf.symfs) | ||
2405 | free((void *)symfs); | ||
2406 | |||
2367 | symbol_conf.initialized = true; | 2407 | symbol_conf.initialized = true; |
2368 | return 0; | 2408 | return 0; |
2369 | 2409 | ||