diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 134 |
1 files changed, 124 insertions, 10 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b4fe0579bd6b..f1dcede14307 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -6,7 +6,16 @@ | |||
6 | #include <libelf.h> | 6 | #include <libelf.h> |
7 | #include <gelf.h> | 7 | #include <gelf.h> |
8 | #include <elf.h> | 8 | #include <elf.h> |
9 | |||
10 | #ifndef NO_DEMANGLE | ||
9 | #include <bfd.h> | 11 | #include <bfd.h> |
12 | #else | ||
13 | static inline | ||
14 | char *bfd_demangle(void __used *v, const char __used *c, int __used i) | ||
15 | { | ||
16 | return NULL; | ||
17 | } | ||
18 | #endif | ||
10 | 19 | ||
11 | const char *sym_hist_filter; | 20 | const char *sym_hist_filter; |
12 | 21 | ||
@@ -15,6 +24,16 @@ const char *sym_hist_filter; | |||
15 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ | 24 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ |
16 | #endif | 25 | #endif |
17 | 26 | ||
27 | enum dso_origin { | ||
28 | DSO__ORIG_KERNEL = 0, | ||
29 | DSO__ORIG_JAVA_JIT, | ||
30 | DSO__ORIG_FEDORA, | ||
31 | DSO__ORIG_UBUNTU, | ||
32 | DSO__ORIG_BUILDID, | ||
33 | DSO__ORIG_DSO, | ||
34 | DSO__ORIG_NOT_FOUND, | ||
35 | }; | ||
36 | |||
18 | static struct symbol *symbol__new(u64 start, u64 len, | 37 | static struct symbol *symbol__new(u64 start, u64 len, |
19 | const char *name, unsigned int priv_size, | 38 | const char *name, unsigned int priv_size, |
20 | u64 obj_start, int verbose) | 39 | u64 obj_start, int verbose) |
@@ -72,6 +91,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) | |||
72 | self->sym_priv_size = sym_priv_size; | 91 | self->sym_priv_size = sym_priv_size; |
73 | self->find_symbol = dso__find_symbol; | 92 | self->find_symbol = dso__find_symbol; |
74 | self->slen_calculated = 0; | 93 | self->slen_calculated = 0; |
94 | self->origin = DSO__ORIG_NOT_FOUND; | ||
75 | } | 95 | } |
76 | 96 | ||
77 | return self; | 97 | return self; |
@@ -652,11 +672,85 @@ out_close: | |||
652 | return err; | 672 | return err; |
653 | } | 673 | } |
654 | 674 | ||
675 | #define BUILD_ID_SIZE 128 | ||
676 | |||
677 | static char *dso__read_build_id(struct dso *self, int verbose) | ||
678 | { | ||
679 | int i; | ||
680 | GElf_Ehdr ehdr; | ||
681 | GElf_Shdr shdr; | ||
682 | Elf_Data *build_id_data; | ||
683 | Elf_Scn *sec; | ||
684 | char *build_id = NULL, *bid; | ||
685 | unsigned char *raw; | ||
686 | Elf *elf; | ||
687 | int fd = open(self->name, O_RDONLY); | ||
688 | |||
689 | if (fd < 0) | ||
690 | goto out; | ||
691 | |||
692 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
693 | if (elf == NULL) { | ||
694 | if (verbose) | ||
695 | fprintf(stderr, "%s: cannot read %s ELF file.\n", | ||
696 | __func__, self->name); | ||
697 | goto out_close; | ||
698 | } | ||
699 | |||
700 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
701 | if (verbose) | ||
702 | fprintf(stderr, "%s: cannot get elf header.\n", __func__); | ||
703 | goto out_elf_end; | ||
704 | } | ||
705 | |||
706 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); | ||
707 | if (sec == NULL) | ||
708 | goto out_elf_end; | ||
709 | |||
710 | build_id_data = elf_getdata(sec, NULL); | ||
711 | if (build_id_data == NULL) | ||
712 | goto out_elf_end; | ||
713 | build_id = malloc(BUILD_ID_SIZE); | ||
714 | if (build_id == NULL) | ||
715 | goto out_elf_end; | ||
716 | raw = build_id_data->d_buf + 16; | ||
717 | bid = build_id; | ||
718 | |||
719 | for (i = 0; i < 20; ++i) { | ||
720 | sprintf(bid, "%02x", *raw); | ||
721 | ++raw; | ||
722 | bid += 2; | ||
723 | } | ||
724 | if (verbose >= 2) | ||
725 | printf("%s(%s): %s\n", __func__, self->name, build_id); | ||
726 | out_elf_end: | ||
727 | elf_end(elf); | ||
728 | out_close: | ||
729 | close(fd); | ||
730 | out: | ||
731 | return build_id; | ||
732 | } | ||
733 | |||
734 | char dso__symtab_origin(const struct dso *self) | ||
735 | { | ||
736 | static const char origin[] = { | ||
737 | [DSO__ORIG_KERNEL] = 'k', | ||
738 | [DSO__ORIG_JAVA_JIT] = 'j', | ||
739 | [DSO__ORIG_FEDORA] = 'f', | ||
740 | [DSO__ORIG_UBUNTU] = 'u', | ||
741 | [DSO__ORIG_BUILDID] = 'b', | ||
742 | [DSO__ORIG_DSO] = 'd', | ||
743 | }; | ||
744 | |||
745 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) | ||
746 | return '!'; | ||
747 | return origin[self->origin]; | ||
748 | } | ||
749 | |||
655 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | 750 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) |
656 | { | 751 | { |
657 | int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); | 752 | int size = PATH_MAX; |
658 | char *name = malloc(size); | 753 | char *name = malloc(size), *build_id = NULL; |
659 | int variant = 0; | ||
660 | int ret = -1; | 754 | int ret = -1; |
661 | int fd; | 755 | int fd; |
662 | 756 | ||
@@ -665,26 +759,43 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | |||
665 | 759 | ||
666 | self->adjust_symbols = 0; | 760 | self->adjust_symbols = 0; |
667 | 761 | ||
668 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) | 762 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) { |
669 | return dso__load_perf_map(self, filter, verbose); | 763 | ret = dso__load_perf_map(self, filter, verbose); |
764 | self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : | ||
765 | DSO__ORIG_NOT_FOUND; | ||
766 | return ret; | ||
767 | } | ||
768 | |||
769 | self->origin = DSO__ORIG_FEDORA - 1; | ||
670 | 770 | ||
671 | more: | 771 | more: |
672 | do { | 772 | do { |
673 | switch (variant) { | 773 | self->origin++; |
674 | case 0: /* Fedora */ | 774 | switch (self->origin) { |
775 | case DSO__ORIG_FEDORA: | ||
675 | snprintf(name, size, "/usr/lib/debug%s.debug", self->name); | 776 | snprintf(name, size, "/usr/lib/debug%s.debug", self->name); |
676 | break; | 777 | break; |
677 | case 1: /* Ubuntu */ | 778 | case DSO__ORIG_UBUNTU: |
678 | snprintf(name, size, "/usr/lib/debug%s", self->name); | 779 | snprintf(name, size, "/usr/lib/debug%s", self->name); |
679 | break; | 780 | break; |
680 | case 2: /* Sane people */ | 781 | case DSO__ORIG_BUILDID: |
782 | build_id = dso__read_build_id(self, verbose); | ||
783 | if (build_id != NULL) { | ||
784 | snprintf(name, size, | ||
785 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
786 | build_id, build_id + 2); | ||
787 | free(build_id); | ||
788 | break; | ||
789 | } | ||
790 | self->origin++; | ||
791 | /* Fall thru */ | ||
792 | case DSO__ORIG_DSO: | ||
681 | snprintf(name, size, "%s", self->name); | 793 | snprintf(name, size, "%s", self->name); |
682 | break; | 794 | break; |
683 | 795 | ||
684 | default: | 796 | default: |
685 | goto out; | 797 | goto out; |
686 | } | 798 | } |
687 | variant++; | ||
688 | 799 | ||
689 | fd = open(name, O_RDONLY); | 800 | fd = open(name, O_RDONLY); |
690 | } while (fd < 0); | 801 | } while (fd < 0); |
@@ -820,6 +931,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, | |||
820 | if (err <= 0) | 931 | if (err <= 0) |
821 | err = dso__load_kallsyms(self, filter, verbose); | 932 | err = dso__load_kallsyms(self, filter, verbose); |
822 | 933 | ||
934 | if (err > 0) | ||
935 | self->origin = DSO__ORIG_KERNEL; | ||
936 | |||
823 | return err; | 937 | return err; |
824 | } | 938 | } |
825 | 939 | ||