diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 447 |
1 files changed, 301 insertions, 146 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 559fb06210f5..e88296899470 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -2,12 +2,14 @@ | |||
2 | #include "../perf.h" | 2 | #include "../perf.h" |
3 | #include "string.h" | 3 | #include "string.h" |
4 | #include "symbol.h" | 4 | #include "symbol.h" |
5 | #include "thread.h" | ||
5 | 6 | ||
6 | #include "debug.h" | 7 | #include "debug.h" |
7 | 8 | ||
8 | #include <libelf.h> | 9 | #include <libelf.h> |
9 | #include <gelf.h> | 10 | #include <gelf.h> |
10 | #include <elf.h> | 11 | #include <elf.h> |
12 | #include <sys/utsname.h> | ||
11 | 13 | ||
12 | const char *sym_hist_filter; | 14 | const char *sym_hist_filter; |
13 | 15 | ||
@@ -18,12 +20,15 @@ enum dso_origin { | |||
18 | DSO__ORIG_UBUNTU, | 20 | DSO__ORIG_UBUNTU, |
19 | DSO__ORIG_BUILDID, | 21 | DSO__ORIG_BUILDID, |
20 | DSO__ORIG_DSO, | 22 | DSO__ORIG_DSO, |
23 | DSO__ORIG_KMODULE, | ||
21 | DSO__ORIG_NOT_FOUND, | 24 | DSO__ORIG_NOT_FOUND, |
22 | }; | 25 | }; |
23 | 26 | ||
24 | static struct symbol *symbol__new(u64 start, u64 len, | 27 | static void dsos__add(struct dso *dso); |
25 | const char *name, unsigned int priv_size, | 28 | static struct dso *dsos__find(const char *name); |
26 | u64 obj_start, int v) | 29 | |
30 | static struct symbol *symbol__new(u64 start, u64 len, const char *name, | ||
31 | unsigned int priv_size, int v) | ||
27 | { | 32 | { |
28 | size_t namelen = strlen(name) + 1; | 33 | size_t namelen = strlen(name) + 1; |
29 | struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); | 34 | struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); |
@@ -32,10 +37,9 @@ static struct symbol *symbol__new(u64 start, u64 len, | |||
32 | return NULL; | 37 | return NULL; |
33 | 38 | ||
34 | if (v >= 2) | 39 | if (v >= 2) |
35 | printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", | 40 | printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n", |
36 | (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); | 41 | start, (unsigned long)len, name, self->hist); |
37 | 42 | ||
38 | self->obj_start= obj_start; | ||
39 | self->hist = NULL; | 43 | self->hist = NULL; |
40 | self->hist_sum = 0; | 44 | self->hist_sum = 0; |
41 | 45 | ||
@@ -60,12 +64,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size) | |||
60 | 64 | ||
61 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 65 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) |
62 | { | 66 | { |
63 | if (!self->module) | 67 | return fprintf(fp, " %llx-%llx %s\n", |
64 | return fprintf(fp, " %llx-%llx %s\n", | ||
65 | self->start, self->end, self->name); | 68 | self->start, self->end, self->name); |
66 | else | ||
67 | return fprintf(fp, " %llx-%llx %s \t[%s]\n", | ||
68 | self->start, self->end, self->name, self->module->name); | ||
69 | } | 69 | } |
70 | 70 | ||
71 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) | 71 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) |
@@ -74,6 +74,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) | |||
74 | 74 | ||
75 | if (self != NULL) { | 75 | if (self != NULL) { |
76 | strcpy(self->name, name); | 76 | strcpy(self->name, name); |
77 | self->long_name = self->name; | ||
78 | self->short_name = self->name; | ||
77 | self->syms = RB_ROOT; | 79 | self->syms = RB_ROOT; |
78 | self->sym_priv_size = sym_priv_size; | 80 | self->sym_priv_size = sym_priv_size; |
79 | self->find_symbol = dso__find_symbol; | 81 | self->find_symbol = dso__find_symbol; |
@@ -100,6 +102,8 @@ static void dso__delete_symbols(struct dso *self) | |||
100 | void dso__delete(struct dso *self) | 102 | void dso__delete(struct dso *self) |
101 | { | 103 | { |
102 | dso__delete_symbols(self); | 104 | dso__delete_symbols(self); |
105 | if (self->long_name != self->name) | ||
106 | free(self->long_name); | ||
103 | free(self); | 107 | free(self); |
104 | } | 108 | } |
105 | 109 | ||
@@ -147,7 +151,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip) | |||
147 | 151 | ||
148 | size_t dso__fprintf(struct dso *self, FILE *fp) | 152 | size_t dso__fprintf(struct dso *self, FILE *fp) |
149 | { | 153 | { |
150 | size_t ret = fprintf(fp, "dso: %s\n", self->name); | 154 | size_t ret = fprintf(fp, "dso: %s\n", self->long_name); |
151 | 155 | ||
152 | struct rb_node *nd; | 156 | struct rb_node *nd; |
153 | for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { | 157 | for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { |
@@ -158,7 +162,8 @@ size_t dso__fprintf(struct dso *self, FILE *fp) | |||
158 | return ret; | 162 | return ret; |
159 | } | 163 | } |
160 | 164 | ||
161 | static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) | 165 | static int dso__load_kallsyms(struct dso *self, struct map *map, |
166 | symbol_filter_t filter, int v) | ||
162 | { | 167 | { |
163 | struct rb_node *nd, *prevnd; | 168 | struct rb_node *nd, *prevnd; |
164 | char *line = NULL; | 169 | char *line = NULL; |
@@ -200,12 +205,12 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) | |||
200 | * Well fix up the end later, when we have all sorted. | 205 | * Well fix up the end later, when we have all sorted. |
201 | */ | 206 | */ |
202 | sym = symbol__new(start, 0xdead, line + len + 2, | 207 | sym = symbol__new(start, 0xdead, line + len + 2, |
203 | self->sym_priv_size, 0, v); | 208 | self->sym_priv_size, v); |
204 | 209 | ||
205 | if (sym == NULL) | 210 | if (sym == NULL) |
206 | goto out_delete_line; | 211 | goto out_delete_line; |
207 | 212 | ||
208 | if (filter && filter(self, sym)) | 213 | if (filter && filter(map, sym)) |
209 | symbol__delete(sym, self->sym_priv_size); | 214 | symbol__delete(sym, self->sym_priv_size); |
210 | else { | 215 | else { |
211 | dso__insert_symbol(self, sym); | 216 | dso__insert_symbol(self, sym); |
@@ -241,14 +246,15 @@ out_failure: | |||
241 | return -1; | 246 | return -1; |
242 | } | 247 | } |
243 | 248 | ||
244 | static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) | 249 | static int dso__load_perf_map(struct dso *self, struct map *map, |
250 | symbol_filter_t filter, int v) | ||
245 | { | 251 | { |
246 | char *line = NULL; | 252 | char *line = NULL; |
247 | size_t n; | 253 | size_t n; |
248 | FILE *file; | 254 | FILE *file; |
249 | int nr_syms = 0; | 255 | int nr_syms = 0; |
250 | 256 | ||
251 | file = fopen(self->name, "r"); | 257 | file = fopen(self->long_name, "r"); |
252 | if (file == NULL) | 258 | if (file == NULL) |
253 | goto out_failure; | 259 | goto out_failure; |
254 | 260 | ||
@@ -279,12 +285,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) | |||
279 | continue; | 285 | continue; |
280 | 286 | ||
281 | sym = symbol__new(start, size, line + len, | 287 | sym = symbol__new(start, size, line + len, |
282 | self->sym_priv_size, start, v); | 288 | self->sym_priv_size, v); |
283 | 289 | ||
284 | if (sym == NULL) | 290 | if (sym == NULL) |
285 | goto out_delete_line; | 291 | goto out_delete_line; |
286 | 292 | ||
287 | if (filter && filter(self, sym)) | 293 | if (filter && filter(map, sym)) |
288 | symbol__delete(sym, self->sym_priv_size); | 294 | symbol__delete(sym, self->sym_priv_size); |
289 | else { | 295 | else { |
290 | dso__insert_symbol(self, sym); | 296 | dso__insert_symbol(self, sym); |
@@ -410,7 +416,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) | |||
410 | Elf *elf; | 416 | Elf *elf; |
411 | int nr = 0, symidx, fd, err = 0; | 417 | int nr = 0, symidx, fd, err = 0; |
412 | 418 | ||
413 | fd = open(self->name, O_RDONLY); | 419 | fd = open(self->long_name, O_RDONLY); |
414 | if (fd < 0) | 420 | if (fd < 0) |
415 | goto out; | 421 | goto out; |
416 | 422 | ||
@@ -478,7 +484,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) | |||
478 | "%s@plt", elf_sym__name(&sym, symstrs)); | 484 | "%s@plt", elf_sym__name(&sym, symstrs)); |
479 | 485 | ||
480 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 486 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
481 | sympltname, self->sym_priv_size, 0, v); | 487 | sympltname, self->sym_priv_size, v); |
482 | if (!f) | 488 | if (!f) |
483 | goto out_elf_end; | 489 | goto out_elf_end; |
484 | 490 | ||
@@ -496,7 +502,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) | |||
496 | "%s@plt", elf_sym__name(&sym, symstrs)); | 502 | "%s@plt", elf_sym__name(&sym, symstrs)); |
497 | 503 | ||
498 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 504 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
499 | sympltname, self->sym_priv_size, 0, v); | 505 | sympltname, self->sym_priv_size, v); |
500 | if (!f) | 506 | if (!f) |
501 | goto out_elf_end; | 507 | goto out_elf_end; |
502 | 508 | ||
@@ -515,12 +521,13 @@ out_close: | |||
515 | return nr; | 521 | return nr; |
516 | out: | 522 | out: |
517 | fprintf(stderr, "%s: problems reading %s PLT info.\n", | 523 | fprintf(stderr, "%s: problems reading %s PLT info.\n", |
518 | __func__, self->name); | 524 | __func__, self->long_name); |
519 | return 0; | 525 | return 0; |
520 | } | 526 | } |
521 | 527 | ||
522 | static int dso__load_sym(struct dso *self, int fd, const char *name, | 528 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, |
523 | symbol_filter_t filter, int v, struct module *mod) | 529 | int fd, symbol_filter_t filter, int kernel, |
530 | int kmodule, int v) | ||
524 | { | 531 | { |
525 | Elf_Data *symstrs, *secstrs; | 532 | Elf_Data *symstrs, *secstrs; |
526 | uint32_t nr_syms; | 533 | uint32_t nr_syms; |
@@ -532,7 +539,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
532 | GElf_Sym sym; | 539 | GElf_Sym sym; |
533 | Elf_Scn *sec, *sec_strndx; | 540 | Elf_Scn *sec, *sec_strndx; |
534 | Elf *elf; | 541 | Elf *elf; |
535 | int nr = 0, kernel = !strcmp("[kernel]", self->name); | 542 | int nr = 0; |
536 | 543 | ||
537 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | 544 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); |
538 | if (elf == NULL) { | 545 | if (elf == NULL) { |
@@ -589,8 +596,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
589 | struct symbol *f; | 596 | struct symbol *f; |
590 | const char *elf_name; | 597 | const char *elf_name; |
591 | char *demangled; | 598 | char *demangled; |
592 | u64 obj_start; | ||
593 | struct section *section = NULL; | ||
594 | int is_label = elf_sym__is_label(&sym); | 599 | int is_label = elf_sym__is_label(&sym); |
595 | const char *section_name; | 600 | const char *section_name; |
596 | 601 | ||
@@ -607,7 +612,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
607 | continue; | 612 | continue; |
608 | 613 | ||
609 | section_name = elf_sec__name(&shdr, secstrs); | 614 | section_name = elf_sec__name(&shdr, secstrs); |
610 | obj_start = sym.st_value; | ||
611 | 615 | ||
612 | if (self->adjust_symbols) { | 616 | if (self->adjust_symbols) { |
613 | if (v >= 2) | 617 | if (v >= 2) |
@@ -615,18 +619,8 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
615 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); | 619 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); |
616 | 620 | ||
617 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 621 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
618 | } | 622 | } else if (kmodule) |
619 | 623 | sym.st_value += shdr.sh_offset; | |
620 | if (mod) { | ||
621 | section = mod->sections->find_section(mod->sections, section_name); | ||
622 | if (section) | ||
623 | sym.st_value += section->vma; | ||
624 | else { | ||
625 | fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", | ||
626 | mod->name, section_name); | ||
627 | goto out_elf_end; | ||
628 | } | ||
629 | } | ||
630 | /* | 624 | /* |
631 | * We need to figure out if the object was created from C++ sources | 625 | * We need to figure out if the object was created from C++ sources |
632 | * DWARF DW_compile_unit has this, but we don't always have access | 626 | * DWARF DW_compile_unit has this, but we don't always have access |
@@ -638,15 +632,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
638 | elf_name = demangled; | 632 | elf_name = demangled; |
639 | 633 | ||
640 | f = symbol__new(sym.st_value, sym.st_size, elf_name, | 634 | f = symbol__new(sym.st_value, sym.st_size, elf_name, |
641 | self->sym_priv_size, obj_start, v); | 635 | self->sym_priv_size, v); |
642 | free(demangled); | 636 | free(demangled); |
643 | if (!f) | 637 | if (!f) |
644 | goto out_elf_end; | 638 | goto out_elf_end; |
645 | 639 | ||
646 | if (filter && filter(self, f)) | 640 | if (filter && filter(map, f)) |
647 | symbol__delete(f, self->sym_priv_size); | 641 | symbol__delete(f, self->sym_priv_size); |
648 | else { | 642 | else { |
649 | f->module = mod; | ||
650 | dso__insert_symbol(self, f); | 643 | dso__insert_symbol(self, f); |
651 | nr++; | 644 | nr++; |
652 | } | 645 | } |
@@ -671,7 +664,7 @@ static char *dso__read_build_id(struct dso *self, int v) | |||
671 | char *build_id = NULL, *bid; | 664 | char *build_id = NULL, *bid; |
672 | unsigned char *raw; | 665 | unsigned char *raw; |
673 | Elf *elf; | 666 | Elf *elf; |
674 | int fd = open(self->name, O_RDONLY); | 667 | int fd = open(self->long_name, O_RDONLY); |
675 | 668 | ||
676 | if (fd < 0) | 669 | if (fd < 0) |
677 | goto out; | 670 | goto out; |
@@ -680,7 +673,7 @@ static char *dso__read_build_id(struct dso *self, int v) | |||
680 | if (elf == NULL) { | 673 | if (elf == NULL) { |
681 | if (v) | 674 | if (v) |
682 | fprintf(stderr, "%s: cannot read %s ELF file.\n", | 675 | fprintf(stderr, "%s: cannot read %s ELF file.\n", |
683 | __func__, self->name); | 676 | __func__, self->long_name); |
684 | goto out_close; | 677 | goto out_close; |
685 | } | 678 | } |
686 | 679 | ||
@@ -709,7 +702,7 @@ static char *dso__read_build_id(struct dso *self, int v) | |||
709 | bid += 2; | 702 | bid += 2; |
710 | } | 703 | } |
711 | if (v >= 2) | 704 | if (v >= 2) |
712 | printf("%s(%s): %s\n", __func__, self->name, build_id); | 705 | printf("%s(%s): %s\n", __func__, self->long_name, build_id); |
713 | out_elf_end: | 706 | out_elf_end: |
714 | elf_end(elf); | 707 | elf_end(elf); |
715 | out_close: | 708 | out_close: |
@@ -727,6 +720,7 @@ char dso__symtab_origin(const struct dso *self) | |||
727 | [DSO__ORIG_UBUNTU] = 'u', | 720 | [DSO__ORIG_UBUNTU] = 'u', |
728 | [DSO__ORIG_BUILDID] = 'b', | 721 | [DSO__ORIG_BUILDID] = 'b', |
729 | [DSO__ORIG_DSO] = 'd', | 722 | [DSO__ORIG_DSO] = 'd', |
723 | [DSO__ORIG_KMODULE] = 'K', | ||
730 | }; | 724 | }; |
731 | 725 | ||
732 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) | 726 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) |
@@ -734,7 +728,7 @@ char dso__symtab_origin(const struct dso *self) | |||
734 | return origin[self->origin]; | 728 | return origin[self->origin]; |
735 | } | 729 | } |
736 | 730 | ||
737 | int dso__load(struct dso *self, symbol_filter_t filter, int v) | 731 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v) |
738 | { | 732 | { |
739 | int size = PATH_MAX; | 733 | int size = PATH_MAX; |
740 | char *name = malloc(size), *build_id = NULL; | 734 | char *name = malloc(size), *build_id = NULL; |
@@ -747,7 +741,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v) | |||
747 | self->adjust_symbols = 0; | 741 | self->adjust_symbols = 0; |
748 | 742 | ||
749 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) { | 743 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) { |
750 | ret = dso__load_perf_map(self, filter, v); | 744 | ret = dso__load_perf_map(self, map, filter, v); |
751 | self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : | 745 | self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : |
752 | DSO__ORIG_NOT_FOUND; | 746 | DSO__ORIG_NOT_FOUND; |
753 | return ret; | 747 | return ret; |
@@ -760,10 +754,12 @@ more: | |||
760 | self->origin++; | 754 | self->origin++; |
761 | switch (self->origin) { | 755 | switch (self->origin) { |
762 | case DSO__ORIG_FEDORA: | 756 | case DSO__ORIG_FEDORA: |
763 | snprintf(name, size, "/usr/lib/debug%s.debug", self->name); | 757 | snprintf(name, size, "/usr/lib/debug%s.debug", |
758 | self->long_name); | ||
764 | break; | 759 | break; |
765 | case DSO__ORIG_UBUNTU: | 760 | case DSO__ORIG_UBUNTU: |
766 | snprintf(name, size, "/usr/lib/debug%s", self->name); | 761 | snprintf(name, size, "/usr/lib/debug%s", |
762 | self->long_name); | ||
767 | break; | 763 | break; |
768 | case DSO__ORIG_BUILDID: | 764 | case DSO__ORIG_BUILDID: |
769 | build_id = dso__read_build_id(self, v); | 765 | build_id = dso__read_build_id(self, v); |
@@ -777,7 +773,7 @@ more: | |||
777 | self->origin++; | 773 | self->origin++; |
778 | /* Fall thru */ | 774 | /* Fall thru */ |
779 | case DSO__ORIG_DSO: | 775 | case DSO__ORIG_DSO: |
780 | snprintf(name, size, "%s", self->name); | 776 | snprintf(name, size, "%s", self->long_name); |
781 | break; | 777 | break; |
782 | 778 | ||
783 | default: | 779 | default: |
@@ -787,7 +783,7 @@ more: | |||
787 | fd = open(name, O_RDONLY); | 783 | fd = open(name, O_RDONLY); |
788 | } while (fd < 0); | 784 | } while (fd < 0); |
789 | 785 | ||
790 | ret = dso__load_sym(self, fd, name, filter, v, NULL); | 786 | ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v); |
791 | close(fd); | 787 | close(fd); |
792 | 788 | ||
793 | /* | 789 | /* |
@@ -808,89 +804,247 @@ out: | |||
808 | return ret; | 804 | return ret; |
809 | } | 805 | } |
810 | 806 | ||
811 | static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, | 807 | static struct rb_root kernel_maps; |
812 | symbol_filter_t filter, int v) | 808 | struct map *kernel_map; |
809 | |||
810 | static void kernel_maps__insert(struct map *map) | ||
813 | { | 811 | { |
814 | struct module *mod = mod_dso__find_module(mods, name); | 812 | maps__insert(&kernel_maps, map); |
815 | int err = 0, fd; | 813 | } |
816 | 814 | ||
817 | if (mod == NULL || !mod->active) | 815 | struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) |
818 | return err; | 816 | { |
817 | /* | ||
818 | * We can't have kernel_map in kernel_maps because it spans an address | ||
819 | * space that includes the modules. The right way to fix this is to | ||
820 | * create several maps, so that we don't have overlapping ranges with | ||
821 | * modules. For now lets look first on the kernel dso. | ||
822 | */ | ||
823 | struct map *map = maps__find(&kernel_maps, ip); | ||
824 | struct symbol *sym; | ||
825 | |||
826 | if (map) { | ||
827 | ip = map->map_ip(map, ip); | ||
828 | sym = map->dso->find_symbol(map->dso, ip); | ||
829 | } else { | ||
830 | map = kernel_map; | ||
831 | sym = map->dso->find_symbol(map->dso, ip); | ||
832 | } | ||
819 | 833 | ||
820 | fd = open(mod->path, O_RDONLY); | 834 | if (mapp) |
835 | *mapp = map; | ||
821 | 836 | ||
822 | if (fd < 0) | 837 | return sym; |
838 | } | ||
839 | |||
840 | struct map *kernel_maps__find_by_dso_name(const char *name) | ||
841 | { | ||
842 | struct rb_node *nd; | ||
843 | |||
844 | for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { | ||
845 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
846 | |||
847 | if (map->dso && strcmp(map->dso->name, name) == 0) | ||
848 | return map; | ||
849 | } | ||
850 | |||
851 | return NULL; | ||
852 | } | ||
853 | |||
854 | static int dso__load_module_sym(struct dso *self, struct map *map, | ||
855 | symbol_filter_t filter, int v) | ||
856 | { | ||
857 | int err = 0, fd = open(self->long_name, O_RDONLY); | ||
858 | |||
859 | if (fd < 0) { | ||
860 | if (v) | ||
861 | fprintf(stderr, "%s: cannot open %s\n", | ||
862 | __func__, self->long_name); | ||
823 | return err; | 863 | return err; |
864 | } | ||
824 | 865 | ||
825 | err = dso__load_sym(self, fd, name, filter, v, mod); | 866 | err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v); |
826 | close(fd); | 867 | close(fd); |
827 | 868 | ||
828 | return err; | 869 | return err; |
829 | } | 870 | } |
830 | 871 | ||
831 | int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) | 872 | static int dsos__load_modules_sym_dir(char *dirname, |
873 | symbol_filter_t filter, int v) | ||
832 | { | 874 | { |
833 | struct mod_dso *mods = mod_dso__new_dso("modules"); | 875 | struct dirent *dent; |
834 | struct module *pos; | 876 | int nr_symbols = 0, err; |
835 | struct rb_node *next; | 877 | DIR *dir = opendir(dirname); |
836 | int err, count = 0; | ||
837 | 878 | ||
838 | err = mod_dso__load_modules(mods); | 879 | if (!dir) { |
880 | if (v) | ||
881 | fprintf(stderr, "%s: cannot open %s dir\n", __func__, | ||
882 | dirname); | ||
883 | return -1; | ||
884 | } | ||
839 | 885 | ||
840 | if (err <= 0) | 886 | while ((dent = readdir(dir)) != NULL) { |
841 | return err; | 887 | char path[PATH_MAX]; |
888 | |||
889 | if (dent->d_type == DT_DIR) { | ||
890 | if (!strcmp(dent->d_name, ".") || | ||
891 | !strcmp(dent->d_name, "..")) | ||
892 | continue; | ||
893 | |||
894 | snprintf(path, sizeof(path), "%s/%s", | ||
895 | dirname, dent->d_name); | ||
896 | err = dsos__load_modules_sym_dir(path, filter, v); | ||
897 | if (err < 0) | ||
898 | goto failure; | ||
899 | } else { | ||
900 | char *dot = strrchr(dent->d_name, '.'), | ||
901 | dso_name[PATH_MAX]; | ||
902 | struct map *map; | ||
903 | struct rb_node *last; | ||
904 | |||
905 | if (dot == NULL || strcmp(dot, ".ko")) | ||
906 | continue; | ||
907 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | ||
908 | (int)(dot - dent->d_name), dent->d_name); | ||
909 | |||
910 | map = kernel_maps__find_by_dso_name(dso_name); | ||
911 | if (map == NULL) | ||
912 | continue; | ||
913 | |||
914 | snprintf(path, sizeof(path), "%s/%s", | ||
915 | dirname, dent->d_name); | ||
916 | |||
917 | map->dso->long_name = strdup(path); | ||
918 | if (map->dso->long_name == NULL) | ||
919 | goto failure; | ||
920 | |||
921 | err = dso__load_module_sym(map->dso, map, filter, v); | ||
922 | if (err < 0) | ||
923 | goto failure; | ||
924 | last = rb_last(&map->dso->syms); | ||
925 | if (last) { | ||
926 | struct symbol *sym; | ||
927 | sym = rb_entry(last, struct symbol, rb_node); | ||
928 | map->end = map->start + sym->end; | ||
929 | } | ||
930 | } | ||
931 | nr_symbols += err; | ||
932 | } | ||
842 | 933 | ||
843 | /* | 934 | return nr_symbols; |
844 | * Iterate over modules, and load active symbols. | 935 | failure: |
845 | */ | 936 | closedir(dir); |
846 | next = rb_first(&mods->mods); | 937 | return -1; |
847 | while (next) { | 938 | } |
848 | pos = rb_entry(next, struct module, rb_node); | ||
849 | err = dso__load_module(self, mods, pos->name, filter, v); | ||
850 | 939 | ||
851 | if (err < 0) | 940 | static int dsos__load_modules_sym(symbol_filter_t filter, int v) |
852 | break; | 941 | { |
942 | struct utsname uts; | ||
943 | char modules_path[PATH_MAX]; | ||
853 | 944 | ||
854 | next = rb_next(&pos->rb_node); | 945 | if (uname(&uts) < 0) |
855 | count += err; | 946 | return -1; |
856 | } | ||
857 | 947 | ||
858 | if (err < 0) { | 948 | snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", |
859 | mod_dso__delete_modules(mods); | 949 | uts.release); |
860 | mod_dso__delete_self(mods); | ||
861 | return err; | ||
862 | } | ||
863 | 950 | ||
864 | return count; | 951 | return dsos__load_modules_sym_dir(modules_path, filter, v); |
865 | } | 952 | } |
866 | 953 | ||
867 | static inline void dso__fill_symbol_holes(struct dso *self) | 954 | /* |
955 | * Constructor variant for modules (where we know from /proc/modules where | ||
956 | * they are loaded) and for vmlinux, where only after we load all the | ||
957 | * symbols we'll know where it starts and ends. | ||
958 | */ | ||
959 | static struct map *map__new2(u64 start, struct dso *dso) | ||
868 | { | 960 | { |
869 | struct symbol *prev = NULL; | 961 | struct map *self = malloc(sizeof(*self)); |
870 | struct rb_node *nd; | ||
871 | 962 | ||
872 | for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { | 963 | if (self != NULL) { |
873 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | 964 | self->start = start; |
965 | /* | ||
966 | * Will be filled after we load all the symbols | ||
967 | */ | ||
968 | self->end = 0; | ||
969 | |||
970 | self->pgoff = 0; | ||
971 | self->dso = dso; | ||
972 | self->map_ip = map__map_ip; | ||
973 | RB_CLEAR_NODE(&self->rb_node); | ||
974 | } | ||
975 | return self; | ||
976 | } | ||
977 | |||
978 | int dsos__load_modules(unsigned int sym_priv_size, | ||
979 | symbol_filter_t filter, int v) | ||
980 | { | ||
981 | char *line = NULL; | ||
982 | size_t n; | ||
983 | FILE *file = fopen("/proc/modules", "r"); | ||
984 | struct map *map; | ||
874 | 985 | ||
875 | if (prev) { | 986 | if (file == NULL) |
876 | u64 hole = 0; | 987 | return -1; |
877 | int alias = pos->start == prev->start; | ||
878 | 988 | ||
879 | if (!alias) | 989 | while (!feof(file)) { |
880 | hole = prev->start - pos->end - 1; | 990 | char name[PATH_MAX]; |
991 | u64 start; | ||
992 | struct dso *dso; | ||
993 | char *sep; | ||
994 | int line_len; | ||
881 | 995 | ||
882 | if (hole || alias) { | 996 | line_len = getline(&line, &n, file); |
883 | if (alias) | 997 | if (line_len < 0) |
884 | pos->end = prev->end; | 998 | break; |
885 | else if (hole) | 999 | |
886 | pos->end = prev->start - 1; | 1000 | if (!line) |
887 | } | 1001 | goto out_failure; |
1002 | |||
1003 | line[--line_len] = '\0'; /* \n */ | ||
1004 | |||
1005 | sep = strrchr(line, 'x'); | ||
1006 | if (sep == NULL) | ||
1007 | continue; | ||
1008 | |||
1009 | hex2u64(sep + 1, &start); | ||
1010 | |||
1011 | sep = strchr(line, ' '); | ||
1012 | if (sep == NULL) | ||
1013 | continue; | ||
1014 | |||
1015 | *sep = '\0'; | ||
1016 | |||
1017 | snprintf(name, sizeof(name), "[%s]", line); | ||
1018 | dso = dso__new(name, sym_priv_size); | ||
1019 | |||
1020 | if (dso == NULL) | ||
1021 | goto out_delete_line; | ||
1022 | |||
1023 | map = map__new2(start, dso); | ||
1024 | if (map == NULL) { | ||
1025 | dso__delete(dso); | ||
1026 | goto out_delete_line; | ||
888 | } | 1027 | } |
889 | prev = pos; | 1028 | |
1029 | dso->origin = DSO__ORIG_KMODULE; | ||
1030 | kernel_maps__insert(map); | ||
1031 | dsos__add(dso); | ||
890 | } | 1032 | } |
1033 | |||
1034 | free(line); | ||
1035 | fclose(file); | ||
1036 | |||
1037 | v = 1; | ||
1038 | return dsos__load_modules_sym(filter, v); | ||
1039 | |||
1040 | out_delete_line: | ||
1041 | free(line); | ||
1042 | out_failure: | ||
1043 | return -1; | ||
891 | } | 1044 | } |
892 | 1045 | ||
893 | static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | 1046 | static int dso__load_vmlinux(struct dso *self, struct map *map, |
1047 | const char *vmlinux, | ||
894 | symbol_filter_t filter, int v) | 1048 | symbol_filter_t filter, int v) |
895 | { | 1049 | { |
896 | int err, fd = open(vmlinux, O_RDONLY); | 1050 | int err, fd = open(vmlinux, O_RDONLY); |
@@ -898,28 +1052,36 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | |||
898 | if (fd < 0) | 1052 | if (fd < 0) |
899 | return -1; | 1053 | return -1; |
900 | 1054 | ||
901 | err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); | 1055 | err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v); |
902 | |||
903 | if (err > 0) | ||
904 | dso__fill_symbol_holes(self); | ||
905 | 1056 | ||
906 | close(fd); | 1057 | close(fd); |
907 | 1058 | ||
908 | return err; | 1059 | return err; |
909 | } | 1060 | } |
910 | 1061 | ||
911 | int dso__load_kernel(struct dso *self, const char *vmlinux, | 1062 | int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, |
912 | symbol_filter_t filter, int v, int use_modules) | 1063 | symbol_filter_t filter, int v, int use_modules) |
913 | { | 1064 | { |
914 | int err = -1; | 1065 | int err = -1; |
1066 | struct dso *dso = dso__new(vmlinux, sym_priv_size); | ||
1067 | |||
1068 | if (dso == NULL) | ||
1069 | return -1; | ||
1070 | |||
1071 | dso->short_name = "[kernel]"; | ||
1072 | kernel_map = map__new2(0, dso); | ||
1073 | if (kernel_map == NULL) | ||
1074 | goto out_delete_dso; | ||
1075 | |||
1076 | kernel_map->map_ip = vdso__map_ip; | ||
915 | 1077 | ||
916 | if (vmlinux) { | 1078 | if (vmlinux) { |
917 | err = dso__load_vmlinux(self, vmlinux, filter, v); | 1079 | err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); |
918 | if (err > 0 && use_modules) { | 1080 | if (err > 0 && use_modules) { |
919 | int syms = dso__load_modules(self, filter, v); | 1081 | int syms = dsos__load_modules(sym_priv_size, filter, v); |
920 | 1082 | ||
921 | if (syms < 0) { | 1083 | if (syms < 0) { |
922 | fprintf(stderr, "dso__load_modules failed!\n"); | 1084 | fprintf(stderr, "dsos__load_modules failed!\n"); |
923 | return syms; | 1085 | return syms; |
924 | } | 1086 | } |
925 | err += syms; | 1087 | err += syms; |
@@ -927,18 +1089,34 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, | |||
927 | } | 1089 | } |
928 | 1090 | ||
929 | if (err <= 0) | 1091 | if (err <= 0) |
930 | err = dso__load_kallsyms(self, filter, v); | 1092 | err = dso__load_kallsyms(dso, kernel_map, filter, v); |
1093 | |||
1094 | if (err > 0) { | ||
1095 | struct rb_node *node = rb_first(&dso->syms); | ||
1096 | struct symbol *sym = rb_entry(node, struct symbol, rb_node); | ||
931 | 1097 | ||
932 | if (err > 0) | 1098 | kernel_map->start = sym->start; |
933 | self->origin = DSO__ORIG_KERNEL; | 1099 | node = rb_last(&dso->syms); |
1100 | sym = rb_entry(node, struct symbol, rb_node); | ||
1101 | kernel_map->end = sym->end; | ||
1102 | |||
1103 | dso->origin = DSO__ORIG_KERNEL; | ||
1104 | /* | ||
1105 | * XXX See kernel_maps__find_symbol comment | ||
1106 | * kernel_maps__insert(kernel_map) | ||
1107 | */ | ||
1108 | dsos__add(dso); | ||
1109 | } | ||
934 | 1110 | ||
935 | return err; | 1111 | return err; |
1112 | |||
1113 | out_delete_dso: | ||
1114 | dso__delete(dso); | ||
1115 | return -1; | ||
936 | } | 1116 | } |
937 | 1117 | ||
938 | LIST_HEAD(dsos); | 1118 | LIST_HEAD(dsos); |
939 | struct dso *kernel_dso; | ||
940 | struct dso *vdso; | 1119 | struct dso *vdso; |
941 | struct dso *hypervisor_dso; | ||
942 | 1120 | ||
943 | const char *vmlinux_name = "vmlinux"; | 1121 | const char *vmlinux_name = "vmlinux"; |
944 | int modules; | 1122 | int modules; |
@@ -970,7 +1148,7 @@ struct dso *dsos__findnew(const char *name) | |||
970 | if (!dso) | 1148 | if (!dso) |
971 | goto out_delete_dso; | 1149 | goto out_delete_dso; |
972 | 1150 | ||
973 | nr = dso__load(dso, NULL, verbose); | 1151 | nr = dso__load(dso, NULL, NULL, verbose); |
974 | if (nr < 0) { | 1152 | if (nr < 0) { |
975 | eprintf("Failed to open: %s\n", name); | 1153 | eprintf("Failed to open: %s\n", name); |
976 | goto out_delete_dso; | 1154 | goto out_delete_dso; |
@@ -995,43 +1173,20 @@ void dsos__fprintf(FILE *fp) | |||
995 | dso__fprintf(pos, fp); | 1173 | dso__fprintf(pos, fp); |
996 | } | 1174 | } |
997 | 1175 | ||
998 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) | ||
999 | { | ||
1000 | return dso__find_symbol(dso, ip); | ||
1001 | } | ||
1002 | |||
1003 | int load_kernel(void) | 1176 | int load_kernel(void) |
1004 | { | 1177 | { |
1005 | int err; | 1178 | if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0) |
1006 | |||
1007 | kernel_dso = dso__new("[kernel]", 0); | ||
1008 | if (!kernel_dso) | ||
1009 | return -1; | 1179 | return -1; |
1010 | 1180 | ||
1011 | err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); | ||
1012 | if (err <= 0) { | ||
1013 | dso__delete(kernel_dso); | ||
1014 | kernel_dso = NULL; | ||
1015 | } else | ||
1016 | dsos__add(kernel_dso); | ||
1017 | |||
1018 | vdso = dso__new("[vdso]", 0); | 1181 | vdso = dso__new("[vdso]", 0); |
1019 | if (!vdso) | 1182 | if (!vdso) |
1020 | return -1; | 1183 | return -1; |
1021 | 1184 | ||
1022 | vdso->find_symbol = vdso__find_symbol; | ||
1023 | |||
1024 | dsos__add(vdso); | 1185 | dsos__add(vdso); |
1025 | 1186 | ||
1026 | hypervisor_dso = dso__new("[hypervisor]", 0); | 1187 | return 0; |
1027 | if (!hypervisor_dso) | ||
1028 | return -1; | ||
1029 | dsos__add(hypervisor_dso); | ||
1030 | |||
1031 | return err; | ||
1032 | } | 1188 | } |
1033 | 1189 | ||
1034 | |||
1035 | void symbol__init(void) | 1190 | void symbol__init(void) |
1036 | { | 1191 | { |
1037 | elf_version(EV_CURRENT); | 1192 | elf_version(EV_CURRENT); |