diff options
author | Cody P Schafer <cody@linux.vnet.ibm.com> | 2012-08-10 15:22:57 -0700 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-08-13 14:31:44 -0300 |
commit | b68e2f919c6d3a0422239c98673c35ff503e52fb (patch) | |
tree | e960118f1892c52efe58ebdb8c605cefe81706d7 /tools/perf/util/symbol-elf.c | |
parent | 21ea4539b4d1b26de7f2eb227b5d1a092b32cc19 (diff) | |
download | op-kernel-dev-b68e2f919c6d3a0422239c98673c35ff503e52fb.zip op-kernel-dev-b68e2f919c6d3a0422239c98673c35ff503e52fb.tar.gz |
perf symbols: Introduce symsrc structure.
Factors opening of certain sections & tracking certain elf info into an
external structure.
The goal here is to keep multiple elfs (and their looked up
sections/indexes) around during the symbol generation process (in
dso__load()).
We need this to properly resolve symbols on PPC due to the use of
function descriptors & the .opd section (ie: symbols which are functions
don't point to their actual location, they point to their function
descriptor in .opd which contains their actual location.
It would be possible to just keep the (Elf *) around, but then we'd end
up with duplicate code for looking up the same sections and checking for
the existence of an important section wouldn't be as clean (and we need
to keep the Elf stuff confined to symtab-elf.c).
Utilized by the later patch
"perf symbols: Use both runtime and debug images"
Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com>
Cc: David Hansen <dave@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Matt Hellsley <matthltc@us.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1344637382-22789-12-git-send-email-cody@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/symbol-elf.c')
-rw-r--r-- | tools/perf/util/symbol-elf.c | 119 |
1 files changed, 90 insertions, 29 deletions
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index a9a194d..6974b2a 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -536,24 +536,25 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata) return 0; } -int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, - symbol_filter_t filter, int kmodule, int want_symtab) + +void symsrc__destroy(struct symsrc *ss) +{ + free(ss->name); + elf_end(ss->elf); + close(ss->fd); +} + +int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, + enum dso_binary_type type) { - struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; - struct map *curr_map = map; - struct dso *curr_dso = dso; - Elf_Data *symstrs, *secstrs; - uint32_t nr_syms; int err = -1; - uint32_t idx; GElf_Ehdr ehdr; - GElf_Shdr shdr, opdshdr; - Elf_Data *syms, *opddata = NULL; - GElf_Sym sym; - Elf_Scn *sec, *sec_strndx, *opdsec; Elf *elf; - int nr = 0; - size_t opdidx = 0; + int fd; + + fd = open(name, O_RDONLY); + if (fd < 0) + return -1; elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); if (elf == NULL) { @@ -580,19 +581,88 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, goto out_elf_end; } - sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); + ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", + NULL); + if (ss->symshdr.sh_type != SHT_SYMTAB) + ss->symtab = NULL; + + ss->dynsym_idx = 0; + ss->dynsym = elf_section_by_name(elf, &ehdr, &ss->dynshdr, ".dynsym", + &ss->dynsym_idx); + if (ss->dynshdr.sh_type != SHT_DYNSYM) + ss->dynsym = NULL; + + ss->opdidx = 0; + ss->opdsec = elf_section_by_name(elf, &ehdr, &ss->opdshdr, ".opd", + &ss->opdidx); + if (ss->opdshdr.sh_type != SHT_PROGBITS) + ss->opdsec = NULL; + + if (dso->kernel == DSO_TYPE_USER) { + GElf_Shdr shdr; + ss->adjust_symbols = (ehdr.e_type == ET_EXEC || + elf_section_by_name(elf, &ehdr, &shdr, + ".gnu.prelink_undo", + NULL) != NULL); + } else { + ss->adjust_symbols = 0; + } + + ss->name = strdup(name); + if (!ss->name) + goto out_elf_end; + + ss->elf = elf; + ss->fd = fd; + ss->ehdr = ehdr; + ss->type = type; + + return 0; + +out_elf_end: + elf_end(elf); +out_close: + close(fd); + return err; +} + +int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *ss, + symbol_filter_t filter, int kmodule, int want_symtab) +{ + struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; + struct map *curr_map = map; + struct dso *curr_dso = dso; + Elf_Data *symstrs, *secstrs; + uint32_t nr_syms; + int err = -1; + uint32_t idx; + GElf_Ehdr ehdr; + GElf_Shdr shdr, opdshdr; + Elf_Data *syms, *opddata = NULL; + GElf_Sym sym; + Elf_Scn *sec, *sec_strndx, *opdsec; + Elf *elf; + int nr = 0; + size_t opdidx = 0; + + elf = ss->elf; + ehdr = ss->ehdr; + sec = ss->symtab; + shdr = ss->symshdr; + if (sec == NULL) { if (want_symtab) goto out_elf_end; - sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); + sec = ss->dynsym; + shdr = ss->dynshdr; if (sec == NULL) goto out_elf_end; } - opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); - if (opdshdr.sh_type != SHT_PROGBITS) - opdsec = NULL; + opdsec = ss->opdsec; + opdshdr = ss->opdshdr; + opdidx = ss->opdidx; if (opdsec) opddata = elf_rawdata(opdsec, NULL); @@ -619,14 +689,7 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, nr_syms = shdr.sh_size / shdr.sh_entsize; memset(&sym, 0, sizeof(sym)); - if (dso->kernel == DSO_TYPE_USER) { - dso->adjust_symbols = (ehdr.e_type == ET_EXEC || - elf_section_by_name(elf, &ehdr, &shdr, - ".gnu.prelink_undo", - NULL) != NULL); - } else { - dso->adjust_symbols = 0; - } + dso->adjust_symbols = ss->adjust_symbols; elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { struct symbol *f; const char *elf_name = elf_sym__name(&sym, symstrs); @@ -770,8 +833,6 @@ new_symbol: } err = nr; out_elf_end: - elf_end(elf); -out_close: return err; } |