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