aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c204
1 files changed, 163 insertions, 41 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b39f499e575a..15ccfba8cdf8 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -22,6 +22,10 @@
22#include <limits.h> 22#include <limits.h>
23#include <sys/utsname.h> 23#include <sys/utsname.h>
24 24
25#ifndef KSYM_NAME_LEN
26#define KSYM_NAME_LEN 128
27#endif
28
25#ifndef NT_GNU_BUILD_ID 29#ifndef NT_GNU_BUILD_ID
26#define NT_GNU_BUILD_ID 3 30#define NT_GNU_BUILD_ID 3
27#endif 31#endif
@@ -41,6 +45,7 @@ struct symbol_conf symbol_conf = {
41 .exclude_other = true, 45 .exclude_other = true,
42 .use_modules = true, 46 .use_modules = true,
43 .try_vmlinux_path = true, 47 .try_vmlinux_path = true,
48 .symfs = "",
44}; 49};
45 50
46int dso__name_len(const struct dso *self) 51int dso__name_len(const struct dso *self)
@@ -92,7 +97,7 @@ static void symbols__fixup_end(struct rb_root *self)
92 prev = curr; 97 prev = curr;
93 curr = rb_entry(nd, struct symbol, rb_node); 98 curr = rb_entry(nd, struct symbol, rb_node);
94 99
95 if (prev->end == prev->start) 100 if (prev->end == prev->start && prev->end != curr->start)
96 prev->end = curr->start - 1; 101 prev->end = curr->start - 1;
97 } 102 }
98 103
@@ -121,7 +126,7 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
121 * We still haven't the actual symbols, so guess the 126 * We still haven't the actual symbols, so guess the
122 * last map final address. 127 * last map final address.
123 */ 128 */
124 curr->end = ~0UL; 129 curr->end = ~0ULL;
125} 130}
126 131
127static void map_groups__fixup_end(struct map_groups *self) 132static void map_groups__fixup_end(struct map_groups *self)
@@ -295,7 +300,9 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
295{ 300{
296 struct rb_node **p = &self->rb_node; 301 struct rb_node **p = &self->rb_node;
297 struct rb_node *parent = NULL; 302 struct rb_node *parent = NULL;
298 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 303 struct symbol_name_rb_node *symn, *s;
304
305 symn = container_of(sym, struct symbol_name_rb_node, sym);
299 306
300 while (*p != NULL) { 307 while (*p != NULL) {
301 parent = *p; 308 parent = *p;
@@ -423,16 +430,25 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
423 430
424int kallsyms__parse(const char *filename, void *arg, 431int kallsyms__parse(const char *filename, void *arg,
425 int (*process_symbol)(void *arg, const char *name, 432 int (*process_symbol)(void *arg, const char *name,
426 char type, u64 start)) 433 char type, u64 start, u64 end))
427{ 434{
428 char *line = NULL; 435 char *line = NULL;
429 size_t n; 436 size_t n;
430 int err = 0; 437 int err = -1;
438 u64 prev_start = 0;
439 char prev_symbol_type = 0;
440 char *prev_symbol_name;
431 FILE *file = fopen(filename, "r"); 441 FILE *file = fopen(filename, "r");
432 442
433 if (file == NULL) 443 if (file == NULL)
434 goto out_failure; 444 goto out_failure;
435 445
446 prev_symbol_name = malloc(KSYM_NAME_LEN);
447 if (prev_symbol_name == NULL)
448 goto out_close;
449
450 err = 0;
451
436 while (!feof(file)) { 452 while (!feof(file)) {
437 u64 start; 453 u64 start;
438 int line_len, len; 454 int line_len, len;
@@ -452,14 +468,33 @@ int kallsyms__parse(const char *filename, void *arg,
452 continue; 468 continue;
453 469
454 symbol_type = toupper(line[len]); 470 symbol_type = toupper(line[len]);
455 symbol_name = line + len + 2; 471 len += 2;
472 symbol_name = line + len;
473 len = line_len - len;
456 474
457 err = process_symbol(arg, symbol_name, symbol_type, start); 475 if (len >= KSYM_NAME_LEN) {
458 if (err) 476 err = -1;
459 break; 477 break;
478 }
479
480 if (prev_symbol_type) {
481 u64 end = start;
482 if (end != prev_start)
483 --end;
484 err = process_symbol(arg, prev_symbol_name,
485 prev_symbol_type, prev_start, end);
486 if (err)
487 break;
488 }
489
490 memcpy(prev_symbol_name, symbol_name, len + 1);
491 prev_symbol_type = symbol_type;
492 prev_start = start;
460 } 493 }
461 494
495 free(prev_symbol_name);
462 free(line); 496 free(line);
497out_close:
463 fclose(file); 498 fclose(file);
464 return err; 499 return err;
465 500
@@ -481,7 +516,7 @@ static u8 kallsyms2elf_type(char type)
481} 516}
482 517
483static int map__process_kallsym_symbol(void *arg, const char *name, 518static int map__process_kallsym_symbol(void *arg, const char *name,
484 char type, u64 start) 519 char type, u64 start, u64 end)
485{ 520{
486 struct symbol *sym; 521 struct symbol *sym;
487 struct process_kallsyms_args *a = arg; 522 struct process_kallsyms_args *a = arg;
@@ -490,11 +525,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
490 if (!symbol_type__is_a(type, a->map->type)) 525 if (!symbol_type__is_a(type, a->map->type))
491 return 0; 526 return 0;
492 527
493 /* 528 sym = symbol__new(start, end - start + 1,
494 * Will fix up the end later, when we have all symbols sorted. 529 kallsyms2elf_type(type), name);
495 */
496 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
497
498 if (sym == NULL) 530 if (sym == NULL)
499 return -ENOMEM; 531 return -ENOMEM;
500 /* 532 /*
@@ -530,7 +562,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
530 struct machine *machine = kmaps->machine; 562 struct machine *machine = kmaps->machine;
531 struct map *curr_map = map; 563 struct map *curr_map = map;
532 struct symbol *pos; 564 struct symbol *pos;
533 int count = 0; 565 int count = 0, moved = 0;
534 struct rb_root *root = &self->symbols[map->type]; 566 struct rb_root *root = &self->symbols[map->type];
535 struct rb_node *next = rb_first(root); 567 struct rb_node *next = rb_first(root);
536 int kernel_range = 0; 568 int kernel_range = 0;
@@ -588,6 +620,11 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
588 char dso_name[PATH_MAX]; 620 char dso_name[PATH_MAX];
589 struct dso *dso; 621 struct dso *dso;
590 622
623 if (count == 0) {
624 curr_map = map;
625 goto filter_symbol;
626 }
627
591 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 628 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
592 snprintf(dso_name, sizeof(dso_name), 629 snprintf(dso_name, sizeof(dso_name),
593 "[guest.kernel].%d", 630 "[guest.kernel].%d",
@@ -613,7 +650,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
613 map_groups__insert(kmaps, curr_map); 650 map_groups__insert(kmaps, curr_map);
614 ++kernel_range; 651 ++kernel_range;
615 } 652 }
616 653filter_symbol:
617 if (filter && filter(curr_map, pos)) { 654 if (filter && filter(curr_map, pos)) {
618discard_symbol: rb_erase(&pos->rb_node, root); 655discard_symbol: rb_erase(&pos->rb_node, root);
619 symbol__delete(pos); 656 symbol__delete(pos);
@@ -621,8 +658,9 @@ discard_symbol: rb_erase(&pos->rb_node, root);
621 if (curr_map != map) { 658 if (curr_map != map) {
622 rb_erase(&pos->rb_node, root); 659 rb_erase(&pos->rb_node, root);
623 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 660 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
624 } 661 ++moved;
625 count++; 662 } else
663 ++count;
626 } 664 }
627 } 665 }
628 666
@@ -632,7 +670,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
632 dso__set_loaded(curr_map->dso, curr_map->type); 670 dso__set_loaded(curr_map->dso, curr_map->type);
633 } 671 }
634 672
635 return count; 673 return count + moved;
636} 674}
637 675
638int dso__load_kallsyms(struct dso *self, const char *filename, 676int dso__load_kallsyms(struct dso *self, const char *filename,
@@ -641,7 +679,6 @@ int dso__load_kallsyms(struct dso *self, const char *filename,
641 if (dso__load_all_kallsyms(self, filename, map) < 0) 679 if (dso__load_all_kallsyms(self, filename, map) < 0)
642 return -1; 680 return -1;
643 681
644 symbols__fixup_end(&self->symbols[map->type]);
645 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 682 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
646 self->origin = DSO__ORIG_GUEST_KERNEL; 683 self->origin = DSO__ORIG_GUEST_KERNEL;
647 else 684 else
@@ -831,8 +868,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
831 char sympltname[1024]; 868 char sympltname[1024];
832 Elf *elf; 869 Elf *elf;
833 int nr = 0, symidx, fd, err = 0; 870 int nr = 0, symidx, fd, err = 0;
871 char name[PATH_MAX];
834 872
835 fd = open(self->long_name, O_RDONLY); 873 snprintf(name, sizeof(name), "%s%s",
874 symbol_conf.symfs, self->long_name);
875 fd = open(name, O_RDONLY);
836 if (fd < 0) 876 if (fd < 0)
837 goto out; 877 goto out;
838 878
@@ -1444,16 +1484,19 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1444 self->origin++) { 1484 self->origin++) {
1445 switch (self->origin) { 1485 switch (self->origin) {
1446 case DSO__ORIG_BUILD_ID_CACHE: 1486 case DSO__ORIG_BUILD_ID_CACHE:
1447 if (dso__build_id_filename(self, name, size) == NULL) 1487 /* skip the locally configured cache if a symfs is given */
1488 if (symbol_conf.symfs[0] ||
1489 (dso__build_id_filename(self, name, size) == NULL)) {
1448 continue; 1490 continue;
1491 }
1449 break; 1492 break;
1450 case DSO__ORIG_FEDORA: 1493 case DSO__ORIG_FEDORA:
1451 snprintf(name, size, "/usr/lib/debug%s.debug", 1494 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1452 self->long_name); 1495 symbol_conf.symfs, self->long_name);
1453 break; 1496 break;
1454 case DSO__ORIG_UBUNTU: 1497 case DSO__ORIG_UBUNTU:
1455 snprintf(name, size, "/usr/lib/debug%s", 1498 snprintf(name, size, "%s/usr/lib/debug%s",
1456 self->long_name); 1499 symbol_conf.symfs, self->long_name);
1457 break; 1500 break;
1458 case DSO__ORIG_BUILDID: { 1501 case DSO__ORIG_BUILDID: {
1459 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1502 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
@@ -1465,19 +1508,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1465 sizeof(self->build_id), 1508 sizeof(self->build_id),
1466 build_id_hex); 1509 build_id_hex);
1467 snprintf(name, size, 1510 snprintf(name, size,
1468 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1511 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1469 build_id_hex, build_id_hex + 2); 1512 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1470 } 1513 }
1471 break; 1514 break;
1472 case DSO__ORIG_DSO: 1515 case DSO__ORIG_DSO:
1473 snprintf(name, size, "%s", self->long_name); 1516 snprintf(name, size, "%s%s",
1517 symbol_conf.symfs, self->long_name);
1474 break; 1518 break;
1475 case DSO__ORIG_GUEST_KMODULE: 1519 case DSO__ORIG_GUEST_KMODULE:
1476 if (map->groups && map->groups->machine) 1520 if (map->groups && map->groups->machine)
1477 root_dir = map->groups->machine->root_dir; 1521 root_dir = map->groups->machine->root_dir;
1478 else 1522 else
1479 root_dir = ""; 1523 root_dir = "";
1480 snprintf(name, size, "%s%s", root_dir, self->long_name); 1524 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1525 root_dir, self->long_name);
1526 break;
1527
1528 case DSO__ORIG_KMODULE:
1529 snprintf(name, size, "%s%s", symbol_conf.symfs,
1530 self->long_name);
1481 break; 1531 break;
1482 1532
1483 default: 1533 default:
@@ -1772,21 +1822,24 @@ out_failure:
1772 return -1; 1822 return -1;
1773} 1823}
1774 1824
1775static int dso__load_vmlinux(struct dso *self, struct map *map, 1825int dso__load_vmlinux(struct dso *self, struct map *map,
1776 const char *vmlinux, symbol_filter_t filter) 1826 const char *vmlinux, symbol_filter_t filter)
1777{ 1827{
1778 int err = -1, fd; 1828 int err = -1, fd;
1829 char symfs_vmlinux[PATH_MAX];
1779 1830
1780 fd = open(vmlinux, O_RDONLY); 1831 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
1832 symbol_conf.symfs, vmlinux);
1833 fd = open(symfs_vmlinux, O_RDONLY);
1781 if (fd < 0) 1834 if (fd < 0)
1782 return -1; 1835 return -1;
1783 1836
1784 dso__set_loaded(self, map->type); 1837 dso__set_loaded(self, map->type);
1785 err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); 1838 err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
1786 close(fd); 1839 close(fd);
1787 1840
1788 if (err > 0) 1841 if (err > 0)
1789 pr_debug("Using %s for symbols\n", vmlinux); 1842 pr_debug("Using %s for symbols\n", symfs_vmlinux);
1790 1843
1791 return err; 1844 return err;
1792} 1845}
@@ -1828,8 +1881,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1828 const char *kallsyms_filename = NULL; 1881 const char *kallsyms_filename = NULL;
1829 char *kallsyms_allocated_filename = NULL; 1882 char *kallsyms_allocated_filename = NULL;
1830 /* 1883 /*
1831 * Step 1: if the user specified a vmlinux filename, use it and only 1884 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1832 * it, reporting errors to the user if it cannot be used. 1885 * it and only it, reporting errors to the user if it cannot be used.
1833 * 1886 *
1834 * For instance, try to analyse an ARM perf.data file _without_ a 1887 * For instance, try to analyse an ARM perf.data file _without_ a
1835 * build-id, or if the user specifies the wrong path to the right 1888 * build-id, or if the user specifies the wrong path to the right
@@ -1842,6 +1895,11 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1842 * validation in dso__load_vmlinux and will bail out if they don't 1895 * validation in dso__load_vmlinux and will bail out if they don't
1843 * match. 1896 * match.
1844 */ 1897 */
1898 if (symbol_conf.kallsyms_name != NULL) {
1899 kallsyms_filename = symbol_conf.kallsyms_name;
1900 goto do_kallsyms;
1901 }
1902
1845 if (symbol_conf.vmlinux_name != NULL) { 1903 if (symbol_conf.vmlinux_name != NULL) {
1846 err = dso__load_vmlinux(self, map, 1904 err = dso__load_vmlinux(self, map,
1847 symbol_conf.vmlinux_name, filter); 1905 symbol_conf.vmlinux_name, filter);
@@ -1859,6 +1917,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1859 goto out_fixup; 1917 goto out_fixup;
1860 } 1918 }
1861 1919
1920 /* do not try local files if a symfs was given */
1921 if (symbol_conf.symfs[0] != 0)
1922 return -1;
1923
1862 /* 1924 /*
1863 * Say the kernel DSO was created when processing the build-id header table, 1925 * Say the kernel DSO was created when processing the build-id header table,
1864 * we have a build-id, so check if it is the same as the running kernel, 1926 * we have a build-id, so check if it is the same as the running kernel,
@@ -2123,14 +2185,55 @@ static struct dso *machine__create_kernel(struct machine *self)
2123 return kernel; 2185 return kernel;
2124} 2186}
2125 2187
2188struct process_args {
2189 u64 start;
2190};
2191
2192static int symbol__in_kernel(void *arg, const char *name,
2193 char type __used, u64 start, u64 end __used)
2194{
2195 struct process_args *args = arg;
2196
2197 if (strchr(name, '['))
2198 return 0;
2199
2200 args->start = start;
2201 return 1;
2202}
2203
2204/* Figure out the start address of kernel map from /proc/kallsyms */
2205static u64 machine__get_kernel_start_addr(struct machine *machine)
2206{
2207 const char *filename;
2208 char path[PATH_MAX];
2209 struct process_args args;
2210
2211 if (machine__is_host(machine)) {
2212 filename = "/proc/kallsyms";
2213 } else {
2214 if (machine__is_default_guest(machine))
2215 filename = (char *)symbol_conf.default_guest_kallsyms;
2216 else {
2217 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2218 filename = path;
2219 }
2220 }
2221
2222 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2223 return 0;
2224
2225 return args.start;
2226}
2227
2126int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2228int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2127{ 2229{
2128 enum map_type type; 2230 enum map_type type;
2231 u64 start = machine__get_kernel_start_addr(self);
2129 2232
2130 for (type = 0; type < MAP__NR_TYPES; ++type) { 2233 for (type = 0; type < MAP__NR_TYPES; ++type) {
2131 struct kmap *kmap; 2234 struct kmap *kmap;
2132 2235
2133 self->vmlinux_maps[type] = map__new2(0, kernel, type); 2236 self->vmlinux_maps[type] = map__new2(start, kernel, type);
2134 if (self->vmlinux_maps[type] == NULL) 2237 if (self->vmlinux_maps[type] == NULL)
2135 return -1; 2238 return -1;
2136 2239
@@ -2208,9 +2311,6 @@ static int vmlinux_path__init(void)
2208 struct utsname uts; 2311 struct utsname uts;
2209 char bf[PATH_MAX]; 2312 char bf[PATH_MAX];
2210 2313
2211 if (uname(&uts) < 0)
2212 return -1;
2213
2214 vmlinux_path = malloc(sizeof(char *) * 5); 2314 vmlinux_path = malloc(sizeof(char *) * 5);
2215 if (vmlinux_path == NULL) 2315 if (vmlinux_path == NULL)
2216 return -1; 2316 return -1;
@@ -2223,6 +2323,14 @@ static int vmlinux_path__init(void)
2223 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2323 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2224 goto out_fail; 2324 goto out_fail;
2225 ++vmlinux_path__nr_entries; 2325 ++vmlinux_path__nr_entries;
2326
2327 /* only try running kernel version if no symfs was given */
2328 if (symbol_conf.symfs[0] != 0)
2329 return 0;
2330
2331 if (uname(&uts) < 0)
2332 return -1;
2333
2226 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2334 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2227 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2335 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2228 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2336 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
@@ -2282,6 +2390,8 @@ static int setup_list(struct strlist **list, const char *list_str,
2282 2390
2283int symbol__init(void) 2391int symbol__init(void)
2284{ 2392{
2393 const char *symfs;
2394
2285 if (symbol_conf.initialized) 2395 if (symbol_conf.initialized)
2286 return 0; 2396 return 0;
2287 2397
@@ -2310,6 +2420,18 @@ int symbol__init(void)
2310 symbol_conf.sym_list_str, "symbol") < 0) 2420 symbol_conf.sym_list_str, "symbol") < 0)
2311 goto out_free_comm_list; 2421 goto out_free_comm_list;
2312 2422
2423 /*
2424 * A path to symbols of "/" is identical to ""
2425 * reset here for simplicity.
2426 */
2427 symfs = realpath(symbol_conf.symfs, NULL);
2428 if (symfs == NULL)
2429 symfs = symbol_conf.symfs;
2430 if (strcmp(symfs, "/") == 0)
2431 symbol_conf.symfs = "";
2432 if (symfs != symbol_conf.symfs)
2433 free((void *)symfs);
2434
2313 symbol_conf.initialized = true; 2435 symbol_conf.initialized = true;
2314 return 0; 2436 return 0;
2315 2437