diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 301 |
1 files changed, 218 insertions, 83 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index b1ed5f766cb3..1dba568e1941 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,39 @@ 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 | }; | ||
70 | |||
71 | struct period_event { | ||
72 | struct perf_event_header header; | ||
73 | __u64 time; | ||
74 | __u64 id; | ||
75 | __u64 sample_period; | ||
76 | }; | 75 | }; |
77 | 76 | ||
78 | typedef union event_union { | 77 | typedef union event_union { |
@@ -81,9 +80,15 @@ typedef union event_union { | |||
81 | struct mmap_event mmap; | 80 | struct mmap_event mmap; |
82 | struct comm_event comm; | 81 | struct comm_event comm; |
83 | struct fork_event fork; | 82 | struct fork_event fork; |
84 | struct period_event period; | ||
85 | } event_t; | 83 | } event_t; |
86 | 84 | ||
85 | |||
86 | struct sym_ext { | ||
87 | struct rb_node node; | ||
88 | double percent; | ||
89 | char *path; | ||
90 | }; | ||
91 | |||
87 | static LIST_HEAD(dsos); | 92 | static LIST_HEAD(dsos); |
88 | static struct dso *kernel_dso; | 93 | static struct dso *kernel_dso; |
89 | static struct dso *vdso; | 94 | static struct dso *vdso; |
@@ -145,9 +150,9 @@ static void dsos__fprintf(FILE *fp) | |||
145 | dso__fprintf(pos, fp); | 150 | dso__fprintf(pos, fp); |
146 | } | 151 | } |
147 | 152 | ||
148 | static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) | 153 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) |
149 | { | 154 | { |
150 | return dso__find_symbol(kernel_dso, ip); | 155 | return dso__find_symbol(dso, ip); |
151 | } | 156 | } |
152 | 157 | ||
153 | static int load_kernel(void) | 158 | static int load_kernel(void) |
@@ -158,8 +163,8 @@ static int load_kernel(void) | |||
158 | if (!kernel_dso) | 163 | if (!kernel_dso) |
159 | return -1; | 164 | return -1; |
160 | 165 | ||
161 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); | 166 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); |
162 | if (err) { | 167 | if (err <= 0) { |
163 | dso__delete(kernel_dso); | 168 | dso__delete(kernel_dso); |
164 | kernel_dso = NULL; | 169 | kernel_dso = NULL; |
165 | } else | 170 | } else |
@@ -178,19 +183,19 @@ static int load_kernel(void) | |||
178 | 183 | ||
179 | struct map { | 184 | struct map { |
180 | struct list_head node; | 185 | struct list_head node; |
181 | __u64 start; | 186 | u64 start; |
182 | __u64 end; | 187 | u64 end; |
183 | __u64 pgoff; | 188 | u64 pgoff; |
184 | __u64 (*map_ip)(struct map *, __u64); | 189 | u64 (*map_ip)(struct map *, u64); |
185 | struct dso *dso; | 190 | struct dso *dso; |
186 | }; | 191 | }; |
187 | 192 | ||
188 | static __u64 map__map_ip(struct map *map, __u64 ip) | 193 | static u64 map__map_ip(struct map *map, u64 ip) |
189 | { | 194 | { |
190 | return ip - map->start + map->pgoff; | 195 | return ip - map->start + map->pgoff; |
191 | } | 196 | } |
192 | 197 | ||
193 | static __u64 vdso__map_ip(struct map *map, __u64 ip) | 198 | static u64 vdso__map_ip(struct map *map __used, u64 ip) |
194 | { | 199 | { |
195 | return ip; | 200 | return ip; |
196 | } | 201 | } |
@@ -373,7 +378,7 @@ static int thread__fork(struct thread *self, struct thread *parent) | |||
373 | return 0; | 378 | return 0; |
374 | } | 379 | } |
375 | 380 | ||
376 | static struct map *thread__find_map(struct thread *self, __u64 ip) | 381 | static struct map *thread__find_map(struct thread *self, u64 ip) |
377 | { | 382 | { |
378 | struct map *pos; | 383 | struct map *pos; |
379 | 384 | ||
@@ -414,7 +419,7 @@ struct hist_entry { | |||
414 | struct map *map; | 419 | struct map *map; |
415 | struct dso *dso; | 420 | struct dso *dso; |
416 | struct symbol *sym; | 421 | struct symbol *sym; |
417 | __u64 ip; | 422 | u64 ip; |
418 | char level; | 423 | char level; |
419 | 424 | ||
420 | uint32_t count; | 425 | uint32_t count; |
@@ -519,7 +524,7 @@ sort__dso_print(FILE *fp, struct hist_entry *self) | |||
519 | if (self->dso) | 524 | if (self->dso) |
520 | return fprintf(fp, "%-25s", self->dso->name); | 525 | return fprintf(fp, "%-25s", self->dso->name); |
521 | 526 | ||
522 | return fprintf(fp, "%016llx ", (__u64)self->ip); | 527 | return fprintf(fp, "%016llx ", (u64)self->ip); |
523 | } | 528 | } |
524 | 529 | ||
525 | static struct sort_entry sort_dso = { | 530 | static struct sort_entry sort_dso = { |
@@ -533,7 +538,7 @@ static struct sort_entry sort_dso = { | |||
533 | static int64_t | 538 | static int64_t |
534 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | 539 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) |
535 | { | 540 | { |
536 | __u64 ip_l, ip_r; | 541 | u64 ip_l, ip_r; |
537 | 542 | ||
538 | if (left->sym == right->sym) | 543 | if (left->sym == right->sym) |
539 | return 0; | 544 | return 0; |
@@ -550,13 +555,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self) | |||
550 | size_t ret = 0; | 555 | size_t ret = 0; |
551 | 556 | ||
552 | if (verbose) | 557 | if (verbose) |
553 | ret += fprintf(fp, "%#018llx ", (__u64)self->ip); | 558 | ret += fprintf(fp, "%#018llx ", (u64)self->ip); |
554 | 559 | ||
555 | if (self->sym) { | 560 | if (self->sym) { |
556 | ret += fprintf(fp, "[%c] %s", | 561 | ret += fprintf(fp, "[%c] %s", |
557 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); | 562 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); |
558 | } else { | 563 | } else { |
559 | ret += fprintf(fp, "%#016llx", (__u64)self->ip); | 564 | ret += fprintf(fp, "%#016llx", (u64)self->ip); |
560 | } | 565 | } |
561 | 566 | ||
562 | return ret; | 567 | return ret; |
@@ -587,7 +592,7 @@ static LIST_HEAD(hist_entry__sort_list); | |||
587 | 592 | ||
588 | static int sort_dimension__add(char *tok) | 593 | static int sort_dimension__add(char *tok) |
589 | { | 594 | { |
590 | int i; | 595 | unsigned int i; |
591 | 596 | ||
592 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { | 597 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { |
593 | struct sort_dimension *sd = &sort_dimensions[i]; | 598 | struct sort_dimension *sd = &sort_dimensions[i]; |
@@ -647,7 +652,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
647 | /* | 652 | /* |
648 | * collect histogram counts | 653 | * collect histogram counts |
649 | */ | 654 | */ |
650 | static void hist_hit(struct hist_entry *he, __u64 ip) | 655 | static void hist_hit(struct hist_entry *he, u64 ip) |
651 | { | 656 | { |
652 | unsigned int sym_size, offset; | 657 | unsigned int sym_size, offset; |
653 | struct symbol *sym = he->sym; | 658 | struct symbol *sym = he->sym; |
@@ -676,7 +681,7 @@ static void hist_hit(struct hist_entry *he, __u64 ip) | |||
676 | 681 | ||
677 | static int | 682 | static int |
678 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | 683 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, |
679 | struct symbol *sym, __u64 ip, char level) | 684 | struct symbol *sym, u64 ip, char level) |
680 | { | 685 | { |
681 | struct rb_node **p = &hist.rb_node; | 686 | struct rb_node **p = &hist.rb_node; |
682 | struct rb_node *parent = NULL; | 687 | struct rb_node *parent = NULL; |
@@ -842,13 +847,13 @@ static unsigned long total = 0, | |||
842 | total_unknown = 0; | 847 | total_unknown = 0; |
843 | 848 | ||
844 | static int | 849 | static int |
845 | process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | 850 | process_sample_event(event_t *event, unsigned long offset, unsigned long head) |
846 | { | 851 | { |
847 | char level; | 852 | char level; |
848 | int show = 0; | 853 | int show = 0; |
849 | struct dso *dso = NULL; | 854 | struct dso *dso = NULL; |
850 | struct thread *thread = threads__findnew(event->ip.pid); | 855 | struct thread *thread = threads__findnew(event->ip.pid); |
851 | __u64 ip = event->ip.ip; | 856 | u64 ip = event->ip.ip; |
852 | struct map *map = NULL; | 857 | struct map *map = NULL; |
853 | 858 | ||
854 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", | 859 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", |
@@ -985,25 +990,12 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) | |||
985 | } | 990 | } |
986 | 991 | ||
987 | static int | 992 | static int |
988 | process_period_event(event_t *event, unsigned long offset, unsigned long head) | ||
989 | { | ||
990 | dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n", | ||
991 | (void *)(offset + head), | ||
992 | (void *)(long)(event->header.size), | ||
993 | event->period.time, | ||
994 | event->period.id, | ||
995 | event->period.sample_period); | ||
996 | |||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | static int | ||
1001 | process_event(event_t *event, unsigned long offset, unsigned long head) | 993 | process_event(event_t *event, unsigned long offset, unsigned long head) |
1002 | { | 994 | { |
1003 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) | ||
1004 | return process_overflow_event(event, offset, head); | ||
1005 | |||
1006 | switch (event->header.type) { | 995 | switch (event->header.type) { |
996 | case PERF_EVENT_SAMPLE: | ||
997 | return process_sample_event(event, offset, head); | ||
998 | |||
1007 | case PERF_EVENT_MMAP: | 999 | case PERF_EVENT_MMAP: |
1008 | return process_mmap_event(event, offset, head); | 1000 | return process_mmap_event(event, offset, head); |
1009 | 1001 | ||
@@ -1012,9 +1004,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1012 | 1004 | ||
1013 | case PERF_EVENT_FORK: | 1005 | case PERF_EVENT_FORK: |
1014 | return process_fork_event(event, offset, head); | 1006 | return process_fork_event(event, offset, head); |
1015 | |||
1016 | case PERF_EVENT_PERIOD: | ||
1017 | return process_period_event(event, offset, head); | ||
1018 | /* | 1007 | /* |
1019 | * We dont process them right now but they are fine: | 1008 | * We dont process them right now but they are fine: |
1020 | */ | 1009 | */ |
@@ -1031,12 +1020,14 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1031 | } | 1020 | } |
1032 | 1021 | ||
1033 | static int | 1022 | static int |
1034 | parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | 1023 | parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) |
1035 | { | 1024 | { |
1036 | char *line = NULL, *tmp, *tmp2; | 1025 | char *line = NULL, *tmp, *tmp2; |
1026 | static const char *prev_line; | ||
1027 | static const char *prev_color; | ||
1037 | unsigned int offset; | 1028 | unsigned int offset; |
1038 | size_t line_len; | 1029 | size_t line_len; |
1039 | __u64 line_ip; | 1030 | s64 line_ip; |
1040 | int ret; | 1031 | int ret; |
1041 | char *c; | 1032 | char *c; |
1042 | 1033 | ||
@@ -1073,27 +1064,36 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
1073 | } | 1064 | } |
1074 | 1065 | ||
1075 | if (line_ip != -1) { | 1066 | if (line_ip != -1) { |
1067 | const char *path = NULL; | ||
1076 | unsigned int hits = 0; | 1068 | unsigned int hits = 0; |
1077 | double percent = 0.0; | 1069 | double percent = 0.0; |
1078 | char *color = PERF_COLOR_NORMAL; | 1070 | char *color; |
1071 | struct sym_ext *sym_ext = sym->priv; | ||
1079 | 1072 | ||
1080 | offset = line_ip - start; | 1073 | offset = line_ip - start; |
1081 | if (offset < len) | 1074 | if (offset < len) |
1082 | hits = sym->hist[offset]; | 1075 | hits = sym->hist[offset]; |
1083 | 1076 | ||
1084 | if (sym->hist_sum) | 1077 | if (offset < len && sym_ext) { |
1078 | path = sym_ext[offset].path; | ||
1079 | percent = sym_ext[offset].percent; | ||
1080 | } else if (sym->hist_sum) | ||
1085 | percent = 100.0 * hits / sym->hist_sum; | 1081 | percent = 100.0 * hits / sym->hist_sum; |
1086 | 1082 | ||
1083 | color = get_percent_color(percent); | ||
1084 | |||
1087 | /* | 1085 | /* |
1088 | * We color high-overhead entries in red, mid-overhead | 1086 | * Also color the filename and line if needed, with |
1089 | * entries in green - and keep the low overhead places | 1087 | * the same color than the percentage. Don't print it |
1090 | * normal: | 1088 | * twice for close colored ip with the same filename:line |
1091 | */ | 1089 | */ |
1092 | if (percent >= 5.0) | 1090 | if (path) { |
1093 | color = PERF_COLOR_RED; | 1091 | if (!prev_line || strcmp(prev_line, path) |
1094 | else { | 1092 | || color != prev_color) { |
1095 | if (percent > 0.5) | 1093 | color_fprintf(stdout, color, " %s", path); |
1096 | color = PERF_COLOR_GREEN; | 1094 | prev_line = path; |
1095 | prev_color = color; | ||
1096 | } | ||
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | color_fprintf(stdout, color, " %7.2f", percent); | 1099 | color_fprintf(stdout, color, " %7.2f", percent); |
@@ -1109,33 +1109,160 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
1109 | return 0; | 1109 | return 0; |
1110 | } | 1110 | } |
1111 | 1111 | ||
1112 | static struct rb_root root_sym_ext; | ||
1113 | |||
1114 | static void insert_source_line(struct sym_ext *sym_ext) | ||
1115 | { | ||
1116 | struct sym_ext *iter; | ||
1117 | struct rb_node **p = &root_sym_ext.rb_node; | ||
1118 | struct rb_node *parent = NULL; | ||
1119 | |||
1120 | while (*p != NULL) { | ||
1121 | parent = *p; | ||
1122 | iter = rb_entry(parent, struct sym_ext, node); | ||
1123 | |||
1124 | if (sym_ext->percent > iter->percent) | ||
1125 | p = &(*p)->rb_left; | ||
1126 | else | ||
1127 | p = &(*p)->rb_right; | ||
1128 | } | ||
1129 | |||
1130 | rb_link_node(&sym_ext->node, parent, p); | ||
1131 | rb_insert_color(&sym_ext->node, &root_sym_ext); | ||
1132 | } | ||
1133 | |||
1134 | static void free_source_line(struct symbol *sym, int len) | ||
1135 | { | ||
1136 | struct sym_ext *sym_ext = sym->priv; | ||
1137 | int i; | ||
1138 | |||
1139 | if (!sym_ext) | ||
1140 | return; | ||
1141 | |||
1142 | for (i = 0; i < len; i++) | ||
1143 | free(sym_ext[i].path); | ||
1144 | free(sym_ext); | ||
1145 | |||
1146 | sym->priv = NULL; | ||
1147 | root_sym_ext = RB_ROOT; | ||
1148 | } | ||
1149 | |||
1150 | /* Get the filename:line for the colored entries */ | ||
1151 | static void | ||
1152 | get_source_line(struct symbol *sym, u64 start, int len, char *filename) | ||
1153 | { | ||
1154 | int i; | ||
1155 | char cmd[PATH_MAX * 2]; | ||
1156 | struct sym_ext *sym_ext; | ||
1157 | |||
1158 | if (!sym->hist_sum) | ||
1159 | return; | ||
1160 | |||
1161 | sym->priv = calloc(len, sizeof(struct sym_ext)); | ||
1162 | if (!sym->priv) | ||
1163 | return; | ||
1164 | |||
1165 | sym_ext = sym->priv; | ||
1166 | |||
1167 | for (i = 0; i < len; i++) { | ||
1168 | char *path = NULL; | ||
1169 | size_t line_len; | ||
1170 | u64 offset; | ||
1171 | FILE *fp; | ||
1172 | |||
1173 | sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; | ||
1174 | if (sym_ext[i].percent <= 0.5) | ||
1175 | continue; | ||
1176 | |||
1177 | offset = start + i; | ||
1178 | sprintf(cmd, "addr2line -e %s %016llx", filename, offset); | ||
1179 | fp = popen(cmd, "r"); | ||
1180 | if (!fp) | ||
1181 | continue; | ||
1182 | |||
1183 | if (getline(&path, &line_len, fp) < 0 || !line_len) | ||
1184 | goto next; | ||
1185 | |||
1186 | sym_ext[i].path = malloc(sizeof(char) * line_len + 1); | ||
1187 | if (!sym_ext[i].path) | ||
1188 | goto next; | ||
1189 | |||
1190 | strcpy(sym_ext[i].path, path); | ||
1191 | insert_source_line(&sym_ext[i]); | ||
1192 | |||
1193 | next: | ||
1194 | pclose(fp); | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | static void print_summary(char *filename) | ||
1199 | { | ||
1200 | struct sym_ext *sym_ext; | ||
1201 | struct rb_node *node; | ||
1202 | |||
1203 | printf("\nSorted summary for file %s\n", filename); | ||
1204 | printf("----------------------------------------------\n\n"); | ||
1205 | |||
1206 | if (RB_EMPTY_ROOT(&root_sym_ext)) { | ||
1207 | printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); | ||
1208 | return; | ||
1209 | } | ||
1210 | |||
1211 | node = rb_first(&root_sym_ext); | ||
1212 | while (node) { | ||
1213 | double percent; | ||
1214 | char *color; | ||
1215 | char *path; | ||
1216 | |||
1217 | sym_ext = rb_entry(node, struct sym_ext, node); | ||
1218 | percent = sym_ext->percent; | ||
1219 | color = get_percent_color(percent); | ||
1220 | path = sym_ext->path; | ||
1221 | |||
1222 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | ||
1223 | node = rb_next(node); | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1112 | static void annotate_sym(struct dso *dso, struct symbol *sym) | 1227 | static void annotate_sym(struct dso *dso, struct symbol *sym) |
1113 | { | 1228 | { |
1114 | char *filename = dso->name; | 1229 | char *filename = dso->name, *d_filename; |
1115 | __u64 start, end, len; | 1230 | u64 start, end, len; |
1116 | char command[PATH_MAX*2]; | 1231 | char command[PATH_MAX*2]; |
1117 | FILE *file; | 1232 | FILE *file; |
1118 | 1233 | ||
1119 | if (!filename) | 1234 | if (!filename) |
1120 | return; | 1235 | return; |
1121 | if (dso == kernel_dso) | 1236 | if (sym->module) |
1237 | filename = sym->module->path; | ||
1238 | else if (dso == kernel_dso) | ||
1122 | filename = vmlinux; | 1239 | filename = vmlinux; |
1123 | 1240 | ||
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; | 1241 | start = sym->obj_start; |
1132 | if (!start) | 1242 | if (!start) |
1133 | start = sym->start; | 1243 | start = sym->start; |
1244 | if (full_paths) | ||
1245 | d_filename = filename; | ||
1246 | else | ||
1247 | d_filename = basename(filename); | ||
1134 | 1248 | ||
1135 | end = start + sym->end - sym->start + 1; | 1249 | end = start + sym->end - sym->start + 1; |
1136 | len = sym->end - sym->start; | 1250 | len = sym->end - sym->start; |
1137 | 1251 | ||
1138 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); | 1252 | if (print_line) { |
1253 | get_source_line(sym, start, len, filename); | ||
1254 | print_summary(filename); | ||
1255 | } | ||
1256 | |||
1257 | printf("\n\n------------------------------------------------\n"); | ||
1258 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); | ||
1259 | printf("------------------------------------------------\n"); | ||
1260 | |||
1261 | if (verbose >= 2) | ||
1262 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | ||
1263 | |||
1264 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", | ||
1265 | (u64)start, (u64)end, filename, filename); | ||
1139 | 1266 | ||
1140 | if (verbose >= 3) | 1267 | if (verbose >= 3) |
1141 | printf("doing: %s\n", command); | 1268 | printf("doing: %s\n", command); |
@@ -1150,6 +1277,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1150 | } | 1277 | } |
1151 | 1278 | ||
1152 | pclose(file); | 1279 | pclose(file); |
1280 | if (print_line) | ||
1281 | free_source_line(sym, len); | ||
1153 | } | 1282 | } |
1154 | 1283 | ||
1155 | static void find_annotations(void) | 1284 | static void find_annotations(void) |
@@ -1264,7 +1393,7 @@ more: | |||
1264 | 1393 | ||
1265 | head += size; | 1394 | head += size; |
1266 | 1395 | ||
1267 | if (offset + head < stat.st_size) | 1396 | if (offset + head < (unsigned long)stat.st_size) |
1268 | goto more; | 1397 | goto more; |
1269 | 1398 | ||
1270 | rc = EXIT_SUCCESS; | 1399 | rc = EXIT_SUCCESS; |
@@ -1308,6 +1437,12 @@ static const struct option options[] = { | |||
1308 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1437 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
1309 | "dump raw trace in ASCII"), | 1438 | "dump raw trace in ASCII"), |
1310 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), | 1439 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), |
1440 | OPT_BOOLEAN('m', "modules", &modules, | ||
1441 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | ||
1442 | OPT_BOOLEAN('l', "print-line", &print_line, | ||
1443 | "print matching source lines (may be slow)"), | ||
1444 | OPT_BOOLEAN('P', "full-paths", &full_paths, | ||
1445 | "Don't shorten the displayed pathnames"), | ||
1311 | OPT_END() | 1446 | OPT_END() |
1312 | }; | 1447 | }; |
1313 | 1448 | ||
@@ -1326,7 +1461,7 @@ static void setup_sorting(void) | |||
1326 | free(str); | 1461 | free(str); |
1327 | } | 1462 | } |
1328 | 1463 | ||
1329 | int cmd_annotate(int argc, const char **argv, const char *prefix) | 1464 | int cmd_annotate(int argc, const char **argv, const char *prefix __used) |
1330 | { | 1465 | { |
1331 | symbol__init(); | 1466 | symbol__init(); |
1332 | 1467 | ||