aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-10-07 12:48:56 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-08 13:27:11 -0400
commit2e538c4a1847291cf01218d4fe7bb4dc60fef7cf (patch)
tree7c2b04cf627ef339feab565e5633a57f2ead5a49 /tools/perf/util/symbol.c
parentda21d1b547cbaa2c026cf645753651c25d340923 (diff)
perf tools: Improve kernel/modules symbol lookup
This removes the ovelapping of vmlinux addresses with modules, using the ELF section name when using --vmlinux and creating a unique DSO name when using /proc/kallsyms ([kernel].N). This is done by creating multiple 'struct map' instances for address ranges backed by DSOs that have just the symbols for that range and a name that is derived from the ELF section name.o Now it is possible to ask for just the symbols in some particular kernel section: $ perf report -m --vmlinux ../build/tip-recvmmsg/vmlinux \ --dsos [kernel].vsyscall_fn | head -15 52.73% Xorg [.] vread_hpet 18.61% firefox [.] vread_hpet 14.50% npviewer.bin [.] vread_hpet 6.83% compiz [.] vread_hpet 5.73% glxgears [.] vread_hpet 0.63% java [.] vread_hpet 0.30% gnome-terminal [.] vread_hpet 0.23% perf [.] vread_hpet 0.18% xchat [.] vread_hpet $ Now we don't have to first lookup the list of modules and then, if it fails, vmlinux symbols, its just a simple lookup for the map then the symbols, just like for threads. Reports generated using /proc/kallsyms and --vmlinux should provide the same results, modulo the DSO name for sections other than ".text". But they don't right now because things like: ffffffff81011c20-ffffffff81012068 system_call ffffffff81011c30-ffffffff81011c9b system_call_after_swapgs ffffffff81011c9c-ffffffff81011cb6 system_call_fastpath ffffffff81011cb7-ffffffff81011cbb ret_from_sys_call I.e. overlapping symbols, again some ASM special case that we have to fixup. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <1254934136-8503-1-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c288
1 files changed, 201 insertions, 87 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index a6887f94dfe..faa84f5d4f5 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -26,27 +26,35 @@ enum dso_origin {
26 26
27static void dsos__add(struct dso *dso); 27static void dsos__add(struct dso *dso);
28static struct dso *dsos__find(const char *name); 28static struct dso *dsos__find(const char *name);
29static struct map *map__new2(u64 start, struct dso *dso);
30static void kernel_maps__insert(struct map *map);
29 31
30static struct rb_root kernel_maps; 32static struct rb_root kernel_maps;
31 33
32static void dso__set_symbols_end(struct dso *self) 34static void dso__fixup_sym_end(struct dso *self)
33{ 35{
34 struct rb_node *nd, *prevnd = rb_first(&self->syms); 36 struct rb_node *nd, *prevnd = rb_first(&self->syms);
37 struct symbol *curr, *prev;
35 38
36 if (prevnd == NULL) 39 if (prevnd == NULL)
37 return; 40 return;
38 41
42 curr = rb_entry(prevnd, struct symbol, rb_node);
43
39 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 44 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
40 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), 45 prev = curr;
41 *curr = rb_entry(nd, struct symbol, rb_node); 46 curr = rb_entry(nd, struct symbol, rb_node);
42 47
43 if (prev->end == prev->start) 48 if (prev->end == prev->start)
44 prev->end = curr->start - 1; 49 prev->end = curr->start - 1;
45 prevnd = nd;
46 } 50 }
51
52 /* Last entry */
53 if (curr->end == curr->start)
54 curr->end = roundup(curr->start, 4096);
47} 55}
48 56
49static void kernel_maps__fixup_sym_end(void) 57static void kernel_maps__fixup_end(void)
50{ 58{
51 struct map *prev, *curr; 59 struct map *prev, *curr;
52 struct rb_node *nd, *prevnd = rb_first(&kernel_maps); 60 struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
@@ -55,13 +63,17 @@ static void kernel_maps__fixup_sym_end(void)
55 return; 63 return;
56 64
57 curr = rb_entry(prevnd, struct map, rb_node); 65 curr = rb_entry(prevnd, struct map, rb_node);
58 dso__set_symbols_end(curr->dso);
59 66
60 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 67 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
61 prev = curr; 68 prev = curr;
62 curr = rb_entry(nd, struct map, rb_node); 69 curr = rb_entry(nd, struct map, rb_node);
63 prev->end = curr->start - 1; 70 prev->end = curr->start - 1;
64 dso__set_symbols_end(curr->dso); 71 }
72
73 nd = rb_last(&curr->dso->syms);
74 if (nd) {
75 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
76 curr->end = sym->end;
65 } 77 }
66} 78}
67 79
@@ -200,13 +212,16 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
200 return ret; 212 return ret;
201} 213}
202 214
203static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v) 215/*
216 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
217 * so that we can in the next step set the symbol ->end address and then
218 * call kernel_maps__split_kallsyms.
219 */
220static int kernel_maps__load_all_kallsyms(int v)
204{ 221{
205 struct map *map = kernel_map;
206 char *line = NULL; 222 char *line = NULL;
207 size_t n; 223 size_t n;
208 FILE *file = fopen("/proc/kallsyms", "r"); 224 FILE *file = fopen("/proc/kallsyms", "r");
209 int count = 0;
210 225
211 if (file == NULL) 226 if (file == NULL)
212 goto out_failure; 227 goto out_failure;
@@ -216,7 +231,7 @@ static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v)
216 struct symbol *sym; 231 struct symbol *sym;
217 int line_len, len; 232 int line_len, len;
218 char symbol_type; 233 char symbol_type;
219 char *module, *symbol_name; 234 char *symbol_name;
220 235
221 line_len = getline(&line, &n, file); 236 line_len = getline(&line, &n, file);
222 if (line_len < 0) 237 if (line_len < 0)
@@ -241,20 +256,55 @@ static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v)
241 continue; 256 continue;
242 257
243 symbol_name = line + len + 2; 258 symbol_name = line + len + 2;
244 module = strchr(symbol_name, '\t'); 259 /*
245 if (module) { 260 * Will fix up the end later, when we have all symbols sorted.
246 char *module_name_end; 261 */
262 sym = symbol__new(start, 0, symbol_name,
263 kernel_map->dso->sym_priv_size, v);
247 264
265 if (sym == NULL)
266 goto out_delete_line;
267
268 dso__insert_symbol(kernel_map->dso, sym);
269 }
270
271 free(line);
272 fclose(file);
273
274 return 0;
275
276out_delete_line:
277 free(line);
278out_failure:
279 return -1;
280}
281
282/*
283 * Split the symbols into maps, making sure there are no overlaps, i.e. the
284 * kernel range is broken in several maps, named [kernel].N, as we don't have
285 * the original ELF section names vmlinux have.
286 */
287static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
288{
289 struct map *map = kernel_map;
290 struct symbol *pos;
291 int count = 0;
292 struct rb_node *next = rb_first(&kernel_map->dso->syms);
293 int kernel_range = 0;
294
295 while (next) {
296 char *module;
297
298 pos = rb_entry(next, struct symbol, rb_node);
299 next = rb_next(&pos->rb_node);
300
301 module = strchr(pos->name, '\t');
302 if (module) {
248 if (!use_modules) 303 if (!use_modules)
249 continue; 304 goto delete_symbol;
250 *module = '\0'; 305
251 module = strchr(module + 1, '['); 306 *module++ = '\0';
252 if (!module) 307
253 continue;
254 module_name_end = strchr(module + 1, ']');
255 if (!module_name_end)
256 continue;
257 *(module_name_end + 1) = '\0';
258 if (strcmp(map->dso->name, module)) { 308 if (strcmp(map->dso->name, module)) {
259 map = kernel_maps__find_by_dso_name(module); 309 map = kernel_maps__find_by_dso_name(module);
260 if (!map) { 310 if (!map) {
@@ -263,50 +313,77 @@ static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v)
263 return -1; 313 return -1;
264 } 314 }
265 } 315 }
266 start = map->map_ip(map, start); 316 /*
267 } else 317 * So that we look just like we get from .ko files,
268 map = kernel_map; 318 * i.e. not prelinked, relative to map->start.
269 /* 319 */
270 * Well fix up the end later, when we have all sorted. 320 pos->start = map->map_ip(map, pos->start);
271 */ 321 pos->end = map->map_ip(map, pos->end);
272 sym = symbol__new(start, 0, symbol_name, 322 } else if (map != kernel_map) {
273 map->dso->sym_priv_size, v); 323 char dso_name[PATH_MAX];
324 struct dso *dso;
325
326 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
327 kernel_range++);
328
329 dso = dso__new(dso_name,
330 kernel_map->dso->sym_priv_size);
331 if (dso == NULL)
332 return -1;
333
334 map = map__new2(pos->start, dso);
335 if (map == NULL) {
336 dso__delete(dso);
337 return -1;
338 }
274 339
275 if (sym == NULL) 340 map->map_ip = vdso__map_ip;
276 goto out_delete_line; 341 kernel_maps__insert(map);
342 ++kernel_range;
343 }
277 344
278 if (filter && filter(map, sym)) 345 if (filter && filter(map, pos)) {
279 symbol__delete(sym, map->dso->sym_priv_size); 346delete_symbol:
280 else { 347 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
281 dso__insert_symbol(map->dso, sym); 348 symbol__delete(pos, kernel_map->dso->sym_priv_size);
349 } else {
350 if (map != kernel_map) {
351 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
352 dso__insert_symbol(map->dso, pos);
353 }
282 count++; 354 count++;
283 } 355 }
284 } 356 }
285 357
286 free(line);
287 fclose(file);
288
289 return count; 358 return count;
359}
290 360
291out_delete_line: 361
292 free(line); 362static int kernel_maps__load_kallsyms(symbol_filter_t filter,
293out_failure: 363 int use_modules, int v)
294 return -1; 364{
365 if (kernel_maps__load_all_kallsyms(v))
366 return -1;
367
368 dso__fixup_sym_end(kernel_map->dso);
369
370 return kernel_maps__split_kallsyms(filter, use_modules);
295} 371}
296 372
297static size_t kernel_maps__fprintf(FILE *fp) 373static size_t kernel_maps__fprintf(FILE *fp, int v)
298{ 374{
299 size_t printed = fprintf(stderr, "Kernel maps:\n"); 375 size_t printed = fprintf(stderr, "Kernel maps:\n");
300 struct rb_node *nd; 376 struct rb_node *nd;
301 377
302 printed += map__fprintf(kernel_map, fp);
303 printed += dso__fprintf(kernel_map->dso, fp);
304
305 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 378 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
306 struct map *pos = rb_entry(nd, struct map, rb_node); 379 struct map *pos = rb_entry(nd, struct map, rb_node);
307 380
381 printed += fprintf(fp, "Map:");
308 printed += map__fprintf(pos, fp); 382 printed += map__fprintf(pos, fp);
309 printed += dso__fprintf(pos->dso, fp); 383 if (v > 1) {
384 printed += dso__fprintf(pos->dso, fp);
385 printed += fprintf(fp, "--\n");
386 }
310 } 387 }
311 388
312 return printed + fprintf(stderr, "END kernel maps\n"); 389 return printed + fprintf(stderr, "END kernel maps\n");
@@ -594,6 +671,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
594 int fd, symbol_filter_t filter, int kernel, 671 int fd, symbol_filter_t filter, int kernel,
595 int kmodule, int v) 672 int kmodule, int v)
596{ 673{
674 struct map *curr_map = map;
675 struct dso *curr_dso = self;
676 size_t dso_name_len = strlen(self->short_name);
597 Elf_Data *symstrs, *secstrs; 677 Elf_Data *symstrs, *secstrs;
598 uint32_t nr_syms; 678 uint32_t nr_syms;
599 int err = -1; 679 int err = -1;
@@ -660,10 +740,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
660 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 740 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
661 struct symbol *f; 741 struct symbol *f;
662 const char *elf_name; 742 const char *elf_name;
663 char *demangled; 743 char *demangled = NULL;
664 int is_label = elf_sym__is_label(&sym); 744 int is_label = elf_sym__is_label(&sym);
665 const char *section_name; 745 const char *section_name;
666 u64 sh_offset = 0;
667 746
668 if (!is_label && !elf_sym__is_function(&sym)) 747 if (!is_label && !elf_sym__is_function(&sym))
669 continue; 748 continue;
@@ -677,14 +756,51 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
677 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 756 if (is_label && !elf_sec__is_text(&shdr, secstrs))
678 continue; 757 continue;
679 758
759 elf_name = elf_sym__name(&sym, symstrs);
680 section_name = elf_sec__name(&shdr, secstrs); 760 section_name = elf_sec__name(&shdr, secstrs);
681 761
682 if ((kernel || kmodule)) { 762 if (kernel || kmodule) {
683 if (strstr(section_name, ".init")) 763 char dso_name[PATH_MAX];
684 sh_offset = shdr.sh_offset; 764
765 if (strcmp(section_name,
766 curr_dso->short_name + dso_name_len) == 0)
767 goto new_symbol;
768
769 if (strcmp(section_name, ".text") == 0) {
770 curr_map = map;
771 curr_dso = self;
772 goto new_symbol;
773 }
774
775 snprintf(dso_name, sizeof(dso_name),
776 "%s%s", self->short_name, section_name);
777
778 curr_map = kernel_maps__find_by_dso_name(dso_name);
779 if (curr_map == NULL) {
780 u64 start = sym.st_value;
781
782 if (kmodule)
783 start += map->start + shdr.sh_offset;
784
785 curr_dso = dso__new(dso_name, self->sym_priv_size);
786 if (curr_dso == NULL)
787 goto out_elf_end;
788 curr_map = map__new2(start, curr_dso);
789 if (curr_map == NULL) {
790 dso__delete(curr_dso);
791 goto out_elf_end;
792 }
793 curr_map->map_ip = vdso__map_ip;
794 curr_dso->origin = DSO__ORIG_KERNEL;
795 kernel_maps__insert(curr_map);
796 dsos__add(curr_dso);
797 } else
798 curr_dso = curr_map->dso;
799
800 goto new_symbol;
685 } 801 }
686 802
687 if (self->adjust_symbols) { 803 if (curr_dso->adjust_symbols) {
688 if (v > 2) 804 if (v > 2)
689 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 805 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
690 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 806 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
@@ -696,25 +812,29 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
696 * DWARF DW_compile_unit has this, but we don't always have access 812 * DWARF DW_compile_unit has this, but we don't always have access
697 * to it... 813 * to it...
698 */ 814 */
699 elf_name = elf_sym__name(&sym, symstrs);
700 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 815 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
701 if (demangled != NULL) 816 if (demangled != NULL)
702 elf_name = demangled; 817 elf_name = demangled;
703 818new_symbol:
704 f = symbol__new(sym.st_value + sh_offset, sym.st_size, elf_name, 819 f = symbol__new(sym.st_value, sym.st_size, elf_name,
705 self->sym_priv_size, v); 820 curr_dso->sym_priv_size, v);
706 free(demangled); 821 free(demangled);
707 if (!f) 822 if (!f)
708 goto out_elf_end; 823 goto out_elf_end;
709 824
710 if (filter && filter(map, f)) 825 if (filter && filter(curr_map, f))
711 symbol__delete(f, self->sym_priv_size); 826 symbol__delete(f, curr_dso->sym_priv_size);
712 else { 827 else {
713 dso__insert_symbol(self, f); 828 dso__insert_symbol(curr_dso, f);
714 nr++; 829 nr++;
715 } 830 }
716 } 831 }
717 832
833 /*
834 * For misannotated, zeroed, ASM function sizes.
835 */
836 if (nr > 0)
837 dso__fixup_sym_end(self);
718 err = nr; 838 err = nr;
719out_elf_end: 839out_elf_end:
720 elf_end(elf); 840 elf_end(elf);
@@ -883,27 +1003,17 @@ static void kernel_maps__insert(struct map *map)
883 1003
884struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) 1004struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
885{ 1005{
886 /*
887 * We can't have kernel_map in kernel_maps because it spans an address
888 * space that includes the modules. The right way to fix this is to
889 * create several maps, so that we don't have overlapping ranges with
890 * modules. For now lets look first on the kernel dso.
891 */
892 struct map *map = maps__find(&kernel_maps, ip); 1006 struct map *map = maps__find(&kernel_maps, ip);
893 struct symbol *sym; 1007
1008 if (mapp)
1009 *mapp = map;
894 1010
895 if (map) { 1011 if (map) {
896 ip = map->map_ip(map, ip); 1012 ip = map->map_ip(map, ip);
897 sym = map->dso->find_symbol(map->dso, ip); 1013 return map->dso->find_symbol(map->dso, ip);
898 } else {
899 map = kernel_map;
900 sym = map->dso->find_symbol(map->dso, ip);
901 } 1014 }
902 1015
903 if (mapp) 1016 return NULL;
904 *mapp = map;
905
906 return sym;
907} 1017}
908 1018
909struct map *kernel_maps__find_by_dso_name(const char *name) 1019struct map *kernel_maps__find_by_dso_name(const char *name)
@@ -994,6 +1104,14 @@ static int dsos__load_modules_sym_dir(char *dirname,
994 last = rb_last(&map->dso->syms); 1104 last = rb_last(&map->dso->syms);
995 if (last) { 1105 if (last) {
996 struct symbol *sym; 1106 struct symbol *sym;
1107 /*
1108 * We do this here as well, even having the
1109 * symbol size found in the symtab because
1110 * misannotated ASM symbols may have the size
1111 * set to zero.
1112 */
1113 dso__fixup_sym_end(map->dso);
1114
997 sym = rb_entry(last, struct symbol, rb_node); 1115 sym = rb_entry(last, struct symbol, rb_node);
998 map->end = map->start + sym->end; 1116 map->end = map->start + sym->end;
999 } 1117 }
@@ -1163,17 +1281,11 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
1163 } 1281 }
1164 1282
1165 if (err <= 0) 1283 if (err <= 0)
1166 err = maps__load_kallsyms(filter, use_modules, v); 1284 err = kernel_maps__load_kallsyms(filter, use_modules, v);
1167 1285
1168 if (err > 0) { 1286 if (err > 0) {
1169 struct rb_node *node = rb_first(&dso->syms); 1287 struct rb_node *node = rb_first(&dso->syms);
1170 struct symbol *sym = rb_entry(node, struct symbol, rb_node); 1288 struct symbol *sym = rb_entry(node, struct symbol, rb_node);
1171 /*
1172 * Now that we have all sorted out, just set the ->end of all
1173 * symbols that still don't have it.
1174 */
1175 dso__set_symbols_end(dso);
1176 kernel_maps__fixup_sym_end();
1177 1289
1178 kernel_map->start = sym->start; 1290 kernel_map->start = sym->start;
1179 node = rb_last(&dso->syms); 1291 node = rb_last(&dso->syms);
@@ -1181,14 +1293,16 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
1181 kernel_map->end = sym->end; 1293 kernel_map->end = sym->end;
1182 1294
1183 dso->origin = DSO__ORIG_KERNEL; 1295 dso->origin = DSO__ORIG_KERNEL;
1296 kernel_maps__insert(kernel_map);
1184 /* 1297 /*
1185 * XXX See kernel_maps__find_symbol comment 1298 * Now that we have all sorted out, just set the ->end of all
1186 * kernel_maps__insert(kernel_map) 1299 * maps:
1187 */ 1300 */
1301 kernel_maps__fixup_end();
1188 dsos__add(dso); 1302 dsos__add(dso);
1189 1303
1190 if (v > 0) 1304 if (v > 0)
1191 kernel_maps__fprintf(stderr); 1305 kernel_maps__fprintf(stderr, v);
1192 } 1306 }
1193 1307
1194 return err; 1308 return err;