diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 73 |
1 files changed, 32 insertions, 41 deletions
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 | ||