aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <daahern@cisco.com>2010-12-09 15:27:07 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-12-21 17:17:51 -0500
commitec5761eab318e50e69fcf8e63e9edaef5949c067 (patch)
treeb81fa986f8c61f3cdcbbf11bc1195db65e8cd036
parenteac23d1c384b55e4bbb89ea9e5a6bb77fb4d1140 (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>
-rw-r--r--tools/perf/Documentation/perf-diff.txt2
-rw-r--r--tools/perf/Documentation/perf-report.txt3
-rw-r--r--tools/perf/Documentation/perf-timechart.txt2
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-report.c2
-rw-r--r--tools/perf/builtin-timechart.c2
-rw-r--r--tools/perf/util/hist.c14
-rw-r--r--tools/perf/util/symbol.c72
-rw-r--r--tools/perf/util/symbol.h1
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
70SEE ALSO 72SEE 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
119SEE ALSO 122SEE ALSO
120-------- 123--------
121linkperf:perf-stat[1] 124linkperf: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
42SEE ALSO 44SEE 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);
1107fallback: 1113fallback:
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
46int dso__name_len(const struct dso *self) 47int 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
2337int symbol__init(void) 2363int 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
91extern struct symbol_conf symbol_conf; 92extern struct symbol_conf symbol_conf;