1 // SPDX-License-Identifier: GPL-2.0
2 #include "../../util/util.h"
3 #include "../browser.h"
4 #include "../helpline.h"
7 #include "../../util/annotate.h"
8 #include "../../util/hist.h"
9 #include "../../util/sort.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 <sys/ttydefaults.h>
20 struct disasm_line_samples
{
22 struct sym_hist_entry he
;
27 struct annotate_browser
{
29 struct rb_root entries
;
30 struct rb_node
*curr_hot
;
31 struct annotation_line
*selection
;
33 struct annotation_options
*opts
;
34 bool searching_backwards
;
38 static inline struct annotation
*browser__annotation(struct ui_browser
*browser
)
40 struct map_symbol
*ms
= browser
->priv
;
41 return symbol__annotation(ms
->sym
);
44 static bool disasm_line__filter(struct ui_browser
*browser
, void *entry
)
46 struct annotation
*notes
= browser__annotation(browser
);
47 struct annotation_line
*al
= list_entry(entry
, struct annotation_line
, node
);
48 return annotation_line__filter(al
, notes
);
51 static int ui_browser__jumps_percent_color(struct ui_browser
*browser
, int nr
, bool current
)
53 struct annotation
*notes
= browser__annotation(browser
);
55 if (current
&& (!browser
->use_navkeypressed
|| browser
->navkeypressed
))
56 return HE_COLORSET_SELECTED
;
57 if (nr
== notes
->max_jump_sources
)
58 return HE_COLORSET_TOP
;
60 return HE_COLORSET_MEDIUM
;
61 return HE_COLORSET_NORMAL
;
64 static int ui_browser__set_jumps_percent_color(void *browser
, int nr
, bool current
)
66 int color
= ui_browser__jumps_percent_color(browser
, nr
, current
);
67 return ui_browser__set_color(browser
, color
);
70 static int annotate_browser__set_color(void *browser
, int color
)
72 return ui_browser__set_color(browser
, color
);
75 static void annotate_browser__write_graph(void *browser
, int graph
)
77 ui_browser__write_graph(browser
, graph
);
80 static void annotate_browser__set_percent_color(void *browser
, double percent
, bool current
)
82 ui_browser__set_percent_color(browser
, percent
, current
);
85 static void annotate_browser__printf(void *browser
, const char *fmt
, ...)
90 ui_browser__vprintf(browser
, fmt
, args
);
94 static void annotate_browser__write(struct ui_browser
*browser
, void *entry
, int row
)
96 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
97 struct annotation
*notes
= browser__annotation(browser
);
98 struct annotation_line
*al
= list_entry(entry
, struct annotation_line
, node
);
99 struct annotation_write_ops ops
= {
100 .first_line
= row
== 0,
101 .current_entry
= ui_browser__is_current_entry(browser
, row
),
102 .change_color
= (!notes
->options
->hide_src_code
&&
103 (!ops
.current_entry
||
104 (browser
->use_navkeypressed
&&
105 !browser
->navkeypressed
))),
106 .width
= browser
->width
,
108 .set_color
= annotate_browser__set_color
,
109 .set_percent_color
= annotate_browser__set_percent_color
,
110 .set_jumps_percent_color
= ui_browser__set_jumps_percent_color
,
111 .printf
= annotate_browser__printf
,
112 .write_graph
= annotate_browser__write_graph
,
115 /* The scroll bar isn't being used */
116 if (!browser
->navkeypressed
)
119 annotation_line__write(al
, notes
, &ops
, ab
->opts
);
121 if (ops
.current_entry
)
125 static bool is_fused(struct annotate_browser
*ab
, struct disasm_line
*cursor
)
127 struct disasm_line
*pos
= list_prev_entry(cursor
, al
.node
);
133 if (ins__is_lock(&pos
->ins
))
134 name
= pos
->ops
.locked
.ins
.name
;
136 name
= pos
->ins
.name
;
138 if (!name
|| !cursor
->ins
.name
)
141 return ins__is_fused(ab
->arch
, name
, cursor
->ins
.name
);
144 static void annotate_browser__draw_current_jump(struct ui_browser
*browser
)
146 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
147 struct disasm_line
*cursor
= disasm_line(ab
->selection
);
148 struct annotation_line
*target
;
149 unsigned int from
, to
;
150 struct map_symbol
*ms
= ab
->b
.priv
;
151 struct symbol
*sym
= ms
->sym
;
152 struct annotation
*notes
= symbol__annotation(sym
);
153 u8 pcnt_width
= annotation__pcnt_width(notes
);
156 /* PLT symbols contain external offsets */
157 if (strstr(sym
->name
, "@plt"))
160 if (!disasm_line__is_valid_local_jump(cursor
, sym
))
164 * This first was seen with a gcc function, _cpp_lex_token, that
165 * has the usual jumps:
167 * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92>
169 * I.e. jumps to a label inside that function (_cpp_lex_token), and
170 * those works, but also this kind:
172 * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72>
174 * I.e. jumps to another function, outside _cpp_lex_token, which
175 * are not being correctly handled generating as a side effect references
176 * to ab->offset[] entries that are set to NULL, so to make this code
177 * more robust, check that here.
179 * A proper fix for will be put in place, looking at the function
180 * name right after the '<' token and probably treating this like a
181 * 'call' instruction.
183 target
= notes
->offsets
[cursor
->ops
.target
.offset
];
184 if (target
== NULL
) {
185 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
186 cursor
->ops
.target
.offset
);
190 if (notes
->options
->hide_src_code
) {
191 from
= cursor
->al
.idx_asm
;
192 to
= target
->idx_asm
;
194 from
= (u64
)cursor
->al
.idx
;
195 to
= (u64
)target
->idx
;
198 width
= annotation__cycles_width(notes
);
200 ui_browser__set_color(browser
, HE_COLORSET_JUMP_ARROWS
);
201 __ui_browser__line_arrow(browser
,
202 pcnt_width
+ 2 + notes
->widths
.addr
+ width
,
205 if (is_fused(ab
, cursor
)) {
206 ui_browser__mark_fused(browser
,
207 pcnt_width
+ 3 + notes
->widths
.addr
+ width
,
209 to
> from
? true : false);
213 static unsigned int annotate_browser__refresh(struct ui_browser
*browser
)
215 struct annotation
*notes
= browser__annotation(browser
);
216 int ret
= ui_browser__list_head_refresh(browser
);
217 int pcnt_width
= annotation__pcnt_width(notes
);
219 if (notes
->options
->jump_arrows
)
220 annotate_browser__draw_current_jump(browser
);
222 ui_browser__set_color(browser
, HE_COLORSET_NORMAL
);
223 __ui_browser__vline(browser
, pcnt_width
, 0, browser
->rows
- 1);
227 static int disasm__cmp(struct annotation_line
*a
, struct annotation_line
*b
)
231 for (i
= 0; i
< a
->data_nr
; i
++) {
232 if (a
->data
[i
].percent
== b
->data
[i
].percent
)
234 return a
->data
[i
].percent
< b
->data
[i
].percent
;
239 static void disasm_rb_tree__insert(struct rb_root
*root
, struct annotation_line
*al
)
241 struct rb_node
**p
= &root
->rb_node
;
242 struct rb_node
*parent
= NULL
;
243 struct annotation_line
*l
;
247 l
= rb_entry(parent
, struct annotation_line
, rb_node
);
249 if (disasm__cmp(al
, l
))
254 rb_link_node(&al
->rb_node
, parent
, p
);
255 rb_insert_color(&al
->rb_node
, root
);
258 static void annotate_browser__set_top(struct annotate_browser
*browser
,
259 struct annotation_line
*pos
, u32 idx
)
261 struct annotation
*notes
= browser__annotation(&browser
->b
);
264 ui_browser__refresh_dimensions(&browser
->b
);
265 back
= browser
->b
.height
/ 2;
266 browser
->b
.top_idx
= browser
->b
.index
= idx
;
268 while (browser
->b
.top_idx
!= 0 && back
!= 0) {
269 pos
= list_entry(pos
->node
.prev
, struct annotation_line
, node
);
271 if (annotation_line__filter(pos
, notes
))
274 --browser
->b
.top_idx
;
278 browser
->b
.top
= pos
;
279 browser
->b
.navkeypressed
= true;
282 static void annotate_browser__set_rb_top(struct annotate_browser
*browser
,
285 struct annotation
*notes
= browser__annotation(&browser
->b
);
286 struct annotation_line
* pos
= rb_entry(nd
, struct annotation_line
, rb_node
);
289 if (notes
->options
->hide_src_code
)
291 annotate_browser__set_top(browser
, pos
, idx
);
292 browser
->curr_hot
= nd
;
295 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
296 struct perf_evsel
*evsel
)
298 struct map_symbol
*ms
= browser
->b
.priv
;
299 struct symbol
*sym
= ms
->sym
;
300 struct annotation
*notes
= symbol__annotation(sym
);
301 struct disasm_line
*pos
;
303 browser
->entries
= RB_ROOT
;
305 pthread_mutex_lock(¬es
->lock
);
307 symbol__calc_percent(sym
, evsel
);
309 list_for_each_entry(pos
, ¬es
->src
->source
, al
.node
) {
310 double max_percent
= 0.0;
313 if (pos
->al
.offset
== -1) {
314 RB_CLEAR_NODE(&pos
->al
.rb_node
);
318 for (i
= 0; i
< pos
->al
.data_nr
; i
++) {
321 percent
= annotation_data__percent(&pos
->al
.data
[i
],
322 browser
->opts
->percent_type
);
324 if (max_percent
< percent
)
325 max_percent
= percent
;
328 if (max_percent
< 0.01 && pos
->al
.ipc
== 0) {
329 RB_CLEAR_NODE(&pos
->al
.rb_node
);
332 disasm_rb_tree__insert(&browser
->entries
, &pos
->al
);
334 pthread_mutex_unlock(¬es
->lock
);
336 browser
->curr_hot
= rb_last(&browser
->entries
);
339 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
341 struct annotation
*notes
= browser__annotation(&browser
->b
);
342 struct annotation_line
*al
;
343 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
345 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
346 al
= list_entry(browser
->b
.top
, struct annotation_line
, node
);
348 if (notes
->options
->hide_src_code
) {
349 if (al
->idx_asm
< offset
)
352 browser
->b
.nr_entries
= notes
->nr_entries
;
353 notes
->options
->hide_src_code
= false;
354 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
355 browser
->b
.top_idx
= al
->idx
- offset
;
356 browser
->b
.index
= al
->idx
;
358 if (al
->idx_asm
< 0) {
359 ui_helpline__puts("Only available for assembly lines.");
360 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
364 if (al
->idx_asm
< offset
)
365 offset
= al
->idx_asm
;
367 browser
->b
.nr_entries
= notes
->nr_asm_entries
;
368 notes
->options
->hide_src_code
= true;
369 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
370 browser
->b
.top_idx
= al
->idx_asm
- offset
;
371 browser
->b
.index
= al
->idx_asm
;
377 static void ui_browser__init_asm_mode(struct ui_browser
*browser
)
379 struct annotation
*notes
= browser__annotation(browser
);
380 ui_browser__reset_index(browser
);
381 browser
->nr_entries
= notes
->nr_asm_entries
;
384 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
386 static int sym_title(struct symbol
*sym
, struct map
*map
, char *title
,
387 size_t sz
, int percent_type
)
389 return snprintf(title
, sz
, "%s %s [Percent: %s]", sym
->name
, map
->dso
->long_name
,
390 percent_type_str(percent_type
));
394 * This can be called from external jumps, i.e. jumps from one functon
395 * to another, like from the kernel's entry_SYSCALL_64 function to the
396 * swapgs_restore_regs_and_return_to_usermode() function.
398 * So all we check here is that dl->ops.target.sym is set, if it is, just
399 * go to that function and when exiting from its disassembly, come back
400 * to the calling function.
402 static bool annotate_browser__callq(struct annotate_browser
*browser
,
403 struct perf_evsel
*evsel
,
404 struct hist_browser_timer
*hbt
)
406 struct map_symbol
*ms
= browser
->b
.priv
;
407 struct disasm_line
*dl
= disasm_line(browser
->selection
);
408 struct annotation
*notes
;
409 char title
[SYM_TITLE_MAX_SIZE
];
411 if (!dl
->ops
.target
.sym
) {
412 ui_helpline__puts("The called function was not found.");
416 notes
= symbol__annotation(dl
->ops
.target
.sym
);
417 pthread_mutex_lock(¬es
->lock
);
419 if (!symbol__hists(dl
->ops
.target
.sym
, evsel
->evlist
->nr_entries
)) {
420 pthread_mutex_unlock(¬es
->lock
);
421 ui__warning("Not enough memory for annotating '%s' symbol!\n",
422 dl
->ops
.target
.sym
->name
);
426 pthread_mutex_unlock(¬es
->lock
);
427 symbol__tui_annotate(dl
->ops
.target
.sym
, ms
->map
, evsel
, hbt
, browser
->opts
);
428 sym_title(ms
->sym
, ms
->map
, title
, sizeof(title
), browser
->opts
->percent_type
);
429 ui_browser__show_title(&browser
->b
, title
);
434 struct disasm_line
*annotate_browser__find_offset(struct annotate_browser
*browser
,
435 s64 offset
, s64
*idx
)
437 struct annotation
*notes
= browser__annotation(&browser
->b
);
438 struct disasm_line
*pos
;
441 list_for_each_entry(pos
, ¬es
->src
->source
, al
.node
) {
442 if (pos
->al
.offset
== offset
)
444 if (!annotation_line__filter(&pos
->al
, notes
))
451 static bool annotate_browser__jump(struct annotate_browser
*browser
,
452 struct perf_evsel
*evsel
,
453 struct hist_browser_timer
*hbt
)
455 struct disasm_line
*dl
= disasm_line(browser
->selection
);
459 if (!ins__is_jump(&dl
->ins
))
462 if (dl
->ops
.target
.outside
) {
463 annotate_browser__callq(browser
, evsel
, hbt
);
467 offset
= dl
->ops
.target
.offset
;
468 dl
= annotate_browser__find_offset(browser
, offset
, &idx
);
470 ui_helpline__printf("Invalid jump offset: %" PRIx64
, offset
);
474 annotate_browser__set_top(browser
, &dl
->al
, idx
);
480 struct annotation_line
*annotate_browser__find_string(struct annotate_browser
*browser
,
483 struct annotation
*notes
= browser__annotation(&browser
->b
);
484 struct annotation_line
*al
= browser
->selection
;
486 *idx
= browser
->b
.index
;
487 list_for_each_entry_continue(al
, ¬es
->src
->source
, node
) {
488 if (annotation_line__filter(al
, notes
))
493 if (al
->line
&& strstr(al
->line
, s
) != NULL
)
500 static bool __annotate_browser__search(struct annotate_browser
*browser
)
502 struct annotation_line
*al
;
505 al
= annotate_browser__find_string(browser
, browser
->search_bf
, &idx
);
507 ui_helpline__puts("String not found!");
511 annotate_browser__set_top(browser
, al
, idx
);
512 browser
->searching_backwards
= false;
517 struct annotation_line
*annotate_browser__find_string_reverse(struct annotate_browser
*browser
,
520 struct annotation
*notes
= browser__annotation(&browser
->b
);
521 struct annotation_line
*al
= browser
->selection
;
523 *idx
= browser
->b
.index
;
524 list_for_each_entry_continue_reverse(al
, ¬es
->src
->source
, node
) {
525 if (annotation_line__filter(al
, notes
))
530 if (al
->line
&& strstr(al
->line
, s
) != NULL
)
537 static bool __annotate_browser__search_reverse(struct annotate_browser
*browser
)
539 struct annotation_line
*al
;
542 al
= annotate_browser__find_string_reverse(browser
, browser
->search_bf
, &idx
);
544 ui_helpline__puts("String not found!");
548 annotate_browser__set_top(browser
, al
, idx
);
549 browser
->searching_backwards
= true;
553 static bool annotate_browser__search_window(struct annotate_browser
*browser
,
556 if (ui_browser__input_window("Search", "String: ", browser
->search_bf
,
557 "ENTER: OK, ESC: Cancel",
558 delay_secs
* 2) != K_ENTER
||
559 !*browser
->search_bf
)
565 static bool annotate_browser__search(struct annotate_browser
*browser
, int delay_secs
)
567 if (annotate_browser__search_window(browser
, delay_secs
))
568 return __annotate_browser__search(browser
);
573 static bool annotate_browser__continue_search(struct annotate_browser
*browser
,
576 if (!*browser
->search_bf
)
577 return annotate_browser__search(browser
, delay_secs
);
579 return __annotate_browser__search(browser
);
582 static bool annotate_browser__search_reverse(struct annotate_browser
*browser
,
585 if (annotate_browser__search_window(browser
, delay_secs
))
586 return __annotate_browser__search_reverse(browser
);
592 bool annotate_browser__continue_search_reverse(struct annotate_browser
*browser
,
595 if (!*browser
->search_bf
)
596 return annotate_browser__search_reverse(browser
, delay_secs
);
598 return __annotate_browser__search_reverse(browser
);
601 static int annotate_browser__show(struct ui_browser
*browser
, char *title
, const char *help
)
603 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
604 struct map_symbol
*ms
= browser
->priv
;
605 struct symbol
*sym
= ms
->sym
;
606 char symbol_dso
[SYM_TITLE_MAX_SIZE
];
608 if (ui_browser__show(browser
, title
, help
) < 0)
611 sym_title(sym
, ms
->map
, symbol_dso
, sizeof(symbol_dso
), ab
->opts
->percent_type
);
613 ui_browser__gotorc_title(browser
, 0, 0);
614 ui_browser__set_color(browser
, HE_COLORSET_ROOT
);
615 ui_browser__write_nstring(browser
, symbol_dso
, browser
->width
+ 1);
620 switch_percent_type(struct annotation_options
*opts
, bool base
)
622 switch (opts
->percent_type
) {
623 case PERCENT_HITS_LOCAL
:
625 opts
->percent_type
= PERCENT_PERIOD_LOCAL
;
627 opts
->percent_type
= PERCENT_HITS_GLOBAL
;
629 case PERCENT_HITS_GLOBAL
:
631 opts
->percent_type
= PERCENT_PERIOD_GLOBAL
;
633 opts
->percent_type
= PERCENT_HITS_LOCAL
;
635 case PERCENT_PERIOD_LOCAL
:
637 opts
->percent_type
= PERCENT_HITS_LOCAL
;
639 opts
->percent_type
= PERCENT_PERIOD_GLOBAL
;
641 case PERCENT_PERIOD_GLOBAL
:
643 opts
->percent_type
= PERCENT_HITS_GLOBAL
;
645 opts
->percent_type
= PERCENT_PERIOD_LOCAL
;
652 static int annotate_browser__run(struct annotate_browser
*browser
,
653 struct perf_evsel
*evsel
,
654 struct hist_browser_timer
*hbt
)
656 struct rb_node
*nd
= NULL
;
657 struct hists
*hists
= evsel__hists(evsel
);
658 struct map_symbol
*ms
= browser
->b
.priv
;
659 struct symbol
*sym
= ms
->sym
;
660 struct annotation
*notes
= symbol__annotation(ms
->sym
);
661 const char *help
= "Press 'h' for help on key bindings";
662 int delay_secs
= hbt
? hbt
->refresh
: 0;
666 hists__scnprintf_title(hists
, title
, sizeof(title
));
667 if (annotate_browser__show(&browser
->b
, title
, help
) < 0)
670 annotate_browser__calc_percent(browser
, evsel
);
672 if (browser
->curr_hot
) {
673 annotate_browser__set_rb_top(browser
, browser
->curr_hot
);
674 browser
->b
.navkeypressed
= false;
677 nd
= browser
->curr_hot
;
680 key
= ui_browser__run(&browser
->b
, delay_secs
);
682 if (delay_secs
!= 0) {
683 annotate_browser__calc_percent(browser
, evsel
);
685 * Current line focus got out of the list of most active
686 * lines, NULL it so that if TAB|UNTAB is pressed, we
687 * move to curr_hot (current hottest line).
689 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
696 hbt
->timer(hbt
->arg
);
698 if (delay_secs
!= 0) {
699 symbol__annotate_decay_histogram(sym
, evsel
->idx
);
700 hists__scnprintf_title(hists
, title
, sizeof(title
));
701 annotate_browser__show(&browser
->b
, title
, help
);
708 nd
= rb_last(&browser
->entries
);
710 nd
= browser
->curr_hot
;
716 nd
= rb_first(&browser
->entries
);
718 nd
= browser
->curr_hot
;
722 ui_browser__help_window(&browser
->b
,
724 "PGDN/SPACE Navigate\n"
725 "q/ESC/CTRL+C Exit\n\n"
726 "ENTER Go to target\n"
728 "H Go to hottest instruction\n"
729 "TAB/shift+TAB Cycle thru hottest instructions\n"
730 "j Toggle showing jump to target arrows\n"
731 "J Toggle showing number of jump sources on targets\n"
732 "n Search next string\n"
733 "o Toggle disassembler output/simplified view\n"
734 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
735 "s Toggle source code view\n"
736 "t Circulate percent, total period, samples view\n"
737 "c Show min/max cycle\n"
739 "k Toggle line numbers\n"
740 "P Print to [symbol_name].annotation file.\n"
741 "r Run available scripts\n"
742 "p Toggle percent type [local/global]\n"
743 "b Toggle percent base [period/hits]\n"
744 "? Search string backwards\n");
752 notes
->options
->show_linenr
= !notes
->options
->show_linenr
;
755 nd
= browser
->curr_hot
;
758 if (annotate_browser__toggle_source(browser
))
759 ui_helpline__puts(help
);
762 notes
->options
->use_offset
= !notes
->options
->use_offset
;
763 annotation__update_column_widths(notes
);
766 if (++notes
->options
->offset_level
> ANNOTATION__MAX_OFFSET_LEVEL
)
767 notes
->options
->offset_level
= ANNOTATION__MIN_OFFSET_LEVEL
;
770 notes
->options
->jump_arrows
= !notes
->options
->jump_arrows
;
773 notes
->options
->show_nr_jumps
= !notes
->options
->show_nr_jumps
;
774 annotation__update_column_widths(notes
);
777 if (annotate_browser__search(browser
, delay_secs
)) {
779 ui_helpline__puts(help
);
783 if (browser
->searching_backwards
?
784 annotate_browser__continue_search_reverse(browser
, delay_secs
) :
785 annotate_browser__continue_search(browser
, delay_secs
))
789 if (annotate_browser__search_reverse(browser
, delay_secs
))
795 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
796 seq
++, browser
->b
.nr_entries
,
800 notes
->nr_asm_entries
);
806 struct disasm_line
*dl
= disasm_line(browser
->selection
);
808 if (browser
->selection
== NULL
)
809 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
810 else if (browser
->selection
->offset
== -1)
811 ui_helpline__puts("Actions are only available for assembly lines.");
812 else if (!dl
->ins
.ops
)
814 else if (ins__is_ret(&dl
->ins
))
816 else if (!(annotate_browser__jump(browser
, evsel
, hbt
) ||
817 annotate_browser__callq(browser
, evsel
, hbt
))) {
819 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
824 map_symbol__annotation_dump(ms
, evsel
, browser
->opts
);
827 if (notes
->options
->show_total_period
) {
828 notes
->options
->show_total_period
= false;
829 notes
->options
->show_nr_samples
= true;
830 } else if (notes
->options
->show_nr_samples
)
831 notes
->options
->show_nr_samples
= false;
833 notes
->options
->show_total_period
= true;
834 annotation__update_column_widths(notes
);
837 if (notes
->options
->show_minmax_cycle
)
838 notes
->options
->show_minmax_cycle
= false;
840 notes
->options
->show_minmax_cycle
= true;
841 annotation__update_column_widths(notes
);
845 switch_percent_type(browser
->opts
, key
== 'b');
846 hists__scnprintf_title(hists
, title
, sizeof(title
));
847 annotate_browser__show(&browser
->b
, title
, help
);
859 annotate_browser__set_rb_top(browser
, nd
);
862 ui_browser__hide(&browser
->b
);
866 int map_symbol__tui_annotate(struct map_symbol
*ms
, struct perf_evsel
*evsel
,
867 struct hist_browser_timer
*hbt
,
868 struct annotation_options
*opts
)
870 return symbol__tui_annotate(ms
->sym
, ms
->map
, evsel
, hbt
, opts
);
873 int hist_entry__tui_annotate(struct hist_entry
*he
, struct perf_evsel
*evsel
,
874 struct hist_browser_timer
*hbt
,
875 struct annotation_options
*opts
)
877 /* reset abort key so that it can get Ctrl-C as a key */
879 SLang_init_tty(0, 0, 0);
881 return map_symbol__tui_annotate(&he
->ms
, evsel
, hbt
, opts
);
884 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
,
885 struct perf_evsel
*evsel
,
886 struct hist_browser_timer
*hbt
,
887 struct annotation_options
*opts
)
889 struct annotation
*notes
= symbol__annotation(sym
);
890 struct map_symbol ms
= {
894 struct annotate_browser browser
= {
896 .refresh
= annotate_browser__refresh
,
897 .seek
= ui_browser__list_head_seek
,
898 .write
= annotate_browser__write
,
899 .filter
= disasm_line__filter
,
900 .extra_title_lines
= 1, /* for hists__scnprintf_title() */
902 .use_navkeypressed
= true,
911 if (map
->dso
->annotate_warned
)
914 err
= symbol__annotate2(sym
, map
, evsel
, opts
, &browser
.arch
);
917 symbol__strerror_disassemble(sym
, map
, err
, msg
, sizeof(msg
));
918 ui__error("Couldn't annotate %s:\n%s", sym
->name
, msg
);
919 goto out_free_offsets
;
922 ui_helpline__push("Press ESC to exit");
924 browser
.b
.width
= notes
->max_line_len
;
925 browser
.b
.nr_entries
= notes
->nr_entries
;
926 browser
.b
.entries
= ¬es
->src
->source
,
927 browser
.b
.width
+= 18; /* Percentage */
929 if (notes
->options
->hide_src_code
)
930 ui_browser__init_asm_mode(&browser
.b
);
932 ret
= annotate_browser__run(&browser
, evsel
, hbt
);
934 annotated_source__purge(notes
->src
);
937 zfree(¬es
->offsets
);