diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
| -rw-r--r-- | tools/perf/builtin-annotate.c | 283 |
1 files changed, 221 insertions, 62 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index b1ed5f766cb3..5f9eefecc574 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -10,9 +10,9 @@ | |||
| 10 | #include "util/util.h" | 10 | #include "util/util.h" |
| 11 | 11 | ||
| 12 | #include "util/color.h" | 12 | #include "util/color.h" |
| 13 | #include "util/list.h" | 13 | #include <linux/list.h> |
| 14 | #include "util/cache.h" | 14 | #include "util/cache.h" |
| 15 | #include "util/rbtree.h" | 15 | #include <linux/rbtree.h> |
| 16 | #include "util/symbol.h" | 16 | #include "util/symbol.h" |
| 17 | #include "util/string.h" | 17 | #include "util/string.h" |
| 18 | 18 | ||
| @@ -39,40 +39,46 @@ static int dump_trace = 0; | |||
| 39 | 39 | ||
| 40 | static int verbose; | 40 | static int verbose; |
| 41 | 41 | ||
| 42 | static int modules; | ||
| 43 | |||
| 44 | static int full_paths; | ||
| 45 | |||
| 46 | static int print_line; | ||
| 47 | |||
| 42 | static unsigned long page_size; | 48 | static unsigned long page_size; |
| 43 | static unsigned long mmap_window = 32; | 49 | static unsigned long mmap_window = 32; |
| 44 | 50 | ||
| 45 | struct ip_event { | 51 | struct ip_event { |
| 46 | struct perf_event_header header; | 52 | struct perf_event_header header; |
| 47 | __u64 ip; | 53 | u64 ip; |
| 48 | __u32 pid, tid; | 54 | u32 pid, tid; |
| 49 | }; | 55 | }; |
| 50 | 56 | ||
| 51 | struct mmap_event { | 57 | struct mmap_event { |
| 52 | struct perf_event_header header; | 58 | struct perf_event_header header; |
| 53 | __u32 pid, tid; | 59 | u32 pid, tid; |
| 54 | __u64 start; | 60 | u64 start; |
| 55 | __u64 len; | 61 | u64 len; |
| 56 | __u64 pgoff; | 62 | u64 pgoff; |
| 57 | char filename[PATH_MAX]; | 63 | char filename[PATH_MAX]; |
| 58 | }; | 64 | }; |
| 59 | 65 | ||
| 60 | struct comm_event { | 66 | struct comm_event { |
| 61 | struct perf_event_header header; | 67 | struct perf_event_header header; |
| 62 | __u32 pid, tid; | 68 | u32 pid, tid; |
| 63 | char comm[16]; | 69 | char comm[16]; |
| 64 | }; | 70 | }; |
| 65 | 71 | ||
| 66 | struct fork_event { | 72 | struct fork_event { |
| 67 | struct perf_event_header header; | 73 | struct perf_event_header header; |
| 68 | __u32 pid, ppid; | 74 | u32 pid, ppid; |
| 69 | }; | 75 | }; |
| 70 | 76 | ||
| 71 | struct period_event { | 77 | struct period_event { |
| 72 | struct perf_event_header header; | 78 | struct perf_event_header header; |
| 73 | __u64 time; | 79 | u64 time; |
| 74 | __u64 id; | 80 | u64 id; |
| 75 | __u64 sample_period; | 81 | u64 sample_period; |
| 76 | }; | 82 | }; |
| 77 | 83 | ||
| 78 | typedef union event_union { | 84 | typedef union event_union { |
| @@ -84,6 +90,13 @@ typedef union event_union { | |||
| 84 | struct period_event period; | 90 | struct period_event period; |
| 85 | } event_t; | 91 | } event_t; |
| 86 | 92 | ||
| 93 | |||
| 94 | struct sym_ext { | ||
| 95 | struct rb_node node; | ||
| 96 | double percent; | ||
| 97 | char *path; | ||
| 98 | }; | ||
| 99 | |||
| 87 | static LIST_HEAD(dsos); | 100 | static LIST_HEAD(dsos); |
| 88 | static struct dso *kernel_dso; | 101 | static struct dso *kernel_dso; |
| 89 | static struct dso *vdso; | 102 | static struct dso *vdso; |
| @@ -145,9 +158,9 @@ static void dsos__fprintf(FILE *fp) | |||
| 145 | dso__fprintf(pos, fp); | 158 | dso__fprintf(pos, fp); |
| 146 | } | 159 | } |
| 147 | 160 | ||
| 148 | static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) | 161 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) |
| 149 | { | 162 | { |
| 150 | return dso__find_symbol(kernel_dso, ip); | 163 | return dso__find_symbol(dso, ip); |
| 151 | } | 164 | } |
| 152 | 165 | ||
| 153 | static int load_kernel(void) | 166 | static int load_kernel(void) |
| @@ -158,8 +171,8 @@ static int load_kernel(void) | |||
| 158 | if (!kernel_dso) | 171 | if (!kernel_dso) |
| 159 | return -1; | 172 | return -1; |
| 160 | 173 | ||
| 161 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); | 174 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); |
| 162 | if (err) { | 175 | if (err <= 0) { |
| 163 | dso__delete(kernel_dso); | 176 | dso__delete(kernel_dso); |
| 164 | kernel_dso = NULL; | 177 | kernel_dso = NULL; |
| 165 | } else | 178 | } else |
| @@ -178,19 +191,19 @@ static int load_kernel(void) | |||
| 178 | 191 | ||
| 179 | struct map { | 192 | struct map { |
| 180 | struct list_head node; | 193 | struct list_head node; |
| 181 | __u64 start; | 194 | u64 start; |
| 182 | __u64 end; | 195 | u64 end; |
| 183 | __u64 pgoff; | 196 | u64 pgoff; |
| 184 | __u64 (*map_ip)(struct map *, __u64); | 197 | u64 (*map_ip)(struct map *, u64); |
| 185 | struct dso *dso; | 198 | struct dso *dso; |
| 186 | }; | 199 | }; |
| 187 | 200 | ||
| 188 | static __u64 map__map_ip(struct map *map, __u64 ip) | 201 | static u64 map__map_ip(struct map *map, u64 ip) |
| 189 | { | 202 | { |
| 190 | return ip - map->start + map->pgoff; | 203 | return ip - map->start + map->pgoff; |
| 191 | } | 204 | } |
| 192 | 205 | ||
| 193 | static __u64 vdso__map_ip(struct map *map, __u64 ip) | 206 | static u64 vdso__map_ip(struct map *map __used, u64 ip) |
| 194 | { | 207 | { |
| 195 | return ip; | 208 | return ip; |
| 196 | } | 209 | } |
| @@ -373,7 +386,7 @@ static int thread__fork(struct thread *self, struct thread *parent) | |||
| 373 | return 0; | 386 | return 0; |
| 374 | } | 387 | } |
| 375 | 388 | ||
| 376 | static struct map *thread__find_map(struct thread *self, __u64 ip) | 389 | static struct map *thread__find_map(struct thread *self, u64 ip) |
| 377 | { | 390 | { |
| 378 | struct map *pos; | 391 | struct map *pos; |
| 379 | 392 | ||
| @@ -414,7 +427,7 @@ struct hist_entry { | |||
| 414 | struct map *map; | 427 | struct map *map; |
| 415 | struct dso *dso; | 428 | struct dso *dso; |
| 416 | struct symbol *sym; | 429 | struct symbol *sym; |
| 417 | __u64 ip; | 430 | u64 ip; |
| 418 | char level; | 431 | char level; |
| 419 | 432 | ||
| 420 | uint32_t count; | 433 | uint32_t count; |
| @@ -519,7 +532,7 @@ sort__dso_print(FILE *fp, struct hist_entry *self) | |||
| 519 | if (self->dso) | 532 | if (self->dso) |
| 520 | return fprintf(fp, "%-25s", self->dso->name); | 533 | return fprintf(fp, "%-25s", self->dso->name); |
| 521 | 534 | ||
| 522 | return fprintf(fp, "%016llx ", (__u64)self->ip); | 535 | return fprintf(fp, "%016llx ", (u64)self->ip); |
| 523 | } | 536 | } |
| 524 | 537 | ||
| 525 | static struct sort_entry sort_dso = { | 538 | static struct sort_entry sort_dso = { |
| @@ -533,7 +546,7 @@ static struct sort_entry sort_dso = { | |||
| 533 | static int64_t | 546 | static int64_t |
| 534 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | 547 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) |
| 535 | { | 548 | { |
| 536 | __u64 ip_l, ip_r; | 549 | u64 ip_l, ip_r; |
| 537 | 550 | ||
| 538 | if (left->sym == right->sym) | 551 | if (left->sym == right->sym) |
| 539 | return 0; | 552 | return 0; |
| @@ -550,13 +563,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self) | |||
| 550 | size_t ret = 0; | 563 | size_t ret = 0; |
| 551 | 564 | ||
| 552 | if (verbose) | 565 | if (verbose) |
| 553 | ret += fprintf(fp, "%#018llx ", (__u64)self->ip); | 566 | ret += fprintf(fp, "%#018llx ", (u64)self->ip); |
| 554 | 567 | ||
| 555 | if (self->sym) { | 568 | if (self->sym) { |
| 556 | ret += fprintf(fp, "[%c] %s", | 569 | ret += fprintf(fp, "[%c] %s", |
| 557 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); | 570 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); |
| 558 | } else { | 571 | } else { |
| 559 | ret += fprintf(fp, "%#016llx", (__u64)self->ip); | 572 | ret += fprintf(fp, "%#016llx", (u64)self->ip); |
| 560 | } | 573 | } |
| 561 | 574 | ||
| 562 | return ret; | 575 | return ret; |
| @@ -587,7 +600,7 @@ static LIST_HEAD(hist_entry__sort_list); | |||
| 587 | 600 | ||
| 588 | static int sort_dimension__add(char *tok) | 601 | static int sort_dimension__add(char *tok) |
| 589 | { | 602 | { |
| 590 | int i; | 603 | unsigned int i; |
| 591 | 604 | ||
| 592 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { | 605 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { |
| 593 | struct sort_dimension *sd = &sort_dimensions[i]; | 606 | struct sort_dimension *sd = &sort_dimensions[i]; |
| @@ -647,7 +660,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
| 647 | /* | 660 | /* |
| 648 | * collect histogram counts | 661 | * collect histogram counts |
| 649 | */ | 662 | */ |
| 650 | static void hist_hit(struct hist_entry *he, __u64 ip) | 663 | static void hist_hit(struct hist_entry *he, u64 ip) |
| 651 | { | 664 | { |
| 652 | unsigned int sym_size, offset; | 665 | unsigned int sym_size, offset; |
| 653 | struct symbol *sym = he->sym; | 666 | struct symbol *sym = he->sym; |
| @@ -676,7 +689,7 @@ static void hist_hit(struct hist_entry *he, __u64 ip) | |||
| 676 | 689 | ||
| 677 | static int | 690 | static int |
| 678 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | 691 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, |
| 679 | struct symbol *sym, __u64 ip, char level) | 692 | struct symbol *sym, u64 ip, char level) |
| 680 | { | 693 | { |
| 681 | struct rb_node **p = &hist.rb_node; | 694 | struct rb_node **p = &hist.rb_node; |
| 682 | struct rb_node *parent = NULL; | 695 | struct rb_node *parent = NULL; |
| @@ -842,13 +855,13 @@ static unsigned long total = 0, | |||
| 842 | total_unknown = 0; | 855 | total_unknown = 0; |
| 843 | 856 | ||
| 844 | static int | 857 | static int |
| 845 | process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | 858 | process_sample_event(event_t *event, unsigned long offset, unsigned long head) |
| 846 | { | 859 | { |
| 847 | char level; | 860 | char level; |
| 848 | int show = 0; | 861 | int show = 0; |
| 849 | struct dso *dso = NULL; | 862 | struct dso *dso = NULL; |
| 850 | struct thread *thread = threads__findnew(event->ip.pid); | 863 | struct thread *thread = threads__findnew(event->ip.pid); |
| 851 | __u64 ip = event->ip.ip; | 864 | u64 ip = event->ip.ip; |
| 852 | struct map *map = NULL; | 865 | struct map *map = NULL; |
| 853 | 866 | ||
| 854 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", | 867 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", |
| @@ -1000,10 +1013,10 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1000 | static int | 1013 | static int |
| 1001 | process_event(event_t *event, unsigned long offset, unsigned long head) | 1014 | process_event(event_t *event, unsigned long offset, unsigned long head) |
| 1002 | { | 1015 | { |
| 1003 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) | ||
| 1004 | return process_overflow_event(event, offset, head); | ||
| 1005 | |||
| 1006 | switch (event->header.type) { | 1016 | switch (event->header.type) { |
| 1017 | case PERF_EVENT_SAMPLE: | ||
| 1018 | return process_sample_event(event, offset, head); | ||
| 1019 | |||
| 1007 | case PERF_EVENT_MMAP: | 1020 | case PERF_EVENT_MMAP: |
| 1008 | return process_mmap_event(event, offset, head); | 1021 | return process_mmap_event(event, offset, head); |
| 1009 | 1022 | ||
| @@ -1031,12 +1044,14 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1031 | } | 1044 | } |
| 1032 | 1045 | ||
| 1033 | static int | 1046 | static int |
| 1034 | parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | 1047 | parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) |
| 1035 | { | 1048 | { |
| 1036 | char *line = NULL, *tmp, *tmp2; | 1049 | char *line = NULL, *tmp, *tmp2; |
| 1050 | static const char *prev_line; | ||
| 1051 | static const char *prev_color; | ||
| 1037 | unsigned int offset; | 1052 | unsigned int offset; |
| 1038 | size_t line_len; | 1053 | size_t line_len; |
| 1039 | __u64 line_ip; | 1054 | s64 line_ip; |
| 1040 | int ret; | 1055 | int ret; |
| 1041 | char *c; | 1056 | char *c; |
| 1042 | 1057 | ||
| @@ -1073,27 +1088,36 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
| 1073 | } | 1088 | } |
| 1074 | 1089 | ||
| 1075 | if (line_ip != -1) { | 1090 | if (line_ip != -1) { |
| 1091 | const char *path = NULL; | ||
| 1076 | unsigned int hits = 0; | 1092 | unsigned int hits = 0; |
| 1077 | double percent = 0.0; | 1093 | double percent = 0.0; |
| 1078 | char *color = PERF_COLOR_NORMAL; | 1094 | char *color; |
| 1095 | struct sym_ext *sym_ext = sym->priv; | ||
| 1079 | 1096 | ||
| 1080 | offset = line_ip - start; | 1097 | offset = line_ip - start; |
| 1081 | if (offset < len) | 1098 | if (offset < len) |
| 1082 | hits = sym->hist[offset]; | 1099 | hits = sym->hist[offset]; |
| 1083 | 1100 | ||
| 1084 | if (sym->hist_sum) | 1101 | if (offset < len && sym_ext) { |
| 1102 | path = sym_ext[offset].path; | ||
| 1103 | percent = sym_ext[offset].percent; | ||
| 1104 | } else if (sym->hist_sum) | ||
| 1085 | percent = 100.0 * hits / sym->hist_sum; | 1105 | percent = 100.0 * hits / sym->hist_sum; |
| 1086 | 1106 | ||
| 1107 | color = get_percent_color(percent); | ||
| 1108 | |||
| 1087 | /* | 1109 | /* |
| 1088 | * We color high-overhead entries in red, mid-overhead | 1110 | * Also color the filename and line if needed, with |
| 1089 | * entries in green - and keep the low overhead places | 1111 | * the same color than the percentage. Don't print it |
| 1090 | * normal: | 1112 | * twice for close colored ip with the same filename:line |
| 1091 | */ | 1113 | */ |
| 1092 | if (percent >= 5.0) | 1114 | if (path) { |
| 1093 | color = PERF_COLOR_RED; | 1115 | if (!prev_line || strcmp(prev_line, path) |
| 1094 | else { | 1116 | || color != prev_color) { |
| 1095 | if (percent > 0.5) | 1117 | color_fprintf(stdout, color, " %s", path); |
| 1096 | color = PERF_COLOR_GREEN; | 1118 | prev_line = path; |
| 1119 | prev_color = color; | ||
| 1120 | } | ||
| 1097 | } | 1121 | } |
| 1098 | 1122 | ||
| 1099 | color_fprintf(stdout, color, " %7.2f", percent); | 1123 | color_fprintf(stdout, color, " %7.2f", percent); |
| @@ -1109,33 +1133,160 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
| 1109 | return 0; | 1133 | return 0; |
| 1110 | } | 1134 | } |
| 1111 | 1135 | ||
| 1136 | static struct rb_root root_sym_ext; | ||
| 1137 | |||
| 1138 | static void insert_source_line(struct sym_ext *sym_ext) | ||
| 1139 | { | ||
| 1140 | struct sym_ext *iter; | ||
| 1141 | struct rb_node **p = &root_sym_ext.rb_node; | ||
| 1142 | struct rb_node *parent = NULL; | ||
| 1143 | |||
| 1144 | while (*p != NULL) { | ||
| 1145 | parent = *p; | ||
| 1146 | iter = rb_entry(parent, struct sym_ext, node); | ||
| 1147 | |||
| 1148 | if (sym_ext->percent > iter->percent) | ||
| 1149 | p = &(*p)->rb_left; | ||
| 1150 | else | ||
| 1151 | p = &(*p)->rb_right; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | rb_link_node(&sym_ext->node, parent, p); | ||
| 1155 | rb_insert_color(&sym_ext->node, &root_sym_ext); | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | static void free_source_line(struct symbol *sym, int len) | ||
| 1159 | { | ||
| 1160 | struct sym_ext *sym_ext = sym->priv; | ||
| 1161 | int i; | ||
| 1162 | |||
| 1163 | if (!sym_ext) | ||
| 1164 | return; | ||
| 1165 | |||
| 1166 | for (i = 0; i < len; i++) | ||
| 1167 | free(sym_ext[i].path); | ||
| 1168 | free(sym_ext); | ||
| 1169 | |||
| 1170 | sym->priv = NULL; | ||
| 1171 | root_sym_ext = RB_ROOT; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | /* Get the filename:line for the colored entries */ | ||
| 1175 | static void | ||
| 1176 | get_source_line(struct symbol *sym, u64 start, int len, char *filename) | ||
| 1177 | { | ||
| 1178 | int i; | ||
| 1179 | char cmd[PATH_MAX * 2]; | ||
| 1180 | struct sym_ext *sym_ext; | ||
| 1181 | |||
| 1182 | if (!sym->hist_sum) | ||
| 1183 | return; | ||
| 1184 | |||
| 1185 | sym->priv = calloc(len, sizeof(struct sym_ext)); | ||
| 1186 | if (!sym->priv) | ||
| 1187 | return; | ||
| 1188 | |||
| 1189 | sym_ext = sym->priv; | ||
| 1190 | |||
| 1191 | for (i = 0; i < len; i++) { | ||
| 1192 | char *path = NULL; | ||
| 1193 | size_t line_len; | ||
| 1194 | u64 offset; | ||
| 1195 | FILE *fp; | ||
| 1196 | |||
| 1197 | sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; | ||
| 1198 | if (sym_ext[i].percent <= 0.5) | ||
| 1199 | continue; | ||
| 1200 | |||
| 1201 | offset = start + i; | ||
| 1202 | sprintf(cmd, "addr2line -e %s %016llx", filename, offset); | ||
| 1203 | fp = popen(cmd, "r"); | ||
| 1204 | if (!fp) | ||
| 1205 | continue; | ||
| 1206 | |||
| 1207 | if (getline(&path, &line_len, fp) < 0 || !line_len) | ||
| 1208 | goto next; | ||
| 1209 | |||
| 1210 | sym_ext[i].path = malloc(sizeof(char) * line_len + 1); | ||
| 1211 | if (!sym_ext[i].path) | ||
| 1212 | goto next; | ||
| 1213 | |||
| 1214 | strcpy(sym_ext[i].path, path); | ||
| 1215 | insert_source_line(&sym_ext[i]); | ||
| 1216 | |||
| 1217 | next: | ||
| 1218 | pclose(fp); | ||
| 1219 | } | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | static void print_summary(char *filename) | ||
| 1223 | { | ||
| 1224 | struct sym_ext *sym_ext; | ||
| 1225 | struct rb_node *node; | ||
| 1226 | |||
| 1227 | printf("\nSorted summary for file %s\n", filename); | ||
| 1228 | printf("----------------------------------------------\n\n"); | ||
| 1229 | |||
| 1230 | if (RB_EMPTY_ROOT(&root_sym_ext)) { | ||
| 1231 | printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); | ||
| 1232 | return; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | node = rb_first(&root_sym_ext); | ||
| 1236 | while (node) { | ||
| 1237 | double percent; | ||
| 1238 | char *color; | ||
| 1239 | char *path; | ||
| 1240 | |||
| 1241 | sym_ext = rb_entry(node, struct sym_ext, node); | ||
| 1242 | percent = sym_ext->percent; | ||
| 1243 | color = get_percent_color(percent); | ||
| 1244 | path = sym_ext->path; | ||
| 1245 | |||
| 1246 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | ||
| 1247 | node = rb_next(node); | ||
| 1248 | } | ||
| 1249 | } | ||
| 1250 | |||
| 1112 | static void annotate_sym(struct dso *dso, struct symbol *sym) | 1251 | static void annotate_sym(struct dso *dso, struct symbol *sym) |
| 1113 | { | 1252 | { |
| 1114 | char *filename = dso->name; | 1253 | char *filename = dso->name, *d_filename; |
| 1115 | __u64 start, end, len; | 1254 | u64 start, end, len; |
| 1116 | char command[PATH_MAX*2]; | 1255 | char command[PATH_MAX*2]; |
| 1117 | FILE *file; | 1256 | FILE *file; |
| 1118 | 1257 | ||
| 1119 | if (!filename) | 1258 | if (!filename) |
| 1120 | return; | 1259 | return; |
| 1121 | if (dso == kernel_dso) | 1260 | if (sym->module) |
| 1261 | filename = sym->module->path; | ||
| 1262 | else if (dso == kernel_dso) | ||
| 1122 | filename = vmlinux; | 1263 | filename = vmlinux; |
| 1123 | 1264 | ||
| 1124 | printf("\n------------------------------------------------\n"); | ||
| 1125 | printf(" Percent | Source code & Disassembly of %s\n", filename); | ||
| 1126 | printf("------------------------------------------------\n"); | ||
| 1127 | |||
| 1128 | if (verbose >= 2) | ||
| 1129 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | ||
| 1130 | |||
| 1131 | start = sym->obj_start; | 1265 | start = sym->obj_start; |
| 1132 | if (!start) | 1266 | if (!start) |
| 1133 | start = sym->start; | 1267 | start = sym->start; |
| 1268 | if (full_paths) | ||
| 1269 | d_filename = filename; | ||
| 1270 | else | ||
| 1271 | d_filename = basename(filename); | ||
| 1134 | 1272 | ||
| 1135 | end = start + sym->end - sym->start + 1; | 1273 | end = start + sym->end - sym->start + 1; |
| 1136 | len = sym->end - sym->start; | 1274 | len = sym->end - sym->start; |
| 1137 | 1275 | ||
| 1138 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); | 1276 | if (print_line) { |
| 1277 | get_source_line(sym, start, len, filename); | ||
| 1278 | print_summary(filename); | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | printf("\n\n------------------------------------------------\n"); | ||
| 1282 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); | ||
| 1283 | printf("------------------------------------------------\n"); | ||
| 1284 | |||
| 1285 | if (verbose >= 2) | ||
| 1286 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | ||
| 1287 | |||
| 1288 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", | ||
| 1289 | (u64)start, (u64)end, filename, filename); | ||
| 1139 | 1290 | ||
| 1140 | if (verbose >= 3) | 1291 | if (verbose >= 3) |
| 1141 | printf("doing: %s\n", command); | 1292 | printf("doing: %s\n", command); |
| @@ -1150,6 +1301,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
| 1150 | } | 1301 | } |
| 1151 | 1302 | ||
| 1152 | pclose(file); | 1303 | pclose(file); |
| 1304 | if (print_line) | ||
| 1305 | free_source_line(sym, len); | ||
| 1153 | } | 1306 | } |
| 1154 | 1307 | ||
| 1155 | static void find_annotations(void) | 1308 | static void find_annotations(void) |
| @@ -1264,7 +1417,7 @@ more: | |||
| 1264 | 1417 | ||
| 1265 | head += size; | 1418 | head += size; |
| 1266 | 1419 | ||
| 1267 | if (offset + head < stat.st_size) | 1420 | if (offset + head < (unsigned long)stat.st_size) |
| 1268 | goto more; | 1421 | goto more; |
| 1269 | 1422 | ||
| 1270 | rc = EXIT_SUCCESS; | 1423 | rc = EXIT_SUCCESS; |
| @@ -1308,6 +1461,12 @@ static const struct option options[] = { | |||
| 1308 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1461 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
| 1309 | "dump raw trace in ASCII"), | 1462 | "dump raw trace in ASCII"), |
| 1310 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), | 1463 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), |
| 1464 | OPT_BOOLEAN('m', "modules", &modules, | ||
| 1465 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | ||
| 1466 | OPT_BOOLEAN('l', "print-line", &print_line, | ||
| 1467 | "print matching source lines (may be slow)"), | ||
| 1468 | OPT_BOOLEAN('P', "full-paths", &full_paths, | ||
| 1469 | "Don't shorten the displayed pathnames"), | ||
| 1311 | OPT_END() | 1470 | OPT_END() |
| 1312 | }; | 1471 | }; |
| 1313 | 1472 | ||
| @@ -1326,7 +1485,7 @@ static void setup_sorting(void) | |||
| 1326 | free(str); | 1485 | free(str); |
| 1327 | } | 1486 | } |
| 1328 | 1487 | ||
| 1329 | int cmd_annotate(int argc, const char **argv, const char *prefix) | 1488 | int cmd_annotate(int argc, const char **argv, const char *prefix __used) |
| 1330 | { | 1489 | { |
| 1331 | symbol__init(); | 1490 | symbol__init(); |
| 1332 | 1491 | ||
