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 double disasm__cmp(struct annotation_line
*a
, struct annotation_line
*b
,
232 for (i
= 0; i
< a
->data_nr
; i
++) {
233 if (a
->data
[i
].percent
[percent_type
] == b
->data
[i
].percent
[percent_type
])
235 return a
->data
[i
].percent
[percent_type
] -
236 b
->data
[i
].percent
[percent_type
];
241 static void disasm_rb_tree__insert(struct annotate_browser
*browser
,
242 struct annotation_line
*al
)
244 struct rb_root
*root
= &browser
->entries
;
245 struct rb_node
**p
= &root
->rb_node
;
246 struct rb_node
*parent
= NULL
;
247 struct annotation_line
*l
;
251 l
= rb_entry(parent
, struct annotation_line
, rb_node
);
253 if (disasm__cmp(al
, l
, browser
->opts
->percent_type
) < 0)
258 rb_link_node(&al
->rb_node
, parent
, p
);
259 rb_insert_color(&al
->rb_node
, root
);
262 static void annotate_browser__set_top(struct annotate_browser
*browser
,
263 struct annotation_line
*pos
, u32 idx
)
265 struct annotation
*notes
= browser__annotation(&browser
->b
);
268 ui_browser__refresh_dimensions(&browser
->b
);
269 back
= browser
->b
.height
/ 2;
270 browser
->b
.top_idx
= browser
->b
.index
= idx
;
272 while (browser
->b
.top_idx
!= 0 && back
!= 0) {
273 pos
= list_entry(pos
->node
.prev
, struct annotation_line
, node
);
275 if (annotation_line__filter(pos
, notes
))
278 --browser
->b
.top_idx
;
282 browser
->b
.top
= pos
;
283 browser
->b
.navkeypressed
= true;
286 static void annotate_browser__set_rb_top(struct annotate_browser
*browser
,
289 struct annotation
*notes
= browser__annotation(&browser
->b
);
290 struct annotation_line
* pos
= rb_entry(nd
, struct annotation_line
, rb_node
);
293 if (notes
->options
->hide_src_code
)
295 annotate_browser__set_top(browser
, pos
, idx
);
296 browser
->curr_hot
= nd
;
299 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
300 struct perf_evsel
*evsel
)
302 struct map_symbol
*ms
= browser
->b
.priv
;
303 struct symbol
*sym
= ms
->sym
;
304 struct annotation
*notes
= symbol__annotation(sym
);
305 struct disasm_line
*pos
;
307 browser
->entries
= RB_ROOT
;
309 pthread_mutex_lock(¬es
->lock
);
311 symbol__calc_percent(sym
, evsel
);
313 list_for_each_entry(pos
, ¬es
->src
->source
, al
.node
) {
314 double max_percent
= 0.0;
317 if (pos
->al
.offset
== -1) {
318 RB_CLEAR_NODE(&pos
->al
.rb_node
);
322 for (i
= 0; i
< pos
->al
.data_nr
; i
++) {
325 percent
= annotation_data__percent(&pos
->al
.data
[i
],
326 browser
->opts
->percent_type
);
328 if (max_percent
< percent
)
329 max_percent
= percent
;
332 if (max_percent
< 0.01 && pos
->al
.ipc
== 0) {
333 RB_CLEAR_NODE(&pos
->al
.rb_node
);
336 disasm_rb_tree__insert(browser
, &pos
->al
);
338 pthread_mutex_unlock(¬es
->lock
);
340 browser
->curr_hot
= rb_last(&browser
->entries
);
343 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
345 struct annotation
*notes
= browser__annotation(&browser
->b
);
346 struct annotation_line
*al
;
347 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
349 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
350 al
= list_entry(browser
->b
.top
, struct annotation_line
, node
);
352 if (notes
->options
->hide_src_code
) {
353 if (al
->idx_asm
< offset
)
356 browser
->b
.nr_entries
= notes
->nr_entries
;
357 notes
->options
->hide_src_code
= false;
358 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
359 browser
->b
.top_idx
= al
->idx
- offset
;
360 browser
->b
.index
= al
->idx
;
362 if (al
->idx_asm
< 0) {
363 ui_helpline__puts("Only available for assembly lines.");
364 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
368 if (al
->idx_asm
< offset
)
369 offset
= al
->idx_asm
;
371 browser
->b
.nr_entries
= notes
->nr_asm_entries
;
372 notes
->options
->hide_src_code
= true;
373 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
374 browser
->b
.top_idx
= al
->idx_asm
- offset
;
375 browser
->b
.index
= al
->idx_asm
;
381 static void ui_browser__init_asm_mode(struct ui_browser
*browser
)
383 struct annotation
*notes
= browser__annotation(browser
);
384 ui_browser__reset_index(browser
);
385 browser
->nr_entries
= notes
->nr_asm_entries
;
388 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
390 static int sym_title(struct symbol
*sym
, struct map
*map
, char *title
,
391 size_t sz
, int percent_type
)
393 return snprintf(title
, sz
, "%s %s [Percent: %s]", sym
->name
, map
->dso
->long_name
,
394 percent_type_str(percent_type
));
398 * This can be called from external jumps, i.e. jumps from one functon
399 * to another, like from the kernel's entry_SYSCALL_64 function to the
400 * swapgs_restore_regs_and_return_to_usermode() function.
402 * So all we check here is that dl->ops.target.sym is set, if it is, just
403 * go to that function and when exiting from its disassembly, come back
404 * to the calling function.
406 static bool annotate_browser__callq(struct annotate_browser
*browser
,
407 struct perf_evsel
*evsel
,
408 struct hist_browser_timer
*hbt
)
410 struct map_symbol
*ms
= browser
->b
.priv
;
411 struct disasm_line
*dl
= disasm_line(browser
->selection
);
412 struct annotation
*notes
;
413 char title
[SYM_TITLE_MAX_SIZE
];
415 if (!dl
->ops
.target
.sym
) {
416 ui_helpline__puts("The called function was not found.");
420 notes
= symbol__annotation(dl
->ops
.target
.sym
);
421 pthread_mutex_lock(¬es
->lock
);
423 if (!symbol__hists(dl
->ops
.target
.sym
, evsel
->evlist
->nr_entries
)) {
424 pthread_mutex_unlock(¬es
->lock
);
425 ui__warning("Not enough memory for annotating '%s' symbol!\n",
426 dl
->ops
.target
.sym
->name
);
430 pthread_mutex_unlock(¬es
->lock
);
431 symbol__tui_annotate(dl
->ops
.target
.sym
, ms
->map
, evsel
, hbt
, browser
->opts
);
432 sym_title(ms
->sym
, ms
->map
, title
, sizeof(title
), browser
->opts
->percent_type
);
433 ui_browser__show_title(&browser
->b
, title
);
438 struct disasm_line
*annotate_browser__find_offset(struct annotate_browser
*browser
,
439 s64 offset
, s64
*idx
)
441 struct annotation
*notes
= browser__annotation(&browser
->b
);
442 struct disasm_line
*pos
;
445 list_for_each_entry(pos
, ¬es
->src
->source
, al
.node
) {
446 if (pos
->al
.offset
== offset
)
448 if (!annotation_line__filter(&pos
->al
, notes
))
455 static bool annotate_browser__jump(struct annotate_browser
*browser
,
456 struct perf_evsel
*evsel
,
457 struct hist_browser_timer
*hbt
)
459 struct disasm_line
*dl
= disasm_line(browser
->selection
);
463 if (!ins__is_jump(&dl
->ins
))
466 if (dl
->ops
.target
.outside
) {
467 annotate_browser__callq(browser
, evsel
, hbt
);
471 offset
= dl
->ops
.target
.offset
;
472 dl
= annotate_browser__find_offset(browser
, offset
, &idx
);
474 ui_helpline__printf("Invalid jump offset: %" PRIx64
, offset
);
478 annotate_browser__set_top(browser
, &dl
->al
, idx
);
484 struct annotation_line
*annotate_browser__find_string(struct annotate_browser
*browser
,
487 struct annotation
*notes
= browser__annotation(&browser
->b
);
488 struct annotation_line
*al
= browser
->selection
;
490 *idx
= browser
->b
.index
;
491 list_for_each_entry_continue(al
, ¬es
->src
->source
, node
) {
492 if (annotation_line__filter(al
, notes
))
497 if (al
->line
&& strstr(al
->line
, s
) != NULL
)
504 static bool __annotate_browser__search(struct annotate_browser
*browser
)
506 struct annotation_line
*al
;
509 al
= annotate_browser__find_string(browser
, browser
->search_bf
, &idx
);
511 ui_helpline__puts("String not found!");
515 annotate_browser__set_top(browser
, al
, idx
);
516 browser
->searching_backwards
= false;
521 struct annotation_line
*annotate_browser__find_string_reverse(struct annotate_browser
*browser
,
524 struct annotation
*notes
= browser__annotation(&browser
->b
);
525 struct annotation_line
*al
= browser
->selection
;
527 *idx
= browser
->b
.index
;
528 list_for_each_entry_continue_reverse(al
, ¬es
->src
->source
, node
) {
529 if (annotation_line__filter(al
, notes
))
534 if (al
->line
&& strstr(al
->line
, s
) != NULL
)
541 static bool __annotate_browser__search_reverse(struct annotate_browser
*browser
)
543 struct annotation_line
*al
;
546 al
= annotate_browser__find_string_reverse(browser
, browser
->search_bf
, &idx
);
548 ui_helpline__puts("String not found!");
552 annotate_browser__set_top(browser
, al
, idx
);
553 browser
->searching_backwards
= true;
557 static bool annotate_browser__search_window(struct annotate_browser
*browser
,
560 if (ui_browser__input_window("Search", "String: ", browser
->search_bf
,
561 "ENTER: OK, ESC: Cancel",
562 delay_secs
* 2) != K_ENTER
||
563 !*browser
->search_bf
)
569 static bool annotate_browser__search(struct annotate_browser
*browser
, int delay_secs
)
571 if (annotate_browser__search_window(browser
, delay_secs
))
572 return __annotate_browser__search(browser
);
577 static bool annotate_browser__continue_search(struct annotate_browser
*browser
,
580 if (!*browser
->search_bf
)
581 return annotate_browser__search(browser
, delay_secs
);
583 return __annotate_browser__search(browser
);
586 static bool annotate_browser__search_reverse(struct annotate_browser
*browser
,
589 if (annotate_browser__search_window(browser
, delay_secs
))
590 return __annotate_browser__search_reverse(browser
);
596 bool annotate_browser__continue_search_reverse(struct annotate_browser
*browser
,
599 if (!*browser
->search_bf
)
600 return annotate_browser__search_reverse(browser
, delay_secs
);
602 return __annotate_browser__search_reverse(browser
);
605 static int annotate_browser__show(struct ui_browser
*browser
, char *title
, const char *help
)
607 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
608 struct map_symbol
*ms
= browser
->priv
;
609 struct symbol
*sym
= ms
->sym
;
610 char symbol_dso
[SYM_TITLE_MAX_SIZE
];
612 if (ui_browser__show(browser
, title
, help
) < 0)
615 sym_title(sym
, ms
->map
, symbol_dso
, sizeof(symbol_dso
), ab
->opts
->percent_type
);
617 ui_browser__gotorc_title(browser
, 0, 0);
618 ui_browser__set_color(browser
, HE_COLORSET_ROOT
);
619 ui_browser__write_nstring(browser
, symbol_dso
, browser
->width
+ 1);
624 switch_percent_type(struct annotation_options
*opts
, bool base
)
626 switch (opts
->percent_type
) {
627 case PERCENT_HITS_LOCAL
:
629 opts
->percent_type
= PERCENT_PERIOD_LOCAL
;
631 opts
->percent_type
= PERCENT_HITS_GLOBAL
;
633 case PERCENT_HITS_GLOBAL
:
635 opts
->percent_type
= PERCENT_PERIOD_GLOBAL
;
637 opts
->percent_type
= PERCENT_HITS_LOCAL
;
639 case PERCENT_PERIOD_LOCAL
:
641 opts
->percent_type
= PERCENT_HITS_LOCAL
;
643 opts
->percent_type
= PERCENT_PERIOD_GLOBAL
;
645 case PERCENT_PERIOD_GLOBAL
:
647 opts
->percent_type
= PERCENT_HITS_GLOBAL
;
649 opts
->percent_type
= PERCENT_PERIOD_LOCAL
;
656 static int annotate_browser__run(struct annotate_browser
*browser
,
657 struct perf_evsel
*evsel
,
658 struct hist_browser_timer
*hbt
)
660 struct rb_node
*nd
= NULL
;
661 struct hists
*hists
= evsel__hists(evsel
);
662 struct map_symbol
*ms
= browser
->b
.priv
;
663 struct symbol
*sym
= ms
->sym
;
664 struct annotation
*notes
= symbol__annotation(ms
->sym
);
665 const char *help
= "Press 'h' for help on key bindings";
666 int delay_secs
= hbt
? hbt
->refresh
: 0;
670 hists__scnprintf_title(hists
, title
, sizeof(title
));
671 if (annotate_browser__show(&browser
->b
, title
, help
) < 0)
674 annotate_browser__calc_percent(browser
, evsel
);
676 if (browser
->curr_hot
) {
677 annotate_browser__set_rb_top(browser
, browser
->curr_hot
);
678 browser
->b
.navkeypressed
= false;
681 nd
= browser
->curr_hot
;
684 key
= ui_browser__run(&browser
->b
, delay_secs
);
686 if (delay_secs
!= 0) {
687 annotate_browser__calc_percent(browser
, evsel
);
689 * Current line focus got out of the list of most active
690 * lines, NULL it so that if TAB|UNTAB is pressed, we
691 * move to curr_hot (current hottest line).
693 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
700 hbt
->timer(hbt
->arg
);
702 if (delay_secs
!= 0) {
703 symbol__annotate_decay_histogram(sym
, evsel
->idx
);
704 hists__scnprintf_title(hists
, title
, sizeof(title
));
705 annotate_browser__show(&browser
->b
, title
, help
);
712 nd
= rb_last(&browser
->entries
);
714 nd
= browser
->curr_hot
;
720 nd
= rb_first(&browser
->entries
);
722 nd
= browser
->curr_hot
;
726 ui_browser__help_window(&browser
->b
,
728 "PGDN/SPACE Navigate\n"
729 "q/ESC/CTRL+C Exit\n\n"
730 "ENTER Go to target\n"
732 "H Go to hottest instruction\n"
733 "TAB/shift+TAB Cycle thru hottest instructions\n"
734 "j Toggle showing jump to target arrows\n"
735 "J Toggle showing number of jump sources on targets\n"
736 "n Search next string\n"
737 "o Toggle disassembler output/simplified view\n"
738 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
739 "s Toggle source code view\n"
740 "t Circulate percent, total period, samples view\n"
741 "c Show min/max cycle\n"
743 "k Toggle line numbers\n"
744 "P Print to [symbol_name].annotation file.\n"
745 "r Run available scripts\n"
746 "p Toggle percent type [local/global]\n"
747 "b Toggle percent base [period/hits]\n"
748 "? Search string backwards\n");
756 notes
->options
->show_linenr
= !notes
->options
->show_linenr
;
759 nd
= browser
->curr_hot
;
762 if (annotate_browser__toggle_source(browser
))
763 ui_helpline__puts(help
);
766 notes
->options
->use_offset
= !notes
->options
->use_offset
;
767 annotation__update_column_widths(notes
);
770 if (++notes
->options
->offset_level
> ANNOTATION__MAX_OFFSET_LEVEL
)
771 notes
->options
->offset_level
= ANNOTATION__MIN_OFFSET_LEVEL
;
774 notes
->options
->jump_arrows
= !notes
->options
->jump_arrows
;
777 notes
->options
->show_nr_jumps
= !notes
->options
->show_nr_jumps
;
778 annotation__update_column_widths(notes
);
781 if (annotate_browser__search(browser
, delay_secs
)) {
783 ui_helpline__puts(help
);
787 if (browser
->searching_backwards
?
788 annotate_browser__continue_search_reverse(browser
, delay_secs
) :
789 annotate_browser__continue_search(browser
, delay_secs
))
793 if (annotate_browser__search_reverse(browser
, delay_secs
))
799 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
800 seq
++, browser
->b
.nr_entries
,
804 notes
->nr_asm_entries
);
810 struct disasm_line
*dl
= disasm_line(browser
->selection
);
812 if (browser
->selection
== NULL
)
813 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
814 else if (browser
->selection
->offset
== -1)
815 ui_helpline__puts("Actions are only available for assembly lines.");
816 else if (!dl
->ins
.ops
)
818 else if (ins__is_ret(&dl
->ins
))
820 else if (!(annotate_browser__jump(browser
, evsel
, hbt
) ||
821 annotate_browser__callq(browser
, evsel
, hbt
))) {
823 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
828 map_symbol__annotation_dump(ms
, evsel
, browser
->opts
);
831 if (notes
->options
->show_total_period
) {
832 notes
->options
->show_total_period
= false;
833 notes
->options
->show_nr_samples
= true;
834 } else if (notes
->options
->show_nr_samples
)
835 notes
->options
->show_nr_samples
= false;
837 notes
->options
->show_total_period
= true;
838 annotation__update_column_widths(notes
);
841 if (notes
->options
->show_minmax_cycle
)
842 notes
->options
->show_minmax_cycle
= false;
844 notes
->options
->show_minmax_cycle
= true;
845 annotation__update_column_widths(notes
);
849 switch_percent_type(browser
->opts
, key
== 'b');
850 hists__scnprintf_title(hists
, title
, sizeof(title
));
851 annotate_browser__show(&browser
->b
, title
, help
);
863 annotate_browser__set_rb_top(browser
, nd
);
866 ui_browser__hide(&browser
->b
);
870 int map_symbol__tui_annotate(struct map_symbol
*ms
, struct perf_evsel
*evsel
,
871 struct hist_browser_timer
*hbt
,
872 struct annotation_options
*opts
)
874 return symbol__tui_annotate(ms
->sym
, ms
->map
, evsel
, hbt
, opts
);
877 int hist_entry__tui_annotate(struct hist_entry
*he
, struct perf_evsel
*evsel
,
878 struct hist_browser_timer
*hbt
,
879 struct annotation_options
*opts
)
881 /* reset abort key so that it can get Ctrl-C as a key */
883 SLang_init_tty(0, 0, 0);
885 return map_symbol__tui_annotate(&he
->ms
, evsel
, hbt
, opts
);
888 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
,
889 struct perf_evsel
*evsel
,
890 struct hist_browser_timer
*hbt
,
891 struct annotation_options
*opts
)
893 struct annotation
*notes
= symbol__annotation(sym
);
894 struct map_symbol ms
= {
898 struct annotate_browser browser
= {
900 .refresh
= annotate_browser__refresh
,
901 .seek
= ui_browser__list_head_seek
,
902 .write
= annotate_browser__write
,
903 .filter
= disasm_line__filter
,
904 .extra_title_lines
= 1, /* for hists__scnprintf_title() */
906 .use_navkeypressed
= true,
915 if (map
->dso
->annotate_warned
)
918 err
= symbol__annotate2(sym
, map
, evsel
, opts
, &browser
.arch
);
921 symbol__strerror_disassemble(sym
, map
, err
, msg
, sizeof(msg
));
922 ui__error("Couldn't annotate %s:\n%s", sym
->name
, msg
);
923 goto out_free_offsets
;
926 ui_helpline__push("Press ESC to exit");
928 browser
.b
.width
= notes
->max_line_len
;
929 browser
.b
.nr_entries
= notes
->nr_entries
;
930 browser
.b
.entries
= ¬es
->src
->source
,
931 browser
.b
.width
+= 18; /* Percentage */
933 if (notes
->options
->hide_src_code
)
934 ui_browser__init_asm_mode(&browser
.b
);
936 ret
= annotate_browser__run(&browser
, evsel
, hbt
);
938 annotated_source__purge(notes
->src
);
941 zfree(¬es
->offsets
);