1 #include "../../util/util.h"
2 #include "../browser.h"
3 #include "../helpline.h"
4 #include "../libslang.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"
14 struct disasm_line_samples
{
19 struct browser_disasm_line
{
20 struct rb_node rb_node
;
25 * actual length of this array is saved on the nr_events field
26 * of the struct annotate_browser
28 struct disasm_line_samples samples
[1];
31 static struct annotate_browser_opt
{
38 } annotate_browser__opts
= {
43 struct annotate_browser
{
45 struct rb_root entries
;
46 struct rb_node
*curr_hot
;
47 struct disasm_line
*selection
;
48 struct disasm_line
**offsets
;
55 bool searching_backwards
;
64 static inline struct browser_disasm_line
*disasm_line__browser(struct disasm_line
*dl
)
66 return (struct browser_disasm_line
*)(dl
+ 1);
69 static bool disasm_line__filter(struct ui_browser
*browser __maybe_unused
,
72 if (annotate_browser__opts
.hide_src_code
) {
73 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
74 return dl
->offset
== -1;
80 static int annotate_browser__jumps_percent_color(struct annotate_browser
*browser
,
83 if (current
&& (!browser
->b
.use_navkeypressed
|| browser
->b
.navkeypressed
))
84 return HE_COLORSET_SELECTED
;
85 if (nr
== browser
->max_jump_sources
)
86 return HE_COLORSET_TOP
;
88 return HE_COLORSET_MEDIUM
;
89 return HE_COLORSET_NORMAL
;
92 static int annotate_browser__set_jumps_percent_color(struct annotate_browser
*browser
,
95 int color
= annotate_browser__jumps_percent_color(browser
, nr
, current
);
96 return ui_browser__set_color(&browser
->b
, color
);
99 static void annotate_browser__write(struct ui_browser
*browser
, void *entry
, int row
)
101 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
102 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
103 struct browser_disasm_line
*bdl
= disasm_line__browser(dl
);
104 bool current_entry
= ui_browser__is_current_entry(browser
, row
);
105 bool change_color
= (!annotate_browser__opts
.hide_src_code
&&
106 (!current_entry
|| (browser
->use_navkeypressed
&&
107 !browser
->navkeypressed
)));
108 int width
= browser
->width
, printed
;
109 int i
, pcnt_width
= 7 * ab
->nr_events
;
110 double percent_max
= 0.0;
113 for (i
= 0; i
< ab
->nr_events
; i
++) {
114 if (bdl
->samples
[i
].percent
> percent_max
)
115 percent_max
= bdl
->samples
[i
].percent
;
118 if (dl
->offset
!= -1 && percent_max
!= 0.0) {
119 for (i
= 0; i
< ab
->nr_events
; i
++) {
120 ui_browser__set_percent_color(browser
,
121 bdl
->samples
[i
].percent
,
123 if (annotate_browser__opts
.show_total_period
)
124 slsmg_printf("%6" PRIu64
" ",
127 slsmg_printf("%6.2f ", bdl
->samples
[i
].percent
);
130 ui_browser__set_percent_color(browser
, 0, current_entry
);
131 slsmg_write_nstring(" ", pcnt_width
);
134 SLsmg_write_char(' ');
136 /* The scroll bar isn't being used */
137 if (!browser
->navkeypressed
)
141 slsmg_write_nstring(" ", width
- pcnt_width
);
142 else if (dl
->offset
== -1) {
143 if (dl
->line_nr
&& annotate_browser__opts
.show_linenr
)
144 printed
= scnprintf(bf
, sizeof(bf
), "%-*d ",
145 ab
->addr_width
+ 1, dl
->line_nr
);
147 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
148 ab
->addr_width
, " ");
149 slsmg_write_nstring(bf
, printed
);
150 slsmg_write_nstring(dl
->line
, width
- printed
- pcnt_width
+ 1);
152 u64 addr
= dl
->offset
;
155 if (!annotate_browser__opts
.use_offset
)
158 if (!annotate_browser__opts
.use_offset
) {
159 printed
= scnprintf(bf
, sizeof(bf
), "%" PRIx64
": ", addr
);
161 if (bdl
->jump_sources
) {
162 if (annotate_browser__opts
.show_nr_jumps
) {
164 printed
= scnprintf(bf
, sizeof(bf
), "%*d ",
167 prev
= annotate_browser__set_jumps_percent_color(ab
, bdl
->jump_sources
,
169 slsmg_write_nstring(bf
, printed
);
170 ui_browser__set_color(browser
, prev
);
173 printed
= scnprintf(bf
, sizeof(bf
), "%*" PRIx64
": ",
174 ab
->target_width
, addr
);
176 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
177 ab
->addr_width
, " ");
182 color
= ui_browser__set_color(browser
, HE_COLORSET_ADDR
);
183 slsmg_write_nstring(bf
, printed
);
185 ui_browser__set_color(browser
, color
);
186 if (dl
->ins
&& dl
->ins
->ops
->scnprintf
) {
187 if (ins__is_jump(dl
->ins
)) {
188 bool fwd
= dl
->ops
.target
.offset
> (u64
)dl
->offset
;
190 ui_browser__write_graph(browser
, fwd
? SLSMG_DARROW_CHAR
:
192 SLsmg_write_char(' ');
193 } else if (ins__is_call(dl
->ins
)) {
194 ui_browser__write_graph(browser
, SLSMG_RARROW_CHAR
);
195 SLsmg_write_char(' ');
197 slsmg_write_nstring(" ", 2);
200 if (strcmp(dl
->name
, "retq")) {
201 slsmg_write_nstring(" ", 2);
203 ui_browser__write_graph(browser
, SLSMG_LARROW_CHAR
);
204 SLsmg_write_char(' ');
208 disasm_line__scnprintf(dl
, bf
, sizeof(bf
), !annotate_browser__opts
.use_offset
);
209 slsmg_write_nstring(bf
, width
- pcnt_width
- 3 - printed
);
216 static bool disasm_line__is_valid_jump(struct disasm_line
*dl
, struct symbol
*sym
)
218 if (!dl
|| !dl
->ins
|| !ins__is_jump(dl
->ins
)
219 || !disasm_line__has_offset(dl
)
220 || dl
->ops
.target
.offset
>= symbol__size(sym
))
226 static void annotate_browser__draw_current_jump(struct ui_browser
*browser
)
228 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
229 struct disasm_line
*cursor
= ab
->selection
, *target
;
230 struct browser_disasm_line
*btarget
, *bcursor
;
231 unsigned int from
, to
;
232 struct map_symbol
*ms
= ab
->b
.priv
;
233 struct symbol
*sym
= ms
->sym
;
236 /* PLT symbols contain external offsets */
237 if (strstr(sym
->name
, "@plt"))
240 if (!disasm_line__is_valid_jump(cursor
, sym
))
243 target
= ab
->offsets
[cursor
->ops
.target
.offset
];
247 bcursor
= disasm_line__browser(cursor
);
248 btarget
= disasm_line__browser(target
);
250 if (annotate_browser__opts
.hide_src_code
) {
251 from
= bcursor
->idx_asm
;
252 to
= btarget
->idx_asm
;
254 from
= (u64
)bcursor
->idx
;
255 to
= (u64
)btarget
->idx
;
258 pcnt_width
*= ab
->nr_events
;
260 ui_browser__set_color(browser
, HE_COLORSET_CODE
);
261 __ui_browser__line_arrow(browser
, pcnt_width
+ 2 + ab
->addr_width
,
265 static unsigned int annotate_browser__refresh(struct ui_browser
*browser
)
267 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
268 int ret
= ui_browser__list_head_refresh(browser
);
271 pcnt_width
= 7 * ab
->nr_events
;
273 if (annotate_browser__opts
.jump_arrows
)
274 annotate_browser__draw_current_jump(browser
);
276 ui_browser__set_color(browser
, HE_COLORSET_NORMAL
);
277 __ui_browser__vline(browser
, pcnt_width
, 0, browser
->height
- 1);
281 static int disasm__cmp(struct browser_disasm_line
*a
,
282 struct browser_disasm_line
*b
, int nr_pcnt
)
286 for (i
= 0; i
< nr_pcnt
; i
++) {
287 if (a
->samples
[i
].percent
== b
->samples
[i
].percent
)
289 return a
->samples
[i
].percent
< b
->samples
[i
].percent
;
294 static void disasm_rb_tree__insert(struct rb_root
*root
, struct browser_disasm_line
*bdl
,
297 struct rb_node
**p
= &root
->rb_node
;
298 struct rb_node
*parent
= NULL
;
299 struct browser_disasm_line
*l
;
303 l
= rb_entry(parent
, struct browser_disasm_line
, rb_node
);
305 if (disasm__cmp(bdl
, l
, nr_events
))
310 rb_link_node(&bdl
->rb_node
, parent
, p
);
311 rb_insert_color(&bdl
->rb_node
, root
);
314 static void annotate_browser__set_top(struct annotate_browser
*browser
,
315 struct disasm_line
*pos
, u32 idx
)
319 ui_browser__refresh_dimensions(&browser
->b
);
320 back
= browser
->b
.height
/ 2;
321 browser
->b
.top_idx
= browser
->b
.index
= idx
;
323 while (browser
->b
.top_idx
!= 0 && back
!= 0) {
324 pos
= list_entry(pos
->node
.prev
, struct disasm_line
, node
);
326 if (disasm_line__filter(&browser
->b
, &pos
->node
))
329 --browser
->b
.top_idx
;
333 browser
->b
.top
= pos
;
334 browser
->b
.navkeypressed
= true;
337 static void annotate_browser__set_rb_top(struct annotate_browser
*browser
,
340 struct browser_disasm_line
*bpos
;
341 struct disasm_line
*pos
;
344 bpos
= rb_entry(nd
, struct browser_disasm_line
, rb_node
);
345 pos
= ((struct disasm_line
*)bpos
) - 1;
347 if (annotate_browser__opts
.hide_src_code
)
349 annotate_browser__set_top(browser
, pos
, idx
);
350 browser
->curr_hot
= nd
;
353 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
354 struct perf_evsel
*evsel
)
356 struct map_symbol
*ms
= browser
->b
.priv
;
357 struct symbol
*sym
= ms
->sym
;
358 struct annotation
*notes
= symbol__annotation(sym
);
359 struct disasm_line
*pos
, *next
;
360 s64 len
= symbol__size(sym
);
362 browser
->entries
= RB_ROOT
;
364 pthread_mutex_lock(¬es
->lock
);
366 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
367 struct browser_disasm_line
*bpos
= disasm_line__browser(pos
);
368 const char *path
= NULL
;
369 double max_percent
= 0.0;
372 if (pos
->offset
== -1) {
373 RB_CLEAR_NODE(&bpos
->rb_node
);
377 next
= disasm__get_next_ip_line(¬es
->src
->source
, pos
);
379 for (i
= 0; i
< browser
->nr_events
; i
++) {
382 bpos
->samples
[i
].percent
= disasm__calc_percent(notes
,
385 next
? next
->offset
: len
,
387 bpos
->samples
[i
].nr
= nr_samples
;
389 if (max_percent
< bpos
->samples
[i
].percent
)
390 max_percent
= bpos
->samples
[i
].percent
;
393 if (max_percent
< 0.01) {
394 RB_CLEAR_NODE(&bpos
->rb_node
);
397 disasm_rb_tree__insert(&browser
->entries
, bpos
,
400 pthread_mutex_unlock(¬es
->lock
);
402 browser
->curr_hot
= rb_last(&browser
->entries
);
405 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
407 struct disasm_line
*dl
;
408 struct browser_disasm_line
*bdl
;
409 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
411 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
412 dl
= list_entry(browser
->b
.top
, struct disasm_line
, node
);
413 bdl
= disasm_line__browser(dl
);
415 if (annotate_browser__opts
.hide_src_code
) {
416 if (bdl
->idx_asm
< offset
)
419 browser
->b
.nr_entries
= browser
->nr_entries
;
420 annotate_browser__opts
.hide_src_code
= false;
421 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
422 browser
->b
.top_idx
= bdl
->idx
- offset
;
423 browser
->b
.index
= bdl
->idx
;
425 if (bdl
->idx_asm
< 0) {
426 ui_helpline__puts("Only available for assembly lines.");
427 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
431 if (bdl
->idx_asm
< offset
)
432 offset
= bdl
->idx_asm
;
434 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
435 annotate_browser__opts
.hide_src_code
= true;
436 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
437 browser
->b
.top_idx
= bdl
->idx_asm
- offset
;
438 browser
->b
.index
= bdl
->idx_asm
;
444 static void annotate_browser__init_asm_mode(struct annotate_browser
*browser
)
446 ui_browser__reset_index(&browser
->b
);
447 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
450 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
452 static int sym_title(struct symbol
*sym
, struct map
*map
, char *title
,
455 return snprintf(title
, sz
, "%s %s", sym
->name
, map
->dso
->long_name
);
458 static bool annotate_browser__callq(struct annotate_browser
*browser
,
459 struct perf_evsel
*evsel
,
460 struct hist_browser_timer
*hbt
)
462 struct map_symbol
*ms
= browser
->b
.priv
;
463 struct disasm_line
*dl
= browser
->selection
;
464 struct annotation
*notes
;
465 struct addr_map_symbol target
= {
467 .addr
= map__objdump_2mem(ms
->map
, dl
->ops
.target
.addr
),
469 char title
[SYM_TITLE_MAX_SIZE
];
471 if (!ins__is_call(dl
->ins
))
474 if (map_groups__find_ams(&target
, NULL
) ||
475 map__rip_2objdump(target
.map
, target
.map
->map_ip(target
.map
,
477 dl
->ops
.target
.addr
) {
478 ui_helpline__puts("The called function was not found.");
482 notes
= symbol__annotation(target
.sym
);
483 pthread_mutex_lock(¬es
->lock
);
485 if (notes
->src
== NULL
&& symbol__alloc_hist(target
.sym
) < 0) {
486 pthread_mutex_unlock(¬es
->lock
);
487 ui__warning("Not enough memory for annotating '%s' symbol!\n",
492 pthread_mutex_unlock(¬es
->lock
);
493 symbol__tui_annotate(target
.sym
, target
.map
, evsel
, hbt
);
494 sym_title(ms
->sym
, ms
->map
, title
, sizeof(title
));
495 ui_browser__show_title(&browser
->b
, title
);
500 struct disasm_line
*annotate_browser__find_offset(struct annotate_browser
*browser
,
501 s64 offset
, s64
*idx
)
503 struct map_symbol
*ms
= browser
->b
.priv
;
504 struct symbol
*sym
= ms
->sym
;
505 struct annotation
*notes
= symbol__annotation(sym
);
506 struct disasm_line
*pos
;
509 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
510 if (pos
->offset
== offset
)
512 if (!disasm_line__filter(&browser
->b
, &pos
->node
))
519 static bool annotate_browser__jump(struct annotate_browser
*browser
)
521 struct disasm_line
*dl
= browser
->selection
;
524 if (!ins__is_jump(dl
->ins
))
527 dl
= annotate_browser__find_offset(browser
, dl
->ops
.target
.offset
, &idx
);
529 ui_helpline__puts("Invalid jump offset");
533 annotate_browser__set_top(browser
, dl
, idx
);
539 struct disasm_line
*annotate_browser__find_string(struct annotate_browser
*browser
,
542 struct map_symbol
*ms
= browser
->b
.priv
;
543 struct symbol
*sym
= ms
->sym
;
544 struct annotation
*notes
= symbol__annotation(sym
);
545 struct disasm_line
*pos
= browser
->selection
;
547 *idx
= browser
->b
.index
;
548 list_for_each_entry_continue(pos
, ¬es
->src
->source
, node
) {
549 if (disasm_line__filter(&browser
->b
, &pos
->node
))
554 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
561 static bool __annotate_browser__search(struct annotate_browser
*browser
)
563 struct disasm_line
*dl
;
566 dl
= annotate_browser__find_string(browser
, browser
->search_bf
, &idx
);
568 ui_helpline__puts("String not found!");
572 annotate_browser__set_top(browser
, dl
, idx
);
573 browser
->searching_backwards
= false;
578 struct disasm_line
*annotate_browser__find_string_reverse(struct annotate_browser
*browser
,
581 struct map_symbol
*ms
= browser
->b
.priv
;
582 struct symbol
*sym
= ms
->sym
;
583 struct annotation
*notes
= symbol__annotation(sym
);
584 struct disasm_line
*pos
= browser
->selection
;
586 *idx
= browser
->b
.index
;
587 list_for_each_entry_continue_reverse(pos
, ¬es
->src
->source
, node
) {
588 if (disasm_line__filter(&browser
->b
, &pos
->node
))
593 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
600 static bool __annotate_browser__search_reverse(struct annotate_browser
*browser
)
602 struct disasm_line
*dl
;
605 dl
= annotate_browser__find_string_reverse(browser
, browser
->search_bf
, &idx
);
607 ui_helpline__puts("String not found!");
611 annotate_browser__set_top(browser
, dl
, idx
);
612 browser
->searching_backwards
= true;
616 static bool annotate_browser__search_window(struct annotate_browser
*browser
,
619 if (ui_browser__input_window("Search", "String: ", browser
->search_bf
,
620 "ENTER: OK, ESC: Cancel",
621 delay_secs
* 2) != K_ENTER
||
622 !*browser
->search_bf
)
628 static bool annotate_browser__search(struct annotate_browser
*browser
, int delay_secs
)
630 if (annotate_browser__search_window(browser
, delay_secs
))
631 return __annotate_browser__search(browser
);
636 static bool annotate_browser__continue_search(struct annotate_browser
*browser
,
639 if (!*browser
->search_bf
)
640 return annotate_browser__search(browser
, delay_secs
);
642 return __annotate_browser__search(browser
);
645 static bool annotate_browser__search_reverse(struct annotate_browser
*browser
,
648 if (annotate_browser__search_window(browser
, delay_secs
))
649 return __annotate_browser__search_reverse(browser
);
655 bool annotate_browser__continue_search_reverse(struct annotate_browser
*browser
,
658 if (!*browser
->search_bf
)
659 return annotate_browser__search_reverse(browser
, delay_secs
);
661 return __annotate_browser__search_reverse(browser
);
664 static void annotate_browser__update_addr_width(struct annotate_browser
*browser
)
666 if (annotate_browser__opts
.use_offset
)
667 browser
->target_width
= browser
->min_addr_width
;
669 browser
->target_width
= browser
->max_addr_width
;
671 browser
->addr_width
= browser
->target_width
;
673 if (annotate_browser__opts
.show_nr_jumps
)
674 browser
->addr_width
+= browser
->jumps_width
+ 1;
677 static int annotate_browser__run(struct annotate_browser
*browser
,
678 struct perf_evsel
*evsel
,
679 struct hist_browser_timer
*hbt
)
681 struct rb_node
*nd
= NULL
;
682 struct map_symbol
*ms
= browser
->b
.priv
;
683 struct symbol
*sym
= ms
->sym
;
684 const char *help
= "Press 'h' for help on key bindings";
685 int delay_secs
= hbt
? hbt
->refresh
: 0;
687 char title
[SYM_TITLE_MAX_SIZE
];
689 sym_title(sym
, ms
->map
, title
, sizeof(title
));
690 if (ui_browser__show(&browser
->b
, title
, help
) < 0)
693 annotate_browser__calc_percent(browser
, evsel
);
695 if (browser
->curr_hot
) {
696 annotate_browser__set_rb_top(browser
, browser
->curr_hot
);
697 browser
->b
.navkeypressed
= false;
700 nd
= browser
->curr_hot
;
703 key
= ui_browser__run(&browser
->b
, delay_secs
);
705 if (delay_secs
!= 0) {
706 annotate_browser__calc_percent(browser
, evsel
);
708 * Current line focus got out of the list of most active
709 * lines, NULL it so that if TAB|UNTAB is pressed, we
710 * move to curr_hot (current hottest line).
712 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
719 hbt
->timer(hbt
->arg
);
722 symbol__annotate_decay_histogram(sym
, evsel
->idx
);
728 nd
= rb_last(&browser
->entries
);
730 nd
= browser
->curr_hot
;
736 nd
= rb_first(&browser
->entries
);
738 nd
= browser
->curr_hot
;
742 ui_browser__help_window(&browser
->b
,
744 "PGDN/SPACE Navigate\n"
745 "q/ESC/CTRL+C Exit\n\n"
748 "H Cycle thru hottest instructions\n"
749 "j Toggle showing jump to target arrows\n"
750 "J Toggle showing number of jump sources on targets\n"
751 "n Search next string\n"
752 "o Toggle disassembler output/simplified view\n"
753 "s Toggle source code view\n"
754 "t Toggle total period view\n"
756 "k Toggle line numbers\n"
757 "r Run available scripts\n"
758 "? Search string backwards\n");
766 annotate_browser__opts
.show_linenr
=
767 !annotate_browser__opts
.show_linenr
;
770 nd
= browser
->curr_hot
;
773 if (annotate_browser__toggle_source(browser
))
774 ui_helpline__puts(help
);
777 annotate_browser__opts
.use_offset
= !annotate_browser__opts
.use_offset
;
778 annotate_browser__update_addr_width(browser
);
781 annotate_browser__opts
.jump_arrows
= !annotate_browser__opts
.jump_arrows
;
784 annotate_browser__opts
.show_nr_jumps
= !annotate_browser__opts
.show_nr_jumps
;
785 annotate_browser__update_addr_width(browser
);
788 if (annotate_browser__search(browser
, delay_secs
)) {
790 ui_helpline__puts(help
);
794 if (browser
->searching_backwards
?
795 annotate_browser__continue_search_reverse(browser
, delay_secs
) :
796 annotate_browser__continue_search(browser
, delay_secs
))
800 if (annotate_browser__search_reverse(browser
, delay_secs
))
806 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
807 seq
++, browser
->b
.nr_entries
,
811 browser
->nr_asm_entries
);
816 if (browser
->selection
== NULL
)
817 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
818 else if (browser
->selection
->offset
== -1)
819 ui_helpline__puts("Actions are only available for assembly lines.");
820 else if (!browser
->selection
->ins
) {
821 if (strcmp(browser
->selection
->name
, "retq"))
824 } else if (!(annotate_browser__jump(browser
) ||
825 annotate_browser__callq(browser
, evsel
, hbt
))) {
827 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
831 annotate_browser__opts
.show_total_period
=
832 !annotate_browser__opts
.show_total_period
;
833 annotate_browser__update_addr_width(browser
);
845 annotate_browser__set_rb_top(browser
, nd
);
848 ui_browser__hide(&browser
->b
);
852 int map_symbol__tui_annotate(struct map_symbol
*ms
, struct perf_evsel
*evsel
,
853 struct hist_browser_timer
*hbt
)
855 /* Set default value for show_total_period. */
856 annotate_browser__opts
.show_total_period
=
857 symbol_conf
.show_total_period
;
859 return symbol__tui_annotate(ms
->sym
, ms
->map
, evsel
, hbt
);
862 int hist_entry__tui_annotate(struct hist_entry
*he
, struct perf_evsel
*evsel
,
863 struct hist_browser_timer
*hbt
)
865 /* reset abort key so that it can get Ctrl-C as a key */
867 SLang_init_tty(0, 0, 0);
869 return map_symbol__tui_annotate(&he
->ms
, evsel
, hbt
);
872 static void annotate_browser__mark_jump_targets(struct annotate_browser
*browser
,
876 struct map_symbol
*ms
= browser
->b
.priv
;
877 struct symbol
*sym
= ms
->sym
;
879 /* PLT symbols contain external offsets */
880 if (strstr(sym
->name
, "@plt"))
883 for (offset
= 0; offset
< size
; ++offset
) {
884 struct disasm_line
*dl
= browser
->offsets
[offset
], *dlt
;
885 struct browser_disasm_line
*bdlt
;
887 if (!disasm_line__is_valid_jump(dl
, sym
))
890 dlt
= browser
->offsets
[dl
->ops
.target
.offset
];
892 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
893 * have to adjust to the previous offset?
898 bdlt
= disasm_line__browser(dlt
);
899 if (++bdlt
->jump_sources
> browser
->max_jump_sources
)
900 browser
->max_jump_sources
= bdlt
->jump_sources
;
906 static inline int width_jumps(int n
)
915 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
,
916 struct perf_evsel
*evsel
,
917 struct hist_browser_timer
*hbt
)
919 struct disasm_line
*pos
, *n
;
920 struct annotation
*notes
;
922 struct map_symbol ms
= {
926 struct annotate_browser browser
= {
928 .refresh
= annotate_browser__refresh
,
929 .seek
= ui_browser__list_head_seek
,
930 .write
= annotate_browser__write
,
931 .filter
= disasm_line__filter
,
933 .use_navkeypressed
= true,
938 size_t sizeof_bdl
= sizeof(struct browser_disasm_line
);
943 size
= symbol__size(sym
);
945 if (map
->dso
->annotate_warned
)
948 browser
.offsets
= zalloc(size
* sizeof(struct disasm_line
*));
949 if (browser
.offsets
== NULL
) {
950 ui__error("Not enough memory!");
954 if (perf_evsel__is_group_event(evsel
)) {
955 nr_pcnt
= evsel
->nr_members
;
956 sizeof_bdl
+= sizeof(struct disasm_line_samples
) *
960 if (symbol__annotate(sym
, map
, sizeof_bdl
) < 0) {
961 ui__error("%s", ui_helpline__last_msg
);
962 goto out_free_offsets
;
965 ui_helpline__push("Press <- or ESC to exit");
967 notes
= symbol__annotation(sym
);
968 browser
.start
= map__rip_2objdump(map
, sym
->start
);
970 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
971 struct browser_disasm_line
*bpos
;
972 size_t line_len
= strlen(pos
->line
);
974 if (browser
.b
.width
< line_len
)
975 browser
.b
.width
= line_len
;
976 bpos
= disasm_line__browser(pos
);
977 bpos
->idx
= browser
.nr_entries
++;
978 if (pos
->offset
!= -1) {
979 bpos
->idx_asm
= browser
.nr_asm_entries
++;
981 * FIXME: short term bandaid to cope with assembly
982 * routines that comes with labels in the same column
983 * as the address in objdump, sigh.
985 * E.g. copy_user_generic_unrolled
987 if (pos
->offset
< (s64
)size
)
988 browser
.offsets
[pos
->offset
] = pos
;
993 annotate_browser__mark_jump_targets(&browser
, size
);
995 browser
.addr_width
= browser
.target_width
= browser
.min_addr_width
= hex_width(size
);
996 browser
.max_addr_width
= hex_width(sym
->end
);
997 browser
.jumps_width
= width_jumps(browser
.max_jump_sources
);
998 browser
.nr_events
= nr_pcnt
;
999 browser
.b
.nr_entries
= browser
.nr_entries
;
1000 browser
.b
.entries
= ¬es
->src
->source
,
1001 browser
.b
.width
+= 18; /* Percentage */
1003 if (annotate_browser__opts
.hide_src_code
)
1004 annotate_browser__init_asm_mode(&browser
);
1006 annotate_browser__update_addr_width(&browser
);
1008 ret
= annotate_browser__run(&browser
, evsel
, hbt
);
1009 list_for_each_entry_safe(pos
, n
, ¬es
->src
->source
, node
) {
1010 list_del(&pos
->node
);
1011 disasm_line__free(pos
);
1015 free(browser
.offsets
);
1019 #define ANNOTATE_CFG(n) \
1020 { .name = #n, .value = &annotate_browser__opts.n, }
1023 * Keep the entries sorted, they are bsearch'ed
1025 static struct annotate_config
{
1028 } annotate__configs
[] = {
1029 ANNOTATE_CFG(hide_src_code
),
1030 ANNOTATE_CFG(jump_arrows
),
1031 ANNOTATE_CFG(show_linenr
),
1032 ANNOTATE_CFG(show_nr_jumps
),
1033 ANNOTATE_CFG(use_offset
),
1034 ANNOTATE_CFG(show_total_period
),
1039 static int annotate_config__cmp(const void *name
, const void *cfgp
)
1041 const struct annotate_config
*cfg
= cfgp
;
1043 return strcmp(name
, cfg
->name
);
1046 static int annotate__config(const char *var
, const char *value
,
1047 void *data __maybe_unused
)
1049 struct annotate_config
*cfg
;
1052 if (prefixcmp(var
, "annotate.") != 0)
1056 cfg
= bsearch(name
, annotate__configs
, ARRAY_SIZE(annotate__configs
),
1057 sizeof(struct annotate_config
), annotate_config__cmp
);
1062 *cfg
->value
= perf_config_bool(name
, value
);
1066 void annotate_browser__init(void)
1068 perf_config(annotate__config
, NULL
);