aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol-elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/symbol-elf.c')
-rw-r--r--tools/perf/util/symbol-elf.c190
1 files changed, 181 insertions, 9 deletions
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 4b12bf850325..a9c829be5216 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -8,6 +8,22 @@
8#include "symbol.h" 8#include "symbol.h"
9#include "debug.h" 9#include "debug.h"
10 10
11#ifndef HAVE_ELF_GETPHDRNUM
12static int elf_getphdrnum(Elf *elf, size_t *dst)
13{
14 GElf_Ehdr gehdr;
15 GElf_Ehdr *ehdr;
16
17 ehdr = gelf_getehdr(elf, &gehdr);
18 if (!ehdr)
19 return -1;
20
21 *dst = ehdr->e_phnum;
22
23 return 0;
24}
25#endif
26
11#ifndef NT_GNU_BUILD_ID 27#ifndef NT_GNU_BUILD_ID
12#define NT_GNU_BUILD_ID 3 28#define NT_GNU_BUILD_ID 3
13#endif 29#endif
@@ -599,11 +615,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
599 if (dso->kernel == DSO_TYPE_USER) { 615 if (dso->kernel == DSO_TYPE_USER) {
600 GElf_Shdr shdr; 616 GElf_Shdr shdr;
601 ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 617 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
618 ehdr.e_type == ET_REL ||
602 elf_section_by_name(elf, &ehdr, &shdr, 619 elf_section_by_name(elf, &ehdr, &shdr,
603 ".gnu.prelink_undo", 620 ".gnu.prelink_undo",
604 NULL) != NULL); 621 NULL) != NULL);
605 } else { 622 } else {
606 ss->adjust_symbols = 0; 623 ss->adjust_symbols = ehdr.e_type == ET_EXEC ||
624 ehdr.e_type == ET_REL;
607 } 625 }
608 626
609 ss->name = strdup(name); 627 ss->name = strdup(name);
@@ -624,6 +642,37 @@ out_close:
624 return err; 642 return err;
625} 643}
626 644
645/**
646 * ref_reloc_sym_not_found - has kernel relocation symbol been found.
647 * @kmap: kernel maps and relocation reference symbol
648 *
649 * This function returns %true if we are dealing with the kernel maps and the
650 * relocation reference symbol has not yet been found. Otherwise %false is
651 * returned.
652 */
653static bool ref_reloc_sym_not_found(struct kmap *kmap)
654{
655 return kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
656 !kmap->ref_reloc_sym->unrelocated_addr;
657}
658
659/**
660 * ref_reloc - kernel relocation offset.
661 * @kmap: kernel maps and relocation reference symbol
662 *
663 * This function returns the offset of kernel addresses as determined by using
664 * the relocation reference symbol i.e. if the kernel has not been relocated
665 * then the return value is zero.
666 */
667static u64 ref_reloc(struct kmap *kmap)
668{
669 if (kmap && kmap->ref_reloc_sym &&
670 kmap->ref_reloc_sym->unrelocated_addr)
671 return kmap->ref_reloc_sym->addr -
672 kmap->ref_reloc_sym->unrelocated_addr;
673 return 0;
674}
675
627int dso__load_sym(struct dso *dso, struct map *map, 676int dso__load_sym(struct dso *dso, struct map *map,
628 struct symsrc *syms_ss, struct symsrc *runtime_ss, 677 struct symsrc *syms_ss, struct symsrc *runtime_ss,
629 symbol_filter_t filter, int kmodule) 678 symbol_filter_t filter, int kmodule)
@@ -642,8 +691,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
642 Elf_Scn *sec, *sec_strndx; 691 Elf_Scn *sec, *sec_strndx;
643 Elf *elf; 692 Elf *elf;
644 int nr = 0; 693 int nr = 0;
694 bool remap_kernel = false, adjust_kernel_syms = false;
645 695
646 dso->symtab_type = syms_ss->type; 696 dso->symtab_type = syms_ss->type;
697 dso->rel = syms_ss->ehdr.e_type == ET_REL;
698
699 /*
700 * Modules may already have symbols from kallsyms, but those symbols
701 * have the wrong values for the dso maps, so remove them.
702 */
703 if (kmodule && syms_ss->symtab)
704 symbols__delete(&dso->symbols[map->type]);
647 705
648 if (!syms_ss->symtab) { 706 if (!syms_ss->symtab) {
649 syms_ss->symtab = syms_ss->dynsym; 707 syms_ss->symtab = syms_ss->dynsym;
@@ -681,7 +739,31 @@ int dso__load_sym(struct dso *dso, struct map *map,
681 nr_syms = shdr.sh_size / shdr.sh_entsize; 739 nr_syms = shdr.sh_size / shdr.sh_entsize;
682 740
683 memset(&sym, 0, sizeof(sym)); 741 memset(&sym, 0, sizeof(sym));
684 dso->adjust_symbols = runtime_ss->adjust_symbols; 742
743 /*
744 * The kernel relocation symbol is needed in advance in order to adjust
745 * kernel maps correctly.
746 */
747 if (ref_reloc_sym_not_found(kmap)) {
748 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
749 const char *elf_name = elf_sym__name(&sym, symstrs);
750
751 if (strcmp(elf_name, kmap->ref_reloc_sym->name))
752 continue;
753 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
754 break;
755 }
756 }
757
758 dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap);
759 /*
760 * Initial kernel and module mappings do not map to the dso. For
761 * function mappings, flag the fixups.
762 */
763 if (map->type == MAP__FUNCTION && (dso->kernel || kmodule)) {
764 remap_kernel = true;
765 adjust_kernel_syms = dso->adjust_symbols;
766 }
685 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 767 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
686 struct symbol *f; 768 struct symbol *f;
687 const char *elf_name = elf_sym__name(&sym, symstrs); 769 const char *elf_name = elf_sym__name(&sym, symstrs);
@@ -690,10 +772,6 @@ int dso__load_sym(struct dso *dso, struct map *map,
690 const char *section_name; 772 const char *section_name;
691 bool used_opd = false; 773 bool used_opd = false;
692 774
693 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
694 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
695 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
696
697 if (!is_label && !elf_sym__is_a(&sym, map->type)) 775 if (!is_label && !elf_sym__is_a(&sym, map->type))
698 continue; 776 continue;
699 777
@@ -745,20 +823,55 @@ int dso__load_sym(struct dso *dso, struct map *map,
745 (sym.st_value & 1)) 823 (sym.st_value & 1))
746 --sym.st_value; 824 --sym.st_value;
747 825
748 if (dso->kernel != DSO_TYPE_USER || kmodule) { 826 if (dso->kernel || kmodule) {
749 char dso_name[PATH_MAX]; 827 char dso_name[PATH_MAX];
750 828
829 /* Adjust symbol to map to file offset */
830 if (adjust_kernel_syms)
831 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
832
751 if (strcmp(section_name, 833 if (strcmp(section_name,
752 (curr_dso->short_name + 834 (curr_dso->short_name +
753 dso->short_name_len)) == 0) 835 dso->short_name_len)) == 0)
754 goto new_symbol; 836 goto new_symbol;
755 837
756 if (strcmp(section_name, ".text") == 0) { 838 if (strcmp(section_name, ".text") == 0) {
839 /*
840 * The initial kernel mapping is based on
841 * kallsyms and identity maps. Overwrite it to
842 * map to the kernel dso.
843 */
844 if (remap_kernel && dso->kernel) {
845 remap_kernel = false;
846 map->start = shdr.sh_addr +
847 ref_reloc(kmap);
848 map->end = map->start + shdr.sh_size;
849 map->pgoff = shdr.sh_offset;
850 map->map_ip = map__map_ip;
851 map->unmap_ip = map__unmap_ip;
852 /* Ensure maps are correctly ordered */
853 map_groups__remove(kmap->kmaps, map);
854 map_groups__insert(kmap->kmaps, map);
855 }
856
857 /*
858 * The initial module mapping is based on
859 * /proc/modules mapped to offset zero.
860 * Overwrite it to map to the module dso.
861 */
862 if (remap_kernel && kmodule) {
863 remap_kernel = false;
864 map->pgoff = shdr.sh_offset;
865 }
866
757 curr_map = map; 867 curr_map = map;
758 curr_dso = dso; 868 curr_dso = dso;
759 goto new_symbol; 869 goto new_symbol;
760 } 870 }
761 871
872 if (!kmap)
873 goto new_symbol;
874
762 snprintf(dso_name, sizeof(dso_name), 875 snprintf(dso_name, sizeof(dso_name),
763 "%s%s", dso->short_name, section_name); 876 "%s%s", dso->short_name, section_name);
764 877
@@ -781,8 +894,16 @@ int dso__load_sym(struct dso *dso, struct map *map,
781 dso__delete(curr_dso); 894 dso__delete(curr_dso);
782 goto out_elf_end; 895 goto out_elf_end;
783 } 896 }
784 curr_map->map_ip = identity__map_ip; 897 if (adjust_kernel_syms) {
785 curr_map->unmap_ip = identity__map_ip; 898 curr_map->start = shdr.sh_addr +
899 ref_reloc(kmap);
900 curr_map->end = curr_map->start +
901 shdr.sh_size;
902 curr_map->pgoff = shdr.sh_offset;
903 } else {
904 curr_map->map_ip = identity__map_ip;
905 curr_map->unmap_ip = identity__map_ip;
906 }
786 curr_dso->symtab_type = dso->symtab_type; 907 curr_dso->symtab_type = dso->symtab_type;
787 map_groups__insert(kmap->kmaps, curr_map); 908 map_groups__insert(kmap->kmaps, curr_map);
788 dsos__add(&dso->node, curr_dso); 909 dsos__add(&dso->node, curr_dso);
@@ -846,6 +967,57 @@ out_elf_end:
846 return err; 967 return err;
847} 968}
848 969
970static int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data)
971{
972 GElf_Phdr phdr;
973 size_t i, phdrnum;
974 int err;
975 u64 sz;
976
977 if (elf_getphdrnum(elf, &phdrnum))
978 return -1;
979
980 for (i = 0; i < phdrnum; i++) {
981 if (gelf_getphdr(elf, i, &phdr) == NULL)
982 return -1;
983 if (phdr.p_type != PT_LOAD)
984 continue;
985 if (exe) {
986 if (!(phdr.p_flags & PF_X))
987 continue;
988 } else {
989 if (!(phdr.p_flags & PF_R))
990 continue;
991 }
992 sz = min(phdr.p_memsz, phdr.p_filesz);
993 if (!sz)
994 continue;
995 err = mapfn(phdr.p_vaddr, sz, phdr.p_offset, data);
996 if (err)
997 return err;
998 }
999 return 0;
1000}
1001
1002int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1003 bool *is_64_bit)
1004{
1005 int err;
1006 Elf *elf;
1007
1008 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1009 if (elf == NULL)
1010 return -1;
1011
1012 if (is_64_bit)
1013 *is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
1014
1015 err = elf_read_maps(elf, exe, mapfn, data);
1016
1017 elf_end(elf);
1018 return err;
1019}
1020
849void symbol__elf_init(void) 1021void symbol__elf_init(void)
850{ 1022{
851 elf_version(EV_CURRENT); 1023 elf_version(EV_CURRENT);