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.c134
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
13static inline
14char *bfd_demangle(void __used *v, const char __used *c, int __used i)
15{
16 return NULL;
17}
18#endif
10 19
11const char *sym_hist_filter; 20const 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
27enum 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
18static struct symbol *symbol__new(u64 start, u64 len, 37static 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
677static 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);
726out_elf_end:
727 elf_end(elf);
728out_close:
729 close(fd);
730out:
731 return build_id;
732}
733
734char 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
655int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 750int 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
671more: 771more:
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