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/mutex.h"
12 #include "../../util/symbol.h"
13 #include "../../util/evsel.h"
14 #include "../../util/evlist.h"
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/zalloc.h>
19 #include <sys/ttydefaults.h>
24 struct annotate_browser {
26 struct rb_root entries;
27 struct rb_node *curr_hot;
28 struct annotation_line *selection;
30 bool searching_backwards;
34 static inline struct annotation *browser__annotation(struct ui_browser *browser)
36 struct map_symbol *ms = browser->priv;
37 return symbol__annotation(ms->sym);
40 static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, void *entry)
42 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
43 return annotation_line__filter(al);
46 static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
48 struct annotation *notes = browser__annotation(browser);
50 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
51 return HE_COLORSET_SELECTED;
52 if (nr == notes->max_jump_sources)
53 return HE_COLORSET_TOP;
55 return HE_COLORSET_MEDIUM;
56 return HE_COLORSET_NORMAL;
59 static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
61 int color = ui_browser__jumps_percent_color(browser, nr, current);
62 return ui_browser__set_color(browser, color);
65 static int annotate_browser__set_color(void *browser, int color)
67 return ui_browser__set_color(browser, color);
70 static void annotate_browser__write_graph(void *browser, int graph)
72 ui_browser__write_graph(browser, graph);
75 static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
77 ui_browser__set_percent_color(browser, percent, current);
80 static void annotate_browser__printf(void *browser, const char *fmt, ...)
85 ui_browser__vprintf(browser, fmt, args);
89 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
91 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
92 struct annotation *notes = browser__annotation(browser);
93 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
94 const bool is_current_entry = ui_browser__is_current_entry(browser, row);
95 struct annotation_write_ops ops = {
96 .first_line = row == 0,
97 .current_entry = is_current_entry,
98 .change_color = (!annotate_opts.hide_src_code &&
100 (browser->use_navkeypressed &&
101 !browser->navkeypressed))),
102 .width = browser->width,
104 .set_color = annotate_browser__set_color,
105 .set_percent_color = annotate_browser__set_percent_color,
106 .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
107 .printf = annotate_browser__printf,
108 .write_graph = annotate_browser__write_graph,
111 /* The scroll bar isn't being used */
112 if (!browser->navkeypressed)
115 annotation_line__write(al, notes, &ops);
117 if (ops.current_entry)
121 static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
123 struct disasm_line *pos = list_prev_entry(cursor, al.node);
127 while (pos && pos->al.offset == -1) {
128 pos = list_prev_entry(pos, al.node);
129 if (!annotate_opts.hide_src_code)
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 if (ins__is_fused(ab->arch, name, cursor->ins.name))
149 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
151 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
152 struct disasm_line *cursor = disasm_line(ab->selection);
153 struct annotation_line *target;
154 unsigned int from, to;
155 struct map_symbol *ms = ab->b.priv;
156 struct symbol *sym = ms->sym;
157 struct annotation *notes = symbol__annotation(sym);
158 u8 pcnt_width = annotation__pcnt_width(notes);
162 /* PLT symbols contain external offsets */
163 if (strstr(sym->name, "@plt"))
166 if (!disasm_line__is_valid_local_jump(cursor, sym))
170 * This first was seen with a gcc function, _cpp_lex_token, that
171 * has the usual jumps:
173 * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92>
175 * I.e. jumps to a label inside that function (_cpp_lex_token), and
176 * those works, but also this kind:
178 * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72>
180 * I.e. jumps to another function, outside _cpp_lex_token, which
181 * are not being correctly handled generating as a side effect references
182 * to ab->offset[] entries that are set to NULL, so to make this code
183 * more robust, check that here.
185 * A proper fix for will be put in place, looking at the function
186 * name right after the '<' token and probably treating this like a
187 * 'call' instruction.
189 target = notes->src->offsets[cursor->ops.target.offset];
190 if (target == NULL) {
191 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
192 cursor->ops.target.offset);
196 if (annotate_opts.hide_src_code) {
197 from = cursor->al.idx_asm;
198 to = target->idx_asm;
200 from = (u64)cursor->al.idx;
201 to = (u64)target->idx;
204 width = annotation__cycles_width(notes);
206 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
207 __ui_browser__line_arrow(browser,
208 pcnt_width + 2 + notes->widths.addr + width,
211 diff = is_fused(ab, cursor);
213 ui_browser__mark_fused(browser,
214 pcnt_width + 3 + notes->widths.addr + width,
215 from - diff, diff, to > from);
219 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
221 struct annotation *notes = browser__annotation(browser);
222 int ret = ui_browser__list_head_refresh(browser);
223 int pcnt_width = annotation__pcnt_width(notes);
225 if (annotate_opts.jump_arrows)
226 annotate_browser__draw_current_jump(browser);
228 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
229 __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
233 static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
238 for (i = 0; i < a->data_nr; i++) {
239 if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
241 return a->data[i].percent[percent_type] -
242 b->data[i].percent[percent_type];
247 static void disasm_rb_tree__insert(struct annotate_browser *browser,
248 struct annotation_line *al)
250 struct rb_root *root = &browser->entries;
251 struct rb_node **p = &root->rb_node;
252 struct rb_node *parent = NULL;
253 struct annotation_line *l;
257 l = rb_entry(parent, struct annotation_line, rb_node);
259 if (disasm__cmp(al, l, annotate_opts.percent_type) < 0)
264 rb_link_node(&al->rb_node, parent, p);
265 rb_insert_color(&al->rb_node, root);
268 static void annotate_browser__set_top(struct annotate_browser *browser,
269 struct annotation_line *pos, u32 idx)
273 ui_browser__refresh_dimensions(&browser->b);
274 back = browser->b.height / 2;
275 browser->b.top_idx = browser->b.index = idx;
277 while (browser->b.top_idx != 0 && back != 0) {
278 pos = list_entry(pos->node.prev, struct annotation_line, node);
280 if (annotation_line__filter(pos))
283 --browser->b.top_idx;
287 browser->b.top = pos;
288 browser->b.navkeypressed = true;
291 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
294 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
297 if (annotate_opts.hide_src_code)
299 annotate_browser__set_top(browser, pos, idx);
300 browser->curr_hot = nd;
303 static void annotate_browser__calc_percent(struct annotate_browser *browser,
306 struct map_symbol *ms = browser->b.priv;
307 struct symbol *sym = ms->sym;
308 struct annotation *notes = symbol__annotation(sym);
309 struct disasm_line *pos;
311 browser->entries = RB_ROOT;
313 annotation__lock(notes);
315 symbol__calc_percent(sym, evsel);
317 list_for_each_entry(pos, ¬es->src->source, al.node) {
318 double max_percent = 0.0;
321 if (pos->al.offset == -1) {
322 RB_CLEAR_NODE(&pos->al.rb_node);
326 for (i = 0; i < pos->al.data_nr; i++) {
329 percent = annotation_data__percent(&pos->al.data[i],
330 annotate_opts.percent_type);
332 if (max_percent < percent)
333 max_percent = percent;
336 if (max_percent < 0.01 && (!pos->al.cycles || pos->al.cycles->ipc == 0)) {
337 RB_CLEAR_NODE(&pos->al.rb_node);
340 disasm_rb_tree__insert(browser, &pos->al);
342 annotation__unlock(notes);
344 browser->curr_hot = rb_last(&browser->entries);
347 static struct annotation_line *annotate_browser__find_next_asm_line(
348 struct annotate_browser *browser,
349 struct annotation_line *al)
351 struct annotation_line *it = al;
353 /* find next asm line */
354 list_for_each_entry_continue(it, browser->b.entries, node) {
355 if (it->idx_asm >= 0)
359 /* no asm line found forwards, try backwards */
361 list_for_each_entry_continue_reverse(it, browser->b.entries, node) {
362 if (it->idx_asm >= 0)
366 /* There are no asm lines */
370 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
372 struct annotation *notes = browser__annotation(&browser->b);
373 struct annotation_line *al;
374 off_t offset = browser->b.index - browser->b.top_idx;
376 browser->b.seek(&browser->b, offset, SEEK_CUR);
377 al = list_entry(browser->b.top, struct annotation_line, node);
379 if (annotate_opts.hide_src_code) {
380 if (al->idx_asm < offset)
383 browser->b.nr_entries = notes->src->nr_entries;
384 annotate_opts.hide_src_code = false;
385 browser->b.seek(&browser->b, -offset, SEEK_CUR);
386 browser->b.top_idx = al->idx - offset;
387 browser->b.index = al->idx;
389 if (al->idx_asm < 0) {
390 /* move cursor to next asm line */
391 al = annotate_browser__find_next_asm_line(browser, al);
393 browser->b.seek(&browser->b, -offset, SEEK_CUR);
398 if (al->idx_asm < offset)
399 offset = al->idx_asm;
401 browser->b.nr_entries = notes->src->nr_asm_entries;
402 annotate_opts.hide_src_code = true;
403 browser->b.seek(&browser->b, -offset, SEEK_CUR);
404 browser->b.top_idx = al->idx_asm - offset;
405 browser->b.index = al->idx_asm;
411 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
413 static void annotate_browser__show_full_location(struct ui_browser *browser)
415 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
416 struct disasm_line *cursor = disasm_line(ab->selection);
417 struct annotation_line *al = &cursor->al;
419 if (al->offset != -1)
420 ui_helpline__puts("Only available for source code lines.");
421 else if (al->fileloc == NULL)
422 ui_helpline__puts("No source file location.");
424 char help_line[SYM_TITLE_MAX_SIZE];
425 sprintf (help_line, "Source file location: %s", al->fileloc);
426 ui_helpline__puts(help_line);
430 static void ui_browser__init_asm_mode(struct ui_browser *browser)
432 struct annotation *notes = browser__annotation(browser);
433 ui_browser__reset_index(browser);
434 browser->nr_entries = notes->src->nr_asm_entries;
437 static int sym_title(struct symbol *sym, struct map *map, char *title,
438 size_t sz, int percent_type)
440 return snprintf(title, sz, "%s %s [Percent: %s]", sym->name,
441 map__dso(map)->long_name,
442 percent_type_str(percent_type));
446 * This can be called from external jumps, i.e. jumps from one function
447 * to another, like from the kernel's entry_SYSCALL_64 function to the
448 * swapgs_restore_regs_and_return_to_usermode() function.
450 * So all we check here is that dl->ops.target.sym is set, if it is, just
451 * go to that function and when exiting from its disassembly, come back
452 * to the calling function.
454 static bool annotate_browser__callq(struct annotate_browser *browser,
456 struct hist_browser_timer *hbt)
458 struct map_symbol *ms = browser->b.priv, target_ms;
459 struct disasm_line *dl = disasm_line(browser->selection);
460 struct annotation *notes;
461 char title[SYM_TITLE_MAX_SIZE];
463 if (!dl->ops.target.sym) {
464 ui_helpline__puts("The called function was not found.");
468 notes = symbol__annotation(dl->ops.target.sym);
469 annotation__lock(notes);
471 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
472 annotation__unlock(notes);
473 ui__warning("Not enough memory for annotating '%s' symbol!\n",
474 dl->ops.target.sym->name);
478 target_ms.maps = ms->maps;
479 target_ms.map = ms->map;
480 target_ms.sym = dl->ops.target.sym;
481 annotation__unlock(notes);
482 symbol__tui_annotate(&target_ms, evsel, hbt);
483 sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_type);
484 ui_browser__show_title(&browser->b, title);
489 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
490 s64 offset, s64 *idx)
492 struct annotation *notes = browser__annotation(&browser->b);
493 struct disasm_line *pos;
496 list_for_each_entry(pos, ¬es->src->source, al.node) {
497 if (pos->al.offset == offset)
499 if (!annotation_line__filter(&pos->al))
506 static bool annotate_browser__jump(struct annotate_browser *browser,
508 struct hist_browser_timer *hbt)
510 struct disasm_line *dl = disasm_line(browser->selection);
514 if (!ins__is_jump(&dl->ins))
517 if (dl->ops.target.outside) {
518 annotate_browser__callq(browser, evsel, hbt);
522 offset = dl->ops.target.offset;
523 dl = annotate_browser__find_offset(browser, offset, &idx);
525 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
529 annotate_browser__set_top(browser, &dl->al, idx);
535 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
538 struct annotation *notes = browser__annotation(&browser->b);
539 struct annotation_line *al = browser->selection;
541 *idx = browser->b.index;
542 list_for_each_entry_continue(al, ¬es->src->source, node) {
543 if (annotation_line__filter(al))
548 if (al->line && strstr(al->line, s) != NULL)
555 static bool __annotate_browser__search(struct annotate_browser *browser)
557 struct annotation_line *al;
560 al = annotate_browser__find_string(browser, browser->search_bf, &idx);
562 ui_helpline__puts("String not found!");
566 annotate_browser__set_top(browser, al, idx);
567 browser->searching_backwards = false;
572 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
575 struct annotation *notes = browser__annotation(&browser->b);
576 struct annotation_line *al = browser->selection;
578 *idx = browser->b.index;
579 list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
580 if (annotation_line__filter(al))
585 if (al->line && strstr(al->line, s) != NULL)
592 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
594 struct annotation_line *al;
597 al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
599 ui_helpline__puts("String not found!");
603 annotate_browser__set_top(browser, al, idx);
604 browser->searching_backwards = true;
608 static bool annotate_browser__search_window(struct annotate_browser *browser,
611 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
612 "ENTER: OK, ESC: Cancel",
613 delay_secs * 2) != K_ENTER ||
614 !*browser->search_bf)
620 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
622 if (annotate_browser__search_window(browser, delay_secs))
623 return __annotate_browser__search(browser);
628 static bool annotate_browser__continue_search(struct annotate_browser *browser,
631 if (!*browser->search_bf)
632 return annotate_browser__search(browser, delay_secs);
634 return __annotate_browser__search(browser);
637 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
640 if (annotate_browser__search_window(browser, delay_secs))
641 return __annotate_browser__search_reverse(browser);
647 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
650 if (!*browser->search_bf)
651 return annotate_browser__search_reverse(browser, delay_secs);
653 return __annotate_browser__search_reverse(browser);
656 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
658 struct map_symbol *ms = browser->priv;
659 struct symbol *sym = ms->sym;
660 char symbol_dso[SYM_TITLE_MAX_SIZE];
662 if (ui_browser__show(browser, title, help) < 0)
665 sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), annotate_opts.percent_type);
667 ui_browser__gotorc_title(browser, 0, 0);
668 ui_browser__set_color(browser, HE_COLORSET_ROOT);
669 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
674 switch_percent_type(struct annotation_options *opts, bool base)
676 switch (opts->percent_type) {
677 case PERCENT_HITS_LOCAL:
679 opts->percent_type = PERCENT_PERIOD_LOCAL;
681 opts->percent_type = PERCENT_HITS_GLOBAL;
683 case PERCENT_HITS_GLOBAL:
685 opts->percent_type = PERCENT_PERIOD_GLOBAL;
687 opts->percent_type = PERCENT_HITS_LOCAL;
689 case PERCENT_PERIOD_LOCAL:
691 opts->percent_type = PERCENT_HITS_LOCAL;
693 opts->percent_type = PERCENT_PERIOD_GLOBAL;
695 case PERCENT_PERIOD_GLOBAL:
697 opts->percent_type = PERCENT_HITS_GLOBAL;
699 opts->percent_type = PERCENT_PERIOD_LOCAL;
706 static int annotate_browser__run(struct annotate_browser *browser,
708 struct hist_browser_timer *hbt)
710 struct rb_node *nd = NULL;
711 struct hists *hists = evsel__hists(evsel);
712 struct map_symbol *ms = browser->b.priv;
713 struct symbol *sym = ms->sym;
714 struct annotation *notes = symbol__annotation(ms->sym);
715 const char *help = "Press 'h' for help on key bindings";
716 int delay_secs = hbt ? hbt->refresh : 0;
720 hists__scnprintf_title(hists, title, sizeof(title));
721 if (annotate_browser__show(&browser->b, title, help) < 0)
724 annotate_browser__calc_percent(browser, evsel);
726 if (browser->curr_hot) {
727 annotate_browser__set_rb_top(browser, browser->curr_hot);
728 browser->b.navkeypressed = false;
731 nd = browser->curr_hot;
734 key = ui_browser__run(&browser->b, delay_secs);
736 if (delay_secs != 0) {
737 annotate_browser__calc_percent(browser, evsel);
739 * Current line focus got out of the list of most active
740 * lines, NULL it so that if TAB|UNTAB is pressed, we
741 * move to curr_hot (current hottest line).
743 if (nd != NULL && RB_EMPTY_NODE(nd))
750 hbt->timer(hbt->arg);
752 if (delay_secs != 0) {
753 symbol__annotate_decay_histogram(sym, evsel->core.idx);
754 hists__scnprintf_title(hists, title, sizeof(title));
755 annotate_browser__show(&browser->b, title, help);
762 nd = rb_last(&browser->entries);
764 nd = browser->curr_hot;
770 nd = rb_first(&browser->entries);
772 nd = browser->curr_hot;
776 ui_browser__help_window(&browser->b,
778 "PGDN/SPACE Navigate\n"
779 "</> Move to prev/next symbol\n"
780 "q/ESC/CTRL+C Exit\n\n"
781 "ENTER Go to target\n"
782 "H Go to hottest instruction\n"
783 "TAB/shift+TAB Cycle thru hottest instructions\n"
784 "j Toggle showing jump to target arrows\n"
785 "J Toggle showing number of jump sources on targets\n"
786 "n Search next string\n"
787 "o Toggle disassembler output/simplified view\n"
788 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
789 "s Toggle source code view\n"
790 "t Circulate percent, total period, samples view\n"
791 "c Show min/max cycle\n"
793 "k Toggle line numbers\n"
794 "l Show full source file location\n"
795 "P Print to [symbol_name].annotation file.\n"
796 "r Run available scripts\n"
797 "p Toggle percent type [local/global]\n"
798 "b Toggle percent base [period/hits]\n"
799 "? Search string backwards\n"
800 "f Toggle showing offsets to full address\n");
803 script_browse(NULL, NULL);
804 annotate_browser__show(&browser->b, title, help);
807 annotate_opts.show_linenr = !annotate_opts.show_linenr;
810 annotate_browser__show_full_location (&browser->b);
813 nd = browser->curr_hot;
816 if (annotate_browser__toggle_source(browser))
817 ui_helpline__puts(help);
820 annotate_opts.use_offset = !annotate_opts.use_offset;
821 annotation__update_column_widths(notes);
824 if (++annotate_opts.offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
825 annotate_opts.offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
828 annotate_opts.jump_arrows = !annotate_opts.jump_arrows;
831 annotate_opts.show_nr_jumps = !annotate_opts.show_nr_jumps;
832 annotation__update_column_widths(notes);
835 if (annotate_browser__search(browser, delay_secs)) {
837 ui_helpline__puts(help);
841 if (browser->searching_backwards ?
842 annotate_browser__continue_search_reverse(browser, delay_secs) :
843 annotate_browser__continue_search(browser, delay_secs))
847 if (annotate_browser__search_reverse(browser, delay_secs))
853 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
854 seq++, browser->b.nr_entries,
858 notes->src->nr_asm_entries);
864 struct disasm_line *dl = disasm_line(browser->selection);
866 if (browser->selection == NULL)
867 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
868 else if (browser->selection->offset == -1)
869 ui_helpline__puts("Actions are only available for assembly lines.");
870 else if (!dl->ins.ops)
872 else if (ins__is_ret(&dl->ins))
874 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
875 annotate_browser__callq(browser, evsel, hbt))) {
877 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
882 map_symbol__annotation_dump(ms, evsel);
885 if (symbol_conf.show_total_period) {
886 symbol_conf.show_total_period = false;
887 symbol_conf.show_nr_samples = true;
888 } else if (symbol_conf.show_nr_samples)
889 symbol_conf.show_nr_samples = false;
891 symbol_conf.show_total_period = true;
892 annotation__update_column_widths(notes);
895 if (annotate_opts.show_minmax_cycle)
896 annotate_opts.show_minmax_cycle = false;
898 annotate_opts.show_minmax_cycle = true;
899 annotation__update_column_widths(notes);
903 switch_percent_type(&annotate_opts, key == 'b');
904 hists__scnprintf_title(hists, title, sizeof(title));
905 annotate_browser__show(&browser->b, title, help);
908 annotation__toggle_full_addr(notes, ms);
922 annotate_browser__set_rb_top(browser, nd);
925 ui_browser__hide(&browser->b);
929 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
930 struct hist_browser_timer *hbt)
932 return symbol__tui_annotate(ms, evsel, hbt);
935 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
936 struct hist_browser_timer *hbt)
938 /* reset abort key so that it can get Ctrl-C as a key */
940 SLang_init_tty(0, 0, 0);
942 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
945 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
946 struct hist_browser_timer *hbt)
948 struct symbol *sym = ms->sym;
949 struct annotation *notes = symbol__annotation(sym);
950 struct annotate_browser browser = {
952 .refresh = annotate_browser__refresh,
953 .seek = ui_browser__list_head_seek,
954 .write = annotate_browser__write,
955 .filter = disasm_line__filter,
956 .extra_title_lines = 1, /* for hists__scnprintf_title() */
958 .use_navkeypressed = true,
963 int not_annotated = list_empty(¬es->src->source);
968 dso = map__dso(ms->map);
969 if (dso->annotate_warned)
973 err = symbol__annotate2(ms, evsel, &browser.arch);
976 dso->annotate_warned = true;
977 symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
978 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
979 goto out_free_offsets;
983 ui_helpline__push("Press ESC to exit");
985 browser.b.width = notes->src->max_line_len;
986 browser.b.nr_entries = notes->src->nr_entries;
987 browser.b.entries = ¬es->src->source,
988 browser.b.width += 18; /* Percentage */
990 if (annotate_opts.hide_src_code)
991 ui_browser__init_asm_mode(&browser.b);
993 ret = annotate_browser__run(&browser, evsel, hbt);
996 annotated_source__purge(notes->src);
1000 zfree(¬es->src->offsets);