diff options
Diffstat (limited to 'tools')
| -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); |
