xref: /linux/tools/perf/ui/browsers/annotate.c (revision 78ce08dfbd180fb85312ee76e607a6c5fe34a06c)
1aca7a94dSNamhyung Kim #include "../../util/util.h"
2aca7a94dSNamhyung Kim #include "../browser.h"
3aca7a94dSNamhyung Kim #include "../helpline.h"
4aca7a94dSNamhyung Kim #include "../ui.h"
5aca7a94dSNamhyung Kim #include "../util.h"
6aca7a94dSNamhyung Kim #include "../../util/annotate.h"
7aca7a94dSNamhyung Kim #include "../../util/hist.h"
8aca7a94dSNamhyung Kim #include "../../util/sort.h"
9aca7a94dSNamhyung Kim #include "../../util/symbol.h"
10db8fd07aSNamhyung Kim #include "../../util/evsel.h"
11aca7a94dSNamhyung Kim #include <pthread.h>
12aca7a94dSNamhyung Kim 
130c4a5bceSMartin Liška struct disasm_line_samples {
140c4a5bceSMartin Liška 	double		percent;
150c4a5bceSMartin Liška 	u64		nr;
160c4a5bceSMartin Liška };
170c4a5bceSMartin Liška 
18f8f4aaeaSAndi Kleen #define IPC_WIDTH 6
19f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6
20f8f4aaeaSAndi Kleen 
21b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
22b793a401SArnaldo Carvalho de Melo 	struct rb_node			rb_node;
23b793a401SArnaldo Carvalho de Melo 	u32				idx;
24b793a401SArnaldo Carvalho de Melo 	int				idx_asm;
257d5b12f5SArnaldo Carvalho de Melo 	int				jump_sources;
26c7e7b610SNamhyung Kim 	/*
27c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
28c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
29c7e7b610SNamhyung Kim 	 */
300c4a5bceSMartin Liška 	struct disasm_line_samples	samples[1];
31b793a401SArnaldo Carvalho de Melo };
32b793a401SArnaldo Carvalho de Melo 
33e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
34e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
35e9823b21SArnaldo Carvalho de Melo 	     use_offset,
36e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
37e592488cSAndi Kleen 	     show_linenr,
380c4a5bceSMartin Liška 	     show_nr_jumps,
390c4a5bceSMartin Liška 	     show_total_period;
40e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
41e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
42e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
43e9823b21SArnaldo Carvalho de Melo };
44e9823b21SArnaldo Carvalho de Melo 
45aca7a94dSNamhyung Kim struct annotate_browser {
46aca7a94dSNamhyung Kim 	struct ui_browser b;
47aca7a94dSNamhyung Kim 	struct rb_root	  entries;
48aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
4929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
50b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
51c7e7b610SNamhyung Kim 	int		    nr_events;
52aca7a94dSNamhyung Kim 	u64		    start;
53aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
54aca7a94dSNamhyung Kim 	int		    nr_entries;
552402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
562402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
57aca7a94dSNamhyung Kim 	bool		    searching_backwards;
5830e863bbSAndi Kleen 	bool		    have_cycles;
5983b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
602402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
612402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
6283b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
6383b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
64aca7a94dSNamhyung Kim 	char		    search_bf[128];
65aca7a94dSNamhyung Kim };
66aca7a94dSNamhyung Kim 
67887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
68aca7a94dSNamhyung Kim {
69887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
70aca7a94dSNamhyung Kim }
71aca7a94dSNamhyung Kim 
721d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
731d037ca1SIrina Tirdea 				void *entry)
74aca7a94dSNamhyung Kim {
75e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
7629ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
7729ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
78aca7a94dSNamhyung Kim 	}
79aca7a94dSNamhyung Kim 
80aca7a94dSNamhyung Kim 	return false;
81aca7a94dSNamhyung Kim }
82aca7a94dSNamhyung Kim 
832402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
842402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
852402e4a9SArnaldo Carvalho de Melo {
862402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
872402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
882402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
892402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
902402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
912402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
922402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
932402e4a9SArnaldo Carvalho de Melo }
942402e4a9SArnaldo Carvalho de Melo 
952402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
962402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
972402e4a9SArnaldo Carvalho de Melo {
982402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
992402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1002402e4a9SArnaldo Carvalho de Melo }
1012402e4a9SArnaldo Carvalho de Melo 
102f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
103f8f4aaeaSAndi Kleen {
104f8f4aaeaSAndi Kleen 	int w = 7 * ab->nr_events;
105f8f4aaeaSAndi Kleen 
106f8f4aaeaSAndi Kleen 	if (ab->have_cycles)
107f8f4aaeaSAndi Kleen 		w += IPC_WIDTH + CYCLES_WIDTH;
108f8f4aaeaSAndi Kleen 	return w;
109f8f4aaeaSAndi Kleen }
110f8f4aaeaSAndi Kleen 
11105e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
112aca7a94dSNamhyung Kim {
11305e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
11429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
115b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
11605e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
117e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
11805e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
11905e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
12005e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
121f8f4aaeaSAndi Kleen 	int i, pcnt_width = annotate_browser__pcnt_width(ab);
122c7e7b610SNamhyung Kim 	double percent_max = 0.0;
12383b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
124aca7a94dSNamhyung Kim 
125c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1260c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1270c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
128c7e7b610SNamhyung Kim 	}
129c7e7b610SNamhyung Kim 
130c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
131f8f4aaeaSAndi Kleen 		if (percent_max != 0.0) {
132c7e7b610SNamhyung Kim 			for (i = 0; i < ab->nr_events; i++) {
1330c4a5bceSMartin Liška 				ui_browser__set_percent_color(browser,
1340c4a5bceSMartin Liška 							bdl->samples[i].percent,
135c7e7b610SNamhyung Kim 							current_entry);
136517dfdb3SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_total_period) {
137517dfdb3SArnaldo Carvalho de Melo 					ui_browser__printf(browser, "%6" PRIu64 " ",
1380c4a5bceSMartin Liška 							   bdl->samples[i].nr);
139517dfdb3SArnaldo Carvalho de Melo 				} else {
140517dfdb3SArnaldo Carvalho de Melo 					ui_browser__printf(browser, "%6.2f ",
141517dfdb3SArnaldo Carvalho de Melo 							   bdl->samples[i].percent);
142517dfdb3SArnaldo Carvalho de Melo 				}
143c7e7b610SNamhyung Kim 			}
144aca7a94dSNamhyung Kim 		} else {
14526270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
146f8f4aaeaSAndi Kleen 		}
147f8f4aaeaSAndi Kleen 	} else {
14805e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
14926270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
150f8f4aaeaSAndi Kleen 	}
151f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
152f8f4aaeaSAndi Kleen 		if (dl->ipc)
153517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
154f8f4aaeaSAndi Kleen 		else
15526270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
156f8f4aaeaSAndi Kleen 		if (dl->cycles)
157517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
158f8f4aaeaSAndi Kleen 					   CYCLES_WIDTH - 1, dl->cycles);
159f8f4aaeaSAndi Kleen 		else
16026270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
161aca7a94dSNamhyung Kim 	}
162aca7a94dSNamhyung Kim 
163cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
164aca7a94dSNamhyung Kim 
165aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
16605e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
167aca7a94dSNamhyung Kim 		width += 1;
168aca7a94dSNamhyung Kim 
16929ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
17026270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width);
17183b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
172e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
173e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
174e592488cSAndi Kleen 					ab->addr_width + 1, dl->line_nr);
175e592488cSAndi Kleen 		else
17683b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
17783b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
17826270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
17926270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
18083b1f2aaSArnaldo Carvalho de Melo 	} else {
18129ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
18283b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
183aca7a94dSNamhyung Kim 
184e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
185aca7a94dSNamhyung Kim 			addr += ab->start;
186aca7a94dSNamhyung Kim 
187e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
188aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
18961e04b33SArnaldo Carvalho de Melo 		} else {
1907d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
191e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
1922402e4a9SArnaldo Carvalho de Melo 					int prev;
1932402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
1942402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
1952402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
1962402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
1972402e4a9SArnaldo Carvalho de Melo 											 current_entry);
19826270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
19905e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2002402e4a9SArnaldo Carvalho de Melo 				}
2012402e4a9SArnaldo Carvalho de Melo 
20261e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2032402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
20461e04b33SArnaldo Carvalho de Melo 			} else {
20561e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
20683b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
20761e04b33SArnaldo Carvalho de Melo 			}
20861e04b33SArnaldo Carvalho de Melo 		}
209b793a401SArnaldo Carvalho de Melo 
210aca7a94dSNamhyung Kim 		if (change_color)
21105e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
21226270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
213aca7a94dSNamhyung Kim 		if (change_color)
21405e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
21528548d78SArnaldo Carvalho de Melo 		if (dl->ins && dl->ins->ops->scnprintf) {
21651a0d455SArnaldo Carvalho de Melo 			if (ins__is_jump(dl->ins)) {
21744d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
21851a0d455SArnaldo Carvalho de Melo 
21905e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
22051a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
22151a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
22288298f5aSArnaldo Carvalho de Melo 			} else if (ins__is_call(dl->ins)) {
22305e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
22488298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
22551a0d455SArnaldo Carvalho de Melo 			} else {
22626270a00SArnaldo Carvalho de Melo 				ui_browser__write_nstring(browser, " ", 2);
22751a0d455SArnaldo Carvalho de Melo 			}
2284ea08b52SArnaldo Carvalho de Melo 		} else {
2294ea08b52SArnaldo Carvalho de Melo 			if (strcmp(dl->name, "retq")) {
23026270a00SArnaldo Carvalho de Melo 				ui_browser__write_nstring(browser, " ", 2);
2314ea08b52SArnaldo Carvalho de Melo 			} else {
23205e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2334ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2344ea08b52SArnaldo Carvalho de Melo 			}
2354ea08b52SArnaldo Carvalho de Melo 		}
2364ea08b52SArnaldo Carvalho de Melo 
237e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
23826270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
239aca7a94dSNamhyung Kim 	}
240aca7a94dSNamhyung Kim 
241aca7a94dSNamhyung Kim 	if (current_entry)
24229ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
243aca7a94dSNamhyung Kim }
244aca7a94dSNamhyung Kim 
245865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
246865c66c4SFrederik Deweerdt {
247865c66c4SFrederik Deweerdt 	if (!dl || !dl->ins || !ins__is_jump(dl->ins)
248865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
249865c66c4SFrederik Deweerdt 	    || dl->ops.target.offset >= symbol__size(sym))
250865c66c4SFrederik Deweerdt 		return false;
251865c66c4SFrederik Deweerdt 
252865c66c4SFrederik Deweerdt 	return true;
253865c66c4SFrederik Deweerdt }
254865c66c4SFrederik Deweerdt 
2559d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
256a3f895beSArnaldo Carvalho de Melo {
257a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
2589d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
2599d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
26083b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
26132ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
26232ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
263f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
26432ae1efdSNamhyung Kim 
26532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
26632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
26732ae1efdSNamhyung Kim 		return;
268a3f895beSArnaldo Carvalho de Melo 
269865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
270a3f895beSArnaldo Carvalho de Melo 		return;
271a3f895beSArnaldo Carvalho de Melo 
2729d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
2739d1ef56dSArnaldo Carvalho de Melo 	if (!target)
2749d1ef56dSArnaldo Carvalho de Melo 		return;
2759d1ef56dSArnaldo Carvalho de Melo 
2769d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2779d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2789d1ef56dSArnaldo Carvalho de Melo 
279e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2809d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
281a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
282a3f895beSArnaldo Carvalho de Melo 	} else {
2839d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
284a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
285a3f895beSArnaldo Carvalho de Melo 	}
286a3f895beSArnaldo Carvalho de Melo 
287*78ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
288c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
289c7e7b610SNamhyung Kim 				 from, to);
290a3f895beSArnaldo Carvalho de Melo }
291a3f895beSArnaldo Carvalho de Melo 
292a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
293a3f895beSArnaldo Carvalho de Melo {
294c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
295a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
296f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
297a3f895beSArnaldo Carvalho de Melo 
298e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
2999d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
300a3f895beSArnaldo Carvalho de Melo 
30183b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
302c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
303a3f895beSArnaldo Carvalho de Melo 	return ret;
304a3f895beSArnaldo Carvalho de Melo }
305a3f895beSArnaldo Carvalho de Melo 
306c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
307c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
308c7e7b610SNamhyung Kim {
309c7e7b610SNamhyung Kim 	int i;
310c7e7b610SNamhyung Kim 
311c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3120c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
313c7e7b610SNamhyung Kim 			continue;
3140c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
315c7e7b610SNamhyung Kim 	}
316c7e7b610SNamhyung Kim 	return 0;
317c7e7b610SNamhyung Kim }
318c7e7b610SNamhyung Kim 
319c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
320c7e7b610SNamhyung Kim 				   int nr_events)
321aca7a94dSNamhyung Kim {
32229ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
323aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
324887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
325aca7a94dSNamhyung Kim 
326aca7a94dSNamhyung Kim 	while (*p != NULL) {
327aca7a94dSNamhyung Kim 		parent = *p;
328887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
329c7e7b610SNamhyung Kim 
330c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
331aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
332aca7a94dSNamhyung Kim 		else
333aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
334aca7a94dSNamhyung Kim 	}
335887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
336887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
337aca7a94dSNamhyung Kim }
338aca7a94dSNamhyung Kim 
33905e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
34029ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
341aca7a94dSNamhyung Kim {
342aca7a94dSNamhyung Kim 	unsigned back;
343aca7a94dSNamhyung Kim 
34405e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
34505e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
34605e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
347aca7a94dSNamhyung Kim 
34805e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
34929ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
350aca7a94dSNamhyung Kim 
35105e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
352aca7a94dSNamhyung Kim 			continue;
353aca7a94dSNamhyung Kim 
35405e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
355aca7a94dSNamhyung Kim 		--back;
356aca7a94dSNamhyung Kim 	}
357aca7a94dSNamhyung Kim 
35805e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
35905e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
360aca7a94dSNamhyung Kim }
361aca7a94dSNamhyung Kim 
362aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
363aca7a94dSNamhyung Kim 					 struct rb_node *nd)
364aca7a94dSNamhyung Kim {
365887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
36629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
367a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
368aca7a94dSNamhyung Kim 
369887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
370887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
371a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
372e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
373a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
374a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
375aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
376aca7a94dSNamhyung Kim }
377aca7a94dSNamhyung Kim 
378aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
379db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
380aca7a94dSNamhyung Kim {
381aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
382aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
383aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
384e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
385e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
386aca7a94dSNamhyung Kim 
387aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
388aca7a94dSNamhyung Kim 
389aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
390aca7a94dSNamhyung Kim 
391aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
392887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
393e64aa75bSNamhyung Kim 		const char *path = NULL;
394c7e7b610SNamhyung Kim 		double max_percent = 0.0;
395c7e7b610SNamhyung Kim 		int i;
396e64aa75bSNamhyung Kim 
397e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
398e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
399e64aa75bSNamhyung Kim 			continue;
400e64aa75bSNamhyung Kim 		}
401e64aa75bSNamhyung Kim 
402e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
403c7e7b610SNamhyung Kim 
404c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
4050c4a5bceSMartin Liška 			u64 nr_samples;
4060c4a5bceSMartin Liška 
4070c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
408c7e7b610SNamhyung Kim 						evsel->idx + i,
409c7e7b610SNamhyung Kim 						pos->offset,
410c7e7b610SNamhyung Kim 						next ? next->offset : len,
4110c4a5bceSMartin Liška 						&path, &nr_samples);
4120c4a5bceSMartin Liška 			bpos->samples[i].nr = nr_samples;
413e64aa75bSNamhyung Kim 
4140c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4150c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
416c7e7b610SNamhyung Kim 		}
417c7e7b610SNamhyung Kim 
41830e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
419887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
420aca7a94dSNamhyung Kim 			continue;
421aca7a94dSNamhyung Kim 		}
422c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
423c7e7b610SNamhyung Kim 				       browser->nr_events);
424aca7a94dSNamhyung Kim 	}
425aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
426aca7a94dSNamhyung Kim 
427aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
428aca7a94dSNamhyung Kim }
429aca7a94dSNamhyung Kim 
430aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
431aca7a94dSNamhyung Kim {
43229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
433887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
434aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
435aca7a94dSNamhyung Kim 
436aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
43729ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
438887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
439aca7a94dSNamhyung Kim 
440e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
441887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
442887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
443aca7a94dSNamhyung Kim 
444aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
445e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
446aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
447887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
448887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
449aca7a94dSNamhyung Kim 	} else {
450887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
451aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
452aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
453aca7a94dSNamhyung Kim 			return false;
454aca7a94dSNamhyung Kim 		}
455aca7a94dSNamhyung Kim 
456887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
457887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
458aca7a94dSNamhyung Kim 
459aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
460e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
461aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
462887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
463887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
464aca7a94dSNamhyung Kim 	}
465aca7a94dSNamhyung Kim 
466aca7a94dSNamhyung Kim 	return true;
467aca7a94dSNamhyung Kim }
468aca7a94dSNamhyung Kim 
469e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
470e9823b21SArnaldo Carvalho de Melo {
471e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
472e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
473e9823b21SArnaldo Carvalho de Melo }
474e9823b21SArnaldo Carvalho de Melo 
47534f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
47634f77abcSAdrian Hunter 
47734f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
47834f77abcSAdrian Hunter 		     size_t sz)
47934f77abcSAdrian Hunter {
48034f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
48134f77abcSAdrian Hunter }
48234f77abcSAdrian Hunter 
483db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
484db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
4859783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
486aca7a94dSNamhyung Kim {
487aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
488657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
489aca7a94dSNamhyung Kim 	struct annotation *notes;
4901179e11bSAdrian Hunter 	struct addr_map_symbol target = {
4911179e11bSAdrian Hunter 		.map = ms->map,
4921d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
4931179e11bSAdrian Hunter 	};
49434f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
495aca7a94dSNamhyung Kim 
496d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_call(dl->ins))
497aca7a94dSNamhyung Kim 		return false;
498aca7a94dSNamhyung Kim 
4991d5077bdSAdrian Hunter 	if (map_groups__find_ams(&target, NULL) ||
5001d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5011d5077bdSAdrian Hunter 							     target.addr)) !=
5021d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
503aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
504aca7a94dSNamhyung Kim 		return true;
505aca7a94dSNamhyung Kim 	}
506aca7a94dSNamhyung Kim 
5071179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
508aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
509aca7a94dSNamhyung Kim 
5101179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
511aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
512aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5131179e11bSAdrian Hunter 			    target.sym->name);
514aca7a94dSNamhyung Kim 		return true;
515aca7a94dSNamhyung Kim 	}
516aca7a94dSNamhyung Kim 
517aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5181179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5191179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
52034f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
521aca7a94dSNamhyung Kim 	return true;
522aca7a94dSNamhyung Kim }
523aca7a94dSNamhyung Kim 
52429ed6e76SArnaldo Carvalho de Melo static
52529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
526aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
527aca7a94dSNamhyung Kim {
528aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
529aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
530aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
53129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
532aca7a94dSNamhyung Kim 
533aca7a94dSNamhyung Kim 	*idx = 0;
534aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
535aca7a94dSNamhyung Kim 		if (pos->offset == offset)
536aca7a94dSNamhyung Kim 			return pos;
53729ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
538aca7a94dSNamhyung Kim 			++*idx;
539aca7a94dSNamhyung Kim 	}
540aca7a94dSNamhyung Kim 
541aca7a94dSNamhyung Kim 	return NULL;
542aca7a94dSNamhyung Kim }
543aca7a94dSNamhyung Kim 
544aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
545aca7a94dSNamhyung Kim {
546657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
5474f9d0325SArnaldo Carvalho de Melo 	s64 idx;
548aca7a94dSNamhyung Kim 
549d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_jump(dl->ins))
550aca7a94dSNamhyung Kim 		return false;
551aca7a94dSNamhyung Kim 
55244d1a3edSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
55329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
554e6f65388SIngo Molnar 		ui_helpline__puts("Invalid jump offset");
555aca7a94dSNamhyung Kim 		return true;
556aca7a94dSNamhyung Kim 	}
557aca7a94dSNamhyung Kim 
55829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
559aca7a94dSNamhyung Kim 
560aca7a94dSNamhyung Kim 	return true;
561aca7a94dSNamhyung Kim }
562aca7a94dSNamhyung Kim 
56329ed6e76SArnaldo Carvalho de Melo static
56429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
565aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
566aca7a94dSNamhyung Kim {
567aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
568aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
569aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
57029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
571aca7a94dSNamhyung Kim 
572aca7a94dSNamhyung Kim 	*idx = browser->b.index;
573aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
57429ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
575aca7a94dSNamhyung Kim 			continue;
576aca7a94dSNamhyung Kim 
577aca7a94dSNamhyung Kim 		++*idx;
578aca7a94dSNamhyung Kim 
579aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
580aca7a94dSNamhyung Kim 			return pos;
581aca7a94dSNamhyung Kim 	}
582aca7a94dSNamhyung Kim 
583aca7a94dSNamhyung Kim 	return NULL;
584aca7a94dSNamhyung Kim }
585aca7a94dSNamhyung Kim 
586aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
587aca7a94dSNamhyung Kim {
58829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
589aca7a94dSNamhyung Kim 	s64 idx;
590aca7a94dSNamhyung Kim 
59129ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
59229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
593aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
594aca7a94dSNamhyung Kim 		return false;
595aca7a94dSNamhyung Kim 	}
596aca7a94dSNamhyung Kim 
59729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
598aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
599aca7a94dSNamhyung Kim 	return true;
600aca7a94dSNamhyung Kim }
601aca7a94dSNamhyung Kim 
60229ed6e76SArnaldo Carvalho de Melo static
60329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
604aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
605aca7a94dSNamhyung Kim {
606aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
607aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
608aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
60929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
610aca7a94dSNamhyung Kim 
611aca7a94dSNamhyung Kim 	*idx = browser->b.index;
612aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
61329ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
614aca7a94dSNamhyung Kim 			continue;
615aca7a94dSNamhyung Kim 
616aca7a94dSNamhyung Kim 		--*idx;
617aca7a94dSNamhyung Kim 
618aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
619aca7a94dSNamhyung Kim 			return pos;
620aca7a94dSNamhyung Kim 	}
621aca7a94dSNamhyung Kim 
622aca7a94dSNamhyung Kim 	return NULL;
623aca7a94dSNamhyung Kim }
624aca7a94dSNamhyung Kim 
625aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
626aca7a94dSNamhyung Kim {
62729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
628aca7a94dSNamhyung Kim 	s64 idx;
629aca7a94dSNamhyung Kim 
63029ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
63129ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
632aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
633aca7a94dSNamhyung Kim 		return false;
634aca7a94dSNamhyung Kim 	}
635aca7a94dSNamhyung Kim 
63629ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
637aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
638aca7a94dSNamhyung Kim 	return true;
639aca7a94dSNamhyung Kim }
640aca7a94dSNamhyung Kim 
641aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
642aca7a94dSNamhyung Kim 					    int delay_secs)
643aca7a94dSNamhyung Kim {
644aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
645aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
646aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
647aca7a94dSNamhyung Kim 	    !*browser->search_bf)
648aca7a94dSNamhyung Kim 		return false;
649aca7a94dSNamhyung Kim 
650aca7a94dSNamhyung Kim 	return true;
651aca7a94dSNamhyung Kim }
652aca7a94dSNamhyung Kim 
653aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
654aca7a94dSNamhyung Kim {
655aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
656aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
657aca7a94dSNamhyung Kim 
658aca7a94dSNamhyung Kim 	return false;
659aca7a94dSNamhyung Kim }
660aca7a94dSNamhyung Kim 
661aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
662aca7a94dSNamhyung Kim 					      int delay_secs)
663aca7a94dSNamhyung Kim {
664aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
665aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
666aca7a94dSNamhyung Kim 
667aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
668aca7a94dSNamhyung Kim }
669aca7a94dSNamhyung Kim 
670aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
671aca7a94dSNamhyung Kim 					   int delay_secs)
672aca7a94dSNamhyung Kim {
673aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
674aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
675aca7a94dSNamhyung Kim 
676aca7a94dSNamhyung Kim 	return false;
677aca7a94dSNamhyung Kim }
678aca7a94dSNamhyung Kim 
679aca7a94dSNamhyung Kim static
680aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
681aca7a94dSNamhyung Kim 					       int delay_secs)
682aca7a94dSNamhyung Kim {
683aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
684aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
685aca7a94dSNamhyung Kim 
686aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
687aca7a94dSNamhyung Kim }
688aca7a94dSNamhyung Kim 
689e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
690e9823b21SArnaldo Carvalho de Melo {
691e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
692e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
693e9823b21SArnaldo Carvalho de Melo 	else
694e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
695e9823b21SArnaldo Carvalho de Melo 
696e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
697e9823b21SArnaldo Carvalho de Melo 
698e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
699e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
700e9823b21SArnaldo Carvalho de Melo }
701e9823b21SArnaldo Carvalho de Melo 
702db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
703db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7049783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
705aca7a94dSNamhyung Kim {
706aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
70705e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
708aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
70954e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7109783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
711aca7a94dSNamhyung Kim 	int key;
71234f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
713aca7a94dSNamhyung Kim 
71434f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
71534f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
716aca7a94dSNamhyung Kim 		return -1;
717aca7a94dSNamhyung Kim 
718db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
719aca7a94dSNamhyung Kim 
72005e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
72105e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
72205e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
723aca7a94dSNamhyung Kim 	}
724aca7a94dSNamhyung Kim 
72505e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
726aca7a94dSNamhyung Kim 
727aca7a94dSNamhyung Kim 	while (1) {
72805e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
729aca7a94dSNamhyung Kim 
730aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
731db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
732aca7a94dSNamhyung Kim 			/*
733aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
734aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
735aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
736aca7a94dSNamhyung Kim 			 */
737aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
738aca7a94dSNamhyung Kim 				nd = NULL;
739aca7a94dSNamhyung Kim 		}
740aca7a94dSNamhyung Kim 
741aca7a94dSNamhyung Kim 		switch (key) {
742aca7a94dSNamhyung Kim 		case K_TIMER:
7439783adf7SNamhyung Kim 			if (hbt)
7449783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
745aca7a94dSNamhyung Kim 
746aca7a94dSNamhyung Kim 			if (delay_secs != 0)
747db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
748aca7a94dSNamhyung Kim 			continue;
749aca7a94dSNamhyung Kim 		case K_TAB:
750aca7a94dSNamhyung Kim 			if (nd != NULL) {
751aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
752aca7a94dSNamhyung Kim 				if (nd == NULL)
75305e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
754aca7a94dSNamhyung Kim 			} else
75505e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
756aca7a94dSNamhyung Kim 			break;
757aca7a94dSNamhyung Kim 		case K_UNTAB:
758d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
759aca7a94dSNamhyung Kim 				nd = rb_next(nd);
760aca7a94dSNamhyung Kim 				if (nd == NULL)
76105e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
762d4913cbdSMarkus Trippelsdorf 			} else
76305e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
764aca7a94dSNamhyung Kim 			break;
76554e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
766aca7a94dSNamhyung Kim 		case 'h':
76705e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
76854e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
76954e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
77054e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
7717727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
7727727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
773107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
77454e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
77554e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
77654e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
77754e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
77854e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
7790c4a5bceSMartin Liška 		"t             Toggle total period view\n"
78054e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
781e592488cSAndi Kleen 		"k             Toggle line numbers\n"
78279ee47faSFeng Tang 		"r             Run available scripts\n"
783fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
78454e7a4e8SArnaldo Carvalho de Melo 			continue;
78579ee47faSFeng Tang 		case 'r':
78679ee47faSFeng Tang 			{
78779ee47faSFeng Tang 				script_browse(NULL);
78879ee47faSFeng Tang 				continue;
78979ee47faSFeng Tang 			}
790e592488cSAndi Kleen 		case 'k':
791e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
792e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
793e592488cSAndi Kleen 			break;
79454e7a4e8SArnaldo Carvalho de Melo 		case 'H':
79505e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
796aca7a94dSNamhyung Kim 			break;
797aca7a94dSNamhyung Kim 		case 's':
79805e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
799aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
800aca7a94dSNamhyung Kim 			continue;
801aca7a94dSNamhyung Kim 		case 'o':
802e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
80305e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
804aca7a94dSNamhyung Kim 			continue;
8059d1ef56dSArnaldo Carvalho de Melo 		case 'j':
806e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8079d1ef56dSArnaldo Carvalho de Melo 			continue;
8082402e4a9SArnaldo Carvalho de Melo 		case 'J':
809e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
81005e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
811e9823b21SArnaldo Carvalho de Melo 			continue;
812aca7a94dSNamhyung Kim 		case '/':
81305e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
814aca7a94dSNamhyung Kim show_help:
815aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
816aca7a94dSNamhyung Kim 			}
817aca7a94dSNamhyung Kim 			continue;
818aca7a94dSNamhyung Kim 		case 'n':
81905e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
82005e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
82105e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
822aca7a94dSNamhyung Kim 				goto show_help;
823aca7a94dSNamhyung Kim 			continue;
824aca7a94dSNamhyung Kim 		case '?':
82505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
826aca7a94dSNamhyung Kim 				goto show_help;
827aca7a94dSNamhyung Kim 			continue;
828e9823b21SArnaldo Carvalho de Melo 		case 'D': {
829e9823b21SArnaldo Carvalho de Melo 			static int seq;
830e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
831e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
83205e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
83305e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
83405e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
83505e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
83605e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
837e9823b21SArnaldo Carvalho de Melo 		}
838e9823b21SArnaldo Carvalho de Melo 			continue;
839aca7a94dSNamhyung Kim 		case K_ENTER:
840aca7a94dSNamhyung Kim 		case K_RIGHT:
84105e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
842aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
84305e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
844aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
84505e8b080SArnaldo Carvalho de Melo 			else if (!browser->selection->ins) {
84605e8b080SArnaldo Carvalho de Melo 				if (strcmp(browser->selection->name, "retq"))
847c4cceae3SArnaldo Carvalho de Melo 					goto show_sup_ins;
848c4cceae3SArnaldo Carvalho de Melo 				goto out;
84905e8b080SArnaldo Carvalho de Melo 			} else if (!(annotate_browser__jump(browser) ||
850db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
851c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
852c4cceae3SArnaldo Carvalho de Melo 				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
853c4cceae3SArnaldo Carvalho de Melo 			}
854aca7a94dSNamhyung Kim 			continue;
8550c4a5bceSMartin Liška 		case 't':
8560c4a5bceSMartin Liška 			annotate_browser__opts.show_total_period =
8570c4a5bceSMartin Liška 			  !annotate_browser__opts.show_total_period;
8580c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
8590c4a5bceSMartin Liška 			continue;
860aca7a94dSNamhyung Kim 		case K_LEFT:
861aca7a94dSNamhyung Kim 		case K_ESC:
862aca7a94dSNamhyung Kim 		case 'q':
863aca7a94dSNamhyung Kim 		case CTRL('c'):
864aca7a94dSNamhyung Kim 			goto out;
865aca7a94dSNamhyung Kim 		default:
866aca7a94dSNamhyung Kim 			continue;
867aca7a94dSNamhyung Kim 		}
868aca7a94dSNamhyung Kim 
869aca7a94dSNamhyung Kim 		if (nd != NULL)
87005e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
871aca7a94dSNamhyung Kim 	}
872aca7a94dSNamhyung Kim out:
87305e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
874aca7a94dSNamhyung Kim 	return key;
875aca7a94dSNamhyung Kim }
876aca7a94dSNamhyung Kim 
877d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
878d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
879d5dbc518SArnaldo Carvalho de Melo {
8800c4a5bceSMartin Liška 	/* Set default value for show_total_period.  */
8810c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
8820c4a5bceSMartin Liška 	  symbol_conf.show_total_period;
8830c4a5bceSMartin Liška 
884d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
885d5dbc518SArnaldo Carvalho de Melo }
886d5dbc518SArnaldo Carvalho de Melo 
887db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
8889783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
889aca7a94dSNamhyung Kim {
890ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
891ed426915SNamhyung Kim 	SLang_reset_tty();
892ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
893ed426915SNamhyung Kim 
894d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
895aca7a94dSNamhyung Kim }
896aca7a94dSNamhyung Kim 
89730e863bbSAndi Kleen 
89830e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
89930e863bbSAndi Kleen {
90030e863bbSAndi Kleen 	unsigned n_insn = 0;
90130e863bbSAndi Kleen 	u64 offset;
90230e863bbSAndi Kleen 
90330e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
90430e863bbSAndi Kleen 		if (browser->offsets[offset])
90530e863bbSAndi Kleen 			n_insn++;
90630e863bbSAndi Kleen 	}
90730e863bbSAndi Kleen 	return n_insn;
90830e863bbSAndi Kleen }
90930e863bbSAndi Kleen 
91030e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
91130e863bbSAndi Kleen 			   struct cyc_hist *ch)
91230e863bbSAndi Kleen {
91330e863bbSAndi Kleen 	unsigned n_insn;
91430e863bbSAndi Kleen 	u64 offset;
91530e863bbSAndi Kleen 
91630e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
91730e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
91830e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
91930e863bbSAndi Kleen 
92030e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
92130e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
92230e863bbSAndi Kleen 			return;
92330e863bbSAndi Kleen 
92430e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
92530e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
92630e863bbSAndi Kleen 
92730e863bbSAndi Kleen 			if (dl)
92830e863bbSAndi Kleen 				dl->ipc = ipc;
92930e863bbSAndi Kleen 		}
93030e863bbSAndi Kleen 	}
93130e863bbSAndi Kleen }
93230e863bbSAndi Kleen 
93330e863bbSAndi Kleen /*
93430e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
93530e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
93630e863bbSAndi Kleen  * which are only here.
93730e863bbSAndi Kleen  */
93830e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
93930e863bbSAndi Kleen 			   struct symbol *sym)
94030e863bbSAndi Kleen {
94130e863bbSAndi Kleen 	u64 offset;
94230e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
94330e863bbSAndi Kleen 
94430e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
94530e863bbSAndi Kleen 		return;
94630e863bbSAndi Kleen 
94730e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
94830e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
94930e863bbSAndi Kleen 		struct cyc_hist *ch;
95030e863bbSAndi Kleen 
95130e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
95230e863bbSAndi Kleen 		if (ch && ch->cycles) {
95330e863bbSAndi Kleen 			struct disasm_line *dl;
95430e863bbSAndi Kleen 
95530e863bbSAndi Kleen 			if (ch->have_start)
95630e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
95730e863bbSAndi Kleen 			dl = browser->offsets[offset];
95830e863bbSAndi Kleen 			if (dl && ch->num_aggr)
95930e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
96030e863bbSAndi Kleen 			browser->have_cycles = true;
96130e863bbSAndi Kleen 		}
96230e863bbSAndi Kleen 	}
96330e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
96430e863bbSAndi Kleen }
96530e863bbSAndi Kleen 
966b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
967b793a401SArnaldo Carvalho de Melo 						size_t size)
968b793a401SArnaldo Carvalho de Melo {
969b793a401SArnaldo Carvalho de Melo 	u64 offset;
97032ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
97132ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
97232ae1efdSNamhyung Kim 
97332ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
97432ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
97532ae1efdSNamhyung Kim 		return;
976b793a401SArnaldo Carvalho de Melo 
977b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
978b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
979b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
980b793a401SArnaldo Carvalho de Melo 
981865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
982b793a401SArnaldo Carvalho de Melo 			continue;
983b793a401SArnaldo Carvalho de Melo 
98444d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
9859481ede9SArnaldo Carvalho de Melo 		/*
9869481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
9879481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
9889481ede9SArnaldo Carvalho de Melo  		 */
9899481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
9909481ede9SArnaldo Carvalho de Melo 			continue;
9919481ede9SArnaldo Carvalho de Melo 
992b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
9932402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
9942402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
9952402e4a9SArnaldo Carvalho de Melo 
9962402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
997b793a401SArnaldo Carvalho de Melo 	}
998b793a401SArnaldo Carvalho de Melo }
999b793a401SArnaldo Carvalho de Melo 
10002402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10012402e4a9SArnaldo Carvalho de Melo {
10022402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10032402e4a9SArnaldo Carvalho de Melo 		return 5;
10042402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10052402e4a9SArnaldo Carvalho de Melo 		return 2;
10062402e4a9SArnaldo Carvalho de Melo 	return 1;
10072402e4a9SArnaldo Carvalho de Melo }
10082402e4a9SArnaldo Carvalho de Melo 
1009db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1010db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10119783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1012aca7a94dSNamhyung Kim {
101329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1014aca7a94dSNamhyung Kim 	struct annotation *notes;
1015c0a58fb2SSamuel Liao 	size_t size;
1016aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1017aca7a94dSNamhyung Kim 		.map = map,
1018aca7a94dSNamhyung Kim 		.sym = sym,
1019aca7a94dSNamhyung Kim 	};
1020aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1021aca7a94dSNamhyung Kim 		.b = {
1022a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1023aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1024aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
102529ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1026aca7a94dSNamhyung Kim 			.priv	 = &ms,
1027aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1028aca7a94dSNamhyung Kim 		},
1029aca7a94dSNamhyung Kim 	};
1030b793a401SArnaldo Carvalho de Melo 	int ret = -1;
1031c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1032c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1033aca7a94dSNamhyung Kim 
1034aca7a94dSNamhyung Kim 	if (sym == NULL)
1035aca7a94dSNamhyung Kim 		return -1;
1036aca7a94dSNamhyung Kim 
1037c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1038c0a58fb2SSamuel Liao 
1039aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1040aca7a94dSNamhyung Kim 		return -1;
1041aca7a94dSNamhyung Kim 
1042b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1043b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1044b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1045b793a401SArnaldo Carvalho de Melo 		return -1;
1046b793a401SArnaldo Carvalho de Melo 	}
1047b793a401SArnaldo Carvalho de Melo 
1048c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1049c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
10500c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
10510c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1052c7e7b610SNamhyung Kim 	}
1053c7e7b610SNamhyung Kim 
1054c7e7b610SNamhyung Kim 	if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
1055aca7a94dSNamhyung Kim 		ui__error("%s", ui_helpline__last_msg);
1056b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1057aca7a94dSNamhyung Kim 	}
1058aca7a94dSNamhyung Kim 
10597727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1060aca7a94dSNamhyung Kim 
1061aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1062aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1063aca7a94dSNamhyung Kim 
1064aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1065887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1066aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1067aca7a94dSNamhyung Kim 
1068aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1069aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1070887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1071887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1072b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1073887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
107497148a97SArnaldo Carvalho de Melo 			/*
107597148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
107697148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
107797148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
107897148a97SArnaldo Carvalho de Melo 			 *
107997148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
108097148a97SArnaldo Carvalho de Melo  			 */
108197148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1082b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1083b793a401SArnaldo Carvalho de Melo 		} else
1084887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1085aca7a94dSNamhyung Kim 	}
1086aca7a94dSNamhyung Kim 
1087b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
108830e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1089b793a401SArnaldo Carvalho de Melo 
10902402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
109183b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
10922402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1093c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1094aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1095aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1096aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1097e9823b21SArnaldo Carvalho de Melo 
1098e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1099e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1100e9823b21SArnaldo Carvalho de Melo 
1101e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1102e9823b21SArnaldo Carvalho de Melo 
1103db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1104aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1105aca7a94dSNamhyung Kim 		list_del(&pos->node);
110629ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1107aca7a94dSNamhyung Kim 	}
1108b793a401SArnaldo Carvalho de Melo 
1109b793a401SArnaldo Carvalho de Melo out_free_offsets:
1110b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1111aca7a94dSNamhyung Kim 	return ret;
1112aca7a94dSNamhyung Kim }
1113c323cf04SArnaldo Carvalho de Melo 
1114c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1115c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1116c323cf04SArnaldo Carvalho de Melo 
1117c323cf04SArnaldo Carvalho de Melo /*
1118c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1119c323cf04SArnaldo Carvalho de Melo  */
11207c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1121c323cf04SArnaldo Carvalho de Melo 	const char *name;
1122c323cf04SArnaldo Carvalho de Melo 	bool *value;
1123c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1124c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1125c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1126e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1127c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11280c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
112939ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1130c323cf04SArnaldo Carvalho de Melo };
1131c323cf04SArnaldo Carvalho de Melo 
1132c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1133c323cf04SArnaldo Carvalho de Melo 
1134c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1135c323cf04SArnaldo Carvalho de Melo {
11367c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1137c323cf04SArnaldo Carvalho de Melo 
1138c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1139c323cf04SArnaldo Carvalho de Melo }
1140c323cf04SArnaldo Carvalho de Melo 
11411d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11421d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1143c323cf04SArnaldo Carvalho de Melo {
11447c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1145c323cf04SArnaldo Carvalho de Melo 	const char *name;
1146c323cf04SArnaldo Carvalho de Melo 
1147c323cf04SArnaldo Carvalho de Melo 	if (prefixcmp(var, "annotate.") != 0)
1148c323cf04SArnaldo Carvalho de Melo 		return 0;
1149c323cf04SArnaldo Carvalho de Melo 
1150c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1151c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
11527c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1153c323cf04SArnaldo Carvalho de Melo 
1154c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1155f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1156f06cff7cSArnaldo Carvalho de Melo 	else
1157c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1158c323cf04SArnaldo Carvalho de Melo 	return 0;
1159c323cf04SArnaldo Carvalho de Melo }
1160c323cf04SArnaldo Carvalho de Melo 
1161c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1162c323cf04SArnaldo Carvalho de Melo {
1163c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1164c323cf04SArnaldo Carvalho de Melo }
1165