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
,
212 to
> from
? true : false);
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 static void ui_browser__init_asm_mode(struct ui_browser
*browser
)
386 struct annotation
*notes
= browser__annotation(browser
);
387 ui_browser__reset_index(browser
);
388 browser
->nr_entries
= notes
->nr_asm_entries
;
391 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
393 static int sym_title(struct symbol
*sym
, struct map
*map
, char *title
,
394 size_t sz
, int percent_type
)
396 return snprintf(title
, sz
, "%s %s [Percent: %s]", sym
->name
, map
->dso
->long_name
,
397 percent_type_str(percent_type
));
401 * This can be called from external jumps, i.e. jumps from one functon
402 * to another, like from the kernel's entry_SYSCALL_64 function to the
403 * swapgs_restore_regs_and_return_to_usermode() function.
405 * So all we check here is that dl->ops.target.sym is set, if it is, just
406 * go to that function and when exiting from its disassembly, come back
407 * to the calling function.
409 static bool annotate_browser__callq(struct annotate_browser
*browser
,
411 struct hist_browser_timer
*hbt
)
413 struct map_symbol
*ms
= browser
->b
.priv
, target_ms
;
414 struct disasm_line
*dl
= disasm_line(browser
->selection
);
415 struct annotation
*notes
;
416 char title
[SYM_TITLE_MAX_SIZE
];
418 if (!dl
->ops
.target
.sym
) {
419 ui_helpline__puts("The called function was not found.");
423 notes
= symbol__annotation(dl
->ops
.target
.sym
);
424 pthread_mutex_lock(¬es
->lock
);
426 if (!symbol__hists(dl
->ops
.target
.sym
, evsel
->evlist
->core
.nr_entries
)) {
427 pthread_mutex_unlock(¬es
->lock
);
428 ui__warning("Not enough memory for annotating '%s' symbol!\n",
429 dl
->ops
.target
.sym
->name
);
433 target_ms
.maps
= ms
->maps
;
434 target_ms
.map
= ms
->map
;
435 target_ms
.sym
= dl
->ops
.target
.sym
;
436 pthread_mutex_unlock(¬es
->lock
);
437 symbol__tui_annotate(&target_ms
, evsel
, hbt
, browser
->opts
);
438 sym_title(ms
->sym
, ms
->map
, title
, sizeof(title
), browser
->opts
->percent_type
);
439 ui_browser__show_title(&browser
->b
, title
);
444 struct disasm_line
*annotate_browser__find_offset(struct annotate_browser
*browser
,
445 s64 offset
, s64
*idx
)
447 struct annotation
*notes
= browser__annotation(&browser
->b
);
448 struct disasm_line
*pos
;
451 list_for_each_entry(pos
, ¬es
->src
->source
, al
.node
) {
452 if (pos
->al
.offset
== offset
)
454 if (!annotation_line__filter(&pos
->al
, notes
))
461 static bool annotate_browser__jump(struct annotate_browser
*browser
,
463 struct hist_browser_timer
*hbt
)
465 struct disasm_line
*dl
= disasm_line(browser
->selection
);
469 if (!ins__is_jump(&dl
->ins
))
472 if (dl
->ops
.target
.outside
) {
473 annotate_browser__callq(browser
, evsel
, hbt
);
477 offset
= dl
->ops
.target
.offset
;
478 dl
= annotate_browser__find_offset(browser
, offset
, &idx
);
480 ui_helpline__printf("Invalid jump offset: %" PRIx64
, offset
);
484 annotate_browser__set_top(browser
, &dl
->al
, idx
);
490 struct annotation_line
*annotate_browser__find_string(struct annotate_browser
*browser
,
493 struct annotation
*notes
= browser__annotation(&browser
->b
);
494 struct annotation_line
*al
= browser
->selection
;
496 *idx
= browser
->b
.index
;
497 list_for_each_entry_continue(al
, ¬es
->src
->source
, node
) {
498 if (annotation_line__filter(al
, notes
))
503 if (al
->line
&& strstr(al
->line
, s
) != NULL
)
510 static bool __annotate_browser__search(struct annotate_browser
*browser
)
512 struct annotation_line
*al
;
515 al
= annotate_browser__find_string(browser
, browser
->search_bf
, &idx
);
517 ui_helpline__puts("String not found!");
521 annotate_browser__set_top(browser
, al
, idx
);
522 browser
->searching_backwards
= false;
527 struct annotation_line
*annotate_browser__find_string_reverse(struct annotate_browser
*browser
,
530 struct annotation
*notes
= browser__annotation(&browser
->b
);
531 struct annotation_line
*al
= browser
->selection
;
533 *idx
= browser
->b
.index
;
534 list_for_each_entry_continue_reverse(al
, ¬es
->src
->source
, node
) {
535 if (annotation_line__filter(al
, notes
))
540 if (al
->line
&& strstr(al
->line
, s
) != NULL
)
547 static bool __annotate_browser__search_reverse(struct annotate_browser
*browser
)
549 struct annotation_line
*al
;
552 al
= annotate_browser__find_string_reverse(browser
, browser
->search_bf
, &idx
);
554 ui_helpline__puts("String not found!");
558 annotate_browser__set_top(browser
, al
, idx
);
559 browser
->searching_backwards
= true;
563 static bool annotate_browser__search_window(struct annotate_browser
*browser
,
566 if (ui_browser__input_window("Search", "String: ", browser
->search_bf
,
567 "ENTER: OK, ESC: Cancel",
568 delay_secs
* 2) != K_ENTER
||
569 !*browser
->search_bf
)
575 static bool annotate_browser__search(struct annotate_browser
*browser
, int delay_secs
)
577 if (annotate_browser__search_window(browser
, delay_secs
))
578 return __annotate_browser__search(browser
);
583 static bool annotate_browser__continue_search(struct annotate_browser
*browser
,
586 if (!*browser
->search_bf
)
587 return annotate_browser__search(browser
, delay_secs
);
589 return __annotate_browser__search(browser
);
592 static bool annotate_browser__search_reverse(struct annotate_browser
*browser
,
595 if (annotate_browser__search_window(browser
, delay_secs
))
596 return __annotate_browser__search_reverse(browser
);
602 bool annotate_browser__continue_search_reverse(struct annotate_browser
*browser
,
605 if (!*browser
->search_bf
)
606 return annotate_browser__search_reverse(browser
, delay_secs
);
608 return __annotate_browser__search_reverse(browser
);
611 static int annotate_browser__show(struct ui_browser
*browser
, char *title
, const char *help
)
613 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
614 struct map_symbol
*ms
= browser
->priv
;
615 struct symbol
*sym
= ms
->sym
;
616 char symbol_dso
[SYM_TITLE_MAX_SIZE
];
618 if (ui_browser__show(browser
, title
, help
) < 0)
621 sym_title(sym
, ms
->map
, symbol_dso
, sizeof(symbol_dso
), ab
->opts
->percent_type
);
623 ui_browser__gotorc_title(browser
, 0, 0);
624 ui_browser__set_color(browser
, HE_COLORSET_ROOT
);
625 ui_browser__write_nstring(browser
, symbol_dso
, browser
->width
+ 1);
630 switch_percent_type(struct annotation_options
*opts
, bool base
)
632 switch (opts
->percent_type
) {
633 case PERCENT_HITS_LOCAL
:
635 opts
->percent_type
= PERCENT_PERIOD_LOCAL
;
637 opts
->percent_type
= PERCENT_HITS_GLOBAL
;
639 case PERCENT_HITS_GLOBAL
:
641 opts
->percent_type
= PERCENT_PERIOD_GLOBAL
;
643 opts
->percent_type
= PERCENT_HITS_LOCAL
;
645 case PERCENT_PERIOD_LOCAL
:
647 opts
->percent_type
= PERCENT_HITS_LOCAL
;
649 opts
->percent_type
= PERCENT_PERIOD_GLOBAL
;
651 case PERCENT_PERIOD_GLOBAL
:
653 opts
->percent_type
= PERCENT_HITS_GLOBAL
;
655 opts
->percent_type
= PERCENT_PERIOD_LOCAL
;
662 static int annotate_browser__run(struct annotate_browser
*browser
,
664 struct hist_browser_timer
*hbt
)
666 struct rb_node
*nd
= NULL
;
667 struct hists
*hists
= evsel__hists(evsel
);
668 struct map_symbol
*ms
= browser
->b
.priv
;
669 struct symbol
*sym
= ms
->sym
;
670 struct annotation
*notes
= symbol__annotation(ms
->sym
);
671 const char *help
= "Press 'h' for help on key bindings";
672 int delay_secs
= hbt
? hbt
->refresh
: 0;
676 hists__scnprintf_title(hists
, title
, sizeof(title
));
677 if (annotate_browser__show(&browser
->b
, title
, help
) < 0)
680 annotate_browser__calc_percent(browser
, evsel
);
682 if (browser
->curr_hot
) {
683 annotate_browser__set_rb_top(browser
, browser
->curr_hot
);
684 browser
->b
.navkeypressed
= false;
687 nd
= browser
->curr_hot
;
690 key
= ui_browser__run(&browser
->b
, delay_secs
);
692 if (delay_secs
!= 0) {
693 annotate_browser__calc_percent(browser
, evsel
);
695 * Current line focus got out of the list of most active
696 * lines, NULL it so that if TAB|UNTAB is pressed, we
697 * move to curr_hot (current hottest line).
699 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
706 hbt
->timer(hbt
->arg
);
708 if (delay_secs
!= 0) {
709 symbol__annotate_decay_histogram(sym
, evsel
->idx
);
710 hists__scnprintf_title(hists
, title
, sizeof(title
));
711 annotate_browser__show(&browser
->b
, title
, help
);
718 nd
= rb_last(&browser
->entries
);
720 nd
= browser
->curr_hot
;
726 nd
= rb_first(&browser
->entries
);
728 nd
= browser
->curr_hot
;
732 ui_browser__help_window(&browser
->b
,
734 "PGDN/SPACE Navigate\n"
735 "q/ESC/CTRL+C Exit\n\n"
736 "ENTER Go to target\n"
738 "H Go to hottest instruction\n"
739 "TAB/shift+TAB Cycle thru hottest instructions\n"
740 "j Toggle showing jump to target arrows\n"
741 "J Toggle showing number of jump sources on targets\n"
742 "n Search next string\n"
743 "o Toggle disassembler output/simplified view\n"
744 "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
745 "s Toggle source code view\n"
746 "t Circulate percent, total period, samples view\n"
747 "c Show min/max cycle\n"
749 "k Toggle line numbers\n"
750 "P Print to [symbol_name].annotation file.\n"
751 "r Run available scripts\n"
752 "p Toggle percent type [local/global]\n"
753 "b Toggle percent base [period/hits]\n"
754 "? Search string backwards\n");
758 script_browse(NULL
, NULL
);
762 notes
->options
->show_linenr
= !notes
->options
->show_linenr
;
765 nd
= browser
->curr_hot
;
768 if (annotate_browser__toggle_source(browser
))
769 ui_helpline__puts(help
);
772 notes
->options
->use_offset
= !notes
->options
->use_offset
;
773 annotation__update_column_widths(notes
);
776 if (++notes
->options
->offset_level
> ANNOTATION__MAX_OFFSET_LEVEL
)
777 notes
->options
->offset_level
= ANNOTATION__MIN_OFFSET_LEVEL
;
780 notes
->options
->jump_arrows
= !notes
->options
->jump_arrows
;
783 notes
->options
->show_nr_jumps
= !notes
->options
->show_nr_jumps
;
784 annotation__update_column_widths(notes
);
787 if (annotate_browser__search(browser
, delay_secs
)) {
789 ui_helpline__puts(help
);
793 if (browser
->searching_backwards
?
794 annotate_browser__continue_search_reverse(browser
, delay_secs
) :
795 annotate_browser__continue_search(browser
, delay_secs
))
799 if (annotate_browser__search_reverse(browser
, delay_secs
))
805 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
806 seq
++, browser
->b
.nr_entries
,
810 notes
->nr_asm_entries
);
816 struct disasm_line
*dl
= disasm_line(browser
->selection
);
818 if (browser
->selection
== NULL
)
819 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
820 else if (browser
->selection
->offset
== -1)
821 ui_helpline__puts("Actions are only available for assembly lines.");
822 else if (!dl
->ins
.ops
)
824 else if (ins__is_ret(&dl
->ins
))
826 else if (!(annotate_browser__jump(browser
, evsel
, hbt
) ||
827 annotate_browser__callq(browser
, evsel
, hbt
))) {
829 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
834 map_symbol__annotation_dump(ms
, evsel
, browser
->opts
);
837 if (notes
->options
->show_total_period
) {
838 notes
->options
->show_total_period
= false;
839 notes
->options
->show_nr_samples
= true;
840 } else if (notes
->options
->show_nr_samples
)
841 notes
->options
->show_nr_samples
= false;
843 notes
->options
->show_total_period
= true;
844 annotation__update_column_widths(notes
);
847 if (notes
->options
->show_minmax_cycle
)
848 notes
->options
->show_minmax_cycle
= false;
850 notes
->options
->show_minmax_cycle
= true;
851 annotation__update_column_widths(notes
);
855 switch_percent_type(browser
->opts
, key
== 'b');
856 hists__scnprintf_title(hists
, title
, sizeof(title
));
857 annotate_browser__show(&browser
->b
, title
, help
);
869 annotate_browser__set_rb_top(browser
, nd
);
872 ui_browser__hide(&browser
->b
);
876 int map_symbol__tui_annotate(struct map_symbol
*ms
, struct evsel
*evsel
,
877 struct hist_browser_timer
*hbt
,
878 struct annotation_options
*opts
)
880 return symbol__tui_annotate(ms
, evsel
, hbt
, opts
);
883 int hist_entry__tui_annotate(struct hist_entry
*he
, struct evsel
*evsel
,
884 struct hist_browser_timer
*hbt
,
885 struct annotation_options
*opts
)
887 /* reset abort key so that it can get Ctrl-C as a key */
889 SLang_init_tty(0, 0, 0);
891 return map_symbol__tui_annotate(&he
->ms
, evsel
, hbt
, opts
);
894 int symbol__tui_annotate(struct map_symbol
*ms
, struct evsel
*evsel
,
895 struct hist_browser_timer
*hbt
,
896 struct annotation_options
*opts
)
898 struct symbol
*sym
= ms
->sym
;
899 struct annotation
*notes
= symbol__annotation(sym
);
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 (ms
->map
->dso
->annotate_warned
)
920 err
= symbol__annotate2(ms
, evsel
, opts
, &browser
.arch
);
923 symbol__strerror_disassemble(ms
, 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
);