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 bool annotate_browser__toggle_source(struct annotate_browser *browser)
348 struct annotation *notes = browser__annotation(&browser->b);
349 struct annotation_line *al;
350 off_t offset = browser->b.index - browser->b.top_idx;
352 browser->b.seek(&browser->b, offset, SEEK_CUR);
353 al = list_entry(browser->b.top, struct annotation_line, node);
355 if (notes->options->hide_src_code) {
356 if (al->idx_asm < offset)
359 browser->b.nr_entries = notes->nr_entries;
360 notes->options->hide_src_code = false;
361 browser->b.seek(&browser->b, -offset, SEEK_CUR);
362 browser->b.top_idx = al->idx - offset;
363 browser->b.index = al->idx;
365 if (al->idx_asm < 0) {
366 ui_helpline__puts("Only available for assembly lines.");
367 browser->b.seek(&browser->b, -offset, SEEK_CUR);
371 if (al->idx_asm < offset)
372 offset = al->idx_asm;
374 browser->b.nr_entries = notes->nr_asm_entries;
375 notes->options->hide_src_code = true;
376 browser->b.seek(&browser->b, -offset, SEEK_CUR);
377 browser->b.top_idx = al->idx_asm - offset;
378 browser->b.index = al->idx_asm;
384 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
386 static void annotate_browser__show_full_location(struct ui_browser *browser)
388 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
389 struct disasm_line *cursor = disasm_line(ab->selection);
390 struct annotation_line *al = &cursor->al;
392 if (al->offset != -1)
393 ui_helpline__puts("Only available for source code lines.");
394 else if (al->fileloc == NULL)
395 ui_helpline__puts("No source file location.");
397 char help_line[SYM_TITLE_MAX_SIZE];
398 sprintf (help_line, "Source file location: %s", al->fileloc);
399 ui_helpline__puts(help_line);
403 static void ui_browser__init_asm_mode(struct ui_browser *browser)
405 struct annotation *notes = browser__annotation(browser);
406 ui_browser__reset_index(browser);
407 browser->nr_entries = notes->nr_asm_entries;
410 static int sym_title(struct symbol *sym, struct map *map, char *title,
411 size_t sz, int percent_type)
413 return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name,
414 percent_type_str(percent_type));
418 * This can be called from external jumps, i.e. jumps from one function
419 * to another, like from the kernel's entry_SYSCALL_64 function to the
420 * swapgs_restore_regs_and_return_to_usermode() function.
422 * So all we check here is that dl->ops.target.sym is set, if it is, just
423 * go to that function and when exiting from its disassembly, come back
424 * to the calling function.
426 static bool annotate_browser__callq(struct annotate_browser *browser,
428 struct hist_browser_timer *hbt)
430 struct map_symbol *ms = browser->b.priv, target_ms;
431 struct disasm_line *dl = disasm_line(browser->selection);
432 struct annotation *notes;
433 char title[SYM_TITLE_MAX_SIZE];
435 if (!dl->ops.target.sym) {
436 ui_helpline__puts("The called function was not found.");
440 notes = symbol__annotation(dl->ops.target.sym);
441 pthread_mutex_lock(¬es->lock);
443 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
444 pthread_mutex_unlock(¬es->lock);
445 ui__warning("Not enough memory for annotating '%s' symbol!\n",
446 dl->ops.target.sym->name);
450 target_ms.maps = ms->maps;
451 target_ms.map = ms->map;
452 target_ms.sym = dl->ops.target.sym;
453 pthread_mutex_unlock(¬es->lock);
454 symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);
455 sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
456 ui_browser__show_title(&browser->b, title);
461 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
462 s64 offset, s64 *idx)
464 struct annotation *notes = browser__annotation(&browser->b);
465 struct disasm_line *pos;
468 list_for_each_entry(pos, ¬es->src->source, al.node) {
469 if (pos->al.offset == offset)
471 if (!annotation_line__filter(&pos->al, notes))
478 static bool annotate_browser__jump(struct annotate_browser *browser,
480 struct hist_browser_timer *hbt)
482 struct disasm_line *dl = disasm_line(browser->selection);
486 if (!ins__is_jump(&dl->ins))
489 if (dl->ops.target.outside) {
490 annotate_browser__callq(browser, evsel, hbt);
494 offset = dl->ops.target.offset;
495 dl = annotate_browser__find_offset(browser, offset, &idx);
497 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
501 annotate_browser__set_top(browser, &dl->al, idx);
507 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
510 struct annotation *notes = browser__annotation(&browser->b);
511 struct annotation_line *al = browser->selection;
513 *idx = browser->b.index;
514 list_for_each_entry_continue(al, ¬es->src->source, node) {
515 if (annotation_line__filter(al, notes))
520 if (al->line && strstr(al->line, s) != NULL)
527 static bool __annotate_browser__search(struct annotate_browser *browser)
529 struct annotation_line *al;
532 al = annotate_browser__find_string(browser, browser->search_bf, &idx);
534 ui_helpline__puts("String not found!");
538 annotate_browser__set_top(browser, al, idx);
539 browser->searching_backwards = false;
544 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
547 struct annotation *notes = browser__annotation(&browser->b);
548 struct annotation_line *al = browser->selection;
550 *idx = browser->b.index;
551 list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
552 if (annotation_line__filter(al, notes))
557 if (al->line && strstr(al->line, s) != NULL)
564 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
566 struct annotation_line *al;
569 al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
571 ui_helpline__puts("String not found!");
575 annotate_browser__set_top(browser, al, idx);
576 browser->searching_backwards = true;
580 static bool annotate_browser__search_window(struct annotate_browser *browser,
583 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
584 "ENTER: OK, ESC: Cancel",
585 delay_secs * 2) != K_ENTER ||
586 !*browser->search_bf)
592 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
594 if (annotate_browser__search_window(browser, delay_secs))
595 return __annotate_browser__search(browser);
600 static bool annotate_browser__continue_search(struct annotate_browser *browser,
603 if (!*browser->search_bf)
604 return annotate_browser__search(browser, delay_secs);
606 return __annotate_browser__search(browser);
609 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
612 if (annotate_browser__search_window(browser, delay_secs))
613 return __annotate_browser__search_reverse(browser);
619 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
622 if (!*browser->search_bf)
623 return annotate_browser__search_reverse(browser, delay_secs);
625 return __annotate_browser__search_reverse(browser);
628 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
630 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
631 struct map_symbol *ms = browser->priv;
632 struct symbol *sym = ms->sym;
633 char symbol_dso[SYM_TITLE_MAX_SIZE];
635 if (ui_browser__show(browser, title, help) < 0)
638 sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
640 ui_browser__gotorc_title(browser, 0, 0);
641 ui_browser__set_color(browser, HE_COLORSET_ROOT);
642 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
647 switch_percent_type(struct annotation_options *opts, bool base)
649 switch (opts->percent_type) {
650 case PERCENT_HITS_LOCAL:
652 opts->percent_type = PERCENT_PERIOD_LOCAL;
654 opts->percent_type = PERCENT_HITS_GLOBAL;
656 case PERCENT_HITS_GLOBAL:
658 opts->percent_type = PERCENT_PERIOD_GLOBAL;
660 opts->percent_type = PERCENT_HITS_LOCAL;
662 case PERCENT_PERIOD_LOCAL:
664 opts->percent_type = PERCENT_HITS_LOCAL;
666 opts->percent_type = PERCENT_PERIOD_GLOBAL;
668 case PERCENT_PERIOD_GLOBAL:
670 opts->percent_type = PERCENT_HITS_GLOBAL;
672 opts->percent_type = PERCENT_PERIOD_LOCAL;
679 static int annotate_browser__run(struct annotate_browser *browser,
681 struct hist_browser_timer *hbt)
683 struct rb_node *nd = NULL;
684 struct hists *hists = evsel__hists(evsel);
685 struct map_symbol *ms = browser->b.priv;
686 struct symbol *sym = ms->sym;
687 struct annotation *notes = symbol__annotation(ms->sym);
688 const char *help = "Press 'h' for help on key bindings";
689 int delay_secs = hbt ? hbt->refresh : 0;
693 hists__scnprintf_title(hists, title, sizeof(title));
694 if (annotate_browser__show(&browser->b, title, help) < 0)
697 annotate_browser__calc_percent(browser, evsel);
699 if (browser->curr_hot) {
700 annotate_browser__set_rb_top(browser, browser->curr_hot);
701 browser->b.navkeypressed = false;
704 nd = browser->curr_hot;
707 key = ui_browser__run(&browser->b, delay_secs);
709 if (delay_secs != 0) {
710 annotate_browser__calc_percent(browser, evsel);
712 * Current line focus got out of the list of most active
713 * lines, NULL it so that if TAB|UNTAB is pressed, we
714 * move to curr_hot (current hottest line).
716 if (nd != NULL && RB_EMPTY_NODE(nd))
723 hbt->timer(hbt->arg);
725 if (delay_secs != 0) {
726 symbol__annotate_decay_histogram(sym, evsel->idx);
727 hists__scnprintf_title(hists, title, sizeof(title));
728 annotate_browser__show(&browser->b, title, help);
735 nd = rb_last(&browser->entries);
737 nd = browser->curr_hot;
743 nd = rb_first(&browser->entries);
745 nd = browser->curr_hot;
749 ui_browser__help_window(&browser->b,
751 "PGDN/SPACE Navigate\n"
752 "q/ESC/CTRL+C Exit\n\n"
753 "ENTER Go to target\n"
755 "H Go to hottest instruction\n"
756 "TAB/shift+TAB Cycle thru hottest instructions\n"
757 "j Toggle showing jump to target arrows\n"
758 "J Toggle showing number of jump sources on targets\n"
759 "n Search next string\n"
760 "o Toggle disassembler output/simplified view\n"
761 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
762 "s Toggle source code view\n"
763 "t Circulate percent, total period, samples view\n"
764 "c Show min/max cycle\n"
766 "k Toggle line numbers\n"
767 "l Show full source file location\n"
768 "P Print to [symbol_name].annotation file.\n"
769 "r Run available scripts\n"
770 "p Toggle percent type [local/global]\n"
771 "b Toggle percent base [period/hits]\n"
772 "? Search string backwards\n");
775 script_browse(NULL, NULL);
776 annotate_browser__show(&browser->b, title, help);
779 notes->options->show_linenr = !notes->options->show_linenr;
782 annotate_browser__show_full_location (&browser->b);
785 nd = browser->curr_hot;
788 if (annotate_browser__toggle_source(browser))
789 ui_helpline__puts(help);
792 notes->options->use_offset = !notes->options->use_offset;
793 annotation__update_column_widths(notes);
796 if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
797 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
800 notes->options->jump_arrows = !notes->options->jump_arrows;
803 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
804 annotation__update_column_widths(notes);
807 if (annotate_browser__search(browser, delay_secs)) {
809 ui_helpline__puts(help);
813 if (browser->searching_backwards ?
814 annotate_browser__continue_search_reverse(browser, delay_secs) :
815 annotate_browser__continue_search(browser, delay_secs))
819 if (annotate_browser__search_reverse(browser, delay_secs))
825 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
826 seq++, browser->b.nr_entries,
830 notes->nr_asm_entries);
836 struct disasm_line *dl = disasm_line(browser->selection);
838 if (browser->selection == NULL)
839 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
840 else if (browser->selection->offset == -1)
841 ui_helpline__puts("Actions are only available for assembly lines.");
842 else if (!dl->ins.ops)
844 else if (ins__is_ret(&dl->ins))
846 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
847 annotate_browser__callq(browser, evsel, hbt))) {
849 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
854 map_symbol__annotation_dump(ms, evsel, browser->opts);
857 if (symbol_conf.show_total_period) {
858 symbol_conf.show_total_period = false;
859 symbol_conf.show_nr_samples = true;
860 } else if (symbol_conf.show_nr_samples)
861 symbol_conf.show_nr_samples = false;
863 symbol_conf.show_total_period = true;
864 annotation__update_column_widths(notes);
867 if (notes->options->show_minmax_cycle)
868 notes->options->show_minmax_cycle = false;
870 notes->options->show_minmax_cycle = true;
871 annotation__update_column_widths(notes);
875 switch_percent_type(browser->opts, key == 'b');
876 hists__scnprintf_title(hists, title, sizeof(title));
877 annotate_browser__show(&browser->b, title, help);
889 annotate_browser__set_rb_top(browser, nd);
892 ui_browser__hide(&browser->b);
896 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
897 struct hist_browser_timer *hbt,
898 struct annotation_options *opts)
900 return symbol__tui_annotate(ms, evsel, hbt, opts);
903 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
904 struct hist_browser_timer *hbt,
905 struct annotation_options *opts)
907 /* reset abort key so that it can get Ctrl-C as a key */
909 SLang_init_tty(0, 0, 0);
911 return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
914 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
915 struct hist_browser_timer *hbt,
916 struct annotation_options *opts)
918 struct symbol *sym = ms->sym;
919 struct annotation *notes = symbol__annotation(sym);
920 struct annotate_browser browser = {
922 .refresh = annotate_browser__refresh,
923 .seek = ui_browser__list_head_seek,
924 .write = annotate_browser__write,
925 .filter = disasm_line__filter,
926 .extra_title_lines = 1, /* for hists__scnprintf_title() */
928 .use_navkeypressed = true,
937 if (ms->map->dso->annotate_warned)
940 err = symbol__annotate2(ms, evsel, opts, &browser.arch);
943 symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
944 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
945 goto out_free_offsets;
948 ui_helpline__push("Press ESC to exit");
950 browser.b.width = notes->max_line_len;
951 browser.b.nr_entries = notes->nr_entries;
952 browser.b.entries = ¬es->src->source,
953 browser.b.width += 18; /* Percentage */
955 if (notes->options->hide_src_code)
956 ui_browser__init_asm_mode(&browser.b);
958 ret = annotate_browser__run(&browser, evsel, hbt);
960 annotated_source__purge(notes->src);
963 zfree(¬es->offsets);