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 browser_disasm_line
{
15 struct rb_node rb_node
;
20 * actual length of this array is saved on the nr_events field
21 * of the struct annotate_browser
26 static struct annotate_browser_opt
{
32 } annotate_browser__opts
= {
37 struct annotate_browser
{
39 struct rb_root entries
;
40 struct rb_node
*curr_hot
;
41 struct disasm_line
*selection
;
42 struct disasm_line
**offsets
;
49 bool searching_backwards
;
58 static inline struct browser_disasm_line
*disasm_line__browser(struct disasm_line
*dl
)
60 return (struct browser_disasm_line
*)(dl
+ 1);
63 static bool disasm_line__filter(struct ui_browser
*browser __maybe_unused
,
66 if (annotate_browser__opts
.hide_src_code
) {
67 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
68 return dl
->offset
== -1;
74 static int annotate_browser__jumps_percent_color(struct annotate_browser
*browser
,
77 if (current
&& (!browser
->b
.use_navkeypressed
|| browser
->b
.navkeypressed
))
78 return HE_COLORSET_SELECTED
;
79 if (nr
== browser
->max_jump_sources
)
80 return HE_COLORSET_TOP
;
82 return HE_COLORSET_MEDIUM
;
83 return HE_COLORSET_NORMAL
;
86 static int annotate_browser__set_jumps_percent_color(struct annotate_browser
*browser
,
89 int color
= annotate_browser__jumps_percent_color(browser
, nr
, current
);
90 return ui_browser__set_color(&browser
->b
, color
);
93 static void annotate_browser__write(struct ui_browser
*browser
, void *entry
, int row
)
95 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
96 struct disasm_line
*dl
= list_entry(entry
, struct disasm_line
, node
);
97 struct browser_disasm_line
*bdl
= disasm_line__browser(dl
);
98 bool current_entry
= ui_browser__is_current_entry(browser
, row
);
99 bool change_color
= (!annotate_browser__opts
.hide_src_code
&&
100 (!current_entry
|| (browser
->use_navkeypressed
&&
101 !browser
->navkeypressed
)));
102 int width
= browser
->width
, printed
;
103 int i
, pcnt_width
= 7 * ab
->nr_events
;
104 double percent_max
= 0.0;
107 for (i
= 0; i
< ab
->nr_events
; i
++) {
108 if (bdl
->percent
[i
] > percent_max
)
109 percent_max
= bdl
->percent
[i
];
112 if (dl
->offset
!= -1 && percent_max
!= 0.0) {
113 for (i
= 0; i
< ab
->nr_events
; i
++) {
114 ui_browser__set_percent_color(browser
, bdl
->percent
[i
],
116 slsmg_printf("%6.2f ", bdl
->percent
[i
]);
119 ui_browser__set_percent_color(browser
, 0, current_entry
);
120 slsmg_write_nstring(" ", pcnt_width
);
123 SLsmg_write_char(' ');
125 /* The scroll bar isn't being used */
126 if (!browser
->navkeypressed
)
130 slsmg_write_nstring(" ", width
- pcnt_width
);
131 else if (dl
->offset
== -1) {
132 if (dl
->line_nr
&& annotate_browser__opts
.show_linenr
)
133 printed
= scnprintf(bf
, sizeof(bf
), "%-*d ",
134 ab
->addr_width
+ 1, dl
->line_nr
);
136 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
137 ab
->addr_width
, " ");
138 slsmg_write_nstring(bf
, printed
);
139 slsmg_write_nstring(dl
->line
, width
- printed
- pcnt_width
+ 1);
141 u64 addr
= dl
->offset
;
144 if (!annotate_browser__opts
.use_offset
)
147 if (!annotate_browser__opts
.use_offset
) {
148 printed
= scnprintf(bf
, sizeof(bf
), "%" PRIx64
": ", addr
);
150 if (bdl
->jump_sources
) {
151 if (annotate_browser__opts
.show_nr_jumps
) {
153 printed
= scnprintf(bf
, sizeof(bf
), "%*d ",
156 prev
= annotate_browser__set_jumps_percent_color(ab
, bdl
->jump_sources
,
158 slsmg_write_nstring(bf
, printed
);
159 ui_browser__set_color(browser
, prev
);
162 printed
= scnprintf(bf
, sizeof(bf
), "%*" PRIx64
": ",
163 ab
->target_width
, addr
);
165 printed
= scnprintf(bf
, sizeof(bf
), "%*s ",
166 ab
->addr_width
, " ");
171 color
= ui_browser__set_color(browser
, HE_COLORSET_ADDR
);
172 slsmg_write_nstring(bf
, printed
);
174 ui_browser__set_color(browser
, color
);
175 if (dl
->ins
&& dl
->ins
->ops
->scnprintf
) {
176 if (ins__is_jump(dl
->ins
)) {
177 bool fwd
= dl
->ops
.target
.offset
> (u64
)dl
->offset
;
179 ui_browser__write_graph(browser
, fwd
? SLSMG_DARROW_CHAR
:
181 SLsmg_write_char(' ');
182 } else if (ins__is_call(dl
->ins
)) {
183 ui_browser__write_graph(browser
, SLSMG_RARROW_CHAR
);
184 SLsmg_write_char(' ');
186 slsmg_write_nstring(" ", 2);
189 if (strcmp(dl
->name
, "retq")) {
190 slsmg_write_nstring(" ", 2);
192 ui_browser__write_graph(browser
, SLSMG_LARROW_CHAR
);
193 SLsmg_write_char(' ');
197 disasm_line__scnprintf(dl
, bf
, sizeof(bf
), !annotate_browser__opts
.use_offset
);
198 slsmg_write_nstring(bf
, width
- pcnt_width
- 3 - printed
);
205 static bool disasm_line__is_valid_jump(struct disasm_line
*dl
, struct symbol
*sym
)
207 if (!dl
|| !dl
->ins
|| !ins__is_jump(dl
->ins
)
208 || !disasm_line__has_offset(dl
)
209 || dl
->ops
.target
.offset
>= symbol__size(sym
))
215 static void annotate_browser__draw_current_jump(struct ui_browser
*browser
)
217 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
218 struct disasm_line
*cursor
= ab
->selection
, *target
;
219 struct browser_disasm_line
*btarget
, *bcursor
;
220 unsigned int from
, to
;
221 struct map_symbol
*ms
= ab
->b
.priv
;
222 struct symbol
*sym
= ms
->sym
;
225 /* PLT symbols contain external offsets */
226 if (strstr(sym
->name
, "@plt"))
229 if (!disasm_line__is_valid_jump(cursor
, sym
))
232 target
= ab
->offsets
[cursor
->ops
.target
.offset
];
236 bcursor
= disasm_line__browser(cursor
);
237 btarget
= disasm_line__browser(target
);
239 if (annotate_browser__opts
.hide_src_code
) {
240 from
= bcursor
->idx_asm
;
241 to
= btarget
->idx_asm
;
243 from
= (u64
)bcursor
->idx
;
244 to
= (u64
)btarget
->idx
;
247 pcnt_width
*= ab
->nr_events
;
249 ui_browser__set_color(browser
, HE_COLORSET_CODE
);
250 __ui_browser__line_arrow(browser
, pcnt_width
+ 2 + ab
->addr_width
,
254 static unsigned int annotate_browser__refresh(struct ui_browser
*browser
)
256 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
257 int ret
= ui_browser__list_head_refresh(browser
);
260 pcnt_width
= 7 * ab
->nr_events
;
262 if (annotate_browser__opts
.jump_arrows
)
263 annotate_browser__draw_current_jump(browser
);
265 ui_browser__set_color(browser
, HE_COLORSET_NORMAL
);
266 __ui_browser__vline(browser
, pcnt_width
, 0, browser
->height
- 1);
270 static int disasm__cmp(struct browser_disasm_line
*a
,
271 struct browser_disasm_line
*b
, int nr_pcnt
)
275 for (i
= 0; i
< nr_pcnt
; i
++) {
276 if (a
->percent
[i
] == b
->percent
[i
])
278 return a
->percent
[i
] < b
->percent
[i
];
283 static void disasm_rb_tree__insert(struct rb_root
*root
, struct browser_disasm_line
*bdl
,
286 struct rb_node
**p
= &root
->rb_node
;
287 struct rb_node
*parent
= NULL
;
288 struct browser_disasm_line
*l
;
292 l
= rb_entry(parent
, struct browser_disasm_line
, rb_node
);
294 if (disasm__cmp(bdl
, l
, nr_events
))
299 rb_link_node(&bdl
->rb_node
, parent
, p
);
300 rb_insert_color(&bdl
->rb_node
, root
);
303 static void annotate_browser__set_top(struct annotate_browser
*browser
,
304 struct disasm_line
*pos
, u32 idx
)
308 ui_browser__refresh_dimensions(&browser
->b
);
309 back
= browser
->b
.height
/ 2;
310 browser
->b
.top_idx
= browser
->b
.index
= idx
;
312 while (browser
->b
.top_idx
!= 0 && back
!= 0) {
313 pos
= list_entry(pos
->node
.prev
, struct disasm_line
, node
);
315 if (disasm_line__filter(&browser
->b
, &pos
->node
))
318 --browser
->b
.top_idx
;
322 browser
->b
.top
= pos
;
323 browser
->b
.navkeypressed
= true;
326 static void annotate_browser__set_rb_top(struct annotate_browser
*browser
,
329 struct browser_disasm_line
*bpos
;
330 struct disasm_line
*pos
;
333 bpos
= rb_entry(nd
, struct browser_disasm_line
, rb_node
);
334 pos
= ((struct disasm_line
*)bpos
) - 1;
336 if (annotate_browser__opts
.hide_src_code
)
338 annotate_browser__set_top(browser
, pos
, idx
);
339 browser
->curr_hot
= nd
;
342 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
343 struct perf_evsel
*evsel
)
345 struct map_symbol
*ms
= browser
->b
.priv
;
346 struct symbol
*sym
= ms
->sym
;
347 struct annotation
*notes
= symbol__annotation(sym
);
348 struct disasm_line
*pos
, *next
;
349 s64 len
= symbol__size(sym
);
351 browser
->entries
= RB_ROOT
;
353 pthread_mutex_lock(¬es
->lock
);
355 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
356 struct browser_disasm_line
*bpos
= disasm_line__browser(pos
);
357 const char *path
= NULL
;
358 double max_percent
= 0.0;
361 if (pos
->offset
== -1) {
362 RB_CLEAR_NODE(&bpos
->rb_node
);
366 next
= disasm__get_next_ip_line(¬es
->src
->source
, pos
);
368 for (i
= 0; i
< browser
->nr_events
; i
++) {
369 bpos
->percent
[i
] = disasm__calc_percent(notes
,
372 next
? next
->offset
: len
,
375 if (max_percent
< bpos
->percent
[i
])
376 max_percent
= bpos
->percent
[i
];
379 if (max_percent
< 0.01) {
380 RB_CLEAR_NODE(&bpos
->rb_node
);
383 disasm_rb_tree__insert(&browser
->entries
, bpos
,
386 pthread_mutex_unlock(¬es
->lock
);
388 browser
->curr_hot
= rb_last(&browser
->entries
);
391 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
393 struct disasm_line
*dl
;
394 struct browser_disasm_line
*bdl
;
395 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
397 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
398 dl
= list_entry(browser
->b
.top
, struct disasm_line
, node
);
399 bdl
= disasm_line__browser(dl
);
401 if (annotate_browser__opts
.hide_src_code
) {
402 if (bdl
->idx_asm
< offset
)
405 browser
->b
.nr_entries
= browser
->nr_entries
;
406 annotate_browser__opts
.hide_src_code
= false;
407 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
408 browser
->b
.top_idx
= bdl
->idx
- offset
;
409 browser
->b
.index
= bdl
->idx
;
411 if (bdl
->idx_asm
< 0) {
412 ui_helpline__puts("Only available for assembly lines.");
413 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
417 if (bdl
->idx_asm
< offset
)
418 offset
= bdl
->idx_asm
;
420 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
421 annotate_browser__opts
.hide_src_code
= true;
422 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
423 browser
->b
.top_idx
= bdl
->idx_asm
- offset
;
424 browser
->b
.index
= bdl
->idx_asm
;
430 static void annotate_browser__init_asm_mode(struct annotate_browser
*browser
)
432 ui_browser__reset_index(&browser
->b
);
433 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
436 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
438 static int sym_title(struct symbol
*sym
, struct map
*map
, char *title
,
441 return snprintf(title
, sz
, "%s %s", sym
->name
, map
->dso
->long_name
);
444 static bool annotate_browser__callq(struct annotate_browser
*browser
,
445 struct perf_evsel
*evsel
,
446 struct hist_browser_timer
*hbt
)
448 struct map_symbol
*ms
= browser
->b
.priv
;
449 struct disasm_line
*dl
= browser
->selection
;
450 struct annotation
*notes
;
451 struct addr_map_symbol target
= {
453 .addr
= map__objdump_2mem(ms
->map
, dl
->ops
.target
.addr
),
455 char title
[SYM_TITLE_MAX_SIZE
];
457 if (!ins__is_call(dl
->ins
))
460 if (map_groups__find_ams(&target
, NULL
) ||
461 map__rip_2objdump(target
.map
, target
.map
->map_ip(target
.map
,
463 dl
->ops
.target
.addr
) {
464 ui_helpline__puts("The called function was not found.");
468 notes
= symbol__annotation(target
.sym
);
469 pthread_mutex_lock(¬es
->lock
);
471 if (notes
->src
== NULL
&& symbol__alloc_hist(target
.sym
) < 0) {
472 pthread_mutex_unlock(¬es
->lock
);
473 ui__warning("Not enough memory for annotating '%s' symbol!\n",
478 pthread_mutex_unlock(¬es
->lock
);
479 symbol__tui_annotate(target
.sym
, target
.map
, evsel
, hbt
);
480 sym_title(ms
->sym
, ms
->map
, title
, sizeof(title
));
481 ui_browser__show_title(&browser
->b
, title
);
486 struct disasm_line
*annotate_browser__find_offset(struct annotate_browser
*browser
,
487 s64 offset
, s64
*idx
)
489 struct map_symbol
*ms
= browser
->b
.priv
;
490 struct symbol
*sym
= ms
->sym
;
491 struct annotation
*notes
= symbol__annotation(sym
);
492 struct disasm_line
*pos
;
495 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
496 if (pos
->offset
== offset
)
498 if (!disasm_line__filter(&browser
->b
, &pos
->node
))
505 static bool annotate_browser__jump(struct annotate_browser
*browser
)
507 struct disasm_line
*dl
= browser
->selection
;
510 if (!ins__is_jump(dl
->ins
))
513 dl
= annotate_browser__find_offset(browser
, dl
->ops
.target
.offset
, &idx
);
515 ui_helpline__puts("Invalid jump offset");
519 annotate_browser__set_top(browser
, dl
, idx
);
525 struct disasm_line
*annotate_browser__find_string(struct annotate_browser
*browser
,
528 struct map_symbol
*ms
= browser
->b
.priv
;
529 struct symbol
*sym
= ms
->sym
;
530 struct annotation
*notes
= symbol__annotation(sym
);
531 struct disasm_line
*pos
= browser
->selection
;
533 *idx
= browser
->b
.index
;
534 list_for_each_entry_continue(pos
, ¬es
->src
->source
, node
) {
535 if (disasm_line__filter(&browser
->b
, &pos
->node
))
540 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
547 static bool __annotate_browser__search(struct annotate_browser
*browser
)
549 struct disasm_line
*dl
;
552 dl
= annotate_browser__find_string(browser
, browser
->search_bf
, &idx
);
554 ui_helpline__puts("String not found!");
558 annotate_browser__set_top(browser
, dl
, idx
);
559 browser
->searching_backwards
= false;
564 struct disasm_line
*annotate_browser__find_string_reverse(struct annotate_browser
*browser
,
567 struct map_symbol
*ms
= browser
->b
.priv
;
568 struct symbol
*sym
= ms
->sym
;
569 struct annotation
*notes
= symbol__annotation(sym
);
570 struct disasm_line
*pos
= browser
->selection
;
572 *idx
= browser
->b
.index
;
573 list_for_each_entry_continue_reverse(pos
, ¬es
->src
->source
, node
) {
574 if (disasm_line__filter(&browser
->b
, &pos
->node
))
579 if (pos
->line
&& strstr(pos
->line
, s
) != NULL
)
586 static bool __annotate_browser__search_reverse(struct annotate_browser
*browser
)
588 struct disasm_line
*dl
;
591 dl
= annotate_browser__find_string_reverse(browser
, browser
->search_bf
, &idx
);
593 ui_helpline__puts("String not found!");
597 annotate_browser__set_top(browser
, dl
, idx
);
598 browser
->searching_backwards
= true;
602 static bool annotate_browser__search_window(struct annotate_browser
*browser
,
605 if (ui_browser__input_window("Search", "String: ", browser
->search_bf
,
606 "ENTER: OK, ESC: Cancel",
607 delay_secs
* 2) != K_ENTER
||
608 !*browser
->search_bf
)
614 static bool annotate_browser__search(struct annotate_browser
*browser
, int delay_secs
)
616 if (annotate_browser__search_window(browser
, delay_secs
))
617 return __annotate_browser__search(browser
);
622 static bool annotate_browser__continue_search(struct annotate_browser
*browser
,
625 if (!*browser
->search_bf
)
626 return annotate_browser__search(browser
, delay_secs
);
628 return __annotate_browser__search(browser
);
631 static bool annotate_browser__search_reverse(struct annotate_browser
*browser
,
634 if (annotate_browser__search_window(browser
, delay_secs
))
635 return __annotate_browser__search_reverse(browser
);
641 bool annotate_browser__continue_search_reverse(struct annotate_browser
*browser
,
644 if (!*browser
->search_bf
)
645 return annotate_browser__search_reverse(browser
, delay_secs
);
647 return __annotate_browser__search_reverse(browser
);
650 static void annotate_browser__update_addr_width(struct annotate_browser
*browser
)
652 if (annotate_browser__opts
.use_offset
)
653 browser
->target_width
= browser
->min_addr_width
;
655 browser
->target_width
= browser
->max_addr_width
;
657 browser
->addr_width
= browser
->target_width
;
659 if (annotate_browser__opts
.show_nr_jumps
)
660 browser
->addr_width
+= browser
->jumps_width
+ 1;
663 static int annotate_browser__run(struct annotate_browser
*browser
,
664 struct perf_evsel
*evsel
,
665 struct hist_browser_timer
*hbt
)
667 struct rb_node
*nd
= NULL
;
668 struct map_symbol
*ms
= browser
->b
.priv
;
669 struct symbol
*sym
= ms
->sym
;
670 const char *help
= "Press 'h' for help on key bindings";
671 int delay_secs
= hbt
? hbt
->refresh
: 0;
673 char title
[SYM_TITLE_MAX_SIZE
];
675 sym_title(sym
, ms
->map
, title
, sizeof(title
));
676 if (ui_browser__show(&browser
->b
, title
, help
) < 0)
679 annotate_browser__calc_percent(browser
, evsel
);
681 if (browser
->curr_hot
) {
682 annotate_browser__set_rb_top(browser
, browser
->curr_hot
);
683 browser
->b
.navkeypressed
= false;
686 nd
= browser
->curr_hot
;
689 key
= ui_browser__run(&browser
->b
, delay_secs
);
691 if (delay_secs
!= 0) {
692 annotate_browser__calc_percent(browser
, evsel
);
694 * Current line focus got out of the list of most active
695 * lines, NULL it so that if TAB|UNTAB is pressed, we
696 * move to curr_hot (current hottest line).
698 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
705 hbt
->timer(hbt
->arg
);
708 symbol__annotate_decay_histogram(sym
, evsel
->idx
);
714 nd
= rb_last(&browser
->entries
);
716 nd
= browser
->curr_hot
;
722 nd
= rb_first(&browser
->entries
);
724 nd
= browser
->curr_hot
;
728 ui_browser__help_window(&browser
->b
,
730 "PGDN/SPACE Navigate\n"
731 "q/ESC/CTRL+C Exit\n\n"
734 "H Cycle thru hottest instructions\n"
735 "j Toggle showing jump to target arrows\n"
736 "J Toggle showing number of jump sources on targets\n"
737 "n Search next string\n"
738 "o Toggle disassembler output/simplified view\n"
739 "s Toggle source code view\n"
741 "k Toggle line numbers\n"
742 "r Run available scripts\n"
743 "? Search string backwards\n");
751 annotate_browser__opts
.show_linenr
=
752 !annotate_browser__opts
.show_linenr
;
755 nd
= browser
->curr_hot
;
758 if (annotate_browser__toggle_source(browser
))
759 ui_helpline__puts(help
);
762 annotate_browser__opts
.use_offset
= !annotate_browser__opts
.use_offset
;
763 annotate_browser__update_addr_width(browser
);
766 annotate_browser__opts
.jump_arrows
= !annotate_browser__opts
.jump_arrows
;
769 annotate_browser__opts
.show_nr_jumps
= !annotate_browser__opts
.show_nr_jumps
;
770 annotate_browser__update_addr_width(browser
);
773 if (annotate_browser__search(browser
, delay_secs
)) {
775 ui_helpline__puts(help
);
779 if (browser
->searching_backwards
?
780 annotate_browser__continue_search_reverse(browser
, delay_secs
) :
781 annotate_browser__continue_search(browser
, delay_secs
))
785 if (annotate_browser__search_reverse(browser
, delay_secs
))
791 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
792 seq
++, browser
->b
.nr_entries
,
796 browser
->nr_asm_entries
);
801 if (browser
->selection
== NULL
)
802 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
803 else if (browser
->selection
->offset
== -1)
804 ui_helpline__puts("Actions are only available for assembly lines.");
805 else if (!browser
->selection
->ins
) {
806 if (strcmp(browser
->selection
->name
, "retq"))
809 } else if (!(annotate_browser__jump(browser
) ||
810 annotate_browser__callq(browser
, evsel
, hbt
))) {
812 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
825 annotate_browser__set_rb_top(browser
, nd
);
828 ui_browser__hide(&browser
->b
);
832 int hist_entry__tui_annotate(struct hist_entry
*he
, struct perf_evsel
*evsel
,
833 struct hist_browser_timer
*hbt
)
835 return symbol__tui_annotate(he
->ms
.sym
, he
->ms
.map
, evsel
, hbt
);
838 static void annotate_browser__mark_jump_targets(struct annotate_browser
*browser
,
842 struct map_symbol
*ms
= browser
->b
.priv
;
843 struct symbol
*sym
= ms
->sym
;
845 /* PLT symbols contain external offsets */
846 if (strstr(sym
->name
, "@plt"))
849 for (offset
= 0; offset
< size
; ++offset
) {
850 struct disasm_line
*dl
= browser
->offsets
[offset
], *dlt
;
851 struct browser_disasm_line
*bdlt
;
853 if (!disasm_line__is_valid_jump(dl
, sym
))
856 dlt
= browser
->offsets
[dl
->ops
.target
.offset
];
858 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
859 * have to adjust to the previous offset?
864 bdlt
= disasm_line__browser(dlt
);
865 if (++bdlt
->jump_sources
> browser
->max_jump_sources
)
866 browser
->max_jump_sources
= bdlt
->jump_sources
;
872 static inline int width_jumps(int n
)
881 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
,
882 struct perf_evsel
*evsel
,
883 struct hist_browser_timer
*hbt
)
885 struct disasm_line
*pos
, *n
;
886 struct annotation
*notes
;
888 struct map_symbol ms
= {
892 struct annotate_browser browser
= {
894 .refresh
= annotate_browser__refresh
,
895 .seek
= ui_browser__list_head_seek
,
896 .write
= annotate_browser__write
,
897 .filter
= disasm_line__filter
,
899 .use_navkeypressed
= true,
904 size_t sizeof_bdl
= sizeof(struct browser_disasm_line
);
909 size
= symbol__size(sym
);
911 if (map
->dso
->annotate_warned
)
914 browser
.offsets
= zalloc(size
* sizeof(struct disasm_line
*));
915 if (browser
.offsets
== NULL
) {
916 ui__error("Not enough memory!");
920 if (perf_evsel__is_group_event(evsel
)) {
921 nr_pcnt
= evsel
->nr_members
;
922 sizeof_bdl
+= sizeof(double) * (nr_pcnt
- 1);
925 if (symbol__annotate(sym
, map
, sizeof_bdl
) < 0) {
926 ui__error("%s", ui_helpline__last_msg
);
927 goto out_free_offsets
;
930 ui_helpline__push("Press <- or ESC to exit");
932 notes
= symbol__annotation(sym
);
933 browser
.start
= map__rip_2objdump(map
, sym
->start
);
935 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
936 struct browser_disasm_line
*bpos
;
937 size_t line_len
= strlen(pos
->line
);
939 if (browser
.b
.width
< line_len
)
940 browser
.b
.width
= line_len
;
941 bpos
= disasm_line__browser(pos
);
942 bpos
->idx
= browser
.nr_entries
++;
943 if (pos
->offset
!= -1) {
944 bpos
->idx_asm
= browser
.nr_asm_entries
++;
946 * FIXME: short term bandaid to cope with assembly
947 * routines that comes with labels in the same column
948 * as the address in objdump, sigh.
950 * E.g. copy_user_generic_unrolled
952 if (pos
->offset
< (s64
)size
)
953 browser
.offsets
[pos
->offset
] = pos
;
958 annotate_browser__mark_jump_targets(&browser
, size
);
960 browser
.addr_width
= browser
.target_width
= browser
.min_addr_width
= hex_width(size
);
961 browser
.max_addr_width
= hex_width(sym
->end
);
962 browser
.jumps_width
= width_jumps(browser
.max_jump_sources
);
963 browser
.nr_events
= nr_pcnt
;
964 browser
.b
.nr_entries
= browser
.nr_entries
;
965 browser
.b
.entries
= ¬es
->src
->source
,
966 browser
.b
.width
+= 18; /* Percentage */
968 if (annotate_browser__opts
.hide_src_code
)
969 annotate_browser__init_asm_mode(&browser
);
971 annotate_browser__update_addr_width(&browser
);
973 ret
= annotate_browser__run(&browser
, evsel
, hbt
);
974 list_for_each_entry_safe(pos
, n
, ¬es
->src
->source
, node
) {
975 list_del(&pos
->node
);
976 disasm_line__free(pos
);
980 free(browser
.offsets
);
984 #define ANNOTATE_CFG(n) \
985 { .name = #n, .value = &annotate_browser__opts.n, }
988 * Keep the entries sorted, they are bsearch'ed
990 static struct annotate_config
{
993 } annotate__configs
[] = {
994 ANNOTATE_CFG(hide_src_code
),
995 ANNOTATE_CFG(jump_arrows
),
996 ANNOTATE_CFG(show_linenr
),
997 ANNOTATE_CFG(show_nr_jumps
),
998 ANNOTATE_CFG(use_offset
),
1003 static int annotate_config__cmp(const void *name
, const void *cfgp
)
1005 const struct annotate_config
*cfg
= cfgp
;
1007 return strcmp(name
, cfg
->name
);
1010 static int annotate__config(const char *var
, const char *value
,
1011 void *data __maybe_unused
)
1013 struct annotate_config
*cfg
;
1016 if (prefixcmp(var
, "annotate.") != 0)
1020 cfg
= bsearch(name
, annotate__configs
, ARRAY_SIZE(annotate__configs
),
1021 sizeof(struct annotate_config
), annotate_config__cmp
);
1026 *cfg
->value
= perf_config_bool(name
, value
);
1030 void annotate_browser__init(void)
1032 perf_config(annotate__config
, NULL
);