aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorCody P Schafer <cody@linux.vnet.ibm.com>2012-08-10 18:22:57 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-08-13 13:31:44 -0400
commitb68e2f919c6d3a0422239c98673c35ff503e52fb (patch)
treee960118f1892c52efe58ebdb8c605cefe81706d7 /tools/perf/util
parent21ea4539b4d1b26de7f2eb227b5d1a092b32cc19 (diff)
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')
-rw-r--r--tools/perf/util/symbol-elf.c119
-rw-r--r--tools/perf/util/symbol-minimal.c30
-rw-r--r--tools/perf/util/symbol.c22
-rw-r--r--tools/perf/util/symbol.h36
4 files changed, 163 insertions, 44 deletions
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index a9a194d49c1b..6974b2a44ee7 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)
536 return 0; 536 return 0;
537} 537}
538 538
539int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, 539
540 symbol_filter_t filter, int kmodule, int want_symtab) 540void symsrc__destroy(struct symsrc *ss)
541{
542 free(ss->name);
543 elf_end(ss->elf);
544 close(ss->fd);
545}
546
547int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
548 enum dso_binary_type type)
541{ 549{
542 struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
543 struct map *curr_map = map;
544 struct dso *curr_dso = dso;
545 Elf_Data *symstrs, *secstrs;
546 uint32_t nr_syms;
547 int err = -1; 550 int err = -1;
548 uint32_t idx;
549 GElf_Ehdr ehdr; 551 GElf_Ehdr ehdr;
550 GElf_Shdr shdr, opdshdr;
551 Elf_Data *syms, *opddata = NULL;
552 GElf_Sym sym;
553 Elf_Scn *sec, *sec_strndx, *opdsec;
554 Elf *elf; 552 Elf *elf;
555 int nr = 0; 553 int fd;
556 size_t opdidx = 0; 554
555 fd = open(name, O_RDONLY);
556 if (fd < 0)
557 return -1;
557 558
558 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 559 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
559 if (elf == NULL) { 560 if (elf == NULL) {
@@ -580,19 +581,88 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
580 goto out_elf_end; 581 goto out_elf_end;
581 } 582 }
582 583
583 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 584 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
585 NULL);
586 if (ss->symshdr.sh_type != SHT_SYMTAB)
587 ss->symtab = NULL;
588
589 ss->dynsym_idx = 0;
590 ss->dynsym = elf_section_by_name(elf, &ehdr, &ss->dynshdr, ".dynsym",
591 &ss->dynsym_idx);
592 if (ss->dynshdr.sh_type != SHT_DYNSYM)
593 ss->dynsym = NULL;
594
595 ss->opdidx = 0;
596 ss->opdsec = elf_section_by_name(elf, &ehdr, &ss->opdshdr, ".opd",
597 &ss->opdidx);
598 if (ss->opdshdr.sh_type != SHT_PROGBITS)
599 ss->opdsec = NULL;
600
601 if (dso->kernel == DSO_TYPE_USER) {
602 GElf_Shdr shdr;
603 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
604 elf_section_by_name(elf, &ehdr, &shdr,
605 ".gnu.prelink_undo",
606 NULL) != NULL);
607 } else {
608 ss->adjust_symbols = 0;
609 }
610
611 ss->name = strdup(name);
612 if (!ss->name)
613 goto out_elf_end;
614
615 ss->elf = elf;
616 ss->fd = fd;
617 ss->ehdr = ehdr;
618 ss->type = type;
619
620 return 0;
621
622out_elf_end:
623 elf_end(elf);
624out_close:
625 close(fd);
626 return err;
627}
628
629int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *ss,
630 symbol_filter_t filter, int kmodule, int want_symtab)
631{
632 struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
633 struct map *curr_map = map;
634 struct dso *curr_dso = dso;
635 Elf_Data *symstrs, *secstrs;
636 uint32_t nr_syms;
637 int err = -1;
638 uint32_t idx;
639 GElf_Ehdr ehdr;
640 GElf_Shdr shdr, opdshdr;
641 Elf_Data *syms, *opddata = NULL;
642 GElf_Sym sym;
643 Elf_Scn *sec, *sec_strndx, *opdsec;
644 Elf *elf;
645 int nr = 0;
646 size_t opdidx = 0;
647
648 elf = ss->elf;
649 ehdr = ss->ehdr;
650 sec = ss->symtab;
651 shdr = ss->symshdr;
652
584 if (sec == NULL) { 653 if (sec == NULL) {
585 if (want_symtab) 654 if (want_symtab)
586 goto out_elf_end; 655 goto out_elf_end;
587 656
588 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 657 sec = ss->dynsym;
658 shdr = ss->dynshdr;
589 if (sec == NULL) 659 if (sec == NULL)
590 goto out_elf_end; 660 goto out_elf_end;
591 } 661 }
592 662
593 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 663 opdsec = ss->opdsec;
594 if (opdshdr.sh_type != SHT_PROGBITS) 664 opdshdr = ss->opdshdr;
595 opdsec = NULL; 665 opdidx = ss->opdidx;
596 if (opdsec) 666 if (opdsec)
597 opddata = elf_rawdata(opdsec, NULL); 667 opddata = elf_rawdata(opdsec, NULL);
598 668
@@ -619,14 +689,7 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
619 nr_syms = shdr.sh_size / shdr.sh_entsize; 689 nr_syms = shdr.sh_size / shdr.sh_entsize;
620 690
621 memset(&sym, 0, sizeof(sym)); 691 memset(&sym, 0, sizeof(sym));
622 if (dso->kernel == DSO_TYPE_USER) { 692 dso->adjust_symbols = ss->adjust_symbols;
623 dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
624 elf_section_by_name(elf, &ehdr, &shdr,
625 ".gnu.prelink_undo",
626 NULL) != NULL);
627 } else {
628 dso->adjust_symbols = 0;
629 }
630 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 693 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
631 struct symbol *f; 694 struct symbol *f;
632 const char *elf_name = elf_sym__name(&sym, symstrs); 695 const char *elf_name = elf_sym__name(&sym, symstrs);
@@ -770,8 +833,6 @@ new_symbol:
770 } 833 }
771 err = nr; 834 err = nr;
772out_elf_end: 835out_elf_end:
773 elf_end(elf);
774out_close:
775 return err; 836 return err;
776} 837}
777 838
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index bd8720b6780c..1b16c2729a36 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -241,6 +241,31 @@ out:
241 return ret; 241 return ret;
242} 242}
243 243
244int symsrc__init(struct symsrc *ss, struct dso *dso __used, const char *name,
245 enum dso_binary_type type)
246{
247 int fd = open(name, O_RDONLY);
248 if (fd < 0)
249 return -1;
250
251 ss->name = strdup(name);
252 if (!ss->name)
253 goto out_close;
254
255 ss->type = type;
256
257 return 0;
258out_close:
259 close(fd);
260 return -1;
261}
262
263void symsrc__destroy(struct symsrc *ss)
264{
265 free(ss->name);
266 close(ss->fd);
267}
268
244int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used, 269int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used,
245 struct map *map __used, 270 struct map *map __used,
246 symbol_filter_t filter __used) 271 symbol_filter_t filter __used)
@@ -248,14 +273,13 @@ int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used,
248 return 0; 273 return 0;
249} 274}
250 275
251int dso__load_sym(struct dso *dso, struct map *map __used, 276int dso__load_sym(struct dso *dso, struct map *map __used, struct symsrc *ss,
252 const char *name, int fd __used,
253 symbol_filter_t filter __used, int kmodule __used, 277 symbol_filter_t filter __used, int kmodule __used,
254 int want_symtab __used) 278 int want_symtab __used)
255{ 279{
256 unsigned char *build_id[BUILD_ID_SIZE]; 280 unsigned char *build_id[BUILD_ID_SIZE];
257 281
258 if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) { 282 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
259 dso__set_build_id(dso, build_id); 283 dso__set_build_id(dso, build_id);
260 return 1; 284 return 1;
261 } 285 }
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8f5cabbfc8bd..afec3f048a94 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)
1026{ 1026{
1027 char *name; 1027 char *name;
1028 int ret = -1; 1028 int ret = -1;
1029 int fd; 1029 struct symsrc ss;
1030 u_int i; 1030 u_int i;
1031 struct machine *machine; 1031 struct machine *machine;
1032 char *root_dir = (char *) ""; 1032 char *root_dir = (char *) "";
@@ -1086,13 +1086,12 @@ restart:
1086 continue; 1086 continue;
1087 1087
1088 /* Name is now the name of the next image to try */ 1088 /* Name is now the name of the next image to try */
1089 fd = open(name, O_RDONLY); 1089 if (symsrc__init(&ss, dso, name, dso->symtab_type) < 0)
1090 if (fd < 0)
1091 continue; 1090 continue;
1092 1091
1093 ret = dso__load_sym(dso, map, name, fd, filter, 0, 1092 ret = dso__load_sym(dso, map, &ss, filter, 0,
1094 want_symtab); 1093 want_symtab);
1095 close(fd); 1094 symsrc__destroy(&ss);
1096 1095
1097 /* 1096 /*
1098 * Some people seem to have debuginfo files _WITHOUT_ debug 1097 * Some people seem to have debuginfo files _WITHOUT_ debug
@@ -1359,22 +1358,23 @@ out_failure:
1359int dso__load_vmlinux(struct dso *dso, struct map *map, 1358int dso__load_vmlinux(struct dso *dso, struct map *map,
1360 const char *vmlinux, symbol_filter_t filter) 1359 const char *vmlinux, symbol_filter_t filter)
1361{ 1360{
1362 int err = -1, fd; 1361 int err = -1;
1362 struct symsrc ss;
1363 char symfs_vmlinux[PATH_MAX]; 1363 char symfs_vmlinux[PATH_MAX];
1364 1364
1365 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1365 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1366 symbol_conf.symfs, vmlinux); 1366 symbol_conf.symfs, vmlinux);
1367 fd = open(symfs_vmlinux, O_RDONLY);
1368 if (fd < 0)
1369 return -1;
1370 1367
1371 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1368 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1372 dso->symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 1369 dso->symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
1373 else 1370 else
1374 dso->symtab_type = DSO_BINARY_TYPE__VMLINUX; 1371 dso->symtab_type = DSO_BINARY_TYPE__VMLINUX;
1375 1372
1376 err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); 1373 if (symsrc__init(&ss, dso, symfs_vmlinux, dso->symtab_type))
1377 close(fd); 1374 return -1;
1375
1376 err = dso__load_sym(dso, map, &ss, filter, 0, 0);
1377 symsrc__destroy(&ss);
1378 1378
1379 if (err > 0) { 1379 if (err > 0) {
1380 dso__set_long_name(dso, (char *)vmlinux); 1380 dso__set_long_name(dso, (char *)vmlinux);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 37f1ea146c16..dd9e8678b355 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -11,6 +11,12 @@
11#include <stdio.h> 11#include <stdio.h>
12#include <byteswap.h> 12#include <byteswap.h>
13 13
14#ifndef NO_LIBELF_SUPPORT
15#include <libelf.h>
16#include <gelf.h>
17#include <elf.h>
18#endif
19
14#ifdef HAVE_CPLUS_DEMANGLE 20#ifdef HAVE_CPLUS_DEMANGLE
15extern char *cplus_demangle(const char *, int); 21extern char *cplus_demangle(const char *, int);
16 22
@@ -219,6 +225,34 @@ struct dso {
219 char name[0]; 225 char name[0];
220}; 226};
221 227
228struct symsrc {
229 char *name;
230 int fd;
231 enum dso_binary_type type;
232
233#ifndef NO_LIBELF_SUPPORT
234 Elf *elf;
235 GElf_Ehdr ehdr;
236
237 Elf_Scn *opdsec;
238 size_t opdidx;
239 GElf_Shdr opdshdr;
240
241 Elf_Scn *symtab;
242 GElf_Shdr symshdr;
243
244 Elf_Scn *dynsym;
245 size_t dynsym_idx;
246 GElf_Shdr dynshdr;
247
248 bool adjust_symbols;
249#endif
250};
251
252void symsrc__destroy(struct symsrc *ss);
253int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
254 enum dso_binary_type type);
255
222#define DSO__SWAP(dso, type, val) \ 256#define DSO__SWAP(dso, type, val) \
223({ \ 257({ \
224 type ____r = val; \ 258 type ____r = val; \
@@ -334,7 +368,7 @@ ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
334 struct machine *machine, u64 addr, 368 struct machine *machine, u64 addr,
335 u8 *data, ssize_t size); 369 u8 *data, ssize_t size);
336int dso__test_data(void); 370int dso__test_data(void);
337int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, 371int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *ss,
338 symbol_filter_t filter, int kmodule, int want_symtab); 372 symbol_filter_t filter, int kmodule, int want_symtab);
339int dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, 373int dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
340 symbol_filter_t filter); 374 symbol_filter_t filter);