diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-12-11 11:50:39 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-12 01:42:10 -0500 |
commit | f1dfa0b1c1a90d4d3bf515ab04a6b6222e086293 (patch) | |
tree | a601efb5a2e27dc2e0ec261469076f4842173aa0 /tools/perf/util | |
parent | d45868d38c1d08d50abf3e884710a938d19fa93c (diff) |
perf symbols: Add support for 'variable' symtabs
Example:
{
u64 addr = strtoull(sym_filter, NULL, 16);
struct map *map = map_groups__find(kmaps, MAP__VARIABLE, addr);
if (map == NULL)
pr_err("couldn't find map!\n");
else {
struct symbol *sym = map__find_symbol(map, addr, NULL);
if (sym == NULL)
pr_err("couldn't find addr!\n");
else
pr_info("addr %#Lx is in %s global var\n", addr, sym->name);
}
exit(0);
}
Added just after symbol__init() call in 'perf top', then:
{
u64 addr = strtoull(sym_filter, NULL, 16);
struct map *map = map_groups__find(kmaps, MAP__VARIABLE, addr);
if (map == NULL)
pr_err("couldn't find map!\n");
else {
struct symbol *sym = map__find_symbol(map, addr, NULL);
if (sym == NULL)
pr_err("couldn't find addr!\n");
else
pr_info("addr %#Lx is in %s global var\n", addr, sym->name);
}
exit(0);
}
[root@doppio linux-2.6-tip]# grep ' [dD] ' /proc/kallsyms | grep ' sched'
ffffffff817827d8 d sched_nr_latency
ffffffff81782ce0 d sched_domains_mutex
ffffffff8178c070 d schedstr.22423
ffffffff817909a0 d sched_register_mutex
ffffffff81823490 d sched_feat_names
ffffffff81823558 d scheduler_running
ffffffff818235b8 d sched_clock_running
ffffffff818235bc D sched_clock_stable
ffffffff81824f00 d sched_switch_trace
[root@doppio linux-2.6-tip]# perf top -s 0xffffffff817827d9
addr 0xffffffff817827d9 is in sched_nr_latency global var
[root@doppio linux-2.6-tip]# perf top -s ffffffff81782ce0
addr 0xffffffff81782ce0 is in sched_domains_mutex global var
[root@doppio linux-2.6-tip]#
[root@doppio linux-2.6-tip]# perf top -s ffffffff81782ce0 --vmlinux OFF
The file OFF cannot be used, trying to use /proc/kallsyms...addr 0xffffffff81782ce0 is in sched_domains_mutex global var
[root@doppio linux-2.6-tip]# perf top -s ffffffff818235bc --vmlinux OFF
The file OFF cannot be used, trying to use /proc/kallsyms...addr 0xffffffff818235bc is in sched_clock_stable global var
[root@doppio linux-2.6-tip]#
So it works with both /proc/kallsyms and with ELF symtabs, either
the one on the vmlinux explicitely passed via --vmlinux or in one
in the vmlinux_path that matches the buildid for the running kernel
or the one found in the buildid header section in a perf.data file.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260550239-5372-4-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/event.h | 3 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 66 |
2 files changed, 53 insertions, 16 deletions
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index d9a65d91e925..56640946b5a9 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -103,9 +103,10 @@ void event__print_totals(void); | |||
103 | 103 | ||
104 | enum map_type { | 104 | enum map_type { |
105 | MAP__FUNCTION = 0, | 105 | MAP__FUNCTION = 0, |
106 | MAP__VARIABLE, | ||
106 | }; | 107 | }; |
107 | 108 | ||
108 | #define MAP__NR_TYPES (MAP__FUNCTION + 1) | 109 | #define MAP__NR_TYPES (MAP__VARIABLE + 1) |
109 | 110 | ||
110 | struct map { | 111 | struct map { |
111 | union { | 112 | union { |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index db8dc97b548b..e63ddb469de7 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -61,6 +61,8 @@ static bool symbol_type__is_a(char symbol_type, enum map_type map_type) | |||
61 | switch (map_type) { | 61 | switch (map_type) { |
62 | case MAP__FUNCTION: | 62 | case MAP__FUNCTION: |
63 | return symbol_type == 'T' || symbol_type == 'W'; | 63 | return symbol_type == 'T' || symbol_type == 'W'; |
64 | case MAP__VARIABLE: | ||
65 | return symbol_type == 'D' || symbol_type == 'd'; | ||
64 | default: | 66 | default: |
65 | return false; | 67 | return false; |
66 | } | 68 | } |
@@ -551,6 +553,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym) | |||
551 | sym->st_shndx != SHN_UNDEF; | 553 | sym->st_shndx != SHN_UNDEF; |
552 | } | 554 | } |
553 | 555 | ||
556 | static inline bool elf_sym__is_object(const GElf_Sym *sym) | ||
557 | { | ||
558 | return elf_sym__type(sym) == STT_OBJECT && | ||
559 | sym->st_name != 0 && | ||
560 | sym->st_shndx != SHN_UNDEF; | ||
561 | } | ||
562 | |||
554 | static inline int elf_sym__is_label(const GElf_Sym *sym) | 563 | static inline int elf_sym__is_label(const GElf_Sym *sym) |
555 | { | 564 | { |
556 | return elf_sym__type(sym) == STT_NOTYPE && | 565 | return elf_sym__type(sym) == STT_NOTYPE && |
@@ -571,6 +580,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr, | |||
571 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; | 580 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; |
572 | } | 581 | } |
573 | 582 | ||
583 | static inline bool elf_sec__is_data(const GElf_Shdr *shdr, | ||
584 | const Elf_Data *secstrs) | ||
585 | { | ||
586 | return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; | ||
587 | } | ||
588 | |||
574 | static inline const char *elf_sym__name(const GElf_Sym *sym, | 589 | static inline const char *elf_sym__name(const GElf_Sym *sym, |
575 | const Elf_Data *symstrs) | 590 | const Elf_Data *symstrs) |
576 | { | 591 | { |
@@ -756,6 +771,8 @@ static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) | |||
756 | switch (type) { | 771 | switch (type) { |
757 | case MAP__FUNCTION: | 772 | case MAP__FUNCTION: |
758 | return elf_sym__is_function(self); | 773 | return elf_sym__is_function(self); |
774 | case MAP__VARIABLE: | ||
775 | return elf_sym__is_object(self); | ||
759 | default: | 776 | default: |
760 | return false; | 777 | return false; |
761 | } | 778 | } |
@@ -766,6 +783,8 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type | |||
766 | switch (type) { | 783 | switch (type) { |
767 | case MAP__FUNCTION: | 784 | case MAP__FUNCTION: |
768 | return elf_sec__is_text(self, secstrs); | 785 | return elf_sec__is_text(self, secstrs); |
786 | case MAP__VARIABLE: | ||
787 | return elf_sec__is_data(self, secstrs); | ||
769 | default: | 788 | default: |
770 | return false; | 789 | return false; |
771 | } | 790 | } |
@@ -1536,42 +1555,59 @@ size_t dsos__fprintf_buildid(FILE *fp) | |||
1536 | __dsos__fprintf_buildid(&dsos__user, fp)); | 1555 | __dsos__fprintf_buildid(&dsos__user, fp)); |
1537 | } | 1556 | } |
1538 | 1557 | ||
1539 | static int map_groups__create_kernel_map(struct map_groups *self, const char *vmlinux) | 1558 | static struct dso *dsos__create_kernel( const char *vmlinux) |
1540 | { | 1559 | { |
1541 | struct map *kmap; | ||
1542 | struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); | 1560 | struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); |
1543 | 1561 | ||
1544 | if (kernel == NULL) | 1562 | if (kernel == NULL) |
1545 | return -1; | 1563 | return NULL; |
1546 | |||
1547 | kmap = map__new2(0, kernel, MAP__FUNCTION); | ||
1548 | if (kmap == NULL) | ||
1549 | goto out_delete_kernel_dso; | ||
1550 | 1564 | ||
1551 | kmap->map_ip = kmap->unmap_ip = identity__map_ip; | ||
1552 | kernel->short_name = "[kernel]"; | 1565 | kernel->short_name = "[kernel]"; |
1553 | kernel->kernel = 1; | 1566 | kernel->kernel = 1; |
1554 | 1567 | ||
1555 | vdso = dso__new("[vdso]"); | 1568 | vdso = dso__new("[vdso]"); |
1556 | if (vdso == NULL) | 1569 | if (vdso == NULL) |
1557 | goto out_delete_kernel_map; | 1570 | goto out_delete_kernel_dso; |
1558 | dso__set_loaded(vdso, MAP__FUNCTION); | 1571 | dso__set_loaded(vdso, MAP__FUNCTION); |
1559 | 1572 | ||
1560 | if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, | 1573 | if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, |
1561 | sizeof(kernel->build_id)) == 0) | 1574 | sizeof(kernel->build_id)) == 0) |
1562 | kernel->has_build_id = true; | 1575 | kernel->has_build_id = true; |
1563 | 1576 | ||
1564 | map_groups__insert(self, kmap); | ||
1565 | dsos__add(&dsos__kernel, kernel); | 1577 | dsos__add(&dsos__kernel, kernel); |
1566 | dsos__add(&dsos__user, vdso); | 1578 | dsos__add(&dsos__user, vdso); |
1567 | 1579 | ||
1568 | return 0; | 1580 | return kernel; |
1569 | 1581 | ||
1570 | out_delete_kernel_map: | ||
1571 | map__delete(kmap); | ||
1572 | out_delete_kernel_dso: | 1582 | out_delete_kernel_dso: |
1573 | dso__delete(kernel); | 1583 | dso__delete(kernel); |
1574 | return -1; | 1584 | return NULL; |
1585 | } | ||
1586 | |||
1587 | static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) | ||
1588 | { | ||
1589 | struct map *functions, *variables; | ||
1590 | struct dso *kernel = dsos__create_kernel(vmlinux); | ||
1591 | |||
1592 | if (kernel == NULL) | ||
1593 | return -1; | ||
1594 | |||
1595 | functions = map__new2(0, kernel, MAP__FUNCTION); | ||
1596 | if (functions == NULL) | ||
1597 | return -1; | ||
1598 | |||
1599 | variables = map__new2(0, kernel, MAP__VARIABLE); | ||
1600 | if (variables == NULL) { | ||
1601 | map__delete(functions); | ||
1602 | return -1; | ||
1603 | } | ||
1604 | |||
1605 | functions->map_ip = functions->unmap_ip = | ||
1606 | variables->map_ip = variables->unmap_ip = identity__map_ip; | ||
1607 | map_groups__insert(self, functions); | ||
1608 | map_groups__insert(self, variables); | ||
1609 | |||
1610 | return 0; | ||
1575 | } | 1611 | } |
1576 | 1612 | ||
1577 | static void vmlinux_path__exit(void) | 1613 | static void vmlinux_path__exit(void) |
@@ -1640,7 +1676,7 @@ int symbol__init(struct symbol_conf *conf) | |||
1640 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) | 1676 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) |
1641 | return -1; | 1677 | return -1; |
1642 | 1678 | ||
1643 | if (map_groups__create_kernel_map(kmaps, pconf->vmlinux_name) < 0) { | 1679 | if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { |
1644 | vmlinux_path__exit(); | 1680 | vmlinux_path__exit(); |
1645 | return -1; | 1681 | return -1; |
1646 | } | 1682 | } |