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 int is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
130 struct disasm_line *pos = list_prev_entry(cursor, al.node);
134 while (pos && pos->al.offset == -1) {
135 pos = list_prev_entry(pos, al.node);
136 if (!ab->opts->hide_src_code)
143 if (ins__is_lock(&pos->ins))
144 name = pos->ops.locked.ins.name;
146 name = pos->ins.name;
148 if (!name || !cursor->ins.name)
151 if (ins__is_fused(ab->arch, name, cursor->ins.name))
156 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
158 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
159 struct disasm_line *cursor = disasm_line(ab->selection);
160 struct annotation_line *target;
161 unsigned int from, to;
162 struct map_symbol *ms = ab->b.priv;
163 struct symbol *sym = ms->sym;
164 struct annotation *notes = symbol__annotation(sym);
165 u8 pcnt_width = annotation__pcnt_width(notes);
169 /* PLT symbols contain external offsets */
170 if (strstr(sym->name, "@plt"))
173 if (!disasm_line__is_valid_local_jump(cursor, sym))
177 * This first was seen with a gcc function, _cpp_lex_token, that
178 * has the usual jumps:
180 * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92>
182 * I.e. jumps to a label inside that function (_cpp_lex_token), and
183 * those works, but also this kind:
185 * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72>
187 * I.e. jumps to another function, outside _cpp_lex_token, which
188 * are not being correctly handled generating as a side effect references
189 * to ab->offset[] entries that are set to NULL, so to make this code
190 * more robust, check that here.
192 * A proper fix for will be put in place, looking at the function
193 * name right after the '<' token and probably treating this like a
194 * 'call' instruction.
196 target = notes->offsets[cursor->ops.target.offset];
197 if (target == NULL) {
198 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
199 cursor->ops.target.offset);
203 if (notes->options->hide_src_code) {
204 from = cursor->al.idx_asm;
205 to = target->idx_asm;
207 from = (u64)cursor->al.idx;
208 to = (u64)target->idx;
211 width = annotation__cycles_width(notes);
213 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
214 __ui_browser__line_arrow(browser,
215 pcnt_width + 2 + notes->widths.addr + width,
218 diff = is_fused(ab, cursor);
220 ui_browser__mark_fused(browser,
221 pcnt_width + 3 + notes->widths.addr + width,
222 from - diff, diff, to > from);
226 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
228 struct annotation *notes = browser__annotation(browser);
229 int ret = ui_browser__list_head_refresh(browser);
230 int pcnt_width = annotation__pcnt_width(notes);
232 if (notes->options->jump_arrows)
233 annotate_browser__draw_current_jump(browser);
235 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
236 __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
240 static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
245 for (i = 0; i < a->data_nr; i++) {
246 if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
248 return a->data[i].percent[percent_type] -
249 b->data[i].percent[percent_type];
254 static void disasm_rb_tree__insert(struct annotate_browser *browser,
255 struct annotation_line *al)
257 struct rb_root *root = &browser->entries;
258 struct rb_node **p = &root->rb_node;
259 struct rb_node *parent = NULL;
260 struct annotation_line *l;
264 l = rb_entry(parent, struct annotation_line, rb_node);
266 if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
271 rb_link_node(&al->rb_node, parent, p);
272 rb_insert_color(&al->rb_node, root);
275 static void annotate_browser__set_top(struct annotate_browser *browser,
276 struct annotation_line *pos, u32 idx)
278 struct annotation *notes = browser__annotation(&browser->b);
281 ui_browser__refresh_dimensions(&browser->b);
282 back = browser->b.height / 2;
283 browser->b.top_idx = browser->b.index = idx;
285 while (browser->b.top_idx != 0 && back != 0) {
286 pos = list_entry(pos->node.prev, struct annotation_line, node);
288 if (annotation_line__filter(pos, notes))
291 --browser->b.top_idx;
295 browser->b.top = pos;
296 browser->b.navkeypressed = true;
299 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
302 struct annotation *notes = browser__annotation(&browser->b);
303 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
306 if (notes->options->hide_src_code)
308 annotate_browser__set_top(browser, pos, idx);
309 browser->curr_hot = nd;
312 static void annotate_browser__calc_percent(struct annotate_browser *browser,
315 struct map_symbol *ms = browser->b.priv;
316 struct symbol *sym = ms->sym;
317 struct annotation *notes = symbol__annotation(sym);
318 struct disasm_line *pos;
320 browser->entries = RB_ROOT;
322 pthread_mutex_lock(¬es->lock);
324 symbol__calc_percent(sym, evsel);
326 list_for_each_entry(pos, ¬es->src->source, al.node) {
327 double max_percent = 0.0;
330 if (pos->al.offset == -1) {
331 RB_CLEAR_NODE(&pos->al.rb_node);
335 for (i = 0; i < pos->al.data_nr; i++) {
338 percent = annotation_data__percent(&pos->al.data[i],
339 browser->opts->percent_type);
341 if (max_percent < percent)
342 max_percent = percent;
345 if (max_percent < 0.01 && pos->al.ipc == 0) {
346 RB_CLEAR_NODE(&pos->al.rb_node);
349 disasm_rb_tree__insert(browser, &pos->al);
351 pthread_mutex_unlock(¬es->lock);
353 browser->curr_hot = rb_last(&browser->entries);
356 static struct annotation_line *annotate_browser__find_next_asm_line(
357 struct annotate_browser *browser,
358 struct annotation_line *al)
360 struct annotation_line *it = al;
362 /* find next asm line */
363 list_for_each_entry_continue(it, browser->b.entries, node) {
364 if (it->idx_asm >= 0)
368 /* no asm line found forwards, try backwards */
370 list_for_each_entry_continue_reverse(it, browser->b.entries, node) {
371 if (it->idx_asm >= 0)
375 /* There are no asm lines */
379 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
381 struct annotation *notes = browser__annotation(&browser->b);
382 struct annotation_line *al;
383 off_t offset = browser->b.index - browser->b.top_idx;
385 browser->b.seek(&browser->b, offset, SEEK_CUR);
386 al = list_entry(browser->b.top, struct annotation_line, node);
388 if (notes->options->hide_src_code) {
389 if (al->idx_asm < offset)
392 browser->b.nr_entries = notes->nr_entries;
393 notes->options->hide_src_code = false;
394 browser->b.seek(&browser->b, -offset, SEEK_CUR);
395 browser->b.top_idx = al->idx - offset;
396 browser->b.index = al->idx;
398 if (al->idx_asm < 0) {
399 /* move cursor to next asm line */
400 al = annotate_browser__find_next_asm_line(browser, al);
402 browser->b.seek(&browser->b, -offset, SEEK_CUR);
407 if (al->idx_asm < offset)
408 offset = al->idx_asm;
410 browser->b.nr_entries = notes->nr_asm_entries;
411 notes->options->hide_src_code = true;
412 browser->b.seek(&browser->b, -offset, SEEK_CUR);
413 browser->b.top_idx = al->idx_asm - offset;
414 browser->b.index = al->idx_asm;
420 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
422 static void annotate_browser__show_full_location(struct ui_browser *browser)
424 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
425 struct disasm_line *cursor = disasm_line(ab->selection);
426 struct annotation_line *al = &cursor->al;
428 if (al->offset != -1)
429 ui_helpline__puts("Only available for source code lines.");
430 else if (al->fileloc == NULL)
431 ui_helpline__puts("No source file location.");
433 char help_line[SYM_TITLE_MAX_SIZE];
434 sprintf (help_line, "Source file location: %s", al->fileloc);
435 ui_helpline__puts(help_line);
439 static void ui_browser__init_asm_mode(struct ui_browser *browser)
441 struct annotation *notes = browser__annotation(browser);
442 ui_browser__reset_index(browser);
443 browser->nr_entries = notes->nr_asm_entries;
446 static int sym_title(struct symbol *sym, struct map *map, char *title,
447 size_t sz, int percent_type)
449 return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name,
450 percent_type_str(percent_type));
454 * This can be called from external jumps, i.e. jumps from one function
455 * to another, like from the kernel's entry_SYSCALL_64 function to the
456 * swapgs_restore_regs_and_return_to_usermode() function.
458 * So all we check here is that dl->ops.target.sym is set, if it is, just
459 * go to that function and when exiting from its disassembly, come back
460 * to the calling function.
462 static bool annotate_browser__callq(struct annotate_browser *browser,
464 struct hist_browser_timer *hbt)
466 struct map_symbol *ms = browser->b.priv, target_ms;
467 struct disasm_line *dl = disasm_line(browser->selection);
468 struct annotation *notes;
469 char title[SYM_TITLE_MAX_SIZE];
471 if (!dl->ops.target.sym) {
472 ui_helpline__puts("The called function was not found.");
476 notes = symbol__annotation(dl->ops.target.sym);
477 pthread_mutex_lock(¬es->lock);
479 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
480 pthread_mutex_unlock(¬es->lock);
481 ui__warning("Not enough memory for annotating '%s' symbol!\n",
482 dl->ops.target.sym->name);
486 target_ms.maps = ms->maps;
487 target_ms.map = ms->map;
488 target_ms.sym = dl->ops.target.sym;
489 pthread_mutex_unlock(¬es->lock);
490 symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);
491 sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
492 ui_browser__show_title(&browser->b, title);
497 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
498 s64 offset, s64 *idx)
500 struct annotation *notes = browser__annotation(&browser->b);
501 struct disasm_line *pos;
504 list_for_each_entry(pos, ¬es->src->source, al.node) {
505 if (pos->al.offset == offset)
507 if (!annotation_line__filter(&pos->al, notes))
514 static bool annotate_browser__jump(struct annotate_browser *browser,
516 struct hist_browser_timer *hbt)
518 struct disasm_line *dl = disasm_line(browser->selection);
522 if (!ins__is_jump(&dl->ins))
525 if (dl->ops.target.outside) {
526 annotate_browser__callq(browser, evsel, hbt);
530 offset = dl->ops.target.offset;
531 dl = annotate_browser__find_offset(browser, offset, &idx);
533 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
537 annotate_browser__set_top(browser, &dl->al, idx);
543 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
546 struct annotation *notes = browser__annotation(&browser->b);
547 struct annotation_line *al = browser->selection;
549 *idx = browser->b.index;
550 list_for_each_entry_continue(al, ¬es->src->source, node) {
551 if (annotation_line__filter(al, notes))
556 if (al->line && strstr(al->line, s) != NULL)
563 static bool __annotate_browser__search(struct annotate_browser *browser)
565 struct annotation_line *al;
568 al = annotate_browser__find_string(browser, browser->search_bf, &idx);
570 ui_helpline__puts("String not found!");
574 annotate_browser__set_top(browser, al, idx);
575 browser->searching_backwards = false;
580 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
583 struct annotation *notes = browser__annotation(&browser->b);
584 struct annotation_line *al = browser->selection;
586 *idx = browser->b.index;
587 list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
588 if (annotation_line__filter(al, notes))
593 if (al->line && strstr(al->line, s) != NULL)
600 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
602 struct annotation_line *al;
605 al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
607 ui_helpline__puts("String not found!");
611 annotate_browser__set_top(browser, al, idx);
612 browser->searching_backwards = true;
616 static bool annotate_browser__search_window(struct annotate_browser *browser,
619 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
620 "ENTER: OK, ESC: Cancel",
621 delay_secs * 2) != K_ENTER ||
622 !*browser->search_bf)
628 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
630 if (annotate_browser__search_window(browser, delay_secs))
631 return __annotate_browser__search(browser);
636 static bool annotate_browser__continue_search(struct annotate_browser *browser,
639 if (!*browser->search_bf)
640 return annotate_browser__search(browser, delay_secs);
642 return __annotate_browser__search(browser);
645 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
648 if (annotate_browser__search_window(browser, delay_secs))
649 return __annotate_browser__search_reverse(browser);
655 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
658 if (!*browser->search_bf)
659 return annotate_browser__search_reverse(browser, delay_secs);
661 return __annotate_browser__search_reverse(browser);
664 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
666 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
667 struct map_symbol *ms = browser->priv;
668 struct symbol *sym = ms->sym;
669 char symbol_dso[SYM_TITLE_MAX_SIZE];
671 if (ui_browser__show(browser, title, help) < 0)
674 sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
676 ui_browser__gotorc_title(browser, 0, 0);
677 ui_browser__set_color(browser, HE_COLORSET_ROOT);
678 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
683 switch_percent_type(struct annotation_options *opts, bool base)
685 switch (opts->percent_type) {
686 case PERCENT_HITS_LOCAL:
688 opts->percent_type = PERCENT_PERIOD_LOCAL;
690 opts->percent_type = PERCENT_HITS_GLOBAL;
692 case PERCENT_HITS_GLOBAL:
694 opts->percent_type = PERCENT_PERIOD_GLOBAL;
696 opts->percent_type = PERCENT_HITS_LOCAL;
698 case PERCENT_PERIOD_LOCAL:
700 opts->percent_type = PERCENT_HITS_LOCAL;
702 opts->percent_type = PERCENT_PERIOD_GLOBAL;
704 case PERCENT_PERIOD_GLOBAL:
706 opts->percent_type = PERCENT_HITS_GLOBAL;
708 opts->percent_type = PERCENT_PERIOD_LOCAL;
715 static int annotate_browser__run(struct annotate_browser *browser,
717 struct hist_browser_timer *hbt)
719 struct rb_node *nd = NULL;
720 struct hists *hists = evsel__hists(evsel);
721 struct map_symbol *ms = browser->b.priv;
722 struct symbol *sym = ms->sym;
723 struct annotation *notes = symbol__annotation(ms->sym);
724 const char *help = "Press 'h' for help on key bindings";
725 int delay_secs = hbt ? hbt->refresh : 0;
729 hists__scnprintf_title(hists, title, sizeof(title));
730 if (annotate_browser__show(&browser->b, title, help) < 0)
733 annotate_browser__calc_percent(browser, evsel);
735 if (browser->curr_hot) {
736 annotate_browser__set_rb_top(browser, browser->curr_hot);
737 browser->b.navkeypressed = false;
740 nd = browser->curr_hot;
743 key = ui_browser__run(&browser->b, delay_secs);
745 if (delay_secs != 0) {
746 annotate_browser__calc_percent(browser, evsel);
748 * Current line focus got out of the list of most active
749 * lines, NULL it so that if TAB|UNTAB is pressed, we
750 * move to curr_hot (current hottest line).
752 if (nd != NULL && RB_EMPTY_NODE(nd))
759 hbt->timer(hbt->arg);
761 if (delay_secs != 0) {
762 symbol__annotate_decay_histogram(sym, evsel->core.idx);
763 hists__scnprintf_title(hists, title, sizeof(title));
764 annotate_browser__show(&browser->b, title, help);
771 nd = rb_last(&browser->entries);
773 nd = browser->curr_hot;
779 nd = rb_first(&browser->entries);
781 nd = browser->curr_hot;
785 ui_browser__help_window(&browser->b,
787 "PGDN/SPACE Navigate\n"
788 "q/ESC/CTRL+C Exit\n\n"
789 "ENTER Go to target\n"
791 "H Go to hottest instruction\n"
792 "TAB/shift+TAB Cycle thru hottest instructions\n"
793 "j Toggle showing jump to target arrows\n"
794 "J Toggle showing number of jump sources on targets\n"
795 "n Search next string\n"
796 "o Toggle disassembler output/simplified view\n"
797 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
798 "s Toggle source code view\n"
799 "t Circulate percent, total period, samples view\n"
800 "c Show min/max cycle\n"
802 "k Toggle line numbers\n"
803 "l Show full source file location\n"
804 "P Print to [symbol_name].annotation file.\n"
805 "r Run available scripts\n"
806 "p Toggle percent type [local/global]\n"
807 "b Toggle percent base [period/hits]\n"
808 "? Search string backwards\n");
811 script_browse(NULL, NULL);
812 annotate_browser__show(&browser->b, title, help);
815 notes->options->show_linenr = !notes->options->show_linenr;
818 annotate_browser__show_full_location (&browser->b);
821 nd = browser->curr_hot;
824 if (annotate_browser__toggle_source(browser))
825 ui_helpline__puts(help);
828 notes->options->use_offset = !notes->options->use_offset;
829 annotation__update_column_widths(notes);
832 if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
833 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
836 notes->options->jump_arrows = !notes->options->jump_arrows;
839 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
840 annotation__update_column_widths(notes);
843 if (annotate_browser__search(browser, delay_secs)) {
845 ui_helpline__puts(help);
849 if (browser->searching_backwards ?
850 annotate_browser__continue_search_reverse(browser, delay_secs) :
851 annotate_browser__continue_search(browser, delay_secs))
855 if (annotate_browser__search_reverse(browser, delay_secs))
861 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
862 seq++, browser->b.nr_entries,
866 notes->nr_asm_entries);
872 struct disasm_line *dl = disasm_line(browser->selection);
874 if (browser->selection == NULL)
875 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
876 else if (browser->selection->offset == -1)
877 ui_helpline__puts("Actions are only available for assembly lines.");
878 else if (!dl->ins.ops)
880 else if (ins__is_ret(&dl->ins))
882 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
883 annotate_browser__callq(browser, evsel, hbt))) {
885 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
890 map_symbol__annotation_dump(ms, evsel, browser->opts);
893 if (symbol_conf.show_total_period) {
894 symbol_conf.show_total_period = false;
895 symbol_conf.show_nr_samples = true;
896 } else if (symbol_conf.show_nr_samples)
897 symbol_conf.show_nr_samples = false;
899 symbol_conf.show_total_period = true;
900 annotation__update_column_widths(notes);
903 if (notes->options->show_minmax_cycle)
904 notes->options->show_minmax_cycle = false;
906 notes->options->show_minmax_cycle = true;
907 annotation__update_column_widths(notes);
911 switch_percent_type(browser->opts, key == 'b');
912 hists__scnprintf_title(hists, title, sizeof(title));
913 annotate_browser__show(&browser->b, title, help);
925 annotate_browser__set_rb_top(browser, nd);
928 ui_browser__hide(&browser->b);
932 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
933 struct hist_browser_timer *hbt,
934 struct annotation_options *opts)
936 return symbol__tui_annotate(ms, evsel, hbt, opts);
939 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
940 struct hist_browser_timer *hbt,
941 struct annotation_options *opts)
943 /* reset abort key so that it can get Ctrl-C as a key */
945 SLang_init_tty(0, 0, 0);
947 return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
950 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
951 struct hist_browser_timer *hbt,
952 struct annotation_options *opts)
954 struct symbol *sym = ms->sym;
955 struct annotation *notes = symbol__annotation(sym);
956 struct annotate_browser browser = {
958 .refresh = annotate_browser__refresh,
959 .seek = ui_browser__list_head_seek,
960 .write = annotate_browser__write,
961 .filter = disasm_line__filter,
962 .extra_title_lines = 1, /* for hists__scnprintf_title() */
964 .use_navkeypressed = true,
969 int not_annotated = list_empty(¬es->src->source);
974 if (ms->map->dso->annotate_warned)
978 err = symbol__annotate2(ms, evsel, opts, &browser.arch);
981 ms->map->dso->annotate_warned = true;
982 symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
983 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
984 goto out_free_offsets;
988 ui_helpline__push("Press ESC to exit");
990 browser.b.width = notes->max_line_len;
991 browser.b.nr_entries = notes->nr_entries;
992 browser.b.entries = ¬es->src->source,
993 browser.b.width += 18; /* Percentage */
995 if (notes->options->hide_src_code)
996 ui_browser__init_asm_mode(&browser.b);
998 ret = annotate_browser__run(&browser, evsel, hbt);
1001 annotated_source__purge(notes->src);
1005 zfree(¬es->offsets);