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