diff options
author | Namhyung Kim <namhyung@gmail.com> | 2012-04-04 03:14:26 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-04-11 16:16:40 -0400 |
commit | aca7a94d6a59d6bf2600768e752f971c6cc0ab57 (patch) | |
tree | 801b40ba5cb8aba9d3d0842a3d87c741b97f58f2 /tools/perf/ui/browsers/annotate.c | |
parent | a31b7cc083b1d3d15bd475729fc4471685ebc5f6 (diff) |
perf tools: Move UI bits to tools/perf/ui directory
Move those files to new directory in order to be prepared to further UI
work. Makefile and header file pathes are adjusted accordingly.
Signed-off-by: Namhyung Kim <namhyung.kim@lge.com>
Suggested-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Acked-by: Pekka Enberg <penberg@kernel.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl
Link: http://lkml.kernel.org/r/1333523666-12057-1-git-send-email-namhyung.kim@lge.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/ui/browsers/annotate.c')
-rw-r--r-- | tools/perf/ui/browsers/annotate.c | 673 |
1 files changed, 673 insertions, 0 deletions
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c new file mode 100644 index 000000000000..4db5186472b5 --- /dev/null +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -0,0 +1,673 @@ | |||
1 | #include "../../util/util.h" | ||
2 | #include "../browser.h" | ||
3 | #include "../helpline.h" | ||
4 | #include "../libslang.h" | ||
5 | #include "../ui.h" | ||
6 | #include "../util.h" | ||
7 | #include "../../util/annotate.h" | ||
8 | #include "../../util/hist.h" | ||
9 | #include "../../util/sort.h" | ||
10 | #include "../../util/symbol.h" | ||
11 | #include <pthread.h> | ||
12 | #include <newt.h> | ||
13 | |||
14 | struct annotate_browser { | ||
15 | struct ui_browser b; | ||
16 | struct rb_root entries; | ||
17 | struct rb_node *curr_hot; | ||
18 | struct objdump_line *selection; | ||
19 | u64 start; | ||
20 | int nr_asm_entries; | ||
21 | int nr_entries; | ||
22 | bool hide_src_code; | ||
23 | bool use_offset; | ||
24 | bool searching_backwards; | ||
25 | char search_bf[128]; | ||
26 | }; | ||
27 | |||
28 | struct objdump_line_rb_node { | ||
29 | struct rb_node rb_node; | ||
30 | double percent; | ||
31 | u32 idx; | ||
32 | int idx_asm; | ||
33 | }; | ||
34 | |||
35 | static inline | ||
36 | struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) | ||
37 | { | ||
38 | return (struct objdump_line_rb_node *)(self + 1); | ||
39 | } | ||
40 | |||
41 | static bool objdump_line__filter(struct ui_browser *browser, void *entry) | ||
42 | { | ||
43 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | ||
44 | |||
45 | if (ab->hide_src_code) { | ||
46 | struct objdump_line *ol = list_entry(entry, struct objdump_line, node); | ||
47 | return ol->offset == -1; | ||
48 | } | ||
49 | |||
50 | return false; | ||
51 | } | ||
52 | |||
53 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) | ||
54 | { | ||
55 | struct annotate_browser *ab = container_of(self, struct annotate_browser, b); | ||
56 | struct objdump_line *ol = list_entry(entry, struct objdump_line, node); | ||
57 | bool current_entry = ui_browser__is_current_entry(self, row); | ||
58 | bool change_color = (!ab->hide_src_code && | ||
59 | (!current_entry || (self->use_navkeypressed && | ||
60 | !self->navkeypressed))); | ||
61 | int width = self->width; | ||
62 | |||
63 | if (ol->offset != -1) { | ||
64 | struct objdump_line_rb_node *olrb = objdump_line__rb(ol); | ||
65 | ui_browser__set_percent_color(self, olrb->percent, current_entry); | ||
66 | slsmg_printf(" %7.2f ", olrb->percent); | ||
67 | } else { | ||
68 | ui_browser__set_percent_color(self, 0, current_entry); | ||
69 | slsmg_write_nstring(" ", 9); | ||
70 | } | ||
71 | |||
72 | SLsmg_write_char(':'); | ||
73 | slsmg_write_nstring(" ", 8); | ||
74 | |||
75 | /* The scroll bar isn't being used */ | ||
76 | if (!self->navkeypressed) | ||
77 | width += 1; | ||
78 | |||
79 | if (ol->offset != -1 && change_color) | ||
80 | ui_browser__set_color(self, HE_COLORSET_CODE); | ||
81 | |||
82 | if (!*ol->line) | ||
83 | slsmg_write_nstring(" ", width - 18); | ||
84 | else if (ol->offset == -1) | ||
85 | slsmg_write_nstring(ol->line, width - 18); | ||
86 | else { | ||
87 | char bf[64]; | ||
88 | u64 addr = ol->offset; | ||
89 | int printed, color = -1; | ||
90 | |||
91 | if (!ab->use_offset) | ||
92 | addr += ab->start; | ||
93 | |||
94 | printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); | ||
95 | if (change_color) | ||
96 | color = ui_browser__set_color(self, HE_COLORSET_ADDR); | ||
97 | slsmg_write_nstring(bf, printed); | ||
98 | if (change_color) | ||
99 | ui_browser__set_color(self, color); | ||
100 | slsmg_write_nstring(ol->line, width - 18 - printed); | ||
101 | } | ||
102 | |||
103 | if (current_entry) | ||
104 | ab->selection = ol; | ||
105 | } | ||
106 | |||
107 | static double objdump_line__calc_percent(struct objdump_line *self, | ||
108 | struct symbol *sym, int evidx) | ||
109 | { | ||
110 | double percent = 0.0; | ||
111 | |||
112 | if (self->offset != -1) { | ||
113 | int len = sym->end - sym->start; | ||
114 | unsigned int hits = 0; | ||
115 | struct annotation *notes = symbol__annotation(sym); | ||
116 | struct source_line *src_line = notes->src->lines; | ||
117 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
118 | s64 offset = self->offset; | ||
119 | struct objdump_line *next; | ||
120 | |||
121 | next = objdump__get_next_ip_line(¬es->src->source, self); | ||
122 | while (offset < (s64)len && | ||
123 | (next == NULL || offset < next->offset)) { | ||
124 | if (src_line) { | ||
125 | percent += src_line[offset].percent; | ||
126 | } else | ||
127 | hits += h->addr[offset]; | ||
128 | |||
129 | ++offset; | ||
130 | } | ||
131 | /* | ||
132 | * If the percentage wasn't already calculated in | ||
133 | * symbol__get_source_line, do it now: | ||
134 | */ | ||
135 | if (src_line == NULL && h->sum) | ||
136 | percent = 100.0 * hits / h->sum; | ||
137 | } | ||
138 | |||
139 | return percent; | ||
140 | } | ||
141 | |||
142 | static void objdump__insert_line(struct rb_root *self, | ||
143 | struct objdump_line_rb_node *line) | ||
144 | { | ||
145 | struct rb_node **p = &self->rb_node; | ||
146 | struct rb_node *parent = NULL; | ||
147 | struct objdump_line_rb_node *l; | ||
148 | |||
149 | while (*p != NULL) { | ||
150 | parent = *p; | ||
151 | l = rb_entry(parent, struct objdump_line_rb_node, rb_node); | ||
152 | if (line->percent < l->percent) | ||
153 | p = &(*p)->rb_left; | ||
154 | else | ||
155 | p = &(*p)->rb_right; | ||
156 | } | ||
157 | rb_link_node(&line->rb_node, parent, p); | ||
158 | rb_insert_color(&line->rb_node, self); | ||
159 | } | ||
160 | |||
161 | static void annotate_browser__set_top(struct annotate_browser *self, | ||
162 | struct objdump_line *pos, u32 idx) | ||
163 | { | ||
164 | unsigned back; | ||
165 | |||
166 | ui_browser__refresh_dimensions(&self->b); | ||
167 | back = self->b.height / 2; | ||
168 | self->b.top_idx = self->b.index = idx; | ||
169 | |||
170 | while (self->b.top_idx != 0 && back != 0) { | ||
171 | pos = list_entry(pos->node.prev, struct objdump_line, node); | ||
172 | |||
173 | if (objdump_line__filter(&self->b, &pos->node)) | ||
174 | continue; | ||
175 | |||
176 | --self->b.top_idx; | ||
177 | --back; | ||
178 | } | ||
179 | |||
180 | self->b.top = pos; | ||
181 | self->b.navkeypressed = true; | ||
182 | } | ||
183 | |||
184 | static void annotate_browser__set_rb_top(struct annotate_browser *browser, | ||
185 | struct rb_node *nd) | ||
186 | { | ||
187 | struct objdump_line_rb_node *rbpos; | ||
188 | struct objdump_line *pos; | ||
189 | |||
190 | rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); | ||
191 | pos = ((struct objdump_line *)rbpos) - 1; | ||
192 | annotate_browser__set_top(browser, pos, rbpos->idx); | ||
193 | browser->curr_hot = nd; | ||
194 | } | ||
195 | |||
196 | static void annotate_browser__calc_percent(struct annotate_browser *browser, | ||
197 | int evidx) | ||
198 | { | ||
199 | struct map_symbol *ms = browser->b.priv; | ||
200 | struct symbol *sym = ms->sym; | ||
201 | struct annotation *notes = symbol__annotation(sym); | ||
202 | struct objdump_line *pos; | ||
203 | |||
204 | browser->entries = RB_ROOT; | ||
205 | |||
206 | pthread_mutex_lock(¬es->lock); | ||
207 | |||
208 | list_for_each_entry(pos, ¬es->src->source, node) { | ||
209 | struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); | ||
210 | rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); | ||
211 | if (rbpos->percent < 0.01) { | ||
212 | RB_CLEAR_NODE(&rbpos->rb_node); | ||
213 | continue; | ||
214 | } | ||
215 | objdump__insert_line(&browser->entries, rbpos); | ||
216 | } | ||
217 | pthread_mutex_unlock(¬es->lock); | ||
218 | |||
219 | browser->curr_hot = rb_last(&browser->entries); | ||
220 | } | ||
221 | |||
222 | static bool annotate_browser__toggle_source(struct annotate_browser *browser) | ||
223 | { | ||
224 | struct objdump_line *ol; | ||
225 | struct objdump_line_rb_node *olrb; | ||
226 | off_t offset = browser->b.index - browser->b.top_idx; | ||
227 | |||
228 | browser->b.seek(&browser->b, offset, SEEK_CUR); | ||
229 | ol = list_entry(browser->b.top, struct objdump_line, node); | ||
230 | olrb = objdump_line__rb(ol); | ||
231 | |||
232 | if (browser->hide_src_code) { | ||
233 | if (olrb->idx_asm < offset) | ||
234 | offset = olrb->idx; | ||
235 | |||
236 | browser->b.nr_entries = browser->nr_entries; | ||
237 | browser->hide_src_code = false; | ||
238 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
239 | browser->b.top_idx = olrb->idx - offset; | ||
240 | browser->b.index = olrb->idx; | ||
241 | } else { | ||
242 | if (olrb->idx_asm < 0) { | ||
243 | ui_helpline__puts("Only available for assembly lines."); | ||
244 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
245 | return false; | ||
246 | } | ||
247 | |||
248 | if (olrb->idx_asm < offset) | ||
249 | offset = olrb->idx_asm; | ||
250 | |||
251 | browser->b.nr_entries = browser->nr_asm_entries; | ||
252 | browser->hide_src_code = true; | ||
253 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
254 | browser->b.top_idx = olrb->idx_asm - offset; | ||
255 | browser->b.index = olrb->idx_asm; | ||
256 | } | ||
257 | |||
258 | return true; | ||
259 | } | ||
260 | |||
261 | static bool annotate_browser__callq(struct annotate_browser *browser, | ||
262 | int evidx, void (*timer)(void *arg), | ||
263 | void *arg, int delay_secs) | ||
264 | { | ||
265 | struct map_symbol *ms = browser->b.priv; | ||
266 | struct symbol *sym = ms->sym; | ||
267 | struct annotation *notes; | ||
268 | struct symbol *target; | ||
269 | char *s = strstr(browser->selection->line, "callq "); | ||
270 | u64 ip; | ||
271 | |||
272 | if (s == NULL) | ||
273 | return false; | ||
274 | |||
275 | s = strchr(s, ' '); | ||
276 | if (s++ == NULL) { | ||
277 | ui_helpline__puts("Invallid callq instruction."); | ||
278 | return true; | ||
279 | } | ||
280 | |||
281 | ip = strtoull(s, NULL, 16); | ||
282 | ip = ms->map->map_ip(ms->map, ip); | ||
283 | target = map__find_symbol(ms->map, ip, NULL); | ||
284 | if (target == NULL) { | ||
285 | ui_helpline__puts("The called function was not found."); | ||
286 | return true; | ||
287 | } | ||
288 | |||
289 | notes = symbol__annotation(target); | ||
290 | pthread_mutex_lock(¬es->lock); | ||
291 | |||
292 | if (notes->src == NULL && symbol__alloc_hist(target) < 0) { | ||
293 | pthread_mutex_unlock(¬es->lock); | ||
294 | ui__warning("Not enough memory for annotating '%s' symbol!\n", | ||
295 | target->name); | ||
296 | return true; | ||
297 | } | ||
298 | |||
299 | pthread_mutex_unlock(¬es->lock); | ||
300 | symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs); | ||
301 | ui_browser__show_title(&browser->b, sym->name); | ||
302 | return true; | ||
303 | } | ||
304 | |||
305 | static struct objdump_line * | ||
306 | annotate_browser__find_offset(struct annotate_browser *browser, | ||
307 | s64 offset, s64 *idx) | ||
308 | { | ||
309 | struct map_symbol *ms = browser->b.priv; | ||
310 | struct symbol *sym = ms->sym; | ||
311 | struct annotation *notes = symbol__annotation(sym); | ||
312 | struct objdump_line *pos; | ||
313 | |||
314 | *idx = 0; | ||
315 | list_for_each_entry(pos, ¬es->src->source, node) { | ||
316 | if (pos->offset == offset) | ||
317 | return pos; | ||
318 | if (!objdump_line__filter(&browser->b, &pos->node)) | ||
319 | ++*idx; | ||
320 | } | ||
321 | |||
322 | return NULL; | ||
323 | } | ||
324 | |||
325 | static bool annotate_browser__jump(struct annotate_browser *browser) | ||
326 | { | ||
327 | const char *jumps[] = { "je ", "jne ", "ja ", "jmpq ", "js ", "jmp ", NULL }; | ||
328 | struct objdump_line *line; | ||
329 | s64 idx, offset; | ||
330 | char *s = NULL; | ||
331 | int i = 0; | ||
332 | |||
333 | while (jumps[i]) { | ||
334 | s = strstr(browser->selection->line, jumps[i++]); | ||
335 | if (s) | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | if (s == NULL) | ||
340 | return false; | ||
341 | |||
342 | s = strchr(s, '+'); | ||
343 | if (s++ == NULL) { | ||
344 | ui_helpline__puts("Invallid jump instruction."); | ||
345 | return true; | ||
346 | } | ||
347 | |||
348 | offset = strtoll(s, NULL, 16); | ||
349 | line = annotate_browser__find_offset(browser, offset, &idx); | ||
350 | if (line == NULL) { | ||
351 | ui_helpline__puts("Invallid jump offset"); | ||
352 | return true; | ||
353 | } | ||
354 | |||
355 | annotate_browser__set_top(browser, line, idx); | ||
356 | |||
357 | return true; | ||
358 | } | ||
359 | |||
360 | static struct objdump_line * | ||
361 | annotate_browser__find_string(struct annotate_browser *browser, | ||
362 | char *s, s64 *idx) | ||
363 | { | ||
364 | struct map_symbol *ms = browser->b.priv; | ||
365 | struct symbol *sym = ms->sym; | ||
366 | struct annotation *notes = symbol__annotation(sym); | ||
367 | struct objdump_line *pos = browser->selection; | ||
368 | |||
369 | *idx = browser->b.index; | ||
370 | list_for_each_entry_continue(pos, ¬es->src->source, node) { | ||
371 | if (objdump_line__filter(&browser->b, &pos->node)) | ||
372 | continue; | ||
373 | |||
374 | ++*idx; | ||
375 | |||
376 | if (pos->line && strstr(pos->line, s) != NULL) | ||
377 | return pos; | ||
378 | } | ||
379 | |||
380 | return NULL; | ||
381 | } | ||
382 | |||
383 | static bool __annotate_browser__search(struct annotate_browser *browser) | ||
384 | { | ||
385 | struct objdump_line *line; | ||
386 | s64 idx; | ||
387 | |||
388 | line = annotate_browser__find_string(browser, browser->search_bf, &idx); | ||
389 | if (line == NULL) { | ||
390 | ui_helpline__puts("String not found!"); | ||
391 | return false; | ||
392 | } | ||
393 | |||
394 | annotate_browser__set_top(browser, line, idx); | ||
395 | browser->searching_backwards = false; | ||
396 | return true; | ||
397 | } | ||
398 | |||
399 | static struct objdump_line * | ||
400 | annotate_browser__find_string_reverse(struct annotate_browser *browser, | ||
401 | char *s, s64 *idx) | ||
402 | { | ||
403 | struct map_symbol *ms = browser->b.priv; | ||
404 | struct symbol *sym = ms->sym; | ||
405 | struct annotation *notes = symbol__annotation(sym); | ||
406 | struct objdump_line *pos = browser->selection; | ||
407 | |||
408 | *idx = browser->b.index; | ||
409 | list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) { | ||
410 | if (objdump_line__filter(&browser->b, &pos->node)) | ||
411 | continue; | ||
412 | |||
413 | --*idx; | ||
414 | |||
415 | if (pos->line && strstr(pos->line, s) != NULL) | ||
416 | return pos; | ||
417 | } | ||
418 | |||
419 | return NULL; | ||
420 | } | ||
421 | |||
422 | static bool __annotate_browser__search_reverse(struct annotate_browser *browser) | ||
423 | { | ||
424 | struct objdump_line *line; | ||
425 | s64 idx; | ||
426 | |||
427 | line = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); | ||
428 | if (line == NULL) { | ||
429 | ui_helpline__puts("String not found!"); | ||
430 | return false; | ||
431 | } | ||
432 | |||
433 | annotate_browser__set_top(browser, line, idx); | ||
434 | browser->searching_backwards = true; | ||
435 | return true; | ||
436 | } | ||
437 | |||
438 | static bool annotate_browser__search_window(struct annotate_browser *browser, | ||
439 | int delay_secs) | ||
440 | { | ||
441 | if (ui_browser__input_window("Search", "String: ", browser->search_bf, | ||
442 | "ENTER: OK, ESC: Cancel", | ||
443 | delay_secs * 2) != K_ENTER || | ||
444 | !*browser->search_bf) | ||
445 | return false; | ||
446 | |||
447 | return true; | ||
448 | } | ||
449 | |||
450 | static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) | ||
451 | { | ||
452 | if (annotate_browser__search_window(browser, delay_secs)) | ||
453 | return __annotate_browser__search(browser); | ||
454 | |||
455 | return false; | ||
456 | } | ||
457 | |||
458 | static bool annotate_browser__continue_search(struct annotate_browser *browser, | ||
459 | int delay_secs) | ||
460 | { | ||
461 | if (!*browser->search_bf) | ||
462 | return annotate_browser__search(browser, delay_secs); | ||
463 | |||
464 | return __annotate_browser__search(browser); | ||
465 | } | ||
466 | |||
467 | static bool annotate_browser__search_reverse(struct annotate_browser *browser, | ||
468 | int delay_secs) | ||
469 | { | ||
470 | if (annotate_browser__search_window(browser, delay_secs)) | ||
471 | return __annotate_browser__search_reverse(browser); | ||
472 | |||
473 | return false; | ||
474 | } | ||
475 | |||
476 | static | ||
477 | bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, | ||
478 | int delay_secs) | ||
479 | { | ||
480 | if (!*browser->search_bf) | ||
481 | return annotate_browser__search_reverse(browser, delay_secs); | ||
482 | |||
483 | return __annotate_browser__search_reverse(browser); | ||
484 | } | ||
485 | |||
486 | static int annotate_browser__run(struct annotate_browser *self, int evidx, | ||
487 | void(*timer)(void *arg), | ||
488 | void *arg, int delay_secs) | ||
489 | { | ||
490 | struct rb_node *nd = NULL; | ||
491 | struct map_symbol *ms = self->b.priv; | ||
492 | struct symbol *sym = ms->sym; | ||
493 | const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, " | ||
494 | "H: Go to hottest line, ->/ENTER: Line action, " | ||
495 | "O: Toggle offset view, " | ||
496 | "S: Toggle source code view"; | ||
497 | int key; | ||
498 | |||
499 | if (ui_browser__show(&self->b, sym->name, help) < 0) | ||
500 | return -1; | ||
501 | |||
502 | annotate_browser__calc_percent(self, evidx); | ||
503 | |||
504 | if (self->curr_hot) { | ||
505 | annotate_browser__set_rb_top(self, self->curr_hot); | ||
506 | self->b.navkeypressed = false; | ||
507 | } | ||
508 | |||
509 | nd = self->curr_hot; | ||
510 | |||
511 | while (1) { | ||
512 | key = ui_browser__run(&self->b, delay_secs); | ||
513 | |||
514 | if (delay_secs != 0) { | ||
515 | annotate_browser__calc_percent(self, evidx); | ||
516 | /* | ||
517 | * Current line focus got out of the list of most active | ||
518 | * lines, NULL it so that if TAB|UNTAB is pressed, we | ||
519 | * move to curr_hot (current hottest line). | ||
520 | */ | ||
521 | if (nd != NULL && RB_EMPTY_NODE(nd)) | ||
522 | nd = NULL; | ||
523 | } | ||
524 | |||
525 | switch (key) { | ||
526 | case K_TIMER: | ||
527 | if (timer != NULL) | ||
528 | timer(arg); | ||
529 | |||
530 | if (delay_secs != 0) | ||
531 | symbol__annotate_decay_histogram(sym, evidx); | ||
532 | continue; | ||
533 | case K_TAB: | ||
534 | if (nd != NULL) { | ||
535 | nd = rb_prev(nd); | ||
536 | if (nd == NULL) | ||
537 | nd = rb_last(&self->entries); | ||
538 | } else | ||
539 | nd = self->curr_hot; | ||
540 | break; | ||
541 | case K_UNTAB: | ||
542 | if (nd != NULL) | ||
543 | nd = rb_next(nd); | ||
544 | if (nd == NULL) | ||
545 | nd = rb_first(&self->entries); | ||
546 | else | ||
547 | nd = self->curr_hot; | ||
548 | break; | ||
549 | case 'H': | ||
550 | case 'h': | ||
551 | nd = self->curr_hot; | ||
552 | break; | ||
553 | case 'S': | ||
554 | case 's': | ||
555 | if (annotate_browser__toggle_source(self)) | ||
556 | ui_helpline__puts(help); | ||
557 | continue; | ||
558 | case 'O': | ||
559 | case 'o': | ||
560 | self->use_offset = !self->use_offset; | ||
561 | continue; | ||
562 | case '/': | ||
563 | if (annotate_browser__search(self, delay_secs)) { | ||
564 | show_help: | ||
565 | ui_helpline__puts(help); | ||
566 | } | ||
567 | continue; | ||
568 | case 'n': | ||
569 | if (self->searching_backwards ? | ||
570 | annotate_browser__continue_search_reverse(self, delay_secs) : | ||
571 | annotate_browser__continue_search(self, delay_secs)) | ||
572 | goto show_help; | ||
573 | continue; | ||
574 | case '?': | ||
575 | if (annotate_browser__search_reverse(self, delay_secs)) | ||
576 | goto show_help; | ||
577 | continue; | ||
578 | case K_ENTER: | ||
579 | case K_RIGHT: | ||
580 | if (self->selection == NULL) | ||
581 | ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); | ||
582 | else if (self->selection->offset == -1) | ||
583 | ui_helpline__puts("Actions are only available for assembly lines."); | ||
584 | else if (!(annotate_browser__jump(self) || | ||
585 | annotate_browser__callq(self, evidx, timer, arg, delay_secs))) | ||
586 | ui_helpline__puts("Actions are only available for the 'callq' and jump instructions."); | ||
587 | continue; | ||
588 | case K_LEFT: | ||
589 | case K_ESC: | ||
590 | case 'q': | ||
591 | case CTRL('c'): | ||
592 | goto out; | ||
593 | default: | ||
594 | continue; | ||
595 | } | ||
596 | |||
597 | if (nd != NULL) | ||
598 | annotate_browser__set_rb_top(self, nd); | ||
599 | } | ||
600 | out: | ||
601 | ui_browser__hide(&self->b); | ||
602 | return key; | ||
603 | } | ||
604 | |||
605 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | ||
606 | void(*timer)(void *arg), void *arg, int delay_secs) | ||
607 | { | ||
608 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, | ||
609 | timer, arg, delay_secs); | ||
610 | } | ||
611 | |||
612 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | ||
613 | void(*timer)(void *arg), void *arg, | ||
614 | int delay_secs) | ||
615 | { | ||
616 | struct objdump_line *pos, *n; | ||
617 | struct annotation *notes; | ||
618 | struct map_symbol ms = { | ||
619 | .map = map, | ||
620 | .sym = sym, | ||
621 | }; | ||
622 | struct annotate_browser browser = { | ||
623 | .b = { | ||
624 | .refresh = ui_browser__list_head_refresh, | ||
625 | .seek = ui_browser__list_head_seek, | ||
626 | .write = annotate_browser__write, | ||
627 | .filter = objdump_line__filter, | ||
628 | .priv = &ms, | ||
629 | .use_navkeypressed = true, | ||
630 | }, | ||
631 | }; | ||
632 | int ret; | ||
633 | |||
634 | if (sym == NULL) | ||
635 | return -1; | ||
636 | |||
637 | if (map->dso->annotate_warned) | ||
638 | return -1; | ||
639 | |||
640 | if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { | ||
641 | ui__error("%s", ui_helpline__last_msg); | ||
642 | return -1; | ||
643 | } | ||
644 | |||
645 | ui_helpline__push("Press <- or ESC to exit"); | ||
646 | |||
647 | notes = symbol__annotation(sym); | ||
648 | browser.start = map__rip_2objdump(map, sym->start); | ||
649 | |||
650 | list_for_each_entry(pos, ¬es->src->source, node) { | ||
651 | struct objdump_line_rb_node *rbpos; | ||
652 | size_t line_len = strlen(pos->line); | ||
653 | |||
654 | if (browser.b.width < line_len) | ||
655 | browser.b.width = line_len; | ||
656 | rbpos = objdump_line__rb(pos); | ||
657 | rbpos->idx = browser.nr_entries++; | ||
658 | if (pos->offset != -1) | ||
659 | rbpos->idx_asm = browser.nr_asm_entries++; | ||
660 | else | ||
661 | rbpos->idx_asm = -1; | ||
662 | } | ||
663 | |||
664 | browser.b.nr_entries = browser.nr_entries; | ||
665 | browser.b.entries = ¬es->src->source, | ||
666 | browser.b.width += 18; /* Percentage */ | ||
667 | ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); | ||
668 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | ||
669 | list_del(&pos->node); | ||
670 | objdump_line__free(pos); | ||
671 | } | ||
672 | return ret; | ||
673 | } | ||