1 // SPDX-License-Identifier: GPL-2.0
2 #include "../browser.h"
3 #include "../helpline.h"
6 #include "../../util/annotate.h"
7 #include "../../util/hist.h"
8 #include "../../util/sort.h"
9 #include "../../util/map.h"
10 #include "../../util/symbol.h"
11 #include "../../util/evsel.h"
12 #include "../../util/evlist.h"
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/zalloc.h>
18 #include <sys/ttydefaults.h>
21 struct disasm_line_samples {
23 struct sym_hist_entry he;
28 struct annotate_browser {
30 struct rb_root entries;
31 struct rb_node *curr_hot;
32 struct annotation_line *selection;
34 struct annotation_options *opts;
35 bool searching_backwards;
39 static inline struct annotation *browser__annotation(struct ui_browser *browser)
41 struct map_symbol *ms = browser->priv;
42 return symbol__annotation(ms->sym);
45 static bool disasm_line__filter(struct ui_browser *browser, void *entry)
47 struct annotation *notes = browser__annotation(browser);
48 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
49 return annotation_line__filter(al, notes);
52 static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
54 struct annotation *notes = browser__annotation(browser);
56 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
57 return HE_COLORSET_SELECTED;
58 if (nr == notes->max_jump_sources)
59 return HE_COLORSET_TOP;
61 return HE_COLORSET_MEDIUM;
62 return HE_COLORSET_NORMAL;
65 static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
67 int color = ui_browser__jumps_percent_color(browser, nr, current);
68 return ui_browser__set_color(browser, color);
71 static int annotate_browser__set_color(void *browser, int color)
73 return ui_browser__set_color(browser, color);
76 static void annotate_browser__write_graph(void *browser, int graph)
78 ui_browser__write_graph(browser, graph);
81 static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
83 ui_browser__set_percent_color(browser, percent, current);
86 static void annotate_browser__printf(void *browser, const char *fmt, ...)
91 ui_browser__vprintf(browser, fmt, args);
95 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
97 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
98 struct annotation *notes = browser__annotation(browser);
99 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
100 const bool is_current_entry = ui_browser__is_current_entry(browser, row);
101 struct annotation_write_ops ops = {
102 .first_line = row == 0,
103 .current_entry = is_current_entry,
104 .change_color = (!notes->options->hide_src_code &&
105 (!is_current_entry ||
106 (browser->use_navkeypressed &&
107 !browser->navkeypressed))),
108 .width = browser->width,
110 .set_color = annotate_browser__set_color,
111 .set_percent_color = annotate_browser__set_percent_color,
112 .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
113 .printf = annotate_browser__printf,
114 .write_graph = annotate_browser__write_graph,
117 /* The scroll bar isn't being used */
118 if (!browser->navkeypressed)
121 annotation_line__write(al, notes, &ops, ab->opts);
123 if (ops.current_entry)
127 static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
129 struct disasm_line *pos = list_prev_entry(cursor, al.node);
135 if (ins__is_lock(&pos->ins))
136 name = pos->ops.locked.ins.name;
138 name = pos->ins.name;
140 if (!name || !cursor->ins.name)
143 return ins__is_fused(ab->arch, name, cursor->ins.name);
146 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
148 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
149 struct disasm_line *cursor = disasm_line(ab->selection);
150 struct annotation_line *target;
151 unsigned int from, to;
152 struct map_symbol *ms = ab->b.priv;
153 struct symbol *sym = ms->sym;
154 struct annotation *notes = symbol__annotation(sym);
155 u8 pcnt_width = annotation__pcnt_width(notes);
158 /* PLT symbols contain external offsets */
159 if (strstr(sym->name, "@plt"))
162 if (!disasm_line__is_valid_local_jump(cursor, sym))
166 * This first was seen with a gcc function, _cpp_lex_token, that
167 * has the usual jumps:
169 * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92>
171 * I.e. jumps to a label inside that function (_cpp_lex_token), and
172 * those works, but also this kind:
174 * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72>
176 * I.e. jumps to another function, outside _cpp_lex_token, which
177 * are not being correctly handled generating as a side effect references
178 * to ab->offset[] entries that are set to NULL, so to make this code
179 * more robust, check that here.
181 * A proper fix for will be put in place, looking at the function
182 * name right after the '<' token and probably treating this like a
183 * 'call' instruction.
185 target = notes->offsets[cursor->ops.target.offset];
186 if (target == NULL) {
187 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
188 cursor->ops.target.offset);
192 if (notes->options->hide_src_code) {
193 from = cursor->al.idx_asm;
194 to = target->idx_asm;
196 from = (u64)cursor->al.idx;
197 to = (u64)target->idx;
200 width = annotation__cycles_width(notes);
202 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
203 __ui_browser__line_arrow(browser,
204 pcnt_width + 2 + notes->widths.addr + width,
207 if (is_fused(ab, cursor)) {
208 ui_browser__mark_fused(browser,
209 pcnt_width + 3 + notes->widths.addr + width,
211 to > from ? true : false);
215 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
217 struct annotation *notes = browser__annotation(browser);
218 int ret = ui_browser__list_head_refresh(browser);
219 int pcnt_width = annotation__pcnt_width(notes);
221 if (notes->options->jump_arrows)
222 annotate_browser__draw_current_jump(browser);
224 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
225 __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
229 static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
234 for (i = 0; i < a->data_nr; i++) {
235 if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
237 return a->data[i].percent[percent_type] -
238 b->data[i].percent[percent_type];
243 static void disasm_rb_tree__insert(struct annotate_browser *browser,
244 struct annotation_line *al)
246 struct rb_root *root = &browser->entries;
247 struct rb_node **p = &root->rb_node;
248 struct rb_node *parent = NULL;
249 struct annotation_line *l;
253 l = rb_entry(parent, struct annotation_line, rb_node);
255 if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
260 rb_link_node(&al->rb_node, parent, p);
261 rb_insert_color(&al->rb_node, root);
264 static void annotate_browser__set_top(struct annotate_browser *browser,
265 struct annotation_line *pos, u32 idx)
267 struct annotation *notes = browser__annotation(&browser->b);
270 ui_browser__refresh_dimensions(&browser->b);
271 back = browser->b.height / 2;
272 browser->b.top_idx = browser->b.index = idx;
274 while (browser->b.top_idx != 0 && back != 0) {
275 pos = list_entry(pos->node.prev, struct annotation_line, node);
277 if (annotation_line__filter(pos, notes))
280 --browser->b.top_idx;
284 browser->b.top = pos;
285 browser->b.navkeypressed = true;
288 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
291 struct annotation *notes = browser__annotation(&browser->b);
292 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
295 if (notes->options->hide_src_code)
297 annotate_browser__set_top(browser, pos, idx);
298 browser->curr_hot = nd;
301 static void annotate_browser__calc_percent(struct annotate_browser *browser,
302 struct perf_evsel *evsel)
304 struct map_symbol *ms = browser->b.priv;
305 struct symbol *sym = ms->sym;
306 struct annotation *notes = symbol__annotation(sym);
307 struct disasm_line *pos;
309 browser->entries = RB_ROOT;
311 pthread_mutex_lock(¬es->lock);
313 symbol__calc_percent(sym, evsel);
315 list_for_each_entry(pos, ¬es->src->source, al.node) {
316 double max_percent = 0.0;
319 if (pos->al.offset == -1) {
320 RB_CLEAR_NODE(&pos->al.rb_node);
324 for (i = 0; i < pos->al.data_nr; i++) {
327 percent = annotation_data__percent(&pos->al.data[i],
328 browser->opts->percent_type);
330 if (max_percent < percent)
331 max_percent = percent;
334 if (max_percent < 0.01 && pos->al.ipc == 0) {
335 RB_CLEAR_NODE(&pos->al.rb_node);
338 disasm_rb_tree__insert(browser, &pos->al);
340 pthread_mutex_unlock(¬es->lock);
342 browser->curr_hot = rb_last(&browser->entries);
345 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
347 struct annotation *notes = browser__annotation(&browser->b);
348 struct annotation_line *al;
349 off_t offset = browser->b.index - browser->b.top_idx;
351 browser->b.seek(&browser->b, offset, SEEK_CUR);
352 al = list_entry(browser->b.top, struct annotation_line, node);
354 if (notes->options->hide_src_code) {
355 if (al->idx_asm < offset)
358 browser->b.nr_entries = notes->nr_entries;
359 notes->options->hide_src_code = false;
360 browser->b.seek(&browser->b, -offset, SEEK_CUR);
361 browser->b.top_idx = al->idx - offset;
362 browser->b.index = al->idx;
364 if (al->idx_asm < 0) {
365 ui_helpline__puts("Only available for assembly lines.");
366 browser->b.seek(&browser->b, -offset, SEEK_CUR);
370 if (al->idx_asm < offset)
371 offset = al->idx_asm;
373 browser->b.nr_entries = notes->nr_asm_entries;
374 notes->options->hide_src_code = true;
375 browser->b.seek(&browser->b, -offset, SEEK_CUR);
376 browser->b.top_idx = al->idx_asm - offset;
377 browser->b.index = al->idx_asm;
383 static void ui_browser__init_asm_mode(struct ui_browser *browser)
385 struct annotation *notes = browser__annotation(browser);
386 ui_browser__reset_index(browser);
387 browser->nr_entries = notes->nr_asm_entries;
390 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
392 static int sym_title(struct symbol *sym, struct map *map, char *title,
393 size_t sz, int percent_type)
395 return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name,
396 percent_type_str(percent_type));
400 * This can be called from external jumps, i.e. jumps from one functon
401 * to another, like from the kernel's entry_SYSCALL_64 function to the
402 * swapgs_restore_regs_and_return_to_usermode() function.
404 * So all we check here is that dl->ops.target.sym is set, if it is, just
405 * go to that function and when exiting from its disassembly, come back
406 * to the calling function.
408 static bool annotate_browser__callq(struct annotate_browser *browser,
409 struct perf_evsel *evsel,
410 struct hist_browser_timer *hbt)
412 struct map_symbol *ms = browser->b.priv;
413 struct disasm_line *dl = disasm_line(browser->selection);
414 struct annotation *notes;
415 char title[SYM_TITLE_MAX_SIZE];
417 if (!dl->ops.target.sym) {
418 ui_helpline__puts("The called function was not found.");
422 notes = symbol__annotation(dl->ops.target.sym);
423 pthread_mutex_lock(¬es->lock);
425 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) {
426 pthread_mutex_unlock(¬es->lock);
427 ui__warning("Not enough memory for annotating '%s' symbol!\n",
428 dl->ops.target.sym->name);
432 pthread_mutex_unlock(¬es->lock);
433 symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
434 sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
435 ui_browser__show_title(&browser->b, title);
440 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
441 s64 offset, s64 *idx)
443 struct annotation *notes = browser__annotation(&browser->b);
444 struct disasm_line *pos;
447 list_for_each_entry(pos, ¬es->src->source, al.node) {
448 if (pos->al.offset == offset)
450 if (!annotation_line__filter(&pos->al, notes))
457 static bool annotate_browser__jump(struct annotate_browser *browser,
458 struct perf_evsel *evsel,
459 struct hist_browser_timer *hbt)
461 struct disasm_line *dl = disasm_line(browser->selection);
465 if (!ins__is_jump(&dl->ins))
468 if (dl->ops.target.outside) {
469 annotate_browser__callq(browser, evsel, hbt);
473 offset = dl->ops.target.offset;
474 dl = annotate_browser__find_offset(browser, offset, &idx);
476 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
480 annotate_browser__set_top(browser, &dl->al, idx);
486 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
489 struct annotation *notes = browser__annotation(&browser->b);
490 struct annotation_line *al = browser->selection;
492 *idx = browser->b.index;
493 list_for_each_entry_continue(al, ¬es->src->source, node) {
494 if (annotation_line__filter(al, notes))
499 if (al->line && strstr(al->line, s) != NULL)
506 static bool __annotate_browser__search(struct annotate_browser *browser)
508 struct annotation_line *al;
511 al = annotate_browser__find_string(browser, browser->search_bf, &idx);
513 ui_helpline__puts("String not found!");
517 annotate_browser__set_top(browser, al, idx);
518 browser->searching_backwards = false;
523 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
526 struct annotation *notes = browser__annotation(&browser->b);
527 struct annotation_line *al = browser->selection;
529 *idx = browser->b.index;
530 list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
531 if (annotation_line__filter(al, notes))
536 if (al->line && strstr(al->line, s) != NULL)
543 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
545 struct annotation_line *al;
548 al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
550 ui_helpline__puts("String not found!");
554 annotate_browser__set_top(browser, al, idx);
555 browser->searching_backwards = true;
559 static bool annotate_browser__search_window(struct annotate_browser *browser,
562 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
563 "ENTER: OK, ESC: Cancel",
564 delay_secs * 2) != K_ENTER ||
565 !*browser->search_bf)
571 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
573 if (annotate_browser__search_window(browser, delay_secs))
574 return __annotate_browser__search(browser);
579 static bool annotate_browser__continue_search(struct annotate_browser *browser,
582 if (!*browser->search_bf)
583 return annotate_browser__search(browser, delay_secs);
585 return __annotate_browser__search(browser);
588 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
591 if (annotate_browser__search_window(browser, delay_secs))
592 return __annotate_browser__search_reverse(browser);
598 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
601 if (!*browser->search_bf)
602 return annotate_browser__search_reverse(browser, delay_secs);
604 return __annotate_browser__search_reverse(browser);
607 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
609 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
610 struct map_symbol *ms = browser->priv;
611 struct symbol *sym = ms->sym;
612 char symbol_dso[SYM_TITLE_MAX_SIZE];
614 if (ui_browser__show(browser, title, help) < 0)
617 sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
619 ui_browser__gotorc_title(browser, 0, 0);
620 ui_browser__set_color(browser, HE_COLORSET_ROOT);
621 ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
626 switch_percent_type(struct annotation_options *opts, bool base)
628 switch (opts->percent_type) {
629 case PERCENT_HITS_LOCAL:
631 opts->percent_type = PERCENT_PERIOD_LOCAL;
633 opts->percent_type = PERCENT_HITS_GLOBAL;
635 case PERCENT_HITS_GLOBAL:
637 opts->percent_type = PERCENT_PERIOD_GLOBAL;
639 opts->percent_type = PERCENT_HITS_LOCAL;
641 case PERCENT_PERIOD_LOCAL:
643 opts->percent_type = PERCENT_HITS_LOCAL;
645 opts->percent_type = PERCENT_PERIOD_GLOBAL;
647 case PERCENT_PERIOD_GLOBAL:
649 opts->percent_type = PERCENT_HITS_GLOBAL;
651 opts->percent_type = PERCENT_PERIOD_LOCAL;
658 static int annotate_browser__run(struct annotate_browser *browser,
659 struct perf_evsel *evsel,
660 struct hist_browser_timer *hbt)
662 struct rb_node *nd = NULL;
663 struct hists *hists = evsel__hists(evsel);
664 struct map_symbol *ms = browser->b.priv;
665 struct symbol *sym = ms->sym;
666 struct annotation *notes = symbol__annotation(ms->sym);
667 const char *help = "Press 'h' for help on key bindings";
668 int delay_secs = hbt ? hbt->refresh : 0;
672 hists__scnprintf_title(hists, title, sizeof(title));
673 if (annotate_browser__show(&browser->b, title, help) < 0)
676 annotate_browser__calc_percent(browser, evsel);
678 if (browser->curr_hot) {
679 annotate_browser__set_rb_top(browser, browser->curr_hot);
680 browser->b.navkeypressed = false;
683 nd = browser->curr_hot;
686 key = ui_browser__run(&browser->b, delay_secs);
688 if (delay_secs != 0) {
689 annotate_browser__calc_percent(browser, evsel);
691 * Current line focus got out of the list of most active
692 * lines, NULL it so that if TAB|UNTAB is pressed, we
693 * move to curr_hot (current hottest line).
695 if (nd != NULL && RB_EMPTY_NODE(nd))
702 hbt->timer(hbt->arg);
704 if (delay_secs != 0) {
705 symbol__annotate_decay_histogram(sym, evsel->idx);
706 hists__scnprintf_title(hists, title, sizeof(title));
707 annotate_browser__show(&browser->b, title, help);
714 nd = rb_last(&browser->entries);
716 nd = browser->curr_hot;
722 nd = rb_first(&browser->entries);
724 nd = browser->curr_hot;
728 ui_browser__help_window(&browser->b,
730 "PGDN/SPACE Navigate\n"
731 "q/ESC/CTRL+C Exit\n\n"
732 "ENTER Go to target\n"
734 "H Go to hottest instruction\n"
735 "TAB/shift+TAB Cycle thru hottest instructions\n"
736 "j Toggle showing jump to target arrows\n"
737 "J Toggle showing number of jump sources on targets\n"
738 "n Search next string\n"
739 "o Toggle disassembler output/simplified view\n"
740 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
741 "s Toggle source code view\n"
742 "t Circulate percent, total period, samples view\n"
743 "c Show min/max cycle\n"
745 "k Toggle line numbers\n"
746 "P Print to [symbol_name].annotation file.\n"
747 "r Run available scripts\n"
748 "p Toggle percent type [local/global]\n"
749 "b Toggle percent base [period/hits]\n"
750 "? Search string backwards\n");
754 script_browse(NULL, NULL);
758 notes->options->show_linenr = !notes->options->show_linenr;
761 nd = browser->curr_hot;
764 if (annotate_browser__toggle_source(browser))
765 ui_helpline__puts(help);
768 notes->options->use_offset = !notes->options->use_offset;
769 annotation__update_column_widths(notes);
772 if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
773 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
776 notes->options->jump_arrows = !notes->options->jump_arrows;
779 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
780 annotation__update_column_widths(notes);
783 if (annotate_browser__search(browser, delay_secs)) {
785 ui_helpline__puts(help);
789 if (browser->searching_backwards ?
790 annotate_browser__continue_search_reverse(browser, delay_secs) :
791 annotate_browser__continue_search(browser, delay_secs))
795 if (annotate_browser__search_reverse(browser, delay_secs))
801 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
802 seq++, browser->b.nr_entries,
806 notes->nr_asm_entries);
812 struct disasm_line *dl = disasm_line(browser->selection);
814 if (browser->selection == NULL)
815 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
816 else if (browser->selection->offset == -1)
817 ui_helpline__puts("Actions are only available for assembly lines.");
818 else if (!dl->ins.ops)
820 else if (ins__is_ret(&dl->ins))
822 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
823 annotate_browser__callq(browser, evsel, hbt))) {
825 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
830 map_symbol__annotation_dump(ms, evsel, browser->opts);
833 if (notes->options->show_total_period) {
834 notes->options->show_total_period = false;
835 notes->options->show_nr_samples = true;
836 } else if (notes->options->show_nr_samples)
837 notes->options->show_nr_samples = false;
839 notes->options->show_total_period = true;
840 annotation__update_column_widths(notes);
843 if (notes->options->show_minmax_cycle)
844 notes->options->show_minmax_cycle = false;
846 notes->options->show_minmax_cycle = true;
847 annotation__update_column_widths(notes);
851 switch_percent_type(browser->opts, key == 'b');
852 hists__scnprintf_title(hists, title, sizeof(title));
853 annotate_browser__show(&browser->b, title, help);
865 annotate_browser__set_rb_top(browser, nd);
868 ui_browser__hide(&browser->b);
872 int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
873 struct hist_browser_timer *hbt,
874 struct annotation_options *opts)
876 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts);
879 int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
880 struct hist_browser_timer *hbt,
881 struct annotation_options *opts)
883 /* reset abort key so that it can get Ctrl-C as a key */
885 SLang_init_tty(0, 0, 0);
887 return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
890 int symbol__tui_annotate(struct symbol *sym, struct map *map,
891 struct perf_evsel *evsel,
892 struct hist_browser_timer *hbt,
893 struct annotation_options *opts)
895 struct annotation *notes = symbol__annotation(sym);
896 struct map_symbol ms = {
900 struct annotate_browser browser = {
902 .refresh = annotate_browser__refresh,
903 .seek = ui_browser__list_head_seek,
904 .write = annotate_browser__write,
905 .filter = disasm_line__filter,
906 .extra_title_lines = 1, /* for hists__scnprintf_title() */
908 .use_navkeypressed = true,
917 if (map->dso->annotate_warned)
920 err = symbol__annotate2(sym, map, evsel, opts, &browser.arch);
923 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
924 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
925 goto out_free_offsets;
928 ui_helpline__push("Press ESC to exit");
930 browser.b.width = notes->max_line_len;
931 browser.b.nr_entries = notes->nr_entries;
932 browser.b.entries = ¬es->src->source,
933 browser.b.width += 18; /* Percentage */
935 if (notes->options->hide_src_code)
936 ui_browser__init_asm_mode(&browser.b);
938 ret = annotate_browser__run(&browser, evsel, hbt);
940 annotated_source__purge(notes->src);
943 zfree(¬es->offsets);