aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-10-02 02:29:58 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-02 04:48:42 -0400
commit439d473b4777de510e1322168ac6f2f377ecd5bc (patch)
treef33622a0b98c2b0ce16637322d48542eb93e2fa3
parent2ccdc450e658053681202d42ac64b3638f22dc1a (diff)
perf tools: Rewrite and improve support for kernel modules
Representing modules as struct map entries, backed by a DSO, etc, using /proc/modules to find where the module is loaded. DSOs now can have a short and long name, so that in verbose mode we can show exactly which .ko or vmlinux image was used. As kernel modules now are a DSO separate from the kernel, we can ask for just the hits for a particular set of kernel modules, just like we can do with shared libraries: [root@doppio linux-2.6-tip]# perf report -n --vmlinux /home/acme/git/build/tip-recvmmsg/vmlinux --modules --dsos \[drm\] | head -15 84.58% 13266 Xorg [k] drm_clflush_pages 4.02% 630 Xorg [k] trace_kmalloc.clone.0 3.95% 619 Xorg [k] drm_ioctl 2.07% 324 Xorg [k] drm_addbufs 1.68% 263 Xorg [k] drm_gem_close_ioctl 0.77% 120 Xorg [k] drm_setmaster_ioctl 0.70% 110 Xorg [k] drm_lastclose 0.68% 106 Xorg [k] drm_open 0.54% 85 Xorg [k] drm_mm_search_free [root@doppio linux-2.6-tip]# Specifying --dsos /lib/modules/2.6.31-tip/kernel/drivers/gpu/drm/drm.ko would have the same effect. Allowing specifying just 'drm.ko' is left for another patch. Processing kallsyms so that per kernel module struct map are instantiated was also left for another patch. That will allow removing the module name from each of its symbols. struct symbol was reduced by removing the ->module backpointer and moving it (well now the map) to struct symbol_entry in perf top, that is its only user right now. The total linecount went down by ~500 lines. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Avi Kivity <avi@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/builtin-annotate.c73
-rw-r--r--tools/perf/builtin-report.c79
-rw-r--r--tools/perf/builtin-top.c74
-rw-r--r--tools/perf/util/event.h6
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/sort.c38
-rw-r--r--tools/perf/util/sort.h7
-rw-r--r--tools/perf/util/symbol.c447
-rw-r--r--tools/perf/util/symbol.h20
-rw-r--r--tools/perf/util/thread.c34
-rw-r--r--tools/perf/util/thread.h4
13 files changed, 453 insertions, 929 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 055290a5b835..8e7509f2d882 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -336,7 +336,6 @@ LIB_H += util/strlist.h
336LIB_H += util/run-command.h 336LIB_H += util/run-command.h
337LIB_H += util/sigchain.h 337LIB_H += util/sigchain.h
338LIB_H += util/symbol.h 338LIB_H += util/symbol.h
339LIB_H += util/module.h
340LIB_H += util/color.h 339LIB_H += util/color.h
341LIB_H += util/values.h 340LIB_H += util/values.h
342LIB_H += util/sort.h 341LIB_H += util/sort.h
@@ -364,7 +363,6 @@ LIB_OBJS += util/usage.o
364LIB_OBJS += util/wrapper.o 363LIB_OBJS += util/wrapper.o
365LIB_OBJS += util/sigchain.o 364LIB_OBJS += util/sigchain.o
366LIB_OBJS += util/symbol.o 365LIB_OBJS += util/symbol.o
367LIB_OBJS += util/module.o
368LIB_OBJS += util/color.o 366LIB_OBJS += util/color.o
369LIB_OBJS += util/pager.o 367LIB_OBJS += util/pager.o
370LIB_OBJS += util/header.o 368LIB_OBJS += util/header.o
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index df516dce9540..7d5a3b1bcda9 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -63,6 +63,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
63 return; 63 return;
64 64
65 sym_size = sym->end - sym->start; 65 sym_size = sym->end - sym->start;
66 ip = he->map->map_ip(he->map, ip);
66 offset = ip - sym->start; 67 offset = ip - sym->start;
67 68
68 if (offset >= sym_size) 69 if (offset >= sym_size)
@@ -80,7 +81,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
80} 81}
81 82
82static int 83static int
83hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 84hist_entry__add(struct thread *thread, struct map *map,
84 struct symbol *sym, u64 ip, char level) 85 struct symbol *sym, u64 ip, char level)
85{ 86{
86 struct rb_node **p = &hist.rb_node; 87 struct rb_node **p = &hist.rb_node;
@@ -89,7 +90,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
89 struct hist_entry entry = { 90 struct hist_entry entry = {
90 .thread = thread, 91 .thread = thread,
91 .map = map, 92 .map = map,
92 .dso = dso,
93 .sym = sym, 93 .sym = sym,
94 .ip = ip, 94 .ip = ip,
95 .level = level, 95 .level = level,
@@ -130,10 +130,10 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
130{ 130{
131 char level; 131 char level;
132 int show = 0; 132 int show = 0;
133 struct dso *dso = NULL;
134 struct thread *thread; 133 struct thread *thread;
135 u64 ip = event->ip.ip; 134 u64 ip = event->ip.ip;
136 struct map *map = NULL; 135 struct map *map = NULL;
136 struct symbol *sym = NULL;
137 137
138 thread = threads__findnew(event->ip.pid, &threads, &last_match); 138 thread = threads__findnew(event->ip.pid, &threads, &last_match);
139 139
@@ -155,32 +155,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
155 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 155 if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
156 show = SHOW_KERNEL; 156 show = SHOW_KERNEL;
157 level = 'k'; 157 level = 'k';
158 158 sym = kernel_maps__find_symbol(ip, &map);
159 dso = kernel_dso; 159 dump_printf(" ...... dso: %s\n",
160 160 map ? map->dso->long_name : "<not found>");
161 dump_printf(" ...... dso: %s\n", dso->name);
162
163 } else if (event->header.misc & PERF_RECORD_MISC_USER) { 161 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
164
165 show = SHOW_USER; 162 show = SHOW_USER;
166 level = '.'; 163 level = '.';
167
168 map = thread__find_map(thread, ip); 164 map = thread__find_map(thread, ip);
169 if (map != NULL) { 165 if (map != NULL) {
166got_map:
170 ip = map->map_ip(map, ip); 167 ip = map->map_ip(map, ip);
171 dso = map->dso; 168 sym = map->dso->find_symbol(map->dso, ip);
172 } else { 169 } else {
173 /* 170 /*
174 * If this is outside of all known maps, 171 * If this is outside of all known maps,
175 * and is a negative address, try to look it 172 * and is a negative address, try to look it
176 * up in the kernel dso, as it might be a 173 * up in the kernel dso, as it might be a
177 * vsyscall (which executes in user-mode): 174 * vsyscall or vdso (which executes in user-mode).
175 *
176 * XXX This is nasty, we should have a symbol list in
177 * the "[vdso]" dso, but for now lets use the old
178 * trick of looking in the whole kernel symbol list.
178 */ 179 */
179 if ((long long)ip < 0) 180 if ((long long)ip < 0) {
180 dso = kernel_dso; 181 map = kernel_map;
182 goto got_map;
183 }
181 } 184 }
182 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 185 dump_printf(" ...... dso: %s\n",
183 186 map ? map->dso->long_name : "<not found>");
184 } else { 187 } else {
185 show = SHOW_HV; 188 show = SHOW_HV;
186 level = 'H'; 189 level = 'H';
@@ -188,12 +191,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
188 } 191 }
189 192
190 if (show & show_mask) { 193 if (show & show_mask) {
191 struct symbol *sym = NULL; 194 if (hist_entry__add(thread, map, sym, ip, level)) {
192
193 if (dso)
194 sym = dso->find_symbol(dso, ip);
195
196 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
197 fprintf(stderr, 195 fprintf(stderr,
198 "problem incrementing symbol count, skipping event\n"); 196 "problem incrementing symbol count, skipping event\n");
199 return -1; 197 return -1;
@@ -313,7 +311,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
313} 311}
314 312
315static int 313static int
316parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) 314parse_line(FILE *file, struct symbol *sym, u64 len)
317{ 315{
318 char *line = NULL, *tmp, *tmp2; 316 char *line = NULL, *tmp, *tmp2;
319 static const char *prev_line; 317 static const char *prev_line;
@@ -363,7 +361,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
363 const char *color; 361 const char *color;
364 struct sym_ext *sym_ext = sym->priv; 362 struct sym_ext *sym_ext = sym->priv;
365 363
366 offset = line_ip - start; 364 offset = line_ip - sym->start;
367 if (offset < len) 365 if (offset < len)
368 hits = sym->hist[offset]; 366 hits = sym->hist[offset];
369 367
@@ -442,7 +440,7 @@ static void free_source_line(struct symbol *sym, int len)
442 440
443/* Get the filename:line for the colored entries */ 441/* Get the filename:line for the colored entries */
444static void 442static void
445get_source_line(struct symbol *sym, u64 start, int len, const char *filename) 443get_source_line(struct symbol *sym, int len, const char *filename)
446{ 444{
447 int i; 445 int i;
448 char cmd[PATH_MAX * 2]; 446 char cmd[PATH_MAX * 2];
@@ -467,7 +465,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
467 if (sym_ext[i].percent <= 0.5) 465 if (sym_ext[i].percent <= 0.5)
468 continue; 466 continue;
469 467
470 offset = start + i; 468 offset = sym->start + i;
471 sprintf(cmd, "addr2line -e %s %016llx", filename, offset); 469 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
472 fp = popen(cmd, "r"); 470 fp = popen(cmd, "r");
473 if (!fp) 471 if (!fp)
@@ -519,31 +517,23 @@ static void print_summary(const char *filename)
519 517
520static void annotate_sym(struct dso *dso, struct symbol *sym) 518static void annotate_sym(struct dso *dso, struct symbol *sym)
521{ 519{
522 const char *filename = dso->name, *d_filename; 520 const char *filename = dso->long_name, *d_filename;
523 u64 start, end, len; 521 u64 len;
524 char command[PATH_MAX*2]; 522 char command[PATH_MAX*2];
525 FILE *file; 523 FILE *file;
526 524
527 if (!filename) 525 if (!filename)
528 return; 526 return;
529 if (sym->module) 527
530 filename = sym->module->path;
531 else if (dso == kernel_dso)
532 filename = vmlinux_name;
533
534 start = sym->obj_start;
535 if (!start)
536 start = sym->start;
537 if (full_paths) 528 if (full_paths)
538 d_filename = filename; 529 d_filename = filename;
539 else 530 else
540 d_filename = basename(filename); 531 d_filename = basename(filename);
541 532
542 end = start + sym->end - sym->start + 1;
543 len = sym->end - sym->start; 533 len = sym->end - sym->start;
544 534
545 if (print_line) { 535 if (print_line) {
546 get_source_line(sym, start, len, filename); 536 get_source_line(sym, len, filename);
547 print_summary(filename); 537 print_summary(filename);
548 } 538 }
549 539
@@ -552,10 +542,11 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
552 printf("------------------------------------------------\n"); 542 printf("------------------------------------------------\n");
553 543
554 if (verbose >= 2) 544 if (verbose >= 2)
555 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 545 printf("annotating [%p] %30s : [%p] %30s\n",
546 dso, dso->long_name, sym, sym->name);
556 547
557 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 548 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
558 (u64)start, (u64)end, filename, filename); 549 sym->start, sym->end, filename, filename);
559 550
560 if (verbose >= 3) 551 if (verbose >= 3)
561 printf("doing: %s\n", command); 552 printf("doing: %s\n", command);
@@ -565,7 +556,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
565 return; 556 return;
566 557
567 while (!feof(file)) { 558 while (!feof(file)) {
568 if (parse_line(file, sym, start, len) < 0) 559 if (parse_line(file, sym, len) < 0)
569 break; 560 break;
570 } 561 }
571 562
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c1a54fc8527a..3ed3baf96ffb 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -349,22 +349,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
349 349
350 350
351static struct symbol * 351static struct symbol *
352resolve_symbol(struct thread *thread, struct map **mapp, 352resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
353 struct dso **dsop, u64 *ipp)
354{ 353{
355 struct dso *dso = dsop ? *dsop : NULL;
356 struct map *map = mapp ? *mapp : NULL; 354 struct map *map = mapp ? *mapp : NULL;
357 u64 ip = *ipp; 355 u64 ip = *ipp;
358 356
359 if (!thread)
360 return NULL;
361
362 if (dso)
363 goto got_dso;
364
365 if (map) 357 if (map)
366 goto got_map; 358 goto got_map;
367 359
360 if (!thread)
361 return NULL;
362
368 map = thread__find_map(thread, ip); 363 map = thread__find_map(thread, ip);
369 if (map != NULL) { 364 if (map != NULL) {
370 /* 365 /*
@@ -379,29 +374,29 @@ resolve_symbol(struct thread *thread, struct map **mapp,
379 *mapp = map; 374 *mapp = map;
380got_map: 375got_map:
381 ip = map->map_ip(map, ip); 376 ip = map->map_ip(map, ip);
382
383 dso = map->dso;
384 } else { 377 } else {
385 /* 378 /*
386 * If this is outside of all known maps, 379 * If this is outside of all known maps,
387 * and is a negative address, try to look it 380 * and is a negative address, try to look it
388 * up in the kernel dso, as it might be a 381 * up in the kernel dso, as it might be a
389 * vsyscall (which executes in user-mode): 382 * vsyscall or vdso (which executes in user-mode).
383 *
384 * XXX This is nasty, we should have a symbol list in
385 * the "[vdso]" dso, but for now lets use the old
386 * trick of looking in the whole kernel symbol list.
390 */ 387 */
391 if ((long long)ip < 0) 388 if ((long long)ip < 0) {
392 dso = kernel_dso; 389 map = kernel_map;
390 if (mapp)
391 *mapp = map;
392 }
393 } 393 }
394 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 394 dump_printf(" ...... dso: %s\n",
395 map ? map->dso->long_name : "<not found>");
395 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); 396 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
396 *ipp = ip; 397 *ipp = ip;
397 398
398 if (dsop) 399 return map ? map->dso->find_symbol(map->dso, ip) : NULL;
399 *dsop = dso;
400
401 if (!dso)
402 return NULL;
403got_dso:
404 return dso->find_symbol(dso, ip);
405} 400}
406 401
407static int call__match(struct symbol *sym) 402static int call__match(struct symbol *sym)
@@ -413,7 +408,7 @@ static int call__match(struct symbol *sym)
413} 408}
414 409
415static struct symbol ** 410static struct symbol **
416resolve_callchain(struct thread *thread, struct map *map __used, 411resolve_callchain(struct thread *thread, struct map *map,
417 struct ip_callchain *chain, struct hist_entry *entry) 412 struct ip_callchain *chain, struct hist_entry *entry)
418{ 413{
419 u64 context = PERF_CONTEXT_MAX; 414 u64 context = PERF_CONTEXT_MAX;
@@ -430,8 +425,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
430 425
431 for (i = 0; i < chain->nr; i++) { 426 for (i = 0; i < chain->nr; i++) {
432 u64 ip = chain->ips[i]; 427 u64 ip = chain->ips[i];
433 struct dso *dso = NULL; 428 struct symbol *sym = NULL;
434 struct symbol *sym;
435 429
436 if (ip >= PERF_CONTEXT_MAX) { 430 if (ip >= PERF_CONTEXT_MAX) {
437 context = ip; 431 context = ip;
@@ -440,17 +434,15 @@ resolve_callchain(struct thread *thread, struct map *map __used,
440 434
441 switch (context) { 435 switch (context) {
442 case PERF_CONTEXT_HV: 436 case PERF_CONTEXT_HV:
443 dso = hypervisor_dso;
444 break; 437 break;
445 case PERF_CONTEXT_KERNEL: 438 case PERF_CONTEXT_KERNEL:
446 dso = kernel_dso; 439 sym = kernel_maps__find_symbol(ip, &map);
447 break; 440 break;
448 default: 441 default:
442 sym = resolve_symbol(thread, &map, &ip);
449 break; 443 break;
450 } 444 }
451 445
452 sym = resolve_symbol(thread, NULL, &dso, &ip);
453
454 if (sym) { 446 if (sym) {
455 if (sort__has_parent && call__match(sym) && 447 if (sort__has_parent && call__match(sym) &&
456 !entry->parent) 448 !entry->parent)
@@ -469,7 +461,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
469 */ 461 */
470 462
471static int 463static int
472hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 464hist_entry__add(struct thread *thread, struct map *map,
473 struct symbol *sym, u64 ip, struct ip_callchain *chain, 465 struct symbol *sym, u64 ip, struct ip_callchain *chain,
474 char level, u64 count) 466 char level, u64 count)
475{ 467{
@@ -480,7 +472,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
480 struct hist_entry entry = { 472 struct hist_entry entry = {
481 .thread = thread, 473 .thread = thread,
482 .map = map, 474 .map = map,
483 .dso = dso,
484 .sym = sym, 475 .sym = sym,
485 .ip = ip, 476 .ip = ip,
486 .level = level, 477 .level = level,
@@ -641,7 +632,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
641{ 632{
642 char level; 633 char level;
643 int show = 0; 634 int show = 0;
644 struct dso *dso = NULL; 635 struct symbol *sym = NULL;
645 struct thread *thread; 636 struct thread *thread;
646 u64 ip = event->ip.ip; 637 u64 ip = event->ip.ip;
647 u64 period = 1; 638 u64 period = 1;
@@ -700,35 +691,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
700 show = SHOW_KERNEL; 691 show = SHOW_KERNEL;
701 level = 'k'; 692 level = 'k';
702 693
703 dso = kernel_dso; 694 sym = kernel_maps__find_symbol(ip, &map);
704 695 dump_printf(" ...... dso: %s\n",
705 dump_printf(" ...... dso: %s\n", dso->name); 696 map ? map->dso->long_name : "<not found>");
706
707 } else if (cpumode == PERF_RECORD_MISC_USER) { 697 } else if (cpumode == PERF_RECORD_MISC_USER) {
708 698
709 show = SHOW_USER; 699 show = SHOW_USER;
710 level = '.'; 700 level = '.';
701 sym = resolve_symbol(thread, &map, &ip);
711 702
712 } else { 703 } else {
713 show = SHOW_HV; 704 show = SHOW_HV;
714 level = 'H'; 705 level = 'H';
715 706
716 dso = hypervisor_dso;
717
718 dump_printf(" ...... dso: [hypervisor]\n"); 707 dump_printf(" ...... dso: [hypervisor]\n");
719 } 708 }
720 709
721 if (show & show_mask) { 710 if (show & show_mask) {
722 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 711 if (dso_list &&
723 712 (!map || !map->dso ||
724 if (dso_list && (!dso || !dso->name || 713 !(strlist__has_entry(dso_list, map->dso->short_name) ||
725 !strlist__has_entry(dso_list, dso->name))) 714 (map->dso->short_name != map->dso->long_name &&
715 strlist__has_entry(dso_list, map->dso->long_name)))))
726 return 0; 716 return 0;
727 717
728 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name))) 718 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
729 return 0; 719 return 0;
730 720
731 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 721 if (hist_entry__add(thread, map, sym, ip,
722 chain, level, period)) {
732 eprintf("problem incrementing symbol count, skipping event\n"); 723 eprintf("problem incrementing symbol count, skipping event\n");
733 return -1; 724 return -1;
734 } 725 }
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index bf464ce7e3e2..befef842757e 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -22,6 +22,7 @@
22 22
23#include "util/symbol.h" 23#include "util/symbol.h"
24#include "util/color.h" 24#include "util/color.h"
25#include "util/thread.h"
25#include "util/util.h" 26#include "util/util.h"
26#include <linux/rbtree.h> 27#include <linux/rbtree.h>
27#include "util/parse-options.h" 28#include "util/parse-options.h"
@@ -103,6 +104,7 @@ struct sym_entry {
103 unsigned long snap_count; 104 unsigned long snap_count;
104 double weight; 105 double weight;
105 int skip; 106 int skip;
107 struct map *map;
106 struct source_line *source; 108 struct source_line *source;
107 struct source_line *lines; 109 struct source_line *lines;
108 struct source_line **lines_tail; 110 struct source_line **lines_tail;
@@ -116,12 +118,11 @@ struct sym_entry {
116static void parse_source(struct sym_entry *syme) 118static void parse_source(struct sym_entry *syme)
117{ 119{
118 struct symbol *sym; 120 struct symbol *sym;
119 struct module *module; 121 struct map *map;
120 struct section *section = NULL;
121 FILE *file; 122 FILE *file;
122 char command[PATH_MAX*2]; 123 char command[PATH_MAX*2];
123 const char *path = vmlinux_name; 124 const char *path;
124 u64 start, end, len; 125 u64 len;
125 126
126 if (!syme) 127 if (!syme)
127 return; 128 return;
@@ -132,27 +133,15 @@ static void parse_source(struct sym_entry *syme)
132 } 133 }
133 134
134 sym = (struct symbol *)(syme + 1); 135 sym = (struct symbol *)(syme + 1);
135 module = sym->module; 136 map = syme->map;
137 path = map->dso->long_name;
136 138
137 if (module)
138 path = module->path;
139 if (!path)
140 return;
141
142 start = sym->obj_start;
143 if (!start)
144 start = sym->start;
145
146 if (module) {
147 section = module->sections->find_section(module->sections, ".text");
148 if (section)
149 start -= section->vma;
150 }
151
152 end = start + sym->end - sym->start + 1;
153 len = sym->end - sym->start; 139 len = sym->end - sym->start;
154 140
155 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); 141 sprintf(command,
142 "objdump --start-address=0x%016Lx "
143 "--stop-address=0x%016Lx -dS %s",
144 sym->start, sym->end, path);
156 145
157 file = popen(command, "r"); 146 file = popen(command, "r");
158 if (!file) 147 if (!file)
@@ -184,13 +173,11 @@ static void parse_source(struct sym_entry *syme)
184 173
185 if (strlen(src->line)>8 && src->line[8] == ':') { 174 if (strlen(src->line)>8 && src->line[8] == ':') {
186 src->eip = strtoull(src->line, NULL, 16); 175 src->eip = strtoull(src->line, NULL, 16);
187 if (section) 176 src->eip += map->start;
188 src->eip += section->vma;
189 } 177 }
190 if (strlen(src->line)>8 && src->line[16] == ':') { 178 if (strlen(src->line)>8 && src->line[16] == ':') {
191 src->eip = strtoull(src->line, NULL, 16); 179 src->eip = strtoull(src->line, NULL, 16);
192 if (section) 180 src->eip += map->start;
193 src->eip += section->vma;
194 } 181 }
195 } 182 }
196 pclose(file); 183 pclose(file);
@@ -242,16 +229,9 @@ static void lookup_sym_source(struct sym_entry *syme)
242 struct symbol *symbol = (struct symbol *)(syme + 1); 229 struct symbol *symbol = (struct symbol *)(syme + 1);
243 struct source_line *line; 230 struct source_line *line;
244 char pattern[PATH_MAX]; 231 char pattern[PATH_MAX];
245 char *idx;
246 232
247 sprintf(pattern, "<%s>:", symbol->name); 233 sprintf(pattern, "<%s>:", symbol->name);
248 234
249 if (symbol->module) {
250 idx = strstr(pattern, "\t");
251 if (idx)
252 *idx = 0;
253 }
254
255 pthread_mutex_lock(&syme->source_lock); 235 pthread_mutex_lock(&syme->source_lock);
256 for (line = syme->lines; line; line = line->next) { 236 for (line = syme->lines; line; line = line->next) {
257 if (strstr(line->line, pattern)) { 237 if (strstr(line->line, pattern)) {
@@ -513,8 +493,8 @@ static void print_sym_table(void)
513 if (verbose) 493 if (verbose)
514 printf(" - %016llx", sym->start); 494 printf(" - %016llx", sym->start);
515 printf(" : %s", sym->name); 495 printf(" : %s", sym->name);
516 if (sym->module) 496 if (syme->map->dso->name[0] == '[')
517 printf("\t[%s]", sym->module->name); 497 printf(" \t%s", syme->map->dso->name);
518 printf("\n"); 498 printf("\n");
519 } 499 }
520} 500}
@@ -784,7 +764,7 @@ static const char *skip_symbols[] = {
784 NULL 764 NULL
785}; 765};
786 766
787static int symbol_filter(struct dso *self, struct symbol *sym) 767static int symbol_filter(struct map *map, struct symbol *sym)
788{ 768{
789 struct sym_entry *syme; 769 struct sym_entry *syme;
790 const char *name = sym->name; 770 const char *name = sym->name;
@@ -806,7 +786,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
806 strstr(name, "_text_end")) 786 strstr(name, "_text_end"))
807 return 1; 787 return 1;
808 788
809 syme = dso__sym_priv(self, sym); 789 syme = dso__sym_priv(map->dso, sym);
790 syme->map = map;
810 pthread_mutex_init(&syme->source_lock, NULL); 791 pthread_mutex_init(&syme->source_lock, NULL);
811 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 792 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
812 sym_filter_entry = syme; 793 sym_filter_entry = syme;
@@ -825,22 +806,14 @@ static int parse_symbols(void)
825{ 806{
826 int use_modules = vmlinux_name ? 1 : 0; 807 int use_modules = vmlinux_name ? 1 : 0;
827 808
828 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); 809 if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry),
829 if (kernel_dso == NULL) 810 symbol_filter, verbose, use_modules) <= 0)
830 return -1; 811 return -1;
831 812
832 if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
833 goto out_delete_dso;
834
835 if (dump_symtab) 813 if (dump_symtab)
836 dso__fprintf(kernel_dso, stderr); 814 dsos__fprintf(stderr);
837 815
838 return 0; 816 return 0;
839
840out_delete_dso:
841 dso__delete(kernel_dso);
842 kernel_dso = NULL;
843 return -1;
844} 817}
845 818
846/* 819/*
@@ -848,10 +821,11 @@ out_delete_dso:
848 */ 821 */
849static void record_ip(u64 ip, int counter) 822static void record_ip(u64 ip, int counter)
850{ 823{
851 struct symbol *sym = dso__find_symbol(kernel_dso, ip); 824 struct map *map;
825 struct symbol *sym = kernel_maps__find_symbol(ip, &map);
852 826
853 if (sym != NULL) { 827 if (sym != NULL) {
854 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); 828 struct sym_entry *syme = dso__sym_priv(map->dso, sym);
855 829
856 if (!syme->skip) { 830 if (!syme->skip) {
857 syme->count[counter]++; 831 syme->count[counter]++;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 4c69eb553807..a39520e6ae8f 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -3,6 +3,7 @@
3 3
4#include "../perf.h" 4#include "../perf.h"
5#include "util.h" 5#include "util.h"
6#include <linux/list.h>
6#include <linux/rbtree.h> 7#include <linux/rbtree.h>
7 8
8enum { 9enum {
@@ -79,7 +80,10 @@ typedef union event_union {
79} event_t; 80} event_t;
80 81
81struct map { 82struct map {
82 struct rb_node rb_node; 83 union {
84 struct rb_node rb_node;
85 struct list_head node;
86 };
83 u64 start; 87 u64 start;
84 u64 end; 88 u64 end;
85 u64 pgoff; 89 u64 pgoff;
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644
index 0d8c85defcd2..000000000000
--- a/tools/perf/util/module.c
+++ /dev/null
@@ -1,545 +0,0 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <libgen.h>
8#include <gelf.h>
9#include <elf.h>
10#include <dirent.h>
11#include <sys/utsname.h>
12
13static unsigned int crc32(const char *p, unsigned int len)
14{
15 int i;
16 unsigned int crc = 0;
17
18 while (len--) {
19 crc ^= *p++;
20 for (i = 0; i < 8; i++)
21 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
22 }
23 return crc;
24}
25
26/* module section methods */
27
28struct sec_dso *sec_dso__new_dso(const char *name)
29{
30 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
31
32 if (self != NULL) {
33 strcpy(self->name, name);
34 self->secs = RB_ROOT;
35 self->find_section = sec_dso__find_section;
36 }
37
38 return self;
39}
40
41static void sec_dso__delete_section(struct section *self)
42{
43 free(((void *)self));
44}
45
46void sec_dso__delete_sections(struct sec_dso *self)
47{
48 struct section *pos;
49 struct rb_node *next = rb_first(&self->secs);
50
51 while (next) {
52 pos = rb_entry(next, struct section, rb_node);
53 next = rb_next(&pos->rb_node);
54 rb_erase(&pos->rb_node, &self->secs);
55 sec_dso__delete_section(pos);
56 }
57}
58
59void sec_dso__delete_self(struct sec_dso *self)
60{
61 sec_dso__delete_sections(self);
62 free(self);
63}
64
65static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
66{
67 struct rb_node **p = &self->secs.rb_node;
68 struct rb_node *parent = NULL;
69 const u64 hash = sec->hash;
70 struct section *s;
71
72 while (*p != NULL) {
73 parent = *p;
74 s = rb_entry(parent, struct section, rb_node);
75 if (hash < s->hash)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80 rb_link_node(&sec->rb_node, parent, p);
81 rb_insert_color(&sec->rb_node, &self->secs);
82}
83
84struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
85{
86 struct rb_node *n;
87 u64 hash;
88 int len;
89
90 if (self == NULL)
91 return NULL;
92
93 len = strlen(name);
94 hash = crc32(name, len);
95
96 n = self->secs.rb_node;
97
98 while (n) {
99 struct section *s = rb_entry(n, struct section, rb_node);
100
101 if (hash < s->hash)
102 n = n->rb_left;
103 else if (hash > s->hash)
104 n = n->rb_right;
105 else {
106 if (!strcmp(name, s->name))
107 return s;
108 else
109 n = rb_next(&s->rb_node);
110 }
111 }
112
113 return NULL;
114}
115
116static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
117{
118 return fprintf(fp, "name:%s vma:%llx path:%s\n",
119 self->name, self->vma, self->path);
120}
121
122size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
123{
124 size_t ret = fprintf(fp, "dso: %s\n", self->name);
125
126 struct rb_node *nd;
127 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
128 struct section *pos = rb_entry(nd, struct section, rb_node);
129 ret += sec_dso__fprintf_section(pos, fp);
130 }
131
132 return ret;
133}
134
135static struct section *section__new(const char *name, const char *path)
136{
137 struct section *self = calloc(1, sizeof(*self));
138
139 if (!self)
140 goto out_failure;
141
142 self->name = calloc(1, strlen(name) + 1);
143 if (!self->name)
144 goto out_failure;
145
146 self->path = calloc(1, strlen(path) + 1);
147 if (!self->path)
148 goto out_failure;
149
150 strcpy(self->name, name);
151 strcpy(self->path, path);
152 self->hash = crc32(self->name, strlen(name));
153
154 return self;
155
156out_failure:
157 if (self) {
158 if (self->name)
159 free(self->name);
160 if (self->path)
161 free(self->path);
162 free(self);
163 }
164
165 return NULL;
166}
167
168/* module methods */
169
170struct mod_dso *mod_dso__new_dso(const char *name)
171{
172 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
173
174 if (self != NULL) {
175 strcpy(self->name, name);
176 self->mods = RB_ROOT;
177 self->find_module = mod_dso__find_module;
178 }
179
180 return self;
181}
182
183static void mod_dso__delete_module(struct module *self)
184{
185 free(((void *)self));
186}
187
188void mod_dso__delete_modules(struct mod_dso *self)
189{
190 struct module *pos;
191 struct rb_node *next = rb_first(&self->mods);
192
193 while (next) {
194 pos = rb_entry(next, struct module, rb_node);
195 next = rb_next(&pos->rb_node);
196 rb_erase(&pos->rb_node, &self->mods);
197 mod_dso__delete_module(pos);
198 }
199}
200
201void mod_dso__delete_self(struct mod_dso *self)
202{
203 mod_dso__delete_modules(self);
204 free(self);
205}
206
207static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
208{
209 struct rb_node **p = &self->mods.rb_node;
210 struct rb_node *parent = NULL;
211 const u64 hash = mod->hash;
212 struct module *m;
213
214 while (*p != NULL) {
215 parent = *p;
216 m = rb_entry(parent, struct module, rb_node);
217 if (hash < m->hash)
218 p = &(*p)->rb_left;
219 else
220 p = &(*p)->rb_right;
221 }
222 rb_link_node(&mod->rb_node, parent, p);
223 rb_insert_color(&mod->rb_node, &self->mods);
224}
225
226struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
227{
228 struct rb_node *n;
229 u64 hash;
230 int len;
231
232 if (self == NULL)
233 return NULL;
234
235 len = strlen(name);
236 hash = crc32(name, len);
237
238 n = self->mods.rb_node;
239
240 while (n) {
241 struct module *m = rb_entry(n, struct module, rb_node);
242
243 if (hash < m->hash)
244 n = n->rb_left;
245 else if (hash > m->hash)
246 n = n->rb_right;
247 else {
248 if (!strcmp(name, m->name))
249 return m;
250 else
251 n = rb_next(&m->rb_node);
252 }
253 }
254
255 return NULL;
256}
257
258static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
259{
260 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
261}
262
263size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
264{
265 struct rb_node *nd;
266 size_t ret;
267
268 ret = fprintf(fp, "dso: %s\n", self->name);
269
270 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
271 struct module *pos = rb_entry(nd, struct module, rb_node);
272
273 ret += mod_dso__fprintf_module(pos, fp);
274 }
275
276 return ret;
277}
278
279static struct module *module__new(const char *name, const char *path)
280{
281 struct module *self = calloc(1, sizeof(*self));
282
283 if (!self)
284 goto out_failure;
285
286 self->name = calloc(1, strlen(name) + 1);
287 if (!self->name)
288 goto out_failure;
289
290 self->path = calloc(1, strlen(path) + 1);
291 if (!self->path)
292 goto out_failure;
293
294 strcpy(self->name, name);
295 strcpy(self->path, path);
296 self->hash = crc32(self->name, strlen(name));
297
298 return self;
299
300out_failure:
301 if (self) {
302 if (self->name)
303 free(self->name);
304 if (self->path)
305 free(self->path);
306 free(self);
307 }
308
309 return NULL;
310}
311
312static int mod_dso__load_sections(struct module *mod)
313{
314 int count = 0, path_len;
315 struct dirent *entry;
316 char *line = NULL;
317 char *dir_path;
318 DIR *dir;
319 size_t n;
320
321 path_len = strlen("/sys/module/");
322 path_len += strlen(mod->name);
323 path_len += strlen("/sections/");
324
325 dir_path = calloc(1, path_len + 1);
326 if (dir_path == NULL)
327 goto out_failure;
328
329 strcat(dir_path, "/sys/module/");
330 strcat(dir_path, mod->name);
331 strcat(dir_path, "/sections/");
332
333 dir = opendir(dir_path);
334 if (dir == NULL)
335 goto out_free;
336
337 while ((entry = readdir(dir))) {
338 struct section *section;
339 char *path, *vma;
340 int line_len;
341 FILE *file;
342
343 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
344 continue;
345
346 path = calloc(1, path_len + strlen(entry->d_name) + 1);
347 if (path == NULL)
348 break;
349 strcat(path, dir_path);
350 strcat(path, entry->d_name);
351
352 file = fopen(path, "r");
353 if (file == NULL) {
354 free(path);
355 break;
356 }
357
358 line_len = getline(&line, &n, file);
359 if (line_len < 0) {
360 free(path);
361 fclose(file);
362 break;
363 }
364
365 if (!line) {
366 free(path);
367 fclose(file);
368 break;
369 }
370
371 line[--line_len] = '\0'; /* \n */
372
373 vma = strstr(line, "0x");
374 if (!vma) {
375 free(path);
376 fclose(file);
377 break;
378 }
379 vma += 2;
380
381 section = section__new(entry->d_name, path);
382 if (!section) {
383 fprintf(stderr, "load_sections: allocation error\n");
384 free(path);
385 fclose(file);
386 break;
387 }
388
389 hex2u64(vma, &section->vma);
390 sec_dso__insert_section(mod->sections, section);
391
392 free(path);
393 fclose(file);
394 count++;
395 }
396
397 closedir(dir);
398 free(line);
399 free(dir_path);
400
401 return count;
402
403out_free:
404 free(dir_path);
405
406out_failure:
407 return count;
408}
409
410static int mod_dso__load_module_paths(struct mod_dso *self)
411{
412 struct utsname uts;
413 int count = 0, len, err = -1;
414 char *line = NULL;
415 FILE *file;
416 char *dpath, *dir;
417 size_t n;
418
419 if (uname(&uts) < 0)
420 return err;
421
422 len = strlen("/lib/modules/");
423 len += strlen(uts.release);
424 len += strlen("/modules.dep");
425
426 dpath = calloc(1, len + 1);
427 if (dpath == NULL)
428 return err;
429
430 strcat(dpath, "/lib/modules/");
431 strcat(dpath, uts.release);
432 strcat(dpath, "/modules.dep");
433
434 file = fopen(dpath, "r");
435 if (file == NULL)
436 goto out_failure;
437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
443 while (!feof(file)) {
444 struct module *module;
445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
448
449 line_len = getline(&line, &n, file);
450 if (line_len < 0)
451 break;
452
453 if (!line)
454 break;
455
456 line[--line_len] = '\0'; /* \n */
457
458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
464 if (!path)
465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
483
484 name = strdup(path);
485 if (!name)
486 break;
487
488 name = strtok(name, "/");
489 tmp = name;
490
491 while (tmp) {
492 tmp = strtok(NULL, "/");
493 if (tmp)
494 name = tmp;
495 }
496
497 name = strsep(&name, ".");
498 if (!name)
499 break;
500
501 /* Quirk: replace '-' with '_' in all modules */
502 for (len = strlen(name); len; len--) {
503 if (*(name+len) == '-')
504 *(name+len) = '_';
505 }
506
507 module = module__new(name, path);
508 if (!module)
509 break;
510 mod_dso__insert_module(self, module);
511
512 module->sections = sec_dso__new_dso("sections");
513 if (!module->sections)
514 break;
515
516 module->active = mod_dso__load_sections(module);
517
518 if (module->active > 0)
519 count++;
520 }
521
522 if (feof(file))
523 err = count;
524 else
525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
526
527out_failure:
528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
536}
537
538int mod_dso__load_modules(struct mod_dso *dso)
539{
540 int err;
541
542 err = mod_dso__load_module_paths(dso);
543
544 return err;
545}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644
index 098e0412bc22..000000000000
--- a/tools/perf/util/module.h
+++ /dev/null
@@ -1,53 +0,0 @@
1#ifndef __PERF_MODULE_
2#define __PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* __PERF_MODULE_ */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 50e75abb1fdd..40c9acd41cad 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -129,20 +129,32 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
129int64_t 129int64_t
130sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 130sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
131{ 131{
132 struct dso *dso_l = left->dso; 132 struct dso *dso_l = left->map ? left->map->dso : NULL;
133 struct dso *dso_r = right->dso; 133 struct dso *dso_r = right->map ? right->map->dso : NULL;
134 const char *dso_name_l, *dso_name_r;
134 135
135 if (!dso_l || !dso_r) 136 if (!dso_l || !dso_r)
136 return cmp_null(dso_l, dso_r); 137 return cmp_null(dso_l, dso_r);
137 138
138 return strcmp(dso_l->name, dso_r->name); 139 if (verbose) {
140 dso_name_l = dso_l->long_name;
141 dso_name_r = dso_r->long_name;
142 } else {
143 dso_name_l = dso_l->short_name;
144 dso_name_r = dso_r->short_name;
145 }
146
147 return strcmp(dso_name_l, dso_name_r);
139} 148}
140 149
141size_t 150size_t
142sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) 151sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
143{ 152{
144 if (self->dso) 153 if (self->map && self->map->dso) {
145 return repsep_fprintf(fp, "%-*s", width, self->dso->name); 154 const char *dso_name = !verbose ? self->map->dso->short_name :
155 self->map->dso->long_name;
156 return repsep_fprintf(fp, "%-*s", width, dso_name);
157 }
146 158
147 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); 159 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
148} 160}
@@ -169,20 +181,16 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
169{ 181{
170 size_t ret = 0; 182 size_t ret = 0;
171 183
172 if (verbose) 184 if (verbose) {
173 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, 185 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
174 dso__symtab_origin(self->dso)); 186 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
187 }
175 188
176 ret += repsep_fprintf(fp, "[%c] ", self->level); 189 ret += repsep_fprintf(fp, "[%c] ", self->level);
177 if (self->sym) { 190 if (self->sym)
178 ret += repsep_fprintf(fp, "%s", self->sym->name); 191 ret += repsep_fprintf(fp, "%s", self->sym->name);
179 192 else
180 if (self->sym->module)
181 ret += repsep_fprintf(fp, "\t[%s]",
182 self->sym->module->name);
183 } else {
184 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); 193 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
185 }
186 194
187 return ret; 195 return ret;
188} 196}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 4684fd6d5c4a..13806d782af6 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -42,18 +42,15 @@ extern unsigned int threads__col_width;
42 42
43struct hist_entry { 43struct hist_entry {
44 struct rb_node rb_node; 44 struct rb_node rb_node;
45 45 u64 count;
46 struct thread *thread; 46 struct thread *thread;
47 struct map *map; 47 struct map *map;
48 struct dso *dso;
49 struct symbol *sym; 48 struct symbol *sym;
50 struct symbol *parent;
51 u64 ip; 49 u64 ip;
52 char level; 50 char level;
51 struct symbol *parent;
53 struct callchain_node callchain; 52 struct callchain_node callchain;
54 struct rb_root sorted_chain; 53 struct rb_root sorted_chain;
55
56 u64 count;
57}; 54};
58 55
59/* 56/*
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
12const char *sym_hist_filter; 14const 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
24static struct symbol *symbol__new(u64 start, u64 len, 27static void dsos__add(struct dso *dso);
25 const char *name, unsigned int priv_size, 28static struct dso *dsos__find(const char *name);
26 u64 obj_start, int v) 29
30static 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
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 65static 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
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 71struct 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)
100void dso__delete(struct dso *self) 102void 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
148size_t dso__fprintf(struct dso *self, FILE *fp) 152size_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
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 165static 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
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 249static 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;
516out: 522out:
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
522static int dso__load_sym(struct dso *self, int fd, const char *name, 528static 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);
713out_elf_end: 706out_elf_end:
714 elf_end(elf); 707 elf_end(elf);
715out_close: 708out_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
737int dso__load(struct dso *self, symbol_filter_t filter, int v) 731int 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
811static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 807static struct rb_root kernel_maps;
812 symbol_filter_t filter, int v) 808struct map *kernel_map;
809
810static 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) 815struct 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
840struct 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
854static 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
831int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 872static 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. 935failure:
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) 940static 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
867static 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 */
959static 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
978int 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
1040out_delete_line:
1041 free(line);
1042out_failure:
1043 return -1;
891} 1044}
892 1045
893static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1046static 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
911int dso__load_kernel(struct dso *self, const char *vmlinux, 1062int 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
1113out_delete_dso:
1114 dso__delete(dso);
1115 return -1;
936} 1116}
937 1117
938LIST_HEAD(dsos); 1118LIST_HEAD(dsos);
939struct dso *kernel_dso;
940struct dso *vdso; 1119struct dso *vdso;
941struct dso *hypervisor_dso;
942 1120
943const char *vmlinux_name = "vmlinux"; 1121const char *vmlinux_name = "vmlinux";
944int modules; 1122int 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
998static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
999{
1000 return dso__find_symbol(dso, ip);
1001}
1002
1003int load_kernel(void) 1176int 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
1035void symbol__init(void) 1190void symbol__init(void)
1036{ 1191{
1037 elf_version(EV_CURRENT); 1192 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ee164f659ed3..5339fd82ec96 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -5,7 +5,6 @@
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"
9#include "event.h" 8#include "event.h"
10 9
11#ifdef HAVE_CPLUS_DEMANGLE 10#ifdef HAVE_CPLUS_DEMANGLE
@@ -36,10 +35,8 @@ struct symbol {
36 struct rb_node rb_node; 35 struct rb_node rb_node;
37 u64 start; 36 u64 start;
38 u64 end; 37 u64 end;
39 u64 obj_start;
40 u64 hist_sum; 38 u64 hist_sum;
41 u64 *hist; 39 u64 *hist;
42 struct module *module;
43 void *priv; 40 void *priv;
44 char name[0]; 41 char name[0];
45}; 42};
@@ -52,12 +49,14 @@ struct dso {
52 unsigned char adjust_symbols; 49 unsigned char adjust_symbols;
53 unsigned char slen_calculated; 50 unsigned char slen_calculated;
54 unsigned char origin; 51 unsigned char origin;
52 const char *short_name;
53 char *long_name;
55 char name[0]; 54 char name[0];
56}; 55};
57 56
58extern const char *sym_hist_filter; 57extern const char *sym_hist_filter;
59 58
60typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); 59typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
61 60
62struct dso *dso__new(const char *name, unsigned int sym_priv_size); 61struct dso *dso__new(const char *name, unsigned int sym_priv_size);
63void dso__delete(struct dso *self); 62void dso__delete(struct dso *self);
@@ -69,10 +68,12 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
69 68
70struct symbol *dso__find_symbol(struct dso *self, u64 ip); 69struct symbol *dso__find_symbol(struct dso *self, u64 ip);
71 70
72int dso__load_kernel(struct dso *self, const char *vmlinux, 71int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
73 symbol_filter_t filter, int verbose, int modules); 72 symbol_filter_t filter, int verbose, int modules);
74int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); 73int dsos__load_modules(unsigned int sym_priv_size, symbol_filter_t filter,
75int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 74 int verbose);
75int dso__load(struct dso *self, struct map *map, symbol_filter_t filter,
76 int verbose);
76struct dso *dsos__findnew(const char *name); 77struct dso *dsos__findnew(const char *name);
77void dsos__fprintf(FILE *fp); 78void dsos__fprintf(FILE *fp);
78 79
@@ -84,9 +85,8 @@ int load_kernel(void);
84void symbol__init(void); 85void symbol__init(void);
85 86
86extern struct list_head dsos; 87extern struct list_head dsos;
87extern struct dso *kernel_dso; 88extern struct map *kernel_map;
88extern struct dso *vdso; 89extern struct dso *vdso;
89extern struct dso *hypervisor_dso;
90extern const char *vmlinux_name; 90extern const char *vmlinux_name;
91extern int modules; 91extern int modules;
92#endif /* __PERF_SYMBOL */ 92#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 9d0945cc66d1..3b56aebb1f4b 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -16,6 +16,7 @@ static struct thread *thread__new(pid_t pid)
16 if (self->comm) 16 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 17 snprintf(self->comm, 32, ":%d", self->pid);
18 self->maps = RB_ROOT; 18 self->maps = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps);
19 } 20 }
20 21
21 return self; 22 return self;
@@ -32,13 +33,20 @@ int thread__set_comm(struct thread *self, const char *comm)
32static size_t thread__fprintf(struct thread *self, FILE *fp) 33static size_t thread__fprintf(struct thread *self, FILE *fp)
33{ 34{
34 struct rb_node *nd; 35 struct rb_node *nd;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 36 struct map *pos;
37 size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
38 self->pid, self->comm);
36 39
37 for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { 40 for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
38 struct map *pos = rb_entry(nd, struct map, rb_node); 41 pos = rb_entry(nd, struct map, rb_node);
39 ret += map__fprintf(pos, fp); 42 ret += map__fprintf(pos, fp);
40 } 43 }
41 44
45 ret = fprintf(fp, "Removed maps:\n");
46
47 list_for_each_entry(pos, &self->removed_maps, node)
48 ret += map__fprintf(pos, fp);
49
42 return ret; 50 return ret;
43} 51}
44 52
@@ -112,21 +120,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map)
112 map__fprintf(pos, stdout); 120 map__fprintf(pos, stdout);
113 } 121 }
114 122
115 if (map->start <= pos->start && map->end > pos->start) 123 rb_erase(&pos->rb_node, &self->maps);
116 pos->start = map->end; 124 /*
117 125 * We may have references to this map, for instance in some
118 if (map->end >= pos->end && map->start < pos->end) 126 * hist_entry instances, so just move them to a separate
119 pos->end = map->start; 127 * list.
120 128 */
121 if (verbose >= 2) { 129 list_add_tail(&pos->node, &self->removed_maps);
122 printf("after collision:\n");
123 map__fprintf(pos, stdout);
124 }
125
126 if (pos->start >= pos->end) {
127 rb_erase(&pos->rb_node, &self->maps);
128 free(pos);
129 }
130 } 130 }
131} 131}
132 132
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index bbb37c1a52ee..845d9b62f96f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -8,6 +8,7 @@
8struct thread { 8struct thread {
9 struct rb_node rb_node; 9 struct rb_node rb_node;
10 struct rb_root maps; 10 struct rb_root maps;
11 struct list_head removed_maps;
11 pid_t pid; 12 pid_t pid;
12 char shortname[3]; 13 char shortname[3];
13 char *comm; 14 char *comm;
@@ -25,6 +26,9 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads);
25void maps__insert(struct rb_root *maps, struct map *map); 26void maps__insert(struct rb_root *maps, struct map *map);
26struct map *maps__find(struct rb_root *maps, u64 ip); 27struct map *maps__find(struct rb_root *maps, u64 ip);
27 28
29struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp);
30struct map *kernel_maps__find_by_dso_name(const char *name);
31
28static inline struct map *thread__find_map(struct thread *self, u64 ip) 32static inline struct map *thread__find_map(struct thread *self, u64 ip)
29{ 33{
30 return self ? maps__find(&self->maps, ip) : NULL; 34 return self ? maps__find(&self->maps, ip) : NULL;