diff options
-rw-r--r-- | tools/perf/Documentation/perf-diff.txt | 2 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-report.txt | 3 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-timechart.txt | 2 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 14 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 72 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 1 |
9 files changed, 81 insertions, 19 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 6a9ec2b35310..74d7481ed7a6 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -66,6 +66,8 @@ OPTIONS | |||
66 | --force:: | 66 | --force:: |
67 | Don't complain, do it. | 67 | Don't complain, do it. |
68 | 68 | ||
69 | --symfs=<directory>:: | ||
70 | Look for files with symbols relative to this directory. | ||
69 | 71 | ||
70 | SEE ALSO | 72 | SEE ALSO |
71 | -------- | 73 | -------- |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index fefea77ec6e9..8ba03d6e5398 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -116,6 +116,9 @@ OPTIONS | |||
116 | --force:: | 116 | --force:: |
117 | Don't complain, do it. | 117 | Don't complain, do it. |
118 | 118 | ||
119 | --symfs=<directory>:: | ||
120 | Look for files with symbols relative to this directory. | ||
121 | |||
119 | SEE ALSO | 122 | SEE ALSO |
120 | -------- | 123 | -------- |
121 | linkperf:perf-stat[1] | 124 | linkperf:perf-stat[1] |
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index 4b1788355eca..d7b79e2ba2ad 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt | |||
@@ -38,6 +38,8 @@ OPTIONS | |||
38 | --process:: | 38 | --process:: |
39 | Select the processes to display, by name or PID | 39 | Select the processes to display, by name or PID |
40 | 40 | ||
41 | --symfs=<directory>:: | ||
42 | Look for files with symbols relative to this directory. | ||
41 | 43 | ||
42 | SEE ALSO | 44 | SEE ALSO |
43 | -------- | 45 | -------- |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 97846dcafc63..3153e492dbcc 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -194,6 +194,8 @@ static const struct option options[] = { | |||
194 | OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", | 194 | OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", |
195 | "separator for columns, no spaces will be added between " | 195 | "separator for columns, no spaces will be added between " |
196 | "columns '.' is reserved."), | 196 | "columns '.' is reserved."), |
197 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | ||
198 | "Look for files with symbols relative to this directory"), | ||
197 | OPT_END() | 199 | OPT_END() |
198 | }; | 200 | }; |
199 | 201 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 4af7ce6e1555..75183a4518e6 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -483,6 +483,8 @@ static const struct option options[] = { | |||
483 | "columns '.' is reserved."), | 483 | "columns '.' is reserved."), |
484 | OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, | 484 | OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, |
485 | "Only display entries resolved to a symbol"), | 485 | "Only display entries resolved to a symbol"), |
486 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | ||
487 | "Look for files with symbols relative to this directory"), | ||
486 | OPT_END() | 488 | OPT_END() |
487 | }; | 489 | }; |
488 | 490 | ||
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 459b5e3db267..d75084bccdb7 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -1022,6 +1022,8 @@ static const struct option options[] = { | |||
1022 | OPT_CALLBACK('p', "process", NULL, "process", | 1022 | OPT_CALLBACK('p', "process", NULL, "process", |
1023 | "process selector. Pass a pid or process name.", | 1023 | "process selector. Pass a pid or process name.", |
1024 | parse_process), | 1024 | parse_process), |
1025 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | ||
1026 | "Look for files with symbols relative to this directory"), | ||
1025 | OPT_END() | 1027 | OPT_END() |
1026 | }; | 1028 | }; |
1027 | 1029 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index a3b84160c42e..d5036700a435 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -1092,6 +1092,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head, | |||
1092 | FILE *file; | 1092 | FILE *file; |
1093 | int err = 0; | 1093 | int err = 0; |
1094 | u64 len; | 1094 | u64 len; |
1095 | char symfs_filename[PATH_MAX]; | ||
1096 | |||
1097 | if (filename) { | ||
1098 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", | ||
1099 | symbol_conf.symfs, filename); | ||
1100 | } | ||
1095 | 1101 | ||
1096 | if (filename == NULL) { | 1102 | if (filename == NULL) { |
1097 | if (dso->has_build_id) { | 1103 | if (dso->has_build_id) { |
@@ -1100,9 +1106,9 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head, | |||
1100 | return -ENOMEM; | 1106 | return -ENOMEM; |
1101 | } | 1107 | } |
1102 | goto fallback; | 1108 | goto fallback; |
1103 | } else if (readlink(filename, command, sizeof(command)) < 0 || | 1109 | } else if (readlink(symfs_filename, command, sizeof(command)) < 0 || |
1104 | strstr(command, "[kernel.kallsyms]") || | 1110 | strstr(command, "[kernel.kallsyms]") || |
1105 | access(filename, R_OK)) { | 1111 | access(symfs_filename, R_OK)) { |
1106 | free(filename); | 1112 | free(filename); |
1107 | fallback: | 1113 | fallback: |
1108 | /* | 1114 | /* |
@@ -1111,6 +1117,8 @@ fallback: | |||
1111 | * DSO is the same as when 'perf record' ran. | 1117 | * DSO is the same as when 'perf record' ran. |
1112 | */ | 1118 | */ |
1113 | filename = dso->long_name; | 1119 | filename = dso->long_name; |
1120 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", | ||
1121 | symbol_conf.symfs, filename); | ||
1114 | free_filename = false; | 1122 | free_filename = false; |
1115 | } | 1123 | } |
1116 | 1124 | ||
@@ -1137,7 +1145,7 @@ fallback: | |||
1137 | "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand", | 1145 | "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand", |
1138 | map__rip_2objdump(map, sym->start), | 1146 | map__rip_2objdump(map, sym->start), |
1139 | map__rip_2objdump(map, sym->end), | 1147 | map__rip_2objdump(map, sym->end), |
1140 | filename, filename); | 1148 | symfs_filename, filename); |
1141 | 1149 | ||
1142 | pr_debug("Executing: %s\n", command); | 1150 | pr_debug("Executing: %s\n", command); |
1143 | 1151 | ||
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 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 12defbe18c13..bcd2f986927e 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -86,6 +86,7 @@ struct symbol_conf { | |||
86 | struct strlist *dso_list, | 86 | struct strlist *dso_list, |
87 | *comm_list, | 87 | *comm_list, |
88 | *sym_list; | 88 | *sym_list; |
89 | const char *symfs; | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | extern struct symbol_conf symbol_conf; | 92 | extern struct symbol_conf symbol_conf; |