diff options
-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; |