diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index a9a194d49c1b5f7b9b89752bda997c9c36ae72f2..6974b2a44ee7bad3d488983a935d248ee122da86 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 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, } err = nr; out_elf_end: - elf_end(elf); -out_close: return err; } diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index bd8720b6780c4f3aae68fc2d1ead38c71addfd19..1b16c2729a3629f8972ba61d5a8522641173188e 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -241,6 +241,31 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) return ret; } +int symsrc__init(struct symsrc *ss, struct dso *dso __used, const char *name, + enum dso_binary_type type) +{ + int fd = open(name, O_RDONLY); + if (fd < 0) + return -1; + + ss->name = strdup(name); + if (!ss->name) + goto out_close; + + ss->type = type; + + return 0; +out_close: + close(fd); + return -1; +} + +void symsrc__destroy(struct symsrc *ss) +{ + free(ss->name); + close(ss->fd); +} + int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used, struct map *map __used, symbol_filter_t filter __used) @@ -248,14 +273,13 @@ int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used, return 0; } -int dso__load_sym(struct dso *dso, struct map *map __used, - const char *name, int fd __used, +int dso__load_sym(struct dso *dso, struct map *map __used, struct symsrc *ss, symbol_filter_t filter __used, int kmodule __used, int want_symtab __used) { unsigned char *build_id[BUILD_ID_SIZE]; - if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) { + if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { dso__set_build_id(dso, build_id); return 1; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8f5cabbfc8bdcaec05f005fa0d282b0aae61e45e..afec3f048a940c54f202e5631ecf241da7e603f6 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1026,7 +1026,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) { char *name; int ret = -1; - int fd; + struct symsrc ss; u_int i; struct machine *machine; char *root_dir = (char *) ""; @@ -1086,13 +1086,12 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) continue; /* Name is now the name of the next image to try */ - fd = open(name, O_RDONLY); - if (fd < 0) + if (symsrc__init(&ss, dso, name, dso->symtab_type) < 0) continue; - ret = dso__load_sym(dso, map, name, fd, filter, 0, + ret = dso__load_sym(dso, map, &ss, filter, 0, want_symtab); - close(fd); + symsrc__destroy(&ss); /* * Some people seem to have debuginfo files _WITHOUT_ debug @@ -1359,22 +1358,23 @@ static int machine__create_modules(struct machine *machine) int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, symbol_filter_t filter) { - int err = -1, fd; + int err = -1; + struct symsrc ss; char symfs_vmlinux[PATH_MAX]; snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", symbol_conf.symfs, vmlinux); - fd = open(symfs_vmlinux, O_RDONLY); - if (fd < 0) - return -1; if (dso->kernel == DSO_TYPE_GUEST_KERNEL) dso->symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; else dso->symtab_type = DSO_BINARY_TYPE__VMLINUX; - err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); - close(fd); + if (symsrc__init(&ss, dso, symfs_vmlinux, dso->symtab_type)) + return -1; + + err = dso__load_sym(dso, map, &ss, filter, 0, 0); + symsrc__destroy(&ss); if (err > 0) { dso__set_long_name(dso, (char *)vmlinux); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 37f1ea146c16cea14235c1280e303e7670640868..dd9e8678b355673db06025a671b91cf92e6d3ff5 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -11,6 +11,12 @@ #include #include +#ifndef NO_LIBELF_SUPPORT +#include +#include +#include +#endif + #ifdef HAVE_CPLUS_DEMANGLE extern char *cplus_demangle(const char *, int); @@ -219,6 +225,34 @@ struct dso { char name[0]; }; +struct symsrc { + char *name; + int fd; + enum dso_binary_type type; + +#ifndef NO_LIBELF_SUPPORT + Elf *elf; + GElf_Ehdr ehdr; + + Elf_Scn *opdsec; + size_t opdidx; + GElf_Shdr opdshdr; + + Elf_Scn *symtab; + GElf_Shdr symshdr; + + Elf_Scn *dynsym; + size_t dynsym_idx; + GElf_Shdr dynshdr; + + bool adjust_symbols; +#endif +}; + +void symsrc__destroy(struct symsrc *ss); +int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, + enum dso_binary_type type); + #define DSO__SWAP(dso, type, val) \ ({ \ type ____r = val; \ @@ -334,7 +368,7 @@ ssize_t dso__data_read_addr(struct dso *dso, struct map *map, struct machine *machine, u64 addr, u8 *data, ssize_t size); int dso__test_data(void); -int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, +int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *ss, symbol_filter_t filter, int kmodule, int want_symtab); int dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, symbol_filter_t filter);