diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 159 |
1 files changed, 149 insertions, 10 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c077b6a14690..98a13114de70 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -35,7 +35,7 @@ static struct symbol *symbol__new(u64 start, u64 len, | |||
35 | self = ((void *)self) + priv_size; | 35 | self = ((void *)self) + priv_size; |
36 | } | 36 | } |
37 | self->start = start; | 37 | self->start = start; |
38 | self->end = start + len - 1; | 38 | self->end = len ? start + len - 1 : start; |
39 | memcpy(self->name, name, namelen); | 39 | memcpy(self->name, name, namelen); |
40 | 40 | ||
41 | return self; | 41 | return self; |
@@ -48,8 +48,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size) | |||
48 | 48 | ||
49 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 49 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) |
50 | { | 50 | { |
51 | return fprintf(fp, " %llx-%llx %s\n", | 51 | if (!self->module) |
52 | return fprintf(fp, " %llx-%llx %s\n", | ||
52 | self->start, self->end, self->name); | 53 | self->start, self->end, self->name); |
54 | else | ||
55 | return fprintf(fp, " %llx-%llx %s \t[%s]\n", | ||
56 | self->start, self->end, self->name, self->module->name); | ||
53 | } | 57 | } |
54 | 58 | ||
55 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) | 59 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) |
@@ -310,6 +314,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym) | |||
310 | sym->st_size != 0; | 314 | sym->st_size != 0; |
311 | } | 315 | } |
312 | 316 | ||
317 | static inline int elf_sym__is_label(const GElf_Sym *sym) | ||
318 | { | ||
319 | return elf_sym__type(sym) == STT_NOTYPE && | ||
320 | sym->st_name != 0 && | ||
321 | sym->st_shndx != SHN_UNDEF && | ||
322 | sym->st_shndx != SHN_ABS; | ||
323 | } | ||
324 | |||
325 | static inline const char *elf_sec__name(const GElf_Shdr *shdr, | ||
326 | const Elf_Data *secstrs) | ||
327 | { | ||
328 | return secstrs->d_buf + shdr->sh_name; | ||
329 | } | ||
330 | |||
331 | static inline int elf_sec__is_text(const GElf_Shdr *shdr, | ||
332 | const Elf_Data *secstrs) | ||
333 | { | ||
334 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; | ||
335 | } | ||
336 | |||
313 | static inline const char *elf_sym__name(const GElf_Sym *sym, | 337 | static inline const char *elf_sym__name(const GElf_Sym *sym, |
314 | const Elf_Data *symstrs) | 338 | const Elf_Data *symstrs) |
315 | { | 339 | { |
@@ -451,9 +475,9 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
451 | } | 475 | } |
452 | 476 | ||
453 | static int dso__load_sym(struct dso *self, int fd, const char *name, | 477 | static int dso__load_sym(struct dso *self, int fd, const char *name, |
454 | symbol_filter_t filter, int verbose) | 478 | symbol_filter_t filter, int verbose, struct module *mod) |
455 | { | 479 | { |
456 | Elf_Data *symstrs; | 480 | Elf_Data *symstrs, *secstrs; |
457 | uint32_t nr_syms; | 481 | uint32_t nr_syms; |
458 | int err = -1; | 482 | int err = -1; |
459 | uint32_t index; | 483 | uint32_t index; |
@@ -461,7 +485,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
461 | GElf_Shdr shdr; | 485 | GElf_Shdr shdr; |
462 | Elf_Data *syms; | 486 | Elf_Data *syms; |
463 | GElf_Sym sym; | 487 | GElf_Sym sym; |
464 | Elf_Scn *sec, *sec_dynsym; | 488 | Elf_Scn *sec, *sec_dynsym, *sec_strndx; |
465 | Elf *elf; | 489 | Elf *elf; |
466 | size_t dynsym_idx; | 490 | size_t dynsym_idx; |
467 | int nr = 0; | 491 | int nr = 0; |
@@ -520,6 +544,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
520 | if (symstrs == NULL) | 544 | if (symstrs == NULL) |
521 | goto out_elf_end; | 545 | goto out_elf_end; |
522 | 546 | ||
547 | sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); | ||
548 | if (sec_strndx == NULL) | ||
549 | goto out_elf_end; | ||
550 | |||
551 | secstrs = elf_getdata(sec_strndx, NULL); | ||
552 | if (symstrs == NULL) | ||
553 | goto out_elf_end; | ||
554 | |||
523 | nr_syms = shdr.sh_size / shdr.sh_entsize; | 555 | nr_syms = shdr.sh_size / shdr.sh_entsize; |
524 | 556 | ||
525 | memset(&sym, 0, sizeof(sym)); | 557 | memset(&sym, 0, sizeof(sym)); |
@@ -529,8 +561,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
529 | elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { | 561 | elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { |
530 | struct symbol *f; | 562 | struct symbol *f; |
531 | u64 obj_start; | 563 | u64 obj_start; |
564 | struct section *section = NULL; | ||
565 | int is_label = elf_sym__is_label(&sym); | ||
566 | const char *section_name; | ||
532 | 567 | ||
533 | if (!elf_sym__is_function(&sym)) | 568 | if (!is_label && !elf_sym__is_function(&sym)) |
534 | continue; | 569 | continue; |
535 | 570 | ||
536 | sec = elf_getscn(elf, sym.st_shndx); | 571 | sec = elf_getscn(elf, sym.st_shndx); |
@@ -538,6 +573,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
538 | goto out_elf_end; | 573 | goto out_elf_end; |
539 | 574 | ||
540 | gelf_getshdr(sec, &shdr); | 575 | gelf_getshdr(sec, &shdr); |
576 | |||
577 | if (is_label && !elf_sec__is_text(&shdr, secstrs)) | ||
578 | continue; | ||
579 | |||
580 | section_name = elf_sec__name(&shdr, secstrs); | ||
541 | obj_start = sym.st_value; | 581 | obj_start = sym.st_value; |
542 | 582 | ||
543 | if (self->prelinked) { | 583 | if (self->prelinked) { |
@@ -548,6 +588,17 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
548 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 588 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
549 | } | 589 | } |
550 | 590 | ||
591 | if (mod) { | ||
592 | section = mod->sections->find_section(mod->sections, section_name); | ||
593 | if (section) | ||
594 | sym.st_value += section->vma; | ||
595 | else { | ||
596 | fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", | ||
597 | mod->name, section_name); | ||
598 | goto out_elf_end; | ||
599 | } | ||
600 | } | ||
601 | |||
551 | f = symbol__new(sym.st_value, sym.st_size, | 602 | f = symbol__new(sym.st_value, sym.st_size, |
552 | elf_sym__name(&sym, symstrs), | 603 | elf_sym__name(&sym, symstrs), |
553 | self->sym_priv_size, obj_start, verbose); | 604 | self->sym_priv_size, obj_start, verbose); |
@@ -557,6 +608,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
557 | if (filter && filter(self, f)) | 608 | if (filter && filter(self, f)) |
558 | symbol__delete(f, self->sym_priv_size); | 609 | symbol__delete(f, self->sym_priv_size); |
559 | else { | 610 | else { |
611 | f->module = mod; | ||
560 | dso__insert_symbol(self, f); | 612 | dso__insert_symbol(self, f); |
561 | nr++; | 613 | nr++; |
562 | } | 614 | } |
@@ -606,7 +658,7 @@ more: | |||
606 | fd = open(name, O_RDONLY); | 658 | fd = open(name, O_RDONLY); |
607 | } while (fd < 0); | 659 | } while (fd < 0); |
608 | 660 | ||
609 | ret = dso__load_sym(self, fd, name, filter, verbose); | 661 | ret = dso__load_sym(self, fd, name, filter, verbose, NULL); |
610 | close(fd); | 662 | close(fd); |
611 | 663 | ||
612 | /* | 664 | /* |
@@ -620,6 +672,86 @@ out: | |||
620 | return ret; | 672 | return ret; |
621 | } | 673 | } |
622 | 674 | ||
675 | static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, | ||
676 | symbol_filter_t filter, int verbose) | ||
677 | { | ||
678 | struct module *mod = mod_dso__find_module(mods, name); | ||
679 | int err = 0, fd; | ||
680 | |||
681 | if (mod == NULL || !mod->active) | ||
682 | return err; | ||
683 | |||
684 | fd = open(mod->path, O_RDONLY); | ||
685 | |||
686 | if (fd < 0) | ||
687 | return err; | ||
688 | |||
689 | err = dso__load_sym(self, fd, name, filter, verbose, mod); | ||
690 | close(fd); | ||
691 | |||
692 | return err; | ||
693 | } | ||
694 | |||
695 | int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose) | ||
696 | { | ||
697 | struct mod_dso *mods = mod_dso__new_dso("modules"); | ||
698 | struct module *pos; | ||
699 | struct rb_node *next; | ||
700 | int err; | ||
701 | |||
702 | err = mod_dso__load_modules(mods); | ||
703 | |||
704 | if (err <= 0) | ||
705 | return err; | ||
706 | |||
707 | /* | ||
708 | * Iterate over modules, and load active symbols. | ||
709 | */ | ||
710 | next = rb_first(&mods->mods); | ||
711 | while (next) { | ||
712 | pos = rb_entry(next, struct module, rb_node); | ||
713 | err = dso__load_module(self, mods, pos->name, filter, verbose); | ||
714 | |||
715 | if (err < 0) | ||
716 | break; | ||
717 | |||
718 | next = rb_next(&pos->rb_node); | ||
719 | } | ||
720 | |||
721 | if (err < 0) { | ||
722 | mod_dso__delete_modules(mods); | ||
723 | mod_dso__delete_self(mods); | ||
724 | } | ||
725 | |||
726 | return err; | ||
727 | } | ||
728 | |||
729 | static inline void dso__fill_symbol_holes(struct dso *self) | ||
730 | { | ||
731 | struct symbol *prev = NULL; | ||
732 | struct rb_node *nd; | ||
733 | |||
734 | for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { | ||
735 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
736 | |||
737 | if (prev) { | ||
738 | u64 hole = 0; | ||
739 | int alias = pos->start == prev->start; | ||
740 | |||
741 | if (!alias) | ||
742 | hole = prev->start - pos->end - 1; | ||
743 | |||
744 | if (hole || alias) { | ||
745 | if (alias) | ||
746 | pos->end = prev->end; | ||
747 | else if (hole) | ||
748 | pos->end = prev->start - 1; | ||
749 | } | ||
750 | } | ||
751 | prev = pos; | ||
752 | } | ||
753 | } | ||
754 | |||
623 | static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | 755 | static int dso__load_vmlinux(struct dso *self, const char *vmlinux, |
624 | symbol_filter_t filter, int verbose) | 756 | symbol_filter_t filter, int verbose) |
625 | { | 757 | { |
@@ -628,19 +760,26 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | |||
628 | if (fd < 0) | 760 | if (fd < 0) |
629 | return -1; | 761 | return -1; |
630 | 762 | ||
631 | err = dso__load_sym(self, fd, vmlinux, filter, verbose); | 763 | err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL); |
764 | |||
765 | if (err > 0) | ||
766 | dso__fill_symbol_holes(self); | ||
767 | |||
632 | close(fd); | 768 | close(fd); |
633 | 769 | ||
634 | return err; | 770 | return err; |
635 | } | 771 | } |
636 | 772 | ||
637 | int dso__load_kernel(struct dso *self, const char *vmlinux, | 773 | int dso__load_kernel(struct dso *self, const char *vmlinux, |
638 | symbol_filter_t filter, int verbose) | 774 | symbol_filter_t filter, int verbose, int modules) |
639 | { | 775 | { |
640 | int err = -1; | 776 | int err = -1; |
641 | 777 | ||
642 | if (vmlinux) | 778 | if (vmlinux) { |
643 | err = dso__load_vmlinux(self, vmlinux, filter, verbose); | 779 | err = dso__load_vmlinux(self, vmlinux, filter, verbose); |
780 | if (err > 0 && modules) | ||
781 | err = dso__load_modules(self, filter, verbose); | ||
782 | } | ||
644 | 783 | ||
645 | if (err <= 0) | 784 | if (err <= 0) |
646 | err = dso__load_kallsyms(self, filter, verbose); | 785 | err = dso__load_kallsyms(self, filter, verbose); |