diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 85 |
1 files changed, 82 insertions, 3 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b4fe0579bd6b..16ddca202948 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 | ||
@@ -652,10 +661,69 @@ out_close: | |||
652 | return err; | 661 | return err; |
653 | } | 662 | } |
654 | 663 | ||
664 | #define BUILD_ID_SIZE 128 | ||
665 | |||
666 | static char *dso__read_build_id(struct dso *self, int verbose) | ||
667 | { | ||
668 | int i; | ||
669 | GElf_Ehdr ehdr; | ||
670 | GElf_Shdr shdr; | ||
671 | Elf_Data *build_id_data; | ||
672 | Elf_Scn *sec; | ||
673 | char *build_id = NULL, *bid; | ||
674 | unsigned char *raw; | ||
675 | Elf *elf; | ||
676 | int fd = open(self->name, O_RDONLY); | ||
677 | |||
678 | if (fd < 0) | ||
679 | goto out; | ||
680 | |||
681 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
682 | if (elf == NULL) { | ||
683 | if (verbose) | ||
684 | fprintf(stderr, "%s: cannot read %s ELF file.\n", | ||
685 | __func__, self->name); | ||
686 | goto out_close; | ||
687 | } | ||
688 | |||
689 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
690 | if (verbose) | ||
691 | fprintf(stderr, "%s: cannot get elf header.\n", __func__); | ||
692 | goto out_elf_end; | ||
693 | } | ||
694 | |||
695 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); | ||
696 | if (sec == NULL) | ||
697 | goto out_elf_end; | ||
698 | |||
699 | build_id_data = elf_getdata(sec, NULL); | ||
700 | if (build_id_data == NULL) | ||
701 | goto out_elf_end; | ||
702 | build_id = malloc(BUILD_ID_SIZE); | ||
703 | if (build_id == NULL) | ||
704 | goto out_elf_end; | ||
705 | raw = build_id_data->d_buf + 16; | ||
706 | bid = build_id; | ||
707 | |||
708 | for (i = 0; i < 20; ++i) { | ||
709 | sprintf(bid, "%02x", *raw); | ||
710 | ++raw; | ||
711 | bid += 2; | ||
712 | } | ||
713 | if (verbose) | ||
714 | printf("%s(%s): %s\n", __func__, self->name, build_id); | ||
715 | out_elf_end: | ||
716 | elf_end(elf); | ||
717 | out_close: | ||
718 | close(fd); | ||
719 | out: | ||
720 | return build_id; | ||
721 | } | ||
722 | |||
655 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | 723 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) |
656 | { | 724 | { |
657 | int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); | 725 | int size = PATH_MAX; |
658 | char *name = malloc(size); | 726 | char *name = malloc(size), *build_id = NULL; |
659 | int variant = 0; | 727 | int variant = 0; |
660 | int ret = -1; | 728 | int ret = -1; |
661 | int fd; | 729 | int fd; |
@@ -677,7 +745,18 @@ more: | |||
677 | case 1: /* Ubuntu */ | 745 | case 1: /* Ubuntu */ |
678 | snprintf(name, size, "/usr/lib/debug%s", self->name); | 746 | snprintf(name, size, "/usr/lib/debug%s", self->name); |
679 | break; | 747 | break; |
680 | case 2: /* Sane people */ | 748 | case 2: |
749 | build_id = dso__read_build_id(self, verbose); | ||
750 | if (build_id != NULL) { | ||
751 | snprintf(name, size, | ||
752 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
753 | build_id, build_id + 2); | ||
754 | free(build_id); | ||
755 | break; | ||
756 | } | ||
757 | variant++; | ||
758 | /* Fall thru */ | ||
759 | case 3: /* Sane people */ | ||
681 | snprintf(name, size, "%s", self->name); | 760 | snprintf(name, size, "%s", self->name); |
682 | break; | 761 | break; |
683 | 762 | ||