1
2#include "../browser.h"
3#include "../helpline.h"
4#include "../ui.h"
5#include "../util.h"
6#include "../../util/annotate.h"
7#include "../../util/hist.h"
8#include "../../util/sort.h"
9#include "../../util/map.h"
10#include "../../util/symbol.h"
11#include "../../util/evsel.h"
12#include "../../util/evlist.h"
13#include <inttypes.h>
14#include <pthread.h>
15#include <linux/kernel.h>
16#include <linux/string.h>
17#include <linux/zalloc.h>
18#include <sys/ttydefaults.h>
19#include <asm/bug.h>
20
21struct disasm_line_samples {
22 double percent;
23 struct sym_hist_entry he;
24};
25
26struct arch;
27
28struct annotate_browser {
29 struct ui_browser b;
30 struct rb_root entries;
31 struct rb_node *curr_hot;
32 struct annotation_line *selection;
33 struct arch *arch;
34 struct annotation_options *opts;
35 bool searching_backwards;
36 char search_bf[128];
37};
38
39static inline struct annotation *browser__annotation(struct ui_browser *browser)
40{
41 struct map_symbol *ms = browser->priv;
42 return symbol__annotation(ms->sym);
43}
44
45static bool disasm_line__filter(struct ui_browser *browser, void *entry)
46{
47 struct annotation *notes = browser__annotation(browser);
48 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
49 return annotation_line__filter(al, notes);
50}
51
52static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
53{
54 struct annotation *notes = browser__annotation(browser);
55
56 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
57 return HE_COLORSET_SELECTED;
58 if (nr == notes->max_jump_sources)
59 return HE_COLORSET_TOP;
60 if (nr > 1)
61 return HE_COLORSET_MEDIUM;
62 return HE_COLORSET_NORMAL;
63}
64
65static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
66{
67 int color = ui_browser__jumps_percent_color(browser, nr, current);
68 return ui_browser__set_color(browser, color);
69}
70
71static int annotate_browser__set_color(void *browser, int color)
72{
73 return ui_browser__set_color(browser, color);
74}
75
76static void annotate_browser__write_graph(void *browser, int graph)
77{
78 ui_browser__write_graph(browser, graph);
79}
80
81static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
82{
83 ui_browser__set_percent_color(browser, percent, current);
84}
85
86static void annotate_browser__printf(void *browser, const char *fmt, ...)
87{
88 va_list args;
89
90 va_start(args, fmt);
91 ui_browser__vprintf(browser, fmt, args);
92 va_end(args);
93}
94
95static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
96{
97 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
98 struct annotation *notes = browser__annotation(browser);
99 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
100 const bool is_current_entry = ui_browser__is_current_entry(browser, row);
101 struct annotation_write_ops ops = {
102 .first_line = row == 0,
103 .current_entry = is_current_entry,
104 .change_color = (!notes->options->hide_src_code &&
105 (!is_current_entry ||
106 (browser->use_navkeypressed &&
107 !browser->navkeypressed))),
108 .width = browser->width,
109 .obj = browser,
110 .set_color = annotate_browser__set_color,
111 .set_percent_color = annotate_browser__set_percent_color,
112 .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
113 .printf = annotate_browser__printf,
114 .write_graph = annotate_browser__write_graph,
115 };
116
117
118 if (!browser->navkeypressed)
119 ops.width += 1;
120
121 annotation_line__write(al, notes, &ops, ab->opts);
122
123 if (ops.current_entry)
124 ab->selection = al;
125}
126
127static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
128{
129 struct disasm_line *pos = list_prev_entry(cursor, al.node);
130 const char *name;
131
132 if (!pos)
133 return false;
134
135 if (ins__is_lock(&pos->ins))
136 name = pos->ops.locked.ins.name;
137 else
138 name = pos->ins.name;
139
140 if (!name || !cursor->ins.name)
141 return false;
142
143 return ins__is_fused(ab->arch, name, cursor->ins.name);
144}
145
146static void annotate_browser__draw_current_jump(struct ui_browser *browser)
147{
148 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
149 struct disasm_line *cursor = disasm_line(ab->selection);
150 struct annotation_line *target;
151 unsigned int from, to;
152 struct map_symbol *ms = ab->b.priv;
153 struct symbol *sym = ms->sym;
154 struct annotation *notes = symbol__annotation(sym);
155 u8 pcnt_width = annotation__pcnt_width(notes);
156 int width;
157
158
159 if (strstr(sym->name, "@plt"))
160 return;
161
162 if (!disasm_line__is_valid_local_jump(cursor, sym))
163 return;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 target = notes->offsets[cursor->ops.target.offset];
186 if (target == NULL) {
187 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
188 cursor->ops.target.offset);
189 return;
190 }
191
192 if (notes->options->hide_src_code) {
193 from = cursor->al.idx_asm;
194 to = target->idx_asm;
195 } else {
196 from = (u64)cursor->al.idx;
197 to = (u64)target->idx;
198 }
199
200 width = annotation__cycles_width(notes);
201
202 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
203 __ui_browser__line_arrow(browser,
204 pcnt_width + 2 + notes->widths.addr + width,
205 from, to);
206
207 if (is_fused(ab, cursor)) {
208 ui_browser__mark_fused(browser,
209 pcnt_width + 3 + notes->widths.addr + width,
210 from - 1,
211 to > from ? true : false);
212 }
213}
214
215static unsigned int annotate_browser__refresh(struct ui_browser *browser)
216{
217 struct annotation *notes = browser__annotation(browser);
218 int ret = ui_browser__list_head_refresh(browser);
219 int pcnt_width = annotation__pcnt_width(notes);
220
221 if (notes->options->jump_arrows)
222 annotate_browser__draw_current_jump(browser);
223
224 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
225 __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
226 return ret;
227}
228
229static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
230 int percent_type)
231{
232 int i;
233
234 for (i = 0; i < a->data_nr; i++) {
235 if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
236 continue;
237 return a->data[i].percent[percent_type] -
238 b->data[i].percent[percent_type];
239 }
240 return 0;
241}
242
243static void disasm_rb_tree__insert(struct annotate_browser *browser,
244 struct annotation_line *al)
245{
246 struct rb_root *root = &browser->entries;
247 struct rb_node **p = &root->rb_node;
248 struct rb_node *parent = NULL;
249 struct annotation_line *l;
250
251 while (*p != NULL) {
252 parent = *p;
253 l = rb_entry(parent, struct annotation_line, rb_node);
254
255 if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
256 p = &(*p)->rb_left;
257 else
258 p = &(*p)->rb_right;
259 }
260 rb_link_node(&al->rb_node, parent, p);
261 rb_insert_color(&al->rb_node, root);
262}
263
264static void annotate_browser__set_top(struct annotate_browser *browser,
265 struct annotation_line *pos, u32 idx)
266{
267 struct annotation *notes = browser__annotation(&browser->b);
268 unsigned back;
269
270 ui_browser__refresh_dimensions(&browser->b);
271 back = browser->b.height / 2;
272 browser->b.top_idx = browser->b.index = idx;
273
274 while (browser->b.top_idx != 0 && back != 0) {
275 pos = list_entry(pos->node.prev, struct annotation_line, node);
276
277 if (annotation_line__filter(pos, notes))
278 continue;
279
280 --browser->b.top_idx;
281 --back;
282 }
283
284 browser->b.top = pos;
285 browser->b.navkeypressed = true;
286}
287
288static void annotate_browser__set_rb_top(struct annotate_browser *browser,
289 struct rb_node *nd)
290{
291 struct annotation *notes = browser__annotation(&browser->b);
292 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
293 u32 idx = pos->idx;
294
295 if (notes->options->hide_src_code)
296 idx = pos->idx_asm;
297 annotate_browser__set_top(browser, pos, idx);
298 browser->curr_hot = nd;
299}
300
301static void annotate_browser__calc_percent(struct annotate_browser *browser,
302 struct perf_evsel *evsel)
303{
304 struct map_symbol *ms = browser->b.priv;
305 struct symbol *sym = ms->sym;
306 struct annotation *notes = symbol__annotation(sym);
307 struct disasm_line *pos;
308
309 browser->entries = RB_ROOT;
310
311 pthread_mutex_lock(¬es->lock);
312
313 symbol__calc_percent(sym, evsel);
314
315 list_for_each_entry(pos, ¬es->src->source, al.node) {
316 double max_percent = 0.0;
317 int i;
318
319 if (pos->al.offset == -1) {
320 RB_CLEAR_NODE(&pos->al.rb_node);
321 continue;
322 }
323
324 for (i = 0; i < pos->al.data_nr; i++) {
325 double percent;
326
327 percent = annotation_data__percent(&pos->al.data[i],
328 browser->opts->percent_type);
329
330 if (max_percent < percent)
331 max_percent = percent;
332 }
333
334 if (max_percent < 0.01 && pos->al.ipc == 0) {
335 RB_CLEAR_NODE(&pos->al.rb_node);
336 continue;
337 }
338 disasm_rb_tree__insert(browser, &pos->al);
339 }
340 pthread_mutex_unlock(¬es->lock);
341
342 browser->curr_hot = rb_last(&browser->entries);
343}
344
345static bool annotate_browser__toggle_source(struct annotate_browser *browser)
346{
347 struct annotation *notes = browser__annotation(&browser->b);
348 struct annotation_line *al;
349 off_t offset = browser->b.index - browser->b.top_idx;
350
351 browser->b.seek(&browser->b, offset, SEEK_CUR);
352 al = list_entry(browser->b.top, struct annotation_line, node);
353
354 if (notes->options->hide_src_code) {
355 if (al->idx_asm < offset)
356 offset = al->idx;
357
358 browser->b.nr_entries = notes->nr_entries;
359 notes->options->hide_src_code = false;
360 browser->b.seek(&browser->b, -offset, SEEK_CUR);
361 browser->b.top_idx = al->idx - offset;
362 browser->b.index = al->idx;
363 } else {
364 if (al->idx_asm < 0) {
365 ui_helpline__puts("Only available for assembly lines.");
366 browser->b.seek(&browser->b, -offset, SEEK_CUR);
367 return false;
368 }
369
370 if (al->idx_asm < offset)
371 offset = al->idx_asm;
372
373 browser->b.nr_entries = notes->nr_asm_entries;
374 notes->options->hide_src_code = true;
375 browser->b.seek(&browser->b, -offset, SEEK_CUR);
376 browser->b.top_idx = al->idx_asm - offset;
377 browser->b.index = al->idx_asm;
378 }
379
380 return true;
381}
382
383static void ui_browser__init_asm_mode(struct ui_browser *browser)
384{
385 struct annotation *notes = browser__annotation(browser);
386 ui_browser__reset_index(browser);
387 browser->nr_entries = notes->nr_asm_entries;
388}
389
390#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
391
392static int sym_title(struct symbol *sym, struct map *map, char *title,
393 size_t sz, int percent_type)
394{
395 return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name,
396 percent_type_str(percent_type));
397}
398
399
400
401
402
403
404
405
406
407
408static bool annotate_browser__callq(struct annotate_browser *browser,
409 struct perf_evsel *evsel,
410 struct hist_browser_timer *hbt)
411{
412 struct map_symbol *ms = browser->b.priv;
413 struct disasm_line *dl = disasm_line(browser->selection);
414 struct annotation *notes;
415 char title[SYM_TITLE_MAX_SIZE];
416
417 if (!dl->ops.target.sym) {
418 ui_helpline__puts("The called function was not found.");
419 return true;
420 }
421
422 notes = symbol__annotation(dl->ops.target.sym);
423 pthread_mutex_lock(¬es->lock);
424
425 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) {
426 pthread_mutex_unlock(¬es->lock);
427 ui__warning("Not enough memory for annotating '%s' symbol!\n",
428 dl->ops.target.sym->name);
429 return true;
430 }
431
432 pthread_mutex_unlock(¬es->lock);
433 symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
434 sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
435 ui_browser__show_title(&browser->b, title);
436 return true;
437}
438
439static
440struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
441 s64 offset, s64 *idx)
442{
443 struct annotation *notes = browser__annotation(&browser->b);
444 struct disasm_line *pos;
445
446 *idx = 0;
447 list_for_each_entry(pos, ¬es->src->source, al.node) {
448 if (pos->al.offset == offset)
449 return pos;
450 if (!annotation_line__filter(&pos->al, notes))
451 ++*idx;
452 }
453
454 return NULL;
455}
456
457static bool annotate_browser__jump(struct annotate_browser *browser,
458 struct perf_evsel *evsel,
459 struct hist_browser_timer *hbt)
460{
461 struct disasm_line *dl = disasm_line(browser->selection);
462 u64 offset;
463 s64 idx;
464
465 if (!ins__is_jump(&dl->ins))
466 return false;
467
468 if (dl->ops.target.outside) {
469 annotate_browser__callq(browser, evsel, hbt);
470 return true;
471 }
472
473 offset = dl->ops.target.offset;
474 dl = annotate_browser__find_offset(browser, offset, &idx);
475 if (dl == NULL) {
476 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
477 return true;
478 }
479
480 annotate_browser__set_top(browser, &dl->al, idx);
481
482 return true;
483}
484
485static
486struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
487 char *s, s64 *idx)
488{
489 struct annotation *notes = browser__annotation(&browser->b);
490 struct annotation_line *al = browser->selection;
491
492 *idx = browser->b.index;
493 list_for_each_entry_continue(al, ¬es->src->source, node) {
494 if (annotation_line__filter(al, notes))
495 continue;
496
497 ++*idx;
498
499 if (al->line && strstr(al->line, s) != NULL)
500 return al;
501 }
502
503 return NULL;
504}
505
506static bool __annotate_browser__search(struct annotate_browser *browser)
507{
508 struct annotation_line *al;
509 s64 idx;
510
511 al = annotate_browser__find_string(browser, browser->search_bf, &idx);
512 if (al == NULL) {
513 ui_helpline__puts("String not found!");
514 return false;
515 }
516
517 annotate_browser__set_top(browser, al, idx);
518 browser->searching_backwards = false;
519 return true;
520}
521
522static
523struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
524 char *s, s64 *idx)
525{
526 struct annotation *notes = browser__annotation(&browser->b);
527 struct annotation_line *al = browser->selection;
528
529 *idx = browser->b.index;
530 list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
531 if (annotation_line__filter(al, notes))
532 continue;
533
534 --*idx;
535
536 if (al->line && strstr(al->line, s) != NULL)
537 return al;
538 }
539
540 return NULL;
541}
542
543static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
544{
545 struct annotation_line *al;
546 s64 idx;
547
548 al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
549 if (al == NULL) {
550 ui_helpline__puts("String not found!");
551 return false;
552 }
553
554 annotate_browser__set_top(browser, al, idx);
555 browser->searching_backwards = true;
556 return true;
557}
558
559static bool annotate_browser__search_window(struct annotate_browser *browser,
560 int delay_secs)
561{
562 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
563 "ENTER: OK, ESC: Cancel",
564 delay_secs * 2) != K_ENTER ||
565 !*browser->search_bf)
566 return false;
567
568 return true;
569}
570
571static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
572{
573 if (annotate_browser__search_window(browser, delay_secs))
574 return __annotate_browser__search(browser);
575
576 return false;
577}
578
579static bool annotate_browser__continue_search(struct annotate_browser *browser,
580 int delay_secs)
581{
582 if (!*browser->search_bf)
583 return annotate_browser__search(browser, delay_secs);
584
585 return __annotate_browser__search(browser);
586}
587
588static bool annotate_browser__search_reverse(struct annotate_browser *browser,
589 int delay_secs)
590{
591 if (annotate_browser__search_window(browser, delay_secs))
592 return __annotate_browser__search_reverse(browser);
593
594 return false;
595}
596
597static
598bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
599 int delay_secs)
600{
601 if (!*browser->search_bf)
602 return annotate_browser__search_reverse(browser, delay_secs);
603
604 return __annotate_browser__search_reverse(browser);
605}
606
607static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
608{
609 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
610 struct map_symbol *ms = browser->priv;
611 struct symbol *sym = ms->sym;
612 char symbol_dso[SYM_TITLE_MAX_SIZE];
613
614 if (ui_browser__show(browser, title, help) < 0)
615 return -1;
616
617 sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
618
619 ui_browser__gotorc_title(browser, 0, 0);
620 ui_browser__set_color(browser, HE_COLORSET_ROOT);
621 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
622 return 0;
623}
624
625static void
626switch_percent_type(struct annotation_options *opts, bool base)
627{
628 switch (opts->percent_type) {
629 case PERCENT_HITS_LOCAL:
630 if (base)
631 opts->percent_type = PERCENT_PERIOD_LOCAL;
632 else
633 opts->percent_type = PERCENT_HITS_GLOBAL;
634 break;
635 case PERCENT_HITS_GLOBAL:
636 if (base)
637 opts->percent_type = PERCENT_PERIOD_GLOBAL;
638 else
639 opts->percent_type = PERCENT_HITS_LOCAL;
640 break;
641 case PERCENT_PERIOD_LOCAL:
642 if (base)
643 opts->percent_type = PERCENT_HITS_LOCAL;
644 else
645 opts->percent_type = PERCENT_PERIOD_GLOBAL;
646 break;
647 case PERCENT_PERIOD_GLOBAL:
648 if (base)
649 opts->percent_type = PERCENT_HITS_GLOBAL;
650 else
651 opts->percent_type = PERCENT_PERIOD_LOCAL;
652 break;
653 default:
654 WARN_ON(1);
655 }
656}
657
658static int annotate_browser__run(struct annotate_browser *browser,
659 struct perf_evsel *evsel,
660 struct hist_browser_timer *hbt)
661{
662 struct rb_node *nd = NULL;
663 struct hists *hists = evsel__hists(evsel);
664 struct map_symbol *ms = browser->b.priv;
665 struct symbol *sym = ms->sym;
666 struct annotation *notes = symbol__annotation(ms->sym);
667 const char *help = "Press 'h' for help on key bindings";
668 int delay_secs = hbt ? hbt->refresh : 0;
669 char title[256];
670 int key;
671
672 hists__scnprintf_title(hists, title, sizeof(title));
673 if (annotate_browser__show(&browser->b, title, help) < 0)
674 return -1;
675
676 annotate_browser__calc_percent(browser, evsel);
677
678 if (browser->curr_hot) {
679 annotate_browser__set_rb_top(browser, browser->curr_hot);
680 browser->b.navkeypressed = false;
681 }
682
683 nd = browser->curr_hot;
684
685 while (1) {
686 key = ui_browser__run(&browser->b, delay_secs);
687
688 if (delay_secs != 0) {
689 annotate_browser__calc_percent(browser, evsel);
690
691
692
693
694
695 if (nd != NULL && RB_EMPTY_NODE(nd))
696 nd = NULL;
697 }
698
699 switch (key) {
700 case K_TIMER:
701 if (hbt)
702 hbt->timer(hbt->arg);
703
704 if (delay_secs != 0) {
705 symbol__annotate_decay_histogram(sym, evsel->idx);
706 hists__scnprintf_title(hists, title, sizeof(title));
707 annotate_browser__show(&browser->b, title, help);
708 }
709 continue;
710 case K_TAB:
711 if (nd != NULL) {
712 nd = rb_prev(nd);
713 if (nd == NULL)
714 nd = rb_last(&browser->entries);
715 } else
716 nd = browser->curr_hot;
717 break;
718 case K_UNTAB:
719 if (nd != NULL) {
720 nd = rb_next(nd);
721 if (nd == NULL)
722 nd = rb_first(&browser->entries);
723 } else
724 nd = browser->curr_hot;
725 break;
726 case K_F1:
727 case 'h':
728 ui_browser__help_window(&browser->b,
729 "UP/DOWN/PGUP\n"
730 "PGDN/SPACE Navigate\n"
731 "q/ESC/CTRL+C Exit\n\n"
732 "ENTER Go to target\n"
733 "ESC Exit\n"
734 "H Go to hottest instruction\n"
735 "TAB/shift+TAB Cycle thru hottest instructions\n"
736 "j Toggle showing jump to target arrows\n"
737 "J Toggle showing number of jump sources on targets\n"
738 "n Search next string\n"
739 "o Toggle disassembler output/simplified view\n"
740 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
741 "s Toggle source code view\n"
742 "t Circulate percent, total period, samples view\n"
743 "c Show min/max cycle\n"
744 "/ Search string\n"
745 "k Toggle line numbers\n"
746 "P Print to [symbol_name].annotation file.\n"
747 "r Run available scripts\n"
748 "p Toggle percent type [local/global]\n"
749 "b Toggle percent base [period/hits]\n"
750 "? Search string backwards\n");
751 continue;
752 case 'r':
753 {
754 script_browse(NULL, NULL);
755 continue;
756 }
757 case 'k':
758 notes->options->show_linenr = !notes->options->show_linenr;
759 break;
760 case 'H':
761 nd = browser->curr_hot;
762 break;
763 case 's':
764 if (annotate_browser__toggle_source(browser))
765 ui_helpline__puts(help);
766 continue;
767 case 'o':
768 notes->options->use_offset = !notes->options->use_offset;
769 annotation__update_column_widths(notes);
770 continue;
771 case 'O':
772 if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
773 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
774 continue;
775 case 'j':
776 notes->options->jump_arrows = !notes->options->jump_arrows;
777 continue;
778 case 'J':
779 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
780 annotation__update_column_widths(notes);
781 continue;
782 case '/':
783 if (annotate_browser__search(browser, delay_secs)) {
784show_help:
785 ui_helpline__puts(help);
786 }
787 continue;
788 case 'n':
789 if (browser->searching_backwards ?
790 annotate_browser__continue_search_reverse(browser, delay_secs) :
791 annotate_browser__continue_search(browser, delay_secs))
792 goto show_help;
793 continue;
794 case '?':
795 if (annotate_browser__search_reverse(browser, delay_secs))
796 goto show_help;
797 continue;
798 case 'D': {
799 static int seq;
800 ui_helpline__pop();
801 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
802 seq++, browser->b.nr_entries,
803 browser->b.height,
804 browser->b.index,
805 browser->b.top_idx,
806 notes->nr_asm_entries);
807 }
808 continue;
809 case K_ENTER:
810 case K_RIGHT:
811 {
812 struct disasm_line *dl = disasm_line(browser->selection);
813
814 if (browser->selection == NULL)
815 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
816 else if (browser->selection->offset == -1)
817 ui_helpline__puts("Actions are only available for assembly lines.");
818 else if (!dl->ins.ops)
819 goto show_sup_ins;
820 else if (ins__is_ret(&dl->ins))
821 goto out;
822 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
823 annotate_browser__callq(browser, evsel, hbt))) {
824show_sup_ins:
825 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
826 }
827 continue;
828 }
829 case 'P':
830 map_symbol__annotation_dump(ms, evsel, browser->opts);
831 continue;
832 case 't':
833 if (notes->options->show_total_period) {
834 notes->options->show_total_period = false;
835 notes->options->show_nr_samples = true;
836 } else if (notes->options->show_nr_samples)
837 notes->options->show_nr_samples = false;
838 else
839 notes->options->show_total_period = true;
840 annotation__update_column_widths(notes);
841 continue;
842 case 'c':
843 if (notes->options->show_minmax_cycle)
844 notes->options->show_minmax_cycle = false;
845 else
846 notes->options->show_minmax_cycle = true;
847 annotation__update_column_widths(notes);
848 continue;
849 case 'p':
850 case 'b':
851 switch_percent_type(browser->opts, key == 'b');
852 hists__scnprintf_title(hists, title, sizeof(title));
853 annotate_browser__show(&browser->b, title, help);
854 continue;
855 case K_LEFT:
856 case K_ESC:
857 case 'q':
858 case CTRL('c'):
859 goto out;
860 default:
861 continue;
862 }
863
864 if (nd != NULL)
865 annotate_browser__set_rb_top(browser, nd);
866 }
867out:
868 ui_browser__hide(&browser->b);
869 return key;
870}
871
872int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
873 struct hist_browser_timer *hbt,
874 struct annotation_options *opts)
875{
876 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts);
877}
878
879int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
880 struct hist_browser_timer *hbt,
881 struct annotation_options *opts)
882{
883
884 SLang_reset_tty();
885 SLang_init_tty(0, 0, 0);
886
887 return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
888}
889
890int symbol__tui_annotate(struct symbol *sym, struct map *map,
891 struct perf_evsel *evsel,
892 struct hist_browser_timer *hbt,
893 struct annotation_options *opts)
894{
895 struct annotation *notes = symbol__annotation(sym);
896 struct map_symbol ms = {
897 .map = map,
898 .sym = sym,
899 };
900 struct annotate_browser browser = {
901 .b = {
902 .refresh = annotate_browser__refresh,
903 .seek = ui_browser__list_head_seek,
904 .write = annotate_browser__write,
905 .filter = disasm_line__filter,
906 .extra_title_lines = 1,
907 .priv = &ms,
908 .use_navkeypressed = true,
909 },
910 .opts = opts,
911 };
912 int ret = -1, err;
913
914 if (sym == NULL)
915 return -1;
916
917 if (map->dso->annotate_warned)
918 return -1;
919
920 err = symbol__annotate2(sym, map, evsel, opts, &browser.arch);
921 if (err) {
922 char msg[BUFSIZ];
923 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
924 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
925 goto out_free_offsets;
926 }
927
928 ui_helpline__push("Press ESC to exit");
929
930 browser.b.width = notes->max_line_len;
931 browser.b.nr_entries = notes->nr_entries;
932 browser.b.entries = ¬es->src->source,
933 browser.b.width += 18;
934
935 if (notes->options->hide_src_code)
936 ui_browser__init_asm_mode(&browser.b);
937
938 ret = annotate_browser__run(&browser, evsel, hbt);
939
940 annotated_source__purge(notes->src);
941
942out_free_offsets:
943 zfree(¬es->offsets);
944 return ret;
945}
946