diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 268 |
1 files changed, 209 insertions, 59 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7508ad3450f..d3d9fed74f1d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -29,11 +29,9 @@ enum dso_origin { | |||
29 | }; | 29 | }; |
30 | 30 | ||
31 | static void dsos__add(struct list_head *head, struct dso *dso); | 31 | static void dsos__add(struct list_head *head, struct dso *dso); |
32 | static struct map *thread__find_map_by_name(struct thread *self, char *name); | ||
33 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 32 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
34 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); | ||
35 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 33 | static int dso__load_kernel_sym(struct dso *self, struct map *map, |
36 | struct thread *thread, symbol_filter_t filter); | 34 | struct map_groups *mg, symbol_filter_t filter); |
37 | unsigned int symbol__priv_size; | 35 | unsigned int symbol__priv_size; |
38 | static int vmlinux_path__nr_entries; | 36 | static int vmlinux_path__nr_entries; |
39 | static char **vmlinux_path; | 37 | static char **vmlinux_path; |
@@ -43,19 +41,41 @@ static struct symbol_conf symbol_conf__defaults = { | |||
43 | .try_vmlinux_path = true, | 41 | .try_vmlinux_path = true, |
44 | }; | 42 | }; |
45 | 43 | ||
46 | static struct thread kthread_mem; | 44 | static struct map_groups kmaps_mem; |
47 | struct thread *kthread = &kthread_mem; | 45 | struct map_groups *kmaps = &kmaps_mem; |
48 | 46 | ||
49 | bool dso__loaded(const struct dso *self, enum map_type type) | 47 | bool dso__loaded(const struct dso *self, enum map_type type) |
50 | { | 48 | { |
51 | return self->loaded & (1 << type); | 49 | return self->loaded & (1 << type); |
52 | } | 50 | } |
53 | 51 | ||
52 | bool dso__sorted_by_name(const struct dso *self, enum map_type type) | ||
53 | { | ||
54 | return self->sorted_by_name & (1 << type); | ||
55 | } | ||
56 | |||
54 | static void dso__set_loaded(struct dso *self, enum map_type type) | 57 | static void dso__set_loaded(struct dso *self, enum map_type type) |
55 | { | 58 | { |
56 | self->loaded |= (1 << type); | 59 | self->loaded |= (1 << type); |
57 | } | 60 | } |
58 | 61 | ||
62 | static void dso__set_sorted_by_name(struct dso *self, enum map_type type) | ||
63 | { | ||
64 | self->sorted_by_name |= (1 << type); | ||
65 | } | ||
66 | |||
67 | static bool symbol_type__is_a(char symbol_type, enum map_type map_type) | ||
68 | { | ||
69 | switch (map_type) { | ||
70 | case MAP__FUNCTION: | ||
71 | return symbol_type == 'T' || symbol_type == 'W'; | ||
72 | case MAP__VARIABLE: | ||
73 | return symbol_type == 'D' || symbol_type == 'd'; | ||
74 | default: | ||
75 | return false; | ||
76 | } | ||
77 | } | ||
78 | |||
59 | static void symbols__fixup_end(struct rb_root *self) | 79 | static void symbols__fixup_end(struct rb_root *self) |
60 | { | 80 | { |
61 | struct rb_node *nd, *prevnd = rb_first(self); | 81 | struct rb_node *nd, *prevnd = rb_first(self); |
@@ -79,7 +99,7 @@ static void symbols__fixup_end(struct rb_root *self) | |||
79 | curr->end = roundup(curr->start, 4096); | 99 | curr->end = roundup(curr->start, 4096); |
80 | } | 100 | } |
81 | 101 | ||
82 | static void __thread__fixup_maps_end(struct thread *self, enum map_type type) | 102 | static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) |
83 | { | 103 | { |
84 | struct map *prev, *curr; | 104 | struct map *prev, *curr; |
85 | struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); | 105 | struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); |
@@ -102,11 +122,11 @@ static void __thread__fixup_maps_end(struct thread *self, enum map_type type) | |||
102 | curr->end = ~0UL; | 122 | curr->end = ~0UL; |
103 | } | 123 | } |
104 | 124 | ||
105 | static void thread__fixup_maps_end(struct thread *self) | 125 | static void map_groups__fixup_end(struct map_groups *self) |
106 | { | 126 | { |
107 | int i; | 127 | int i; |
108 | for (i = 0; i < MAP__NR_TYPES; ++i) | 128 | for (i = 0; i < MAP__NR_TYPES; ++i) |
109 | __thread__fixup_maps_end(self, i); | 129 | __map_groups__fixup_end(self, i); |
110 | } | 130 | } |
111 | 131 | ||
112 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) | 132 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) |
@@ -164,11 +184,11 @@ struct dso *dso__new(const char *name) | |||
164 | dso__set_long_name(self, self->name); | 184 | dso__set_long_name(self, self->name); |
165 | self->short_name = self->name; | 185 | self->short_name = self->name; |
166 | for (i = 0; i < MAP__NR_TYPES; ++i) | 186 | for (i = 0; i < MAP__NR_TYPES; ++i) |
167 | self->symbols[i] = RB_ROOT; | 187 | self->symbols[i] = self->symbol_names[i] = RB_ROOT; |
168 | self->find_symbol = dso__find_symbol; | ||
169 | self->slen_calculated = 0; | 188 | self->slen_calculated = 0; |
170 | self->origin = DSO__ORIG_NOT_FOUND; | 189 | self->origin = DSO__ORIG_NOT_FOUND; |
171 | self->loaded = 0; | 190 | self->loaded = 0; |
191 | self->sorted_by_name = 0; | ||
172 | self->has_build_id = 0; | 192 | self->has_build_id = 0; |
173 | } | 193 | } |
174 | 194 | ||
@@ -246,11 +266,85 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip) | |||
246 | return NULL; | 266 | return NULL; |
247 | } | 267 | } |
248 | 268 | ||
249 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) | 269 | struct symbol_name_rb_node { |
270 | struct rb_node rb_node; | ||
271 | struct symbol sym; | ||
272 | }; | ||
273 | |||
274 | static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) | ||
275 | { | ||
276 | struct rb_node **p = &self->rb_node; | ||
277 | struct rb_node *parent = NULL; | ||
278 | struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; | ||
279 | |||
280 | while (*p != NULL) { | ||
281 | parent = *p; | ||
282 | s = rb_entry(parent, struct symbol_name_rb_node, rb_node); | ||
283 | if (strcmp(sym->name, s->sym.name) < 0) | ||
284 | p = &(*p)->rb_left; | ||
285 | else | ||
286 | p = &(*p)->rb_right; | ||
287 | } | ||
288 | rb_link_node(&symn->rb_node, parent, p); | ||
289 | rb_insert_color(&symn->rb_node, self); | ||
290 | } | ||
291 | |||
292 | static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) | ||
293 | { | ||
294 | struct rb_node *nd; | ||
295 | |||
296 | for (nd = rb_first(source); nd; nd = rb_next(nd)) { | ||
297 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
298 | symbols__insert_by_name(self, pos); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) | ||
303 | { | ||
304 | struct rb_node *n; | ||
305 | |||
306 | if (self == NULL) | ||
307 | return NULL; | ||
308 | |||
309 | n = self->rb_node; | ||
310 | |||
311 | while (n) { | ||
312 | struct symbol_name_rb_node *s; | ||
313 | int cmp; | ||
314 | |||
315 | s = rb_entry(n, struct symbol_name_rb_node, rb_node); | ||
316 | cmp = strcmp(name, s->sym.name); | ||
317 | |||
318 | if (cmp < 0) | ||
319 | n = n->rb_left; | ||
320 | else if (cmp > 0) | ||
321 | n = n->rb_right; | ||
322 | else | ||
323 | return &s->sym; | ||
324 | } | ||
325 | |||
326 | return NULL; | ||
327 | } | ||
328 | |||
329 | struct symbol *dso__find_symbol(struct dso *self, | ||
330 | enum map_type type, u64 addr) | ||
250 | { | 331 | { |
251 | return symbols__find(&self->symbols[type], addr); | 332 | return symbols__find(&self->symbols[type], addr); |
252 | } | 333 | } |
253 | 334 | ||
335 | struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, | ||
336 | const char *name) | ||
337 | { | ||
338 | return symbols__find_by_name(&self->symbol_names[type], name); | ||
339 | } | ||
340 | |||
341 | void dso__sort_by_name(struct dso *self, enum map_type type) | ||
342 | { | ||
343 | dso__set_sorted_by_name(self, type); | ||
344 | return symbols__sort_by_name(&self->symbol_names[type], | ||
345 | &self->symbols[type]); | ||
346 | } | ||
347 | |||
254 | int build_id__sprintf(u8 *self, int len, char *bf) | 348 | int build_id__sprintf(u8 *self, int len, char *bf) |
255 | { | 349 | { |
256 | char *bid = bf; | 350 | char *bid = bf; |
@@ -327,10 +421,7 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map) | |||
327 | continue; | 421 | continue; |
328 | 422 | ||
329 | symbol_type = toupper(line[len]); | 423 | symbol_type = toupper(line[len]); |
330 | /* | 424 | if (!symbol_type__is_a(symbol_type, map->type)) |
331 | * We're interested only in code ('T'ext) | ||
332 | */ | ||
333 | if (symbol_type != 'T' && symbol_type != 'W') | ||
334 | continue; | 425 | continue; |
335 | 426 | ||
336 | symbol_name = line + len + 2; | 427 | symbol_name = line + len + 2; |
@@ -364,8 +455,8 @@ out_failure: | |||
364 | * kernel range is broken in several maps, named [kernel].N, as we don't have | 455 | * kernel range is broken in several maps, named [kernel].N, as we don't have |
365 | * the original ELF section names vmlinux have. | 456 | * the original ELF section names vmlinux have. |
366 | */ | 457 | */ |
367 | static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, | 458 | static int dso__split_kallsyms(struct dso *self, struct map *map, |
368 | symbol_filter_t filter) | 459 | struct map_groups *mg, symbol_filter_t filter) |
369 | { | 460 | { |
370 | struct map *curr_map = map; | 461 | struct map *curr_map = map; |
371 | struct symbol *pos; | 462 | struct symbol *pos; |
@@ -382,13 +473,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread | |||
382 | 473 | ||
383 | module = strchr(pos->name, '\t'); | 474 | module = strchr(pos->name, '\t'); |
384 | if (module) { | 475 | if (module) { |
385 | if (!thread->use_modules) | 476 | if (!mg->use_modules) |
386 | goto discard_symbol; | 477 | goto discard_symbol; |
387 | 478 | ||
388 | *module++ = '\0'; | 479 | *module++ = '\0'; |
389 | 480 | ||
390 | if (strcmp(self->name, module)) { | 481 | if (strcmp(self->name, module)) { |
391 | curr_map = thread__find_map_by_name(thread, module); | 482 | curr_map = map_groups__find_by_name(mg, map->type, module); |
392 | if (curr_map == NULL) { | 483 | if (curr_map == NULL) { |
393 | pr_debug("/proc/{kallsyms,modules} " | 484 | pr_debug("/proc/{kallsyms,modules} " |
394 | "inconsistency!\n"); | 485 | "inconsistency!\n"); |
@@ -419,7 +510,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread | |||
419 | } | 510 | } |
420 | 511 | ||
421 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; | 512 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; |
422 | __thread__insert_map(thread, curr_map); | 513 | map_groups__insert(mg, curr_map); |
423 | ++kernel_range; | 514 | ++kernel_range; |
424 | } | 515 | } |
425 | 516 | ||
@@ -440,7 +531,7 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
440 | 531 | ||
441 | 532 | ||
442 | static int dso__load_kallsyms(struct dso *self, struct map *map, | 533 | static int dso__load_kallsyms(struct dso *self, struct map *map, |
443 | struct thread *thread, symbol_filter_t filter) | 534 | struct map_groups *mg, symbol_filter_t filter) |
444 | { | 535 | { |
445 | if (dso__load_all_kallsyms(self, map) < 0) | 536 | if (dso__load_all_kallsyms(self, map) < 0) |
446 | return -1; | 537 | return -1; |
@@ -448,13 +539,13 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, | |||
448 | symbols__fixup_end(&self->symbols[map->type]); | 539 | symbols__fixup_end(&self->symbols[map->type]); |
449 | self->origin = DSO__ORIG_KERNEL; | 540 | self->origin = DSO__ORIG_KERNEL; |
450 | 541 | ||
451 | return dso__split_kallsyms(self, map, thread, filter); | 542 | return dso__split_kallsyms(self, map, mg, filter); |
452 | } | 543 | } |
453 | 544 | ||
454 | size_t kernel_maps__fprintf(FILE *fp) | 545 | size_t kernel_maps__fprintf(FILE *fp) |
455 | { | 546 | { |
456 | size_t printed = fprintf(fp, "Kernel maps:\n"); | 547 | size_t printed = fprintf(fp, "Kernel maps:\n"); |
457 | printed += thread__fprintf_maps(kthread, fp); | 548 | printed += map_groups__fprintf_maps(kmaps, fp); |
458 | return printed + fprintf(fp, "END kernel maps\n"); | 549 | return printed + fprintf(fp, "END kernel maps\n"); |
459 | } | 550 | } |
460 | 551 | ||
@@ -544,6 +635,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym) | |||
544 | sym->st_shndx != SHN_UNDEF; | 635 | sym->st_shndx != SHN_UNDEF; |
545 | } | 636 | } |
546 | 637 | ||
638 | static inline bool elf_sym__is_object(const GElf_Sym *sym) | ||
639 | { | ||
640 | return elf_sym__type(sym) == STT_OBJECT && | ||
641 | sym->st_name != 0 && | ||
642 | sym->st_shndx != SHN_UNDEF; | ||
643 | } | ||
644 | |||
547 | static inline int elf_sym__is_label(const GElf_Sym *sym) | 645 | static inline int elf_sym__is_label(const GElf_Sym *sym) |
548 | { | 646 | { |
549 | return elf_sym__type(sym) == STT_NOTYPE && | 647 | return elf_sym__type(sym) == STT_NOTYPE && |
@@ -564,6 +662,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr, | |||
564 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; | 662 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; |
565 | } | 663 | } |
566 | 664 | ||
665 | static inline bool elf_sec__is_data(const GElf_Shdr *shdr, | ||
666 | const Elf_Data *secstrs) | ||
667 | { | ||
668 | return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; | ||
669 | } | ||
670 | |||
567 | static inline const char *elf_sym__name(const GElf_Sym *sym, | 671 | static inline const char *elf_sym__name(const GElf_Sym *sym, |
568 | const Elf_Data *symstrs) | 672 | const Elf_Data *symstrs) |
569 | { | 673 | { |
@@ -744,8 +848,32 @@ out: | |||
744 | return 0; | 848 | return 0; |
745 | } | 849 | } |
746 | 850 | ||
851 | static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) | ||
852 | { | ||
853 | switch (type) { | ||
854 | case MAP__FUNCTION: | ||
855 | return elf_sym__is_function(self); | ||
856 | case MAP__VARIABLE: | ||
857 | return elf_sym__is_object(self); | ||
858 | default: | ||
859 | return false; | ||
860 | } | ||
861 | } | ||
862 | |||
863 | static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) | ||
864 | { | ||
865 | switch (type) { | ||
866 | case MAP__FUNCTION: | ||
867 | return elf_sec__is_text(self, secstrs); | ||
868 | case MAP__VARIABLE: | ||
869 | return elf_sec__is_data(self, secstrs); | ||
870 | default: | ||
871 | return false; | ||
872 | } | ||
873 | } | ||
874 | |||
747 | static int dso__load_sym(struct dso *self, struct map *map, | 875 | static int dso__load_sym(struct dso *self, struct map *map, |
748 | struct thread *thread, const char *name, int fd, | 876 | struct map_groups *mg, const char *name, int fd, |
749 | symbol_filter_t filter, int kernel, int kmodule) | 877 | symbol_filter_t filter, int kernel, int kmodule) |
750 | { | 878 | { |
751 | struct map *curr_map = map; | 879 | struct map *curr_map = map; |
@@ -818,7 +946,7 @@ static int dso__load_sym(struct dso *self, struct map *map, | |||
818 | int is_label = elf_sym__is_label(&sym); | 946 | int is_label = elf_sym__is_label(&sym); |
819 | const char *section_name; | 947 | const char *section_name; |
820 | 948 | ||
821 | if (!is_label && !elf_sym__is_function(&sym)) | 949 | if (!is_label && !elf_sym__is_a(&sym, map->type)) |
822 | continue; | 950 | continue; |
823 | 951 | ||
824 | sec = elf_getscn(elf, sym.st_shndx); | 952 | sec = elf_getscn(elf, sym.st_shndx); |
@@ -827,7 +955,7 @@ static int dso__load_sym(struct dso *self, struct map *map, | |||
827 | 955 | ||
828 | gelf_getshdr(sec, &shdr); | 956 | gelf_getshdr(sec, &shdr); |
829 | 957 | ||
830 | if (is_label && !elf_sec__is_text(&shdr, secstrs)) | 958 | if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) |
831 | continue; | 959 | continue; |
832 | 960 | ||
833 | elf_name = elf_sym__name(&sym, symstrs); | 961 | elf_name = elf_sym__name(&sym, symstrs); |
@@ -849,7 +977,7 @@ static int dso__load_sym(struct dso *self, struct map *map, | |||
849 | snprintf(dso_name, sizeof(dso_name), | 977 | snprintf(dso_name, sizeof(dso_name), |
850 | "%s%s", self->short_name, section_name); | 978 | "%s%s", self->short_name, section_name); |
851 | 979 | ||
852 | curr_map = thread__find_map_by_name(thread, dso_name); | 980 | curr_map = map_groups__find_by_name(mg, map->type, dso_name); |
853 | if (curr_map == NULL) { | 981 | if (curr_map == NULL) { |
854 | u64 start = sym.st_value; | 982 | u64 start = sym.st_value; |
855 | 983 | ||
@@ -868,7 +996,7 @@ static int dso__load_sym(struct dso *self, struct map *map, | |||
868 | curr_map->map_ip = identity__map_ip; | 996 | curr_map->map_ip = identity__map_ip; |
869 | curr_map->unmap_ip = identity__map_ip; | 997 | curr_map->unmap_ip = identity__map_ip; |
870 | curr_dso->origin = DSO__ORIG_KERNEL; | 998 | curr_dso->origin = DSO__ORIG_KERNEL; |
871 | __thread__insert_map(kthread, curr_map); | 999 | map_groups__insert(kmaps, curr_map); |
872 | dsos__add(&dsos__kernel, curr_dso); | 1000 | dsos__add(&dsos__kernel, curr_dso); |
873 | } else | 1001 | } else |
874 | curr_dso = curr_map->dso; | 1002 | curr_dso = curr_map->dso; |
@@ -1094,7 +1222,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1094 | dso__set_loaded(self, map->type); | 1222 | dso__set_loaded(self, map->type); |
1095 | 1223 | ||
1096 | if (self->kernel) | 1224 | if (self->kernel) |
1097 | return dso__load_kernel_sym(self, map, kthread, filter); | 1225 | return dso__load_kernel_sym(self, map, kmaps, filter); |
1098 | 1226 | ||
1099 | name = malloc(size); | 1227 | name = malloc(size); |
1100 | if (!name) | 1228 | if (!name) |
@@ -1180,11 +1308,12 @@ out: | |||
1180 | return ret; | 1308 | return ret; |
1181 | } | 1309 | } |
1182 | 1310 | ||
1183 | static struct map *thread__find_map_by_name(struct thread *self, char *name) | 1311 | struct map *map_groups__find_by_name(struct map_groups *self, |
1312 | enum map_type type, const char *name) | ||
1184 | { | 1313 | { |
1185 | struct rb_node *nd; | 1314 | struct rb_node *nd; |
1186 | 1315 | ||
1187 | for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { | 1316 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { |
1188 | struct map *map = rb_entry(nd, struct map, rb_node); | 1317 | struct map *map = rb_entry(nd, struct map, rb_node); |
1189 | 1318 | ||
1190 | if (map->dso && strcmp(map->dso->name, name) == 0) | 1319 | if (map->dso && strcmp(map->dso->name, name) == 0) |
@@ -1228,7 +1357,7 @@ static int dsos__set_modules_path_dir(char *dirname) | |||
1228 | (int)(dot - dent->d_name), dent->d_name); | 1357 | (int)(dot - dent->d_name), dent->d_name); |
1229 | 1358 | ||
1230 | strxfrchar(dso_name, '-', '_'); | 1359 | strxfrchar(dso_name, '-', '_'); |
1231 | map = thread__find_map_by_name(kthread, dso_name); | 1360 | map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name); |
1232 | if (map == NULL) | 1361 | if (map == NULL) |
1233 | continue; | 1362 | continue; |
1234 | 1363 | ||
@@ -1281,7 +1410,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | |||
1281 | return self; | 1410 | return self; |
1282 | } | 1411 | } |
1283 | 1412 | ||
1284 | static int thread__create_module_maps(struct thread *self) | 1413 | static int map_groups__create_module_maps(struct map_groups *self) |
1285 | { | 1414 | { |
1286 | char *line = NULL; | 1415 | char *line = NULL; |
1287 | size_t n; | 1416 | size_t n; |
@@ -1338,7 +1467,7 @@ static int thread__create_module_maps(struct thread *self) | |||
1338 | dso->has_build_id = true; | 1467 | dso->has_build_id = true; |
1339 | 1468 | ||
1340 | dso->origin = DSO__ORIG_KMODULE; | 1469 | dso->origin = DSO__ORIG_KMODULE; |
1341 | __thread__insert_map(self, map); | 1470 | map_groups__insert(self, map); |
1342 | dsos__add(&dsos__kernel, dso); | 1471 | dsos__add(&dsos__kernel, dso); |
1343 | } | 1472 | } |
1344 | 1473 | ||
@@ -1353,7 +1482,8 @@ out_failure: | |||
1353 | return -1; | 1482 | return -1; |
1354 | } | 1483 | } |
1355 | 1484 | ||
1356 | static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, | 1485 | static int dso__load_vmlinux(struct dso *self, struct map *map, |
1486 | struct map_groups *mg, | ||
1357 | const char *vmlinux, symbol_filter_t filter) | 1487 | const char *vmlinux, symbol_filter_t filter) |
1358 | { | 1488 | { |
1359 | int err = -1, fd; | 1489 | int err = -1, fd; |
@@ -1387,14 +1517,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *t | |||
1387 | return -1; | 1517 | return -1; |
1388 | 1518 | ||
1389 | dso__set_loaded(self, map->type); | 1519 | dso__set_loaded(self, map->type); |
1390 | err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0); | 1520 | err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); |
1391 | close(fd); | 1521 | close(fd); |
1392 | 1522 | ||
1393 | return err; | 1523 | return err; |
1394 | } | 1524 | } |
1395 | 1525 | ||
1396 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 1526 | static int dso__load_kernel_sym(struct dso *self, struct map *map, |
1397 | struct thread *thread, symbol_filter_t filter) | 1527 | struct map_groups *mg, symbol_filter_t filter) |
1398 | { | 1528 | { |
1399 | int err; | 1529 | int err; |
1400 | bool is_kallsyms; | 1530 | bool is_kallsyms; |
@@ -1404,7 +1534,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1404 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", | 1534 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", |
1405 | vmlinux_path__nr_entries); | 1535 | vmlinux_path__nr_entries); |
1406 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { | 1536 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { |
1407 | err = dso__load_vmlinux(self, map, thread, | 1537 | err = dso__load_vmlinux(self, map, mg, |
1408 | vmlinux_path[i], filter); | 1538 | vmlinux_path[i], filter); |
1409 | if (err > 0) { | 1539 | if (err > 0) { |
1410 | pr_debug("Using %s for symbols\n", | 1540 | pr_debug("Using %s for symbols\n", |
@@ -1420,12 +1550,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1420 | if (is_kallsyms) | 1550 | if (is_kallsyms) |
1421 | goto do_kallsyms; | 1551 | goto do_kallsyms; |
1422 | 1552 | ||
1423 | err = dso__load_vmlinux(self, map, thread, self->long_name, filter); | 1553 | err = dso__load_vmlinux(self, map, mg, self->long_name, filter); |
1424 | if (err <= 0) { | 1554 | if (err <= 0) { |
1425 | pr_info("The file %s cannot be used, " | 1555 | pr_info("The file %s cannot be used, " |
1426 | "trying to use /proc/kallsyms...", self->long_name); | 1556 | "trying to use /proc/kallsyms...", self->long_name); |
1427 | do_kallsyms: | 1557 | do_kallsyms: |
1428 | err = dso__load_kallsyms(self, map, thread, filter); | 1558 | err = dso__load_kallsyms(self, map, mg, filter); |
1429 | if (err > 0 && !is_kallsyms) | 1559 | if (err > 0 && !is_kallsyms) |
1430 | dso__set_long_name(self, strdup("[kernel.kallsyms]")); | 1560 | dso__set_long_name(self, strdup("[kernel.kallsyms]")); |
1431 | } | 1561 | } |
@@ -1508,42 +1638,59 @@ size_t dsos__fprintf_buildid(FILE *fp) | |||
1508 | __dsos__fprintf_buildid(&dsos__user, fp)); | 1638 | __dsos__fprintf_buildid(&dsos__user, fp)); |
1509 | } | 1639 | } |
1510 | 1640 | ||
1511 | static int thread__create_kernel_map(struct thread *self, const char *vmlinux) | 1641 | static struct dso *dsos__create_kernel( const char *vmlinux) |
1512 | { | 1642 | { |
1513 | struct map *kmap; | ||
1514 | struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); | 1643 | struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); |
1515 | 1644 | ||
1516 | if (kernel == NULL) | 1645 | if (kernel == NULL) |
1517 | return -1; | 1646 | return NULL; |
1518 | |||
1519 | kmap = map__new2(0, kernel, MAP__FUNCTION); | ||
1520 | if (kmap == NULL) | ||
1521 | goto out_delete_kernel_dso; | ||
1522 | 1647 | ||
1523 | kmap->map_ip = kmap->unmap_ip = identity__map_ip; | ||
1524 | kernel->short_name = "[kernel]"; | 1648 | kernel->short_name = "[kernel]"; |
1525 | kernel->kernel = 1; | 1649 | kernel->kernel = 1; |
1526 | 1650 | ||
1527 | vdso = dso__new("[vdso]"); | 1651 | vdso = dso__new("[vdso]"); |
1528 | if (vdso == NULL) | 1652 | if (vdso == NULL) |
1529 | goto out_delete_kernel_map; | 1653 | goto out_delete_kernel_dso; |
1530 | dso__set_loaded(vdso, MAP__FUNCTION); | 1654 | dso__set_loaded(vdso, MAP__FUNCTION); |
1531 | 1655 | ||
1532 | if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, | 1656 | if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, |
1533 | sizeof(kernel->build_id)) == 0) | 1657 | sizeof(kernel->build_id)) == 0) |
1534 | kernel->has_build_id = true; | 1658 | kernel->has_build_id = true; |
1535 | 1659 | ||
1536 | __thread__insert_map(self, kmap); | ||
1537 | dsos__add(&dsos__kernel, kernel); | 1660 | dsos__add(&dsos__kernel, kernel); |
1538 | dsos__add(&dsos__user, vdso); | 1661 | dsos__add(&dsos__user, vdso); |
1539 | 1662 | ||
1540 | return 0; | 1663 | return kernel; |
1541 | 1664 | ||
1542 | out_delete_kernel_map: | ||
1543 | map__delete(kmap); | ||
1544 | out_delete_kernel_dso: | 1665 | out_delete_kernel_dso: |
1545 | dso__delete(kernel); | 1666 | dso__delete(kernel); |
1546 | return -1; | 1667 | return NULL; |
1668 | } | ||
1669 | |||
1670 | static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) | ||
1671 | { | ||
1672 | struct map *functions, *variables; | ||
1673 | struct dso *kernel = dsos__create_kernel(vmlinux); | ||
1674 | |||
1675 | if (kernel == NULL) | ||
1676 | return -1; | ||
1677 | |||
1678 | functions = map__new2(0, kernel, MAP__FUNCTION); | ||
1679 | if (functions == NULL) | ||
1680 | return -1; | ||
1681 | |||
1682 | variables = map__new2(0, kernel, MAP__VARIABLE); | ||
1683 | if (variables == NULL) { | ||
1684 | map__delete(functions); | ||
1685 | return -1; | ||
1686 | } | ||
1687 | |||
1688 | functions->map_ip = functions->unmap_ip = | ||
1689 | variables->map_ip = variables->unmap_ip = identity__map_ip; | ||
1690 | map_groups__insert(self, functions); | ||
1691 | map_groups__insert(self, variables); | ||
1692 | |||
1693 | return 0; | ||
1547 | } | 1694 | } |
1548 | 1695 | ||
1549 | static void vmlinux_path__exit(void) | 1696 | static void vmlinux_path__exit(void) |
@@ -1607,23 +1754,26 @@ int symbol__init(struct symbol_conf *conf) | |||
1607 | 1754 | ||
1608 | elf_version(EV_CURRENT); | 1755 | elf_version(EV_CURRENT); |
1609 | symbol__priv_size = pconf->priv_size; | 1756 | symbol__priv_size = pconf->priv_size; |
1610 | thread__init(kthread, 0); | 1757 | if (pconf->sort_by_name) |
1758 | symbol__priv_size += (sizeof(struct symbol_name_rb_node) - | ||
1759 | sizeof(struct symbol)); | ||
1760 | map_groups__init(kmaps); | ||
1611 | 1761 | ||
1612 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) | 1762 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) |
1613 | return -1; | 1763 | return -1; |
1614 | 1764 | ||
1615 | if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { | 1765 | if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { |
1616 | vmlinux_path__exit(); | 1766 | vmlinux_path__exit(); |
1617 | return -1; | 1767 | return -1; |
1618 | } | 1768 | } |
1619 | 1769 | ||
1620 | kthread->use_modules = pconf->use_modules; | 1770 | kmaps->use_modules = pconf->use_modules; |
1621 | if (pconf->use_modules && thread__create_module_maps(kthread) < 0) | 1771 | if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) |
1622 | pr_debug("Failed to load list of modules in use, " | 1772 | pr_debug("Failed to load list of modules in use, " |
1623 | "continuing...\n"); | 1773 | "continuing...\n"); |
1624 | /* | 1774 | /* |
1625 | * Now that we have all the maps created, just set the ->end of them: | 1775 | * Now that we have all the maps created, just set the ->end of them: |
1626 | */ | 1776 | */ |
1627 | thread__fixup_maps_end(kthread); | 1777 | map_groups__fixup_end(kmaps); |
1628 | return 0; | 1778 | return 0; |
1629 | } | 1779 | } |