diff options
-rw-r--r-- | tools/perf/builtin-annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 159 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 5 |
5 files changed, 156 insertions, 14 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3becc8a35bee..88205686eb6e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -171,7 +171,7 @@ static int load_kernel(void) | |||
171 | if (!kernel_dso) | 171 | if (!kernel_dso) |
172 | return -1; | 172 | return -1; |
173 | 173 | ||
174 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); | 174 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, 0); |
175 | if (err <= 0) { | 175 | if (err <= 0) { |
176 | dso__delete(kernel_dso); | 176 | dso__delete(kernel_dso); |
177 | kernel_dso = NULL; | 177 | kernel_dso = NULL; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 58d1612894ff..38d136fedfb9 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -188,7 +188,7 @@ static int load_kernel(void) | |||
188 | if (!kernel_dso) | 188 | if (!kernel_dso) |
189 | return -1; | 189 | return -1; |
190 | 190 | ||
191 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); | 191 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, 0); |
192 | if (err <= 0) { | 192 | if (err <= 0) { |
193 | dso__delete(kernel_dso); | 193 | dso__delete(kernel_dso); |
194 | kernel_dso = NULL; | 194 | kernel_dso = NULL; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 97fde1d84365..9bb25fc3d4ce 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -364,7 +364,7 @@ static int parse_symbols(void) | |||
364 | if (kernel_dso == NULL) | 364 | if (kernel_dso == NULL) |
365 | return -1; | 365 | return -1; |
366 | 366 | ||
367 | if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) <= 0) | 367 | if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1, 0) <= 0) |
368 | goto out_delete_dso; | 368 | goto out_delete_dso; |
369 | 369 | ||
370 | node = rb_first(&kernel_dso->syms); | 370 | node = rb_first(&kernel_dso->syms); |
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); |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 65a8449b91f5..4e141a30911e 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "types.h" | 5 | #include "types.h" |
6 | #include <linux/list.h> | 6 | #include <linux/list.h> |
7 | #include <linux/rbtree.h> | 7 | #include <linux/rbtree.h> |
8 | #include "module.h" | ||
8 | 9 | ||
9 | struct symbol { | 10 | struct symbol { |
10 | struct rb_node rb_node; | 11 | struct rb_node rb_node; |
@@ -13,6 +14,7 @@ struct symbol { | |||
13 | u64 obj_start; | 14 | u64 obj_start; |
14 | u64 hist_sum; | 15 | u64 hist_sum; |
15 | u64 *hist; | 16 | u64 *hist; |
17 | struct module *module; | ||
16 | void *priv; | 18 | void *priv; |
17 | char name[0]; | 19 | char name[0]; |
18 | }; | 20 | }; |
@@ -41,7 +43,8 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) | |||
41 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); | 43 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); |
42 | 44 | ||
43 | int dso__load_kernel(struct dso *self, const char *vmlinux, | 45 | int dso__load_kernel(struct dso *self, const char *vmlinux, |
44 | symbol_filter_t filter, int verbose); | 46 | symbol_filter_t filter, int verbose, int modules); |
47 | int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); | ||
45 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose); | 48 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose); |
46 | 49 | ||
47 | size_t dso__fprintf(struct dso *self, FILE *fp); | 50 | size_t dso__fprintf(struct dso *self, FILE *fp); |