diff options
Diffstat (limited to 'tools/perf')
| -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; |
