aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-08-11 08:19:09 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-11 08:19:09 -0400
commit89034bc2c7b839702c00a704e79d112737f98be0 (patch)
treee65b1f3d4c751baa840efc81bc4734f089379eb3 /tools/perf/util/symbol.c
parentfb82ad719831db58e9baa4c67015aae3fe27e7e3 (diff)
parent85dfd81dc57e8183a277ddd7a56aa65c96f3f487 (diff)
Merge branch 'linus' into tracing/core
Conflicts: kernel/trace/trace_events_filter.c We use the tracing/core version. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c281
1 files changed, 215 insertions, 66 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 4683b67b5ee4..f1dcede14307 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -7,8 +7,33 @@
7#include <gelf.h> 7#include <gelf.h>
8#include <elf.h> 8#include <elf.h>
9 9
10#ifndef NO_DEMANGLE
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
19
10const char *sym_hist_filter; 20const char *sym_hist_filter;
11 21
22#ifndef DMGL_PARAMS
23#define DMGL_PARAMS (1 << 0) /* Include function args */
24#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
25#endif
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
12static struct symbol *symbol__new(u64 start, u64 len, 37static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 38 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 39 u64 obj_start, int verbose)
@@ -65,6 +90,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
65 self->syms = RB_ROOT; 90 self->syms = RB_ROOT;
66 self->sym_priv_size = sym_priv_size; 91 self->sym_priv_size = sym_priv_size;
67 self->find_symbol = dso__find_symbol; 92 self->find_symbol = dso__find_symbol;
93 self->slen_calculated = 0;
94 self->origin = DSO__ORIG_NOT_FOUND;
68 } 95 }
69 96
70 return self; 97 return self;
@@ -373,36 +400,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
373 idx < nr_entries; \ 400 idx < nr_entries; \
374 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 401 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
375 402
376static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 403/*
377 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 404 * We need to check if we have a .dynsym, so that we can handle the
378 GElf_Shdr *shdr_dynsym, 405 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
379 size_t dynsym_idx, int verbose) 406 * .dynsym or .symtab).
407 * And always look at the original dso, not at debuginfo packages, that
408 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
409 */
410static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
380{ 411{
381 uint32_t nr_rel_entries, idx; 412 uint32_t nr_rel_entries, idx;
382 GElf_Sym sym; 413 GElf_Sym sym;
383 u64 plt_offset; 414 u64 plt_offset;
384 GElf_Shdr shdr_plt; 415 GElf_Shdr shdr_plt;
385 struct symbol *f; 416 struct symbol *f;
386 GElf_Shdr shdr_rel_plt; 417 GElf_Shdr shdr_rel_plt, shdr_dynsym;
387 Elf_Data *reldata, *syms, *symstrs; 418 Elf_Data *reldata, *syms, *symstrs;
388 Elf_Scn *scn_plt_rel, *scn_symstrs; 419 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
420 size_t dynsym_idx;
421 GElf_Ehdr ehdr;
389 char sympltname[1024]; 422 char sympltname[1024];
390 int nr = 0, symidx; 423 Elf *elf;
424 int nr = 0, symidx, fd, err = 0;
425
426 fd = open(self->name, O_RDONLY);
427 if (fd < 0)
428 goto out;
429
430 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
431 if (elf == NULL)
432 goto out_close;
433
434 if (gelf_getehdr(elf, &ehdr) == NULL)
435 goto out_elf_end;
391 436
392 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 437 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
438 ".dynsym", &dynsym_idx);
439 if (scn_dynsym == NULL)
440 goto out_elf_end;
441
442 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
393 ".rela.plt", NULL); 443 ".rela.plt", NULL);
394 if (scn_plt_rel == NULL) { 444 if (scn_plt_rel == NULL) {
395 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 445 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
396 ".rel.plt", NULL); 446 ".rel.plt", NULL);
397 if (scn_plt_rel == NULL) 447 if (scn_plt_rel == NULL)
398 return 0; 448 goto out_elf_end;
399 } 449 }
400 450
451 err = -1;
452
401 if (shdr_rel_plt.sh_link != dynsym_idx) 453 if (shdr_rel_plt.sh_link != dynsym_idx)
402 return 0; 454 goto out_elf_end;
403 455
404 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 456 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
405 return 0; 457 goto out_elf_end;
406 458
407 /* 459 /*
408 * Fetch the relocation section to find the indexes to the GOT 460 * Fetch the relocation section to find the indexes to the GOT
@@ -410,19 +462,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
410 */ 462 */
411 reldata = elf_getdata(scn_plt_rel, NULL); 463 reldata = elf_getdata(scn_plt_rel, NULL);
412 if (reldata == NULL) 464 if (reldata == NULL)
413 return -1; 465 goto out_elf_end;
414 466
415 syms = elf_getdata(scn_dynsym, NULL); 467 syms = elf_getdata(scn_dynsym, NULL);
416 if (syms == NULL) 468 if (syms == NULL)
417 return -1; 469 goto out_elf_end;
418 470
419 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 471 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
420 if (scn_symstrs == NULL) 472 if (scn_symstrs == NULL)
421 return -1; 473 goto out_elf_end;
422 474
423 symstrs = elf_getdata(scn_symstrs, NULL); 475 symstrs = elf_getdata(scn_symstrs, NULL);
424 if (symstrs == NULL) 476 if (symstrs == NULL)
425 return -1; 477 goto out_elf_end;
426 478
427 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 479 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
428 plt_offset = shdr_plt.sh_offset; 480 plt_offset = shdr_plt.sh_offset;
@@ -441,7 +493,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
441 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 493 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
442 sympltname, self->sym_priv_size, 0, verbose); 494 sympltname, self->sym_priv_size, 0, verbose);
443 if (!f) 495 if (!f)
444 return -1; 496 goto out_elf_end;
445 497
446 dso__insert_symbol(self, f); 498 dso__insert_symbol(self, f);
447 ++nr; 499 ++nr;
@@ -459,19 +511,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
459 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 511 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
460 sympltname, self->sym_priv_size, 0, verbose); 512 sympltname, self->sym_priv_size, 0, verbose);
461 if (!f) 513 if (!f)
462 return -1; 514 goto out_elf_end;
463 515
464 dso__insert_symbol(self, f); 516 dso__insert_symbol(self, f);
465 ++nr; 517 ++nr;
466 } 518 }
467 } else {
468 /*
469 * TODO: There are still one more shdr_rel_plt.sh_type
470 * I have to investigate, but probably should be ignored.
471 */
472 } 519 }
473 520
474 return nr; 521 err = 0;
522out_elf_end:
523 elf_end(elf);
524out_close:
525 close(fd);
526
527 if (err == 0)
528 return nr;
529out:
530 fprintf(stderr, "%s: problems reading %s PLT info.\n",
531 __func__, self->name);
532 return 0;
475} 533}
476 534
477static int dso__load_sym(struct dso *self, int fd, const char *name, 535static int dso__load_sym(struct dso *self, int fd, const char *name,
@@ -485,10 +543,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
485 GElf_Shdr shdr; 543 GElf_Shdr shdr;
486 Elf_Data *syms; 544 Elf_Data *syms;
487 GElf_Sym sym; 545 GElf_Sym sym;
488 Elf_Scn *sec, *sec_dynsym, *sec_strndx; 546 Elf_Scn *sec, *sec_strndx;
489 Elf *elf; 547 Elf *elf;
490 size_t dynsym_idx; 548 int nr = 0, kernel = !strcmp("[kernel]", self->name);
491 int nr = 0;
492 549
493 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 550 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
494 if (elf == NULL) { 551 if (elf == NULL) {
@@ -504,32 +561,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
504 goto out_elf_end; 561 goto out_elf_end;
505 } 562 }
506 563
507 /*
508 * We need to check if we have a .dynsym, so that we can handle the
509 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
510 * .dynsym or .symtab)
511 */
512 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
513 ".dynsym", &dynsym_idx);
514 if (sec_dynsym != NULL) {
515 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
516 sec_dynsym, &shdr,
517 dynsym_idx, verbose);
518 if (nr < 0)
519 goto out_elf_end;
520 }
521
522 /*
523 * But if we have a full .symtab (that is a superset of .dynsym) we
524 * should add the symbols not in the .dynsyn
525 */
526 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 564 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
527 if (sec == NULL) { 565 if (sec == NULL) {
528 if (sec_dynsym == NULL) 566 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
567 if (sec == NULL)
529 goto out_elf_end; 568 goto out_elf_end;
530
531 sec = sec_dynsym;
532 gelf_getshdr(sec, &shdr);
533 } 569 }
534 570
535 syms = elf_getdata(sec, NULL); 571 syms = elf_getdata(sec, NULL);
@@ -549,18 +585,23 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
549 goto out_elf_end; 585 goto out_elf_end;
550 586
551 secstrs = elf_getdata(sec_strndx, NULL); 587 secstrs = elf_getdata(sec_strndx, NULL);
552 if (symstrs == NULL) 588 if (secstrs == NULL)
553 goto out_elf_end; 589 goto out_elf_end;
554 590
555 nr_syms = shdr.sh_size / shdr.sh_entsize; 591 nr_syms = shdr.sh_size / shdr.sh_entsize;
556 592
557 memset(&sym, 0, sizeof(sym)); 593 memset(&sym, 0, sizeof(sym));
558 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 594 if (!kernel) {
595 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
559 elf_section_by_name(elf, &ehdr, &shdr, 596 elf_section_by_name(elf, &ehdr, &shdr,
560 ".gnu.prelink_undo", 597 ".gnu.prelink_undo",
561 NULL) != NULL); 598 NULL) != NULL);
599 } else self->adjust_symbols = 0;
600
562 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 601 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
563 struct symbol *f; 602 struct symbol *f;
603 const char *name;
604 char *demangled;
564 u64 obj_start; 605 u64 obj_start;
565 struct section *section = NULL; 606 struct section *section = NULL;
566 int is_label = elf_sym__is_label(&sym); 607 int is_label = elf_sym__is_label(&sym);
@@ -599,10 +640,19 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
599 goto out_elf_end; 640 goto out_elf_end;
600 } 641 }
601 } 642 }
643 /*
644 * We need to figure out if the object was created from C++ sources
645 * DWARF DW_compile_unit has this, but we don't always have access
646 * to it...
647 */
648 name = elf_sym__name(&sym, symstrs);
649 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
650 if (demangled != NULL)
651 name = demangled;
602 652
603 f = symbol__new(sym.st_value, sym.st_size, 653 f = symbol__new(sym.st_value, sym.st_size, name,
604 elf_sym__name(&sym, symstrs),
605 self->sym_priv_size, obj_start, verbose); 654 self->sym_priv_size, obj_start, verbose);
655 free(demangled);
606 if (!f) 656 if (!f)
607 goto out_elf_end; 657 goto out_elf_end;
608 658
@@ -622,11 +672,85 @@ out_close:
622 return err; 672 return err;
623} 673}
624 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
625int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 750int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
626{ 751{
627 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 752 int size = PATH_MAX;
628 char *name = malloc(size); 753 char *name = malloc(size), *build_id = NULL;
629 int variant = 0;
630 int ret = -1; 754 int ret = -1;
631 int fd; 755 int fd;
632 756
@@ -635,26 +759,43 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
635 759
636 self->adjust_symbols = 0; 760 self->adjust_symbols = 0;
637 761
638 if (strncmp(self->name, "/tmp/perf-", 10) == 0) 762 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
639 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;
640 770
641more: 771more:
642 do { 772 do {
643 switch (variant) { 773 self->origin++;
644 case 0: /* Fedora */ 774 switch (self->origin) {
775 case DSO__ORIG_FEDORA:
645 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 776 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
646 break; 777 break;
647 case 1: /* Ubuntu */ 778 case DSO__ORIG_UBUNTU:
648 snprintf(name, size, "/usr/lib/debug%s", self->name); 779 snprintf(name, size, "/usr/lib/debug%s", self->name);
649 break; 780 break;
650 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:
651 snprintf(name, size, "%s", self->name); 793 snprintf(name, size, "%s", self->name);
652 break; 794 break;
653 795
654 default: 796 default:
655 goto out; 797 goto out;
656 } 798 }
657 variant++;
658 799
659 fd = open(name, O_RDONLY); 800 fd = open(name, O_RDONLY);
660 } while (fd < 0); 801 } while (fd < 0);
@@ -668,6 +809,11 @@ more:
668 if (!ret) 809 if (!ret)
669 goto more; 810 goto more;
670 811
812 if (ret > 0) {
813 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
814 if (nr_plt > 0)
815 ret += nr_plt;
816 }
671out: 817out:
672 free(name); 818 free(name);
673 return ret; 819 return ret;
@@ -785,6 +931,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
785 if (err <= 0) 931 if (err <= 0)
786 err = dso__load_kallsyms(self, filter, verbose); 932 err = dso__load_kallsyms(self, filter, verbose);
787 933
934 if (err > 0)
935 self->origin = DSO__ORIG_KERNEL;
936
788 return err; 937 return err;
789} 938}
790 939