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 struct annotation_options *opts;
31 bool searching_backwards;
35 static inline struct annotation *browser__annotation(struct ui_browser *browser)
37 struct map_symbol *ms = browser->priv;
38 return symbol__annotation(ms->sym);
41 static bool disasm_line__filter(struct ui_browser *browser, void *entry)
43 struct annotation *notes = browser__annotation(browser);
44 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
45 return annotation_line__filter(al, notes);
48 static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
50 struct annotation *notes = browser__annotation(browser);
52 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
53 return HE_COLORSET_SELECTED;
54 if (nr == notes->max_jump_sources)
55 return HE_COLORSET_TOP;
57 return HE_COLORSET_MEDIUM;
58 return HE_COLORSET_NORMAL;
61 static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
63 int color = ui_browser__jumps_percent_color(browser, nr, current);
64 return ui_browser__set_color(browser, color);
67 static int annotate_browser__set_color(void *browser, int color)
69 return ui_browser__set_color(browser, color);
72 static void annotate_browser__write_graph(void *browser, int graph)
74 ui_browser__write_graph(browser, graph);
77 static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
79 ui_browser__set_percent_color(browser, percent, current);
82 static void annotate_browser__printf(void *browser, const char *fmt, ...)
87 ui_browser__vprintf(browser, fmt, args);
91 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
93 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
94 struct annotation *notes = browser__annotation(browser);
95 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
96 const bool is_current_entry = ui_browser__is_current_entry(browser, row);
97 struct annotation_write_ops ops = {
98 .first_line = row == 0,
99 .current_entry = is_current_entry,
100 .change_color = (!notes->options->hide_src_code &&
101 (!is_current_entry ||
102 (browser->use_navkeypressed &&
103 !browser->navkeypressed))),
104 .width = browser->width,
106 .set_color = annotate_browser__set_color,
107 .set_percent_color = annotate_browser__set_percent_color,
108 .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
109 .printf = annotate_browser__printf,
110 .write_graph = annotate_browser__write_graph,
113 /* The scroll bar isn't being used */
114 if (!browser->navkeypressed)
117 annotation_line__write(al, notes, &ops, ab->opts);
119 if (ops.current_entry)
123 static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
125 struct disasm_line *pos = list_prev_entry(cursor, al.node);
129 while (pos && pos->al.offset == -1) {
130 pos = list_prev_entry(pos, al.node);
131 if (!ab->opts->hide_src_code)
138 if (ins__is_lock(&pos->ins))
139 name = pos->ops.locked.ins.name;
141 name = pos->ins.name;
143 if (!name || !cursor->ins.name)
146 if (ins__is_fused(ab->arch, name, cursor->ins.name))
151 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
153 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
154 struct disasm_line *cursor = disasm_line(ab->selection);
155 struct annotation_line *target;
156 unsigned int from, to;
157 struct map_symbol *ms = ab->b.priv;
158 struct symbol *sym = ms->sym;
159 struct annotation *notes = symbol__annotation(sym);
160 u8 pcnt_width = annotation__pcnt_width(notes);
164 /* PLT symbols contain external offsets */
165 if (strstr(sym->name, "@plt"))
168 if (!disasm_line__is_valid_local_jump(cursor, sym))
172 * This first was seen with a gcc function, _cpp_lex_token, that
173 * has the usual jumps:
175 * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92>
177 * I.e. jumps to a label inside that function (_cpp_lex_token), and
178 * those works, but also this kind:
180 * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72>
182 * I.e. jumps to another function, outside _cpp_lex_token, which
183 * are not being correctly handled generating as a side effect references
184 * to ab->offset[] entries that are set to NULL, so to make this code
185 * more robust, check that here.
187 * A proper fix for will be put in place, looking at the function
188 * name right after the '<' token and probably treating this like a
189 * 'call' instruction.
191 target = notes->offsets[cursor->ops.target.offset];
192 if (target == NULL) {
193 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
194 cursor->ops.target.offset);
198 if (notes->options->hide_src_code) {
199 from = cursor->al.idx_asm;
200 to = target->idx_asm;
202 from = (u64)cursor->al.idx;
203 to = (u64)target->idx;
206 width = annotation__cycles_width(notes);
208 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
209 __ui_browser__line_arrow(browser,
210 pcnt_width + 2 + notes->widths.addr + width,
213 diff = is_fused(ab, cursor);
215 ui_browser__mark_fused(browser,
216 pcnt_width + 3 + notes->widths.addr + width,
217 from - diff, diff, to > from);
221 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
223 struct annotation *notes = browser__annotation(browser);
224 int ret = ui_browser__list_head_refresh(browser);
225 int pcnt_width = annotation__pcnt_width(notes);
227 if (notes->options->jump_arrows)
228 annotate_browser__draw_current_jump(browser);
230 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
231 __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
235 static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
240 for (i = 0; i < a->data_nr; i++) {
241 if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
243 return a->data[i].percent[percent_type] -
244 b->data[i].percent[percent_type];
249 static void disasm_rb_tree__insert(struct annotate_browser *browser,
250 struct annotation_line *al)
252 struct rb_root *root = &browser->entries;
253 struct rb_node **p = &root->rb_node;
254 struct rb_node *parent = NULL;
255 struct annotation_line *l;
259 l = rb_entry(parent, struct annotation_line, rb_node);
261 if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
266 rb_link_node(&al->rb_node, parent, p);
267 rb_insert_color(&al->rb_node, root);
270 static void annotate_browser__set_top(struct annotate_browser *browser,
271 struct annotation_line *pos, u32 idx)
273 struct annotation *notes = browser__annotation(&browser->b);
276 ui_browser__refresh_dimensions(&browser->b);
277 back = browser->b.height / 2;
278 browser->b.top_idx = browser->b.index = idx;
280 while (browser->b.top_idx != 0 && back != 0) {
281 pos = list_entry(pos->node.prev, struct annotation_line, node);
283 if (annotation_line__filter(pos, notes))
286 --browser->b.top_idx;
290 browser->b.top = pos;
291 browser->b.navkeypressed = true;
294 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
297 struct annotation *notes = browser__annotation(&browser->b);
298 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
301 if (notes->options->hide_src_code)
303 annotate_browser__set_top(browser, pos, idx);
304 browser->curr_hot = nd;
307 static void annotate_browser__calc_percent(struct annotate_browser *browser,
310 struct map_symbol *ms = browser->b.priv;
311 struct symbol *sym = ms->sym;
312 struct annotation *notes = symbol__annotation(sym);
313 struct disasm_line *pos;
315 browser->entries = RB_ROOT;
317 mutex_lock(¬es->lock);
319 symbol__calc_percent(sym, evsel);
321 list_for_each_entry(pos, ¬es->src->source, al.node) {
322 double max_percent = 0.0;
325 if (pos->al.offset == -1) {
326 RB_CLEAR_NODE(&pos->al.rb_node);
330 for (i = 0; i < pos->al.data_nr; i++) {
333 percent = annotation_data__percent(&pos->al.data[i],
334 browser->opts->percent_type);
336 if (max_percent < percent)
337 max_percent = percent;
340 if (max_percent < 0.01 && pos->al.ipc == 0) {
341 RB_CLEAR_NODE(&pos->al.rb_node);
344 disasm_rb_tree__insert(browser, &pos->al);
346 mutex_unlock(¬es->lock);
348 browser->curr_hot = rb_last(&browser->entries);
351 static struct annotation_line *annotate_browser__find_next_asm_line(
352 struct annotate_browser *browser,
353 struct annotation_line *al)
355 struct annotation_line *it = al;
357 /* find next asm line */
358 list_for_each_entry_continue(it, browser->b.entries, node) {
359 if (it->idx_asm >= 0)
363 /* no asm line found forwards, try backwards */
365 list_for_each_entry_continue_reverse(it, browser->b.entries, node) {
366 if (it->idx_asm >= 0)
370 /* There are no asm lines */
374 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
376 struct annotation *notes = browser__annotation(&browser->b);
377 struct annotation_line *al;
378 off_t offset = browser->b.index - browser->b.top_idx;
380 browser->b.seek(&browser->b, offset, SEEK_CUR);
381 al = list_entry(browser->b.top, struct annotation_line, node);
383 if (notes->options->hide_src_code) {
384 if (al->idx_asm < offset)
387 browser->b.nr_entries = notes->nr_entries;
388 notes->options->hide_src_code = false;
389 browser->b.seek(&browser->b, -offset, SEEK_CUR);
390 browser->b.top_idx = al->idx - offset;
391 browser->b.index = al->idx;
393 if (al->idx_asm < 0) {
394 /* move cursor to next asm line */
395 al = annotate_browser__find_next_asm_line(browser, al);
397 browser->b.seek(&browser->b, -offset, SEEK_CUR);
402 if (al->idx_asm < offset)
403 offset = al->idx_asm;
405 browser->b.nr_entries = notes->nr_asm_entries;
406 notes->options->hide_src_code = true;
407 browser->b.seek(&browser->b, -offset, SEEK_CUR);
408 browser->b.top_idx = al->idx_asm - offset;
409 browser->b.index = al->idx_asm;
415 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
417 static void annotate_browser__show_full_location(struct ui_browser *browser)
419 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
420 struct disasm_line *cursor = disasm_line(ab->selection);
421 struct annotation_line *al = &cursor->al;
423 if (al->offset != -1)
424 ui_helpline__puts("Only available for source code lines.");
425 else if (al->fileloc == NULL)
426 ui_helpline__puts("No source file location.");
428 char help_line[SYM_TITLE_MAX_SIZE];
429 sprintf (help_line, "Source file location: %s", al->fileloc);
430 ui_helpline__puts(help_line);
434 static void ui_browser__init_asm_mode(struct ui_browser *browser)
436 struct annotation *notes = browser__annotation(browser);
437 ui_browser__reset_index(browser);
438 browser->nr_entries = notes->nr_asm_entries;
441 static int sym_title(struct symbol *sym, struct map *map, char *title,
442 size_t sz, int percent_type)
444 return snprintf(title, sz, "%s %s [Percent: %s]", sym->name,
445 map__dso(map)->long_name,
446 percent_type_str(percent_type));
450 * This can be called from external jumps, i.e. jumps from one function
451 * to another, like from the kernel's entry_SYSCALL_64 function to the
452 * swapgs_restore_regs_and_return_to_usermode() function.
454 * So all we check here is that dl->ops.target.sym is set, if it is, just
455 * go to that function and when exiting from its disassembly, come back
456 * to the calling function.
458 static bool annotate_browser__callq(struct annotate_browser *browser,
460 struct hist_browser_timer *hbt)
462 struct map_symbol *ms = browser->b.priv, target_ms;
463 struct disasm_line *dl = disasm_line(browser->selection);
464 struct annotation *notes;
465 char title[SYM_TITLE_MAX_SIZE];
467 if (!dl->ops.target.sym) {
468 ui_helpline__puts("The called function was not found.");
472 notes = symbol__annotation(dl->ops.target.sym);
473 mutex_lock(¬es->lock);
475 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
476 mutex_unlock(¬es->lock);
477 ui__warning("Not enough memory for annotating '%s' symbol!\n",
478 dl->ops.target.sym->name);
482 target_ms.maps = ms->maps;
483 target_ms.map = ms->map;
484 target_ms.sym = dl->ops.target.sym;
485 mutex_unlock(¬es->lock);
486 symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);
487 sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
488 ui_browser__show_title(&browser->b, title);
493 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
494 s64 offset, s64 *idx)
496 struct annotation *notes = browser__annotation(&browser->b);
497 struct disasm_line *pos;
500 list_for_each_entry(pos, ¬es->src->source, al.node) {
501 if (pos->al.offset == offset)
503 if (!annotation_line__filter(&pos->al, notes))
510 static bool annotate_browser__jump(struct annotate_browser *browser,
512 struct hist_browser_timer *hbt)
514 struct disasm_line *dl = disasm_line(browser->selection);
518 if (!ins__is_jump(&dl->ins))
521 if (dl->ops.target.outside) {
522 annotate_browser__callq(browser, evsel, hbt);
526 offset = dl->ops.target.offset;
527 dl = annotate_browser__find_offset(browser, offset, &idx);
529 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
533 annotate_browser__set_top(browser, &dl->al, idx);
539 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
542 struct annotation *notes = browser__annotation(&browser->b);
543 struct annotation_line *al = browser->selection;
545 *idx = browser->b.index;
546 list_for_each_entry_continue(al, ¬es->src->source, node) {
547 if (annotation_line__filter(al, notes))
552 if (al->line && strstr(al->line, s) != NULL)
559 static bool __annotate_browser__search(struct annotate_browser *browser)
561 struct annotation_line *al;
564 al = annotate_browser__find_string(browser, browser->search_bf, &idx);
566 ui_helpline__puts("String not found!");
570 annotate_browser__set_top(browser, al, idx);
571 browser->searching_backwards = false;
576 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
579 struct annotation *notes = browser__annotation(&browser->b);
580 struct annotation_line *al = browser->selection;
582 *idx = browser->b.index;
583 list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
584 if (annotation_line__filter(al, notes))
589 if (al->line && strstr(al->line, s) != NULL)
596 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
598 struct annotation_line *al;
601 al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
603 ui_helpline__puts("String not found!");
607 annotate_browser__set_top(browser, al, idx);
608 browser->searching_backwards = true;
612 static bool annotate_browser__search_window(struct annotate_browser *browser,
615 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
616 "ENTER: OK, ESC: Cancel",
617 delay_secs * 2) != K_ENTER ||
618 !*browser->search_bf)
624 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
626 if (annotate_browser__search_window(browser, delay_secs))
627 return __annotate_browser__search(browser);
632 static bool annotate_browser__continue_search(struct annotate_browser *browser,
635 if (!*browser->search_bf)
636 return annotate_browser__search(browser, delay_secs);
638 return __annotate_browser__search(browser);
641 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
644 if (annotate_browser__search_window(browser, delay_secs))
645 return __annotate_browser__search_reverse(browser);
651 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
654 if (!*browser->search_bf)
655 return annotate_browser__search_reverse(browser, delay_secs);
657 return __annotate_browser__search_reverse(browser);
660 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
662 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
663 struct map_symbol *ms = browser->priv;
664 struct symbol *sym = ms->sym;
665 char symbol_dso[SYM_TITLE_MAX_SIZE];
667 if (ui_browser__show(browser, title, help) < 0)
670 sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
672 ui_browser__gotorc_title(browser, 0, 0);
673 ui_browser__set_color(browser, HE_COLORSET_ROOT);
674 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
679 switch_percent_type(struct annotation_options *opts, bool base)
681 switch (opts->percent_type) {
682 case PERCENT_HITS_LOCAL:
684 opts->percent_type = PERCENT_PERIOD_LOCAL;
686 opts->percent_type = PERCENT_HITS_GLOBAL;
688 case PERCENT_HITS_GLOBAL:
690 opts->percent_type = PERCENT_PERIOD_GLOBAL;
692 opts->percent_type = PERCENT_HITS_LOCAL;
694 case PERCENT_PERIOD_LOCAL:
696 opts->percent_type = PERCENT_HITS_LOCAL;
698 opts->percent_type = PERCENT_PERIOD_GLOBAL;
700 case PERCENT_PERIOD_GLOBAL:
702 opts->percent_type = PERCENT_HITS_GLOBAL;
704 opts->percent_type = PERCENT_PERIOD_LOCAL;
711 static int annotate_browser__run(struct annotate_browser *browser,
713 struct hist_browser_timer *hbt)
715 struct rb_node *nd = NULL;
716 struct hists *hists = evsel__hists(evsel);
717 struct map_symbol *ms = browser->b.priv;
718 struct symbol *sym = ms->sym;
719 struct annotation *notes = symbol__annotation(ms->sym);
720 const char *help = "Press 'h' for help on key bindings";
721 int delay_secs = hbt ? hbt->refresh : 0;
725 hists__scnprintf_title(hists, title, sizeof(title));
726 if (annotate_browser__show(&browser->b, title, help) < 0)
729 annotate_browser__calc_percent(browser, evsel);
731 if (browser->curr_hot) {
732 annotate_browser__set_rb_top(browser, browser->curr_hot);
733 browser->b.navkeypressed = false;
736 nd = browser->curr_hot;
739 key = ui_browser__run(&browser->b, delay_secs);
741 if (delay_secs != 0) {
742 annotate_browser__calc_percent(browser, evsel);
744 * Current line focus got out of the list of most active
745 * lines, NULL it so that if TAB|UNTAB is pressed, we
746 * move to curr_hot (current hottest line).
748 if (nd != NULL && RB_EMPTY_NODE(nd))
755 hbt->timer(hbt->arg);
757 if (delay_secs != 0) {
758 symbol__annotate_decay_histogram(sym, evsel->core.idx);
759 hists__scnprintf_title(hists, title, sizeof(title));
760 annotate_browser__show(&browser->b, title, help);
767 nd = rb_last(&browser->entries);
769 nd = browser->curr_hot;
775 nd = rb_first(&browser->entries);
777 nd = browser->curr_hot;
781 ui_browser__help_window(&browser->b,
783 "PGDN/SPACE Navigate\n"
784 "q/ESC/CTRL+C Exit\n\n"
785 "ENTER Go to target\n"
787 "H Go to hottest instruction\n"
788 "TAB/shift+TAB Cycle thru hottest instructions\n"
789 "j Toggle showing jump to target arrows\n"
790 "J Toggle showing number of jump sources on targets\n"
791 "n Search next string\n"
792 "o Toggle disassembler output/simplified view\n"
793 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
794 "s Toggle source code view\n"
795 "t Circulate percent, total period, samples view\n"
796 "c Show min/max cycle\n"
798 "k Toggle line numbers\n"
799 "l Show full source file location\n"
800 "P Print to [symbol_name].annotation file.\n"
801 "r Run available scripts\n"
802 "p Toggle percent type [local/global]\n"
803 "b Toggle percent base [period/hits]\n"
804 "? Search string backwards\n"
805 "f Toggle showing offsets to full address\n");
808 script_browse(NULL, NULL);
809 annotate_browser__show(&browser->b, title, help);
812 notes->options->show_linenr = !notes->options->show_linenr;
815 annotate_browser__show_full_location (&browser->b);
818 nd = browser->curr_hot;
821 if (annotate_browser__toggle_source(browser))
822 ui_helpline__puts(help);
825 notes->options->use_offset = !notes->options->use_offset;
826 annotation__update_column_widths(notes);
829 if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
830 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
833 notes->options->jump_arrows = !notes->options->jump_arrows;
836 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
837 annotation__update_column_widths(notes);
840 if (annotate_browser__search(browser, delay_secs)) {
842 ui_helpline__puts(help);
846 if (browser->searching_backwards ?
847 annotate_browser__continue_search_reverse(browser, delay_secs) :
848 annotate_browser__continue_search(browser, delay_secs))
852 if (annotate_browser__search_reverse(browser, delay_secs))
858 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
859 seq++, browser->b.nr_entries,
863 notes->nr_asm_entries);
869 struct disasm_line *dl = disasm_line(browser->selection);
871 if (browser->selection == NULL)
872 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
873 else if (browser->selection->offset == -1)
874 ui_helpline__puts("Actions are only available for assembly lines.");
875 else if (!dl->ins.ops)
877 else if (ins__is_ret(&dl->ins))
879 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
880 annotate_browser__callq(browser, evsel, hbt))) {
882 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
887 map_symbol__annotation_dump(ms, evsel, browser->opts);
890 if (symbol_conf.show_total_period) {
891 symbol_conf.show_total_period = false;
892 symbol_conf.show_nr_samples = true;
893 } else if (symbol_conf.show_nr_samples)
894 symbol_conf.show_nr_samples = false;
896 symbol_conf.show_total_period = true;
897 annotation__update_column_widths(notes);
900 if (notes->options->show_minmax_cycle)
901 notes->options->show_minmax_cycle = false;
903 notes->options->show_minmax_cycle = true;
904 annotation__update_column_widths(notes);
908 switch_percent_type(browser->opts, key == 'b');
909 hists__scnprintf_title(hists, title, sizeof(title));
910 annotate_browser__show(&browser->b, title, help);
913 annotation__toggle_full_addr(notes, ms);
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,
970 int not_annotated = list_empty(¬es->src->source);
975 dso = map__dso(ms->map);
976 if (dso->annotate_warned)
980 err = symbol__annotate2(ms, evsel, opts, &browser.arch);
983 dso->annotate_warned = true;
984 symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
985 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
986 goto out_free_offsets;
990 ui_helpline__push("Press ESC to exit");
992 browser.b.width = notes->max_line_len;
993 browser.b.nr_entries = notes->nr_entries;
994 browser.b.entries = ¬es->src->source,
995 browser.b.width += 18; /* Percentage */
997 if (notes->options->hide_src_code)
998 ui_browser__init_asm_mode(&browser.b);
1000 ret = annotate_browser__run(&browser, evsel, hbt);
1003 annotated_source__purge(notes->src);
1007 zfree(¬es->offsets);