1 // SPDX-License-Identifier: GPL-2.0
2 #include "../browser.h"
3 #include "../helpline.h"
5 #include "../../util/annotate.h"
6 #include "../../util/debug.h"
7 #include "../../util/dso.h"
8 #include "../../util/hist.h"
9 #include "../../util/sort.h"
10 #include "../../util/map.h"
11 #include "../../util/symbol.h"
12 #include "../../util/evsel.h"
13 #include "../../util/evlist.h"
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/zalloc.h>
19 #include <sys/ttydefaults.h>
22 struct disasm_line_samples {
24 struct sym_hist_entry he;
29 struct annotate_browser {
31 struct rb_root entries;
32 struct rb_node *curr_hot;
33 struct annotation_line *selection;
35 struct annotation_options *opts;
36 bool searching_backwards;
40 static inline struct annotation *browser__annotation(struct ui_browser *browser)
42 struct map_symbol *ms = browser->priv;
43 return symbol__annotation(ms->sym);
46 static bool disasm_line__filter(struct ui_browser *browser, void *entry)
48 struct annotation *notes = browser__annotation(browser);
49 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
50 return annotation_line__filter(al, notes);
53 static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
55 struct annotation *notes = browser__annotation(browser);
57 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
58 return HE_COLORSET_SELECTED;
59 if (nr == notes->max_jump_sources)
60 return HE_COLORSET_TOP;
62 return HE_COLORSET_MEDIUM;
63 return HE_COLORSET_NORMAL;
66 static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
68 int color = ui_browser__jumps_percent_color(browser, nr, current);
69 return ui_browser__set_color(browser, color);
72 static int annotate_browser__set_color(void *browser, int color)
74 return ui_browser__set_color(browser, color);
77 static void annotate_browser__write_graph(void *browser, int graph)
79 ui_browser__write_graph(browser, graph);
82 static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
84 ui_browser__set_percent_color(browser, percent, current);
87 static void annotate_browser__printf(void *browser, const char *fmt, ...)
92 ui_browser__vprintf(browser, fmt, args);
96 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
98 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
99 struct annotation *notes = browser__annotation(browser);
100 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
101 const bool is_current_entry = ui_browser__is_current_entry(browser, row);
102 struct annotation_write_ops ops = {
103 .first_line = row == 0,
104 .current_entry = is_current_entry,
105 .change_color = (!notes->options->hide_src_code &&
106 (!is_current_entry ||
107 (browser->use_navkeypressed &&
108 !browser->navkeypressed))),
109 .width = browser->width,
111 .set_color = annotate_browser__set_color,
112 .set_percent_color = annotate_browser__set_percent_color,
113 .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
114 .printf = annotate_browser__printf,
115 .write_graph = annotate_browser__write_graph,
118 /* The scroll bar isn't being used */
119 if (!browser->navkeypressed)
122 annotation_line__write(al, notes, &ops, ab->opts);
124 if (ops.current_entry)
128 static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
130 struct disasm_line *pos = list_prev_entry(cursor, al.node);
136 if (ins__is_lock(&pos->ins))
137 name = pos->ops.locked.ins.name;
139 name = pos->ins.name;
141 if (!name || !cursor->ins.name)
144 return ins__is_fused(ab->arch, name, cursor->ins.name);
147 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
149 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
150 struct disasm_line *cursor = disasm_line(ab->selection);
151 struct annotation_line *target;
152 unsigned int from, to;
153 struct map_symbol *ms = ab->b.priv;
154 struct symbol *sym = ms->sym;
155 struct annotation *notes = symbol__annotation(sym);
156 u8 pcnt_width = annotation__pcnt_width(notes);
159 /* PLT symbols contain external offsets */
160 if (strstr(sym->name, "@plt"))
163 if (!disasm_line__is_valid_local_jump(cursor, sym))
167 * This first was seen with a gcc function, _cpp_lex_token, that
168 * has the usual jumps:
170 * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92>
172 * I.e. jumps to a label inside that function (_cpp_lex_token), and
173 * those works, but also this kind:
175 * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72>
177 * I.e. jumps to another function, outside _cpp_lex_token, which
178 * are not being correctly handled generating as a side effect references
179 * to ab->offset[] entries that are set to NULL, so to make this code
180 * more robust, check that here.
182 * A proper fix for will be put in place, looking at the function
183 * name right after the '<' token and probably treating this like a
184 * 'call' instruction.
186 target = notes->offsets[cursor->ops.target.offset];
187 if (target == NULL) {
188 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
189 cursor->ops.target.offset);
193 if (notes->options->hide_src_code) {
194 from = cursor->al.idx_asm;
195 to = target->idx_asm;
197 from = (u64)cursor->al.idx;
198 to = (u64)target->idx;
201 width = annotation__cycles_width(notes);
203 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
204 __ui_browser__line_arrow(browser,
205 pcnt_width + 2 + notes->widths.addr + width,
208 if (is_fused(ab, cursor)) {
209 ui_browser__mark_fused(browser,
210 pcnt_width + 3 + notes->widths.addr + width,
216 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
218 struct annotation *notes = browser__annotation(browser);
219 int ret = ui_browser__list_head_refresh(browser);
220 int pcnt_width = annotation__pcnt_width(notes);
222 if (notes->options->jump_arrows)
223 annotate_browser__draw_current_jump(browser);
225 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
226 __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
230 static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
235 for (i = 0; i < a->data_nr; i++) {
236 if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
238 return a->data[i].percent[percent_type] -
239 b->data[i].percent[percent_type];
244 static void disasm_rb_tree__insert(struct annotate_browser *browser,
245 struct annotation_line *al)
247 struct rb_root *root = &browser->entries;
248 struct rb_node **p = &root->rb_node;
249 struct rb_node *parent = NULL;
250 struct annotation_line *l;
254 l = rb_entry(parent, struct annotation_line, rb_node);
256 if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
261 rb_link_node(&al->rb_node, parent, p);
262 rb_insert_color(&al->rb_node, root);
265 static void annotate_browser__set_top(struct annotate_browser *browser,
266 struct annotation_line *pos, u32 idx)
268 struct annotation *notes = browser__annotation(&browser->b);
271 ui_browser__refresh_dimensions(&browser->b);
272 back = browser->b.height / 2;
273 browser->b.top_idx = browser->b.index = idx;
275 while (browser->b.top_idx != 0 && back != 0) {
276 pos = list_entry(pos->node.prev, struct annotation_line, node);
278 if (annotation_line__filter(pos, notes))
281 --browser->b.top_idx;
285 browser->b.top = pos;
286 browser->b.navkeypressed = true;
289 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
292 struct annotation *notes = browser__annotation(&browser->b);
293 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
296 if (notes->options->hide_src_code)
298 annotate_browser__set_top(browser, pos, idx);
299 browser->curr_hot = nd;
302 static void annotate_browser__calc_percent(struct annotate_browser *browser,
305 struct map_symbol *ms = browser->b.priv;
306 struct symbol *sym = ms->sym;
307 struct annotation *notes = symbol__annotation(sym);
308 struct disasm_line *pos;
310 browser->entries = RB_ROOT;
312 pthread_mutex_lock(¬es->lock);
314 symbol__calc_percent(sym, evsel);
316 list_for_each_entry(pos, ¬es->src->source, al.node) {
317 double max_percent = 0.0;
320 if (pos->al.offset == -1) {
321 RB_CLEAR_NODE(&pos->al.rb_node);
325 for (i = 0; i < pos->al.data_nr; i++) {
328 percent = annotation_data__percent(&pos->al.data[i],
329 browser->opts->percent_type);
331 if (max_percent < percent)
332 max_percent = percent;
335 if (max_percent < 0.01 && pos->al.ipc == 0) {
336 RB_CLEAR_NODE(&pos->al.rb_node);
339 disasm_rb_tree__insert(browser, &pos->al);
341 pthread_mutex_unlock(¬es->lock);
343 browser->curr_hot = rb_last(&browser->entries);
346 static struct annotation_line *annotate_browser__find_next_asm_line(
347 struct annotate_browser *browser,
348 struct annotation_line *al)
350 struct annotation_line *it = al;
352 /* find next asm line */
353 list_for_each_entry_continue(it, browser->b.entries, node) {
354 if (it->idx_asm >= 0)
358 /* no asm line found forwards, try backwards */
360 list_for_each_entry_continue_reverse(it, browser->b.entries, node) {
361 if (it->idx_asm >= 0)
365 /* There are no asm lines */
369 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
371 struct annotation *notes = browser__annotation(&browser->b);
372 struct annotation_line *al;
373 off_t offset = browser->b.index - browser->b.top_idx;
375 browser->b.seek(&browser->b, offset, SEEK_CUR);
376 al = list_entry(browser->b.top, struct annotation_line, node);
378 if (notes->options->hide_src_code) {
379 if (al->idx_asm < offset)
382 browser->b.nr_entries = notes->nr_entries;
383 notes->options->hide_src_code = false;
384 browser->b.seek(&browser->b, -offset, SEEK_CUR);
385 browser->b.top_idx = al->idx - offset;
386 browser->b.index = al->idx;
388 if (al->idx_asm < 0) {
389 /* move cursor to next asm line */
390 al = annotate_browser__find_next_asm_line(browser, al);
392 browser->b.seek(&browser->b, -offset, SEEK_CUR);
397 if (al->idx_asm < offset)
398 offset = al->idx_asm;
400 browser->b.nr_entries = notes->nr_asm_entries;
401 notes->options->hide_src_code = true;
402 browser->b.seek(&browser->b, -offset, SEEK_CUR);
403 browser->b.top_idx = al->idx_asm - offset;
404 browser->b.index = al->idx_asm;
410 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
412 static void annotate_browser__show_full_location(struct ui_browser *browser)
414 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
415 struct disasm_line *cursor = disasm_line(ab->selection);
416 struct annotation_line *al = &cursor->al;
418 if (al->offset != -1)
419 ui_helpline__puts("Only available for source code lines.");
420 else if (al->fileloc == NULL)
421 ui_helpline__puts("No source file location.");
423 char help_line[SYM_TITLE_MAX_SIZE];
424 sprintf (help_line, "Source file location: %s", al->fileloc);
425 ui_helpline__puts(help_line);
429 static void ui_browser__init_asm_mode(struct ui_browser *browser)
431 struct annotation *notes = browser__annotation(browser);
432 ui_browser__reset_index(browser);
433 browser->nr_entries = notes->nr_asm_entries;
436 static int sym_title(struct symbol *sym, struct map *map, char *title,
437 size_t sz, int percent_type)
439 return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name,
440 percent_type_str(percent_type));
444 * This can be called from external jumps, i.e. jumps from one function
445 * to another, like from the kernel's entry_SYSCALL_64 function to the
446 * swapgs_restore_regs_and_return_to_usermode() function.
448 * So all we check here is that dl->ops.target.sym is set, if it is, just
449 * go to that function and when exiting from its disassembly, come back
450 * to the calling function.
452 static bool annotate_browser__callq(struct annotate_browser *browser,
454 struct hist_browser_timer *hbt)
456 struct map_symbol *ms = browser->b.priv, target_ms;
457 struct disasm_line *dl = disasm_line(browser->selection);
458 struct annotation *notes;
459 char title[SYM_TITLE_MAX_SIZE];
461 if (!dl->ops.target.sym) {
462 ui_helpline__puts("The called function was not found.");
466 notes = symbol__annotation(dl->ops.target.sym);
467 pthread_mutex_lock(¬es->lock);
469 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
470 pthread_mutex_unlock(¬es->lock);
471 ui__warning("Not enough memory for annotating '%s' symbol!\n",
472 dl->ops.target.sym->name);
476 target_ms.maps = ms->maps;
477 target_ms.map = ms->map;
478 target_ms.sym = dl->ops.target.sym;
479 pthread_mutex_unlock(¬es->lock);
480 symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);
481 sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
482 ui_browser__show_title(&browser->b, title);
487 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
488 s64 offset, s64 *idx)
490 struct annotation *notes = browser__annotation(&browser->b);
491 struct disasm_line *pos;
494 list_for_each_entry(pos, ¬es->src->source, al.node) {
495 if (pos->al.offset == offset)
497 if (!annotation_line__filter(&pos->al, notes))
504 static bool annotate_browser__jump(struct annotate_browser *browser,
506 struct hist_browser_timer *hbt)
508 struct disasm_line *dl = disasm_line(browser->selection);
512 if (!ins__is_jump(&dl->ins))
515 if (dl->ops.target.outside) {
516 annotate_browser__callq(browser, evsel, hbt);
520 offset = dl->ops.target.offset;
521 dl = annotate_browser__find_offset(browser, offset, &idx);
523 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
527 annotate_browser__set_top(browser, &dl->al, idx);
533 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
536 struct annotation *notes = browser__annotation(&browser->b);
537 struct annotation_line *al = browser->selection;
539 *idx = browser->b.index;
540 list_for_each_entry_continue(al, ¬es->src->source, node) {
541 if (annotation_line__filter(al, notes))
546 if (al->line && strstr(al->line, s) != NULL)
553 static bool __annotate_browser__search(struct annotate_browser *browser)
555 struct annotation_line *al;
558 al = annotate_browser__find_string(browser, browser->search_bf, &idx);
560 ui_helpline__puts("String not found!");
564 annotate_browser__set_top(browser, al, idx);
565 browser->searching_backwards = false;
570 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
573 struct annotation *notes = browser__annotation(&browser->b);
574 struct annotation_line *al = browser->selection;
576 *idx = browser->b.index;
577 list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
578 if (annotation_line__filter(al, notes))
583 if (al->line && strstr(al->line, s) != NULL)
590 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
592 struct annotation_line *al;
595 al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
597 ui_helpline__puts("String not found!");
601 annotate_browser__set_top(browser, al, idx);
602 browser->searching_backwards = true;
606 static bool annotate_browser__search_window(struct annotate_browser *browser,
609 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
610 "ENTER: OK, ESC: Cancel",
611 delay_secs * 2) != K_ENTER ||
612 !*browser->search_bf)
618 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
620 if (annotate_browser__search_window(browser, delay_secs))
621 return __annotate_browser__search(browser);
626 static bool annotate_browser__continue_search(struct annotate_browser *browser,
629 if (!*browser->search_bf)
630 return annotate_browser__search(browser, delay_secs);
632 return __annotate_browser__search(browser);
635 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
638 if (annotate_browser__search_window(browser, delay_secs))
639 return __annotate_browser__search_reverse(browser);
645 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
648 if (!*browser->search_bf)
649 return annotate_browser__search_reverse(browser, delay_secs);
651 return __annotate_browser__search_reverse(browser);
654 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
656 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
657 struct map_symbol *ms = browser->priv;
658 struct symbol *sym = ms->sym;
659 char symbol_dso[SYM_TITLE_MAX_SIZE];
661 if (ui_browser__show(browser, title, help) < 0)
664 sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
666 ui_browser__gotorc_title(browser, 0, 0);
667 ui_browser__set_color(browser, HE_COLORSET_ROOT);
668 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
673 switch_percent_type(struct annotation_options *opts, bool base)
675 switch (opts->percent_type) {
676 case PERCENT_HITS_LOCAL:
678 opts->percent_type = PERCENT_PERIOD_LOCAL;
680 opts->percent_type = PERCENT_HITS_GLOBAL;
682 case PERCENT_HITS_GLOBAL:
684 opts->percent_type = PERCENT_PERIOD_GLOBAL;
686 opts->percent_type = PERCENT_HITS_LOCAL;
688 case PERCENT_PERIOD_LOCAL:
690 opts->percent_type = PERCENT_HITS_LOCAL;
692 opts->percent_type = PERCENT_PERIOD_GLOBAL;
694 case PERCENT_PERIOD_GLOBAL:
696 opts->percent_type = PERCENT_HITS_GLOBAL;
698 opts->percent_type = PERCENT_PERIOD_LOCAL;
705 static int annotate_browser__run(struct annotate_browser *browser,
707 struct hist_browser_timer *hbt)
709 struct rb_node *nd = NULL;
710 struct hists *hists = evsel__hists(evsel);
711 struct map_symbol *ms = browser->b.priv;
712 struct symbol *sym = ms->sym;
713 struct annotation *notes = symbol__annotation(ms->sym);
714 const char *help = "Press 'h' for help on key bindings";
715 int delay_secs = hbt ? hbt->refresh : 0;
719 hists__scnprintf_title(hists, title, sizeof(title));
720 if (annotate_browser__show(&browser->b, title, help) < 0)
723 annotate_browser__calc_percent(browser, evsel);
725 if (browser->curr_hot) {
726 annotate_browser__set_rb_top(browser, browser->curr_hot);
727 browser->b.navkeypressed = false;
730 nd = browser->curr_hot;
733 key = ui_browser__run(&browser->b, delay_secs);
735 if (delay_secs != 0) {
736 annotate_browser__calc_percent(browser, evsel);
738 * Current line focus got out of the list of most active
739 * lines, NULL it so that if TAB|UNTAB is pressed, we
740 * move to curr_hot (current hottest line).
742 if (nd != NULL && RB_EMPTY_NODE(nd))
749 hbt->timer(hbt->arg);
751 if (delay_secs != 0) {
752 symbol__annotate_decay_histogram(sym, evsel->core.idx);
753 hists__scnprintf_title(hists, title, sizeof(title));
754 annotate_browser__show(&browser->b, title, help);
761 nd = rb_last(&browser->entries);
763 nd = browser->curr_hot;
769 nd = rb_first(&browser->entries);
771 nd = browser->curr_hot;
775 ui_browser__help_window(&browser->b,
777 "PGDN/SPACE Navigate\n"
778 "q/ESC/CTRL+C Exit\n\n"
779 "ENTER Go to target\n"
781 "H Go to hottest instruction\n"
782 "TAB/shift+TAB Cycle thru hottest instructions\n"
783 "j Toggle showing jump to target arrows\n"
784 "J Toggle showing number of jump sources on targets\n"
785 "n Search next string\n"
786 "o Toggle disassembler output/simplified view\n"
787 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
788 "s Toggle source code view\n"
789 "t Circulate percent, total period, samples view\n"
790 "c Show min/max cycle\n"
792 "k Toggle line numbers\n"
793 "l Show full source file location\n"
794 "P Print to [symbol_name].annotation file.\n"
795 "r Run available scripts\n"
796 "p Toggle percent type [local/global]\n"
797 "b Toggle percent base [period/hits]\n"
798 "? Search string backwards\n");
801 script_browse(NULL, NULL);
802 annotate_browser__show(&browser->b, title, help);
805 notes->options->show_linenr = !notes->options->show_linenr;
808 annotate_browser__show_full_location (&browser->b);
811 nd = browser->curr_hot;
814 if (annotate_browser__toggle_source(browser))
815 ui_helpline__puts(help);
818 notes->options->use_offset = !notes->options->use_offset;
819 annotation__update_column_widths(notes);
822 if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
823 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
826 notes->options->jump_arrows = !notes->options->jump_arrows;
829 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
830 annotation__update_column_widths(notes);
833 if (annotate_browser__search(browser, delay_secs)) {
835 ui_helpline__puts(help);
839 if (browser->searching_backwards ?
840 annotate_browser__continue_search_reverse(browser, delay_secs) :
841 annotate_browser__continue_search(browser, delay_secs))
845 if (annotate_browser__search_reverse(browser, delay_secs))
851 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
852 seq++, browser->b.nr_entries,
856 notes->nr_asm_entries);
862 struct disasm_line *dl = disasm_line(browser->selection);
864 if (browser->selection == NULL)
865 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
866 else if (browser->selection->offset == -1)
867 ui_helpline__puts("Actions are only available for assembly lines.");
868 else if (!dl->ins.ops)
870 else if (ins__is_ret(&dl->ins))
872 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
873 annotate_browser__callq(browser, evsel, hbt))) {
875 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
880 map_symbol__annotation_dump(ms, evsel, browser->opts);
883 if (symbol_conf.show_total_period) {
884 symbol_conf.show_total_period = false;
885 symbol_conf.show_nr_samples = true;
886 } else if (symbol_conf.show_nr_samples)
887 symbol_conf.show_nr_samples = false;
889 symbol_conf.show_total_period = true;
890 annotation__update_column_widths(notes);
893 if (notes->options->show_minmax_cycle)
894 notes->options->show_minmax_cycle = false;
896 notes->options->show_minmax_cycle = true;
897 annotation__update_column_widths(notes);
901 switch_percent_type(browser->opts, key == 'b');
902 hists__scnprintf_title(hists, title, sizeof(title));
903 annotate_browser__show(&browser->b, title, help);
915 annotate_browser__set_rb_top(browser, nd);
918 ui_browser__hide(&browser->b);
922 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
923 struct hist_browser_timer *hbt,
924 struct annotation_options *opts)
926 return symbol__tui_annotate(ms, evsel, hbt, opts);
929 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
930 struct hist_browser_timer *hbt,
931 struct annotation_options *opts)
933 /* reset abort key so that it can get Ctrl-C as a key */
935 SLang_init_tty(0, 0, 0);
937 return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
940 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
941 struct hist_browser_timer *hbt,
942 struct annotation_options *opts)
944 struct symbol *sym = ms->sym;
945 struct annotation *notes = symbol__annotation(sym);
946 struct annotate_browser browser = {
948 .refresh = annotate_browser__refresh,
949 .seek = ui_browser__list_head_seek,
950 .write = annotate_browser__write,
951 .filter = disasm_line__filter,
952 .extra_title_lines = 1, /* for hists__scnprintf_title() */
954 .use_navkeypressed = true,
963 if (ms->map->dso->annotate_warned)
966 err = symbol__annotate2(ms, evsel, opts, &browser.arch);
969 ms->map->dso->annotate_warned = true;
970 symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
971 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
972 goto out_free_offsets;
975 ui_helpline__push("Press ESC to exit");
977 browser.b.width = notes->max_line_len;
978 browser.b.nr_entries = notes->nr_entries;
979 browser.b.entries = ¬es->src->source,
980 browser.b.width += 18; /* Percentage */
982 if (notes->options->hide_src_code)
983 ui_browser__init_asm_mode(&browser.b);
985 ret = annotate_browser__run(&browser, evsel, hbt);
987 annotated_source__purge(notes->src);
990 zfree(¬es->offsets);