xref: /linux/tools/perf/ui/browsers/annotate.c (revision 9cef4b0b5b7f64016f043609313aaa821d682d2e)
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"
1141840d21STaeung Song #include "../../util/config.h"
1269fb09f6SJin Yao #include "../../util/evlist.h"
13fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
14aca7a94dSNamhyung Kim #include <pthread.h>
15877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
168e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h>
17b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h>
18aca7a94dSNamhyung Kim 
190c4a5bceSMartin Liška struct disasm_line_samples {
200c4a5bceSMartin Liška 	double		      percent;
21bb79a232SArnaldo Carvalho de Melo 	struct sym_hist_entry he;
220c4a5bceSMartin Liška };
230c4a5bceSMartin Liška 
24f8f4aaeaSAndi Kleen #define IPC_WIDTH 6
25f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6
26f8f4aaeaSAndi Kleen 
27b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
28b793a401SArnaldo Carvalho de Melo 	struct rb_node			rb_node;
29b793a401SArnaldo Carvalho de Melo 	u32				idx;
30b793a401SArnaldo Carvalho de Melo 	int				idx_asm;
317d5b12f5SArnaldo Carvalho de Melo 	int				jump_sources;
32c7e7b610SNamhyung Kim 	/*
33c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
34c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
35c7e7b610SNamhyung Kim 	 */
360c4a5bceSMartin Liška 	struct disasm_line_samples	samples[1];
37b793a401SArnaldo Carvalho de Melo };
38b793a401SArnaldo Carvalho de Melo 
39e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
40e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
41e9823b21SArnaldo Carvalho de Melo 	     use_offset,
42e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
43e592488cSAndi Kleen 	     show_linenr,
440c4a5bceSMartin Liška 	     show_nr_jumps,
45*9cef4b0bSTaeung Song 	     show_nr_samples,
460c4a5bceSMartin Liška 	     show_total_period;
47e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
48e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
49e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
50e9823b21SArnaldo Carvalho de Melo };
51e9823b21SArnaldo Carvalho de Melo 
52dcaa3948SJin Yao struct arch;
53dcaa3948SJin Yao 
54aca7a94dSNamhyung Kim struct annotate_browser {
55aca7a94dSNamhyung Kim 	struct ui_browser b;
56aca7a94dSNamhyung Kim 	struct rb_root	  entries;
57aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
5829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
59b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
60dcaa3948SJin Yao 	struct arch	    *arch;
61c7e7b610SNamhyung Kim 	int		    nr_events;
62aca7a94dSNamhyung Kim 	u64		    start;
63aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
64aca7a94dSNamhyung Kim 	int		    nr_entries;
652402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
662402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
67aca7a94dSNamhyung Kim 	bool		    searching_backwards;
6830e863bbSAndi Kleen 	bool		    have_cycles;
6983b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
702402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
712402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
7283b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
7383b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
74aca7a94dSNamhyung Kim 	char		    search_bf[128];
75aca7a94dSNamhyung Kim };
76aca7a94dSNamhyung Kim 
77887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
78aca7a94dSNamhyung Kim {
79887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
80aca7a94dSNamhyung Kim }
81aca7a94dSNamhyung Kim 
821d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
831d037ca1SIrina Tirdea 				void *entry)
84aca7a94dSNamhyung Kim {
85e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
8629ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
8729ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
88aca7a94dSNamhyung Kim 	}
89aca7a94dSNamhyung Kim 
90aca7a94dSNamhyung Kim 	return false;
91aca7a94dSNamhyung Kim }
92aca7a94dSNamhyung Kim 
932402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
942402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
952402e4a9SArnaldo Carvalho de Melo {
962402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
972402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
982402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
992402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
1002402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
1012402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
1022402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
1032402e4a9SArnaldo Carvalho de Melo }
1042402e4a9SArnaldo Carvalho de Melo 
1052402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
1062402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1072402e4a9SArnaldo Carvalho de Melo {
1082402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1092402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1102402e4a9SArnaldo Carvalho de Melo }
1112402e4a9SArnaldo Carvalho de Melo 
112f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
113f8f4aaeaSAndi Kleen {
1143861c4a4SArnaldo Carvalho de Melo 	return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events;
115bc1e5d60SArnaldo Carvalho de Melo }
116f8f4aaeaSAndi Kleen 
117bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab)
118bc1e5d60SArnaldo Carvalho de Melo {
119bc1e5d60SArnaldo Carvalho de Melo 	return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
120f8f4aaeaSAndi Kleen }
121f8f4aaeaSAndi Kleen 
12205e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
123aca7a94dSNamhyung Kim {
12405e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
12529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
126b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
12705e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
128e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
12905e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
13005e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
13105e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
132bc1e5d60SArnaldo Carvalho de Melo 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
133bc1e5d60SArnaldo Carvalho de Melo 	       cycles_width = annotate_browser__cycles_width(ab);
134c7e7b610SNamhyung Kim 	double percent_max = 0.0;
13583b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
136ec27ae18SJin Yao 	bool show_title = false;
137aca7a94dSNamhyung Kim 
138c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1390c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1400c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
141c7e7b610SNamhyung Kim 	}
142c7e7b610SNamhyung Kim 
143ec27ae18SJin Yao 	if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) {
144ec27ae18SJin Yao 		if (ab->have_cycles) {
145ec27ae18SJin Yao 			if (dl->ipc == 0.0 && dl->cycles == 0)
146ec27ae18SJin Yao 				show_title = true;
147ec27ae18SJin Yao 		} else
148ec27ae18SJin Yao 			show_title = true;
149ec27ae18SJin Yao 	}
150ec27ae18SJin Yao 
151c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
152c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1530c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1540c4a5bceSMartin Liška 						bdl->samples[i].percent,
155c7e7b610SNamhyung Kim 						current_entry);
156517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
1573861c4a4SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%11" PRIu64 " ",
15829dc267fSTaeung Song 						   bdl->samples[i].he.period);
159*9cef4b0bSTaeung Song 			} else if (annotate_browser__opts.show_nr_samples) {
160*9cef4b0bSTaeung Song 				ui_browser__printf(browser, "%6" PRIu64 " ",
161*9cef4b0bSTaeung Song 						   bdl->samples[i].he.nr_samples);
162517dfdb3SArnaldo Carvalho de Melo 			} else {
163517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
164517dfdb3SArnaldo Carvalho de Melo 						   bdl->samples[i].percent);
165517dfdb3SArnaldo Carvalho de Melo 			}
166c7e7b610SNamhyung Kim 		}
167aca7a94dSNamhyung Kim 	} else {
16805e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
169ec27ae18SJin Yao 
170ec27ae18SJin Yao 		if (!show_title)
171bc1e5d60SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", pcnt_width);
1723861c4a4SArnaldo Carvalho de Melo 		else {
1733861c4a4SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s", pcnt_width,
174*9cef4b0bSTaeung Song 					   annotate_browser__opts.show_total_period ? "Period" :
175*9cef4b0bSTaeung Song 					   annotate_browser__opts.show_nr_samples ? "Samples" : "Percent");
1763861c4a4SArnaldo Carvalho de Melo 		}
177f8f4aaeaSAndi Kleen 	}
178f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
179f8f4aaeaSAndi Kleen 		if (dl->ipc)
180517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
181ec27ae18SJin Yao 		else if (!show_title)
18226270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
183ec27ae18SJin Yao 		else
184ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
185ec27ae18SJin Yao 
186f8f4aaeaSAndi Kleen 		if (dl->cycles)
187517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
188f8f4aaeaSAndi Kleen 					   CYCLES_WIDTH - 1, dl->cycles);
189ec27ae18SJin Yao 		else if (!show_title)
19026270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
191ec27ae18SJin Yao 		else
192ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
193aca7a94dSNamhyung Kim 	}
194aca7a94dSNamhyung Kim 
195cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
196aca7a94dSNamhyung Kim 
197aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
19805e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
199aca7a94dSNamhyung Kim 		width += 1;
200aca7a94dSNamhyung Kim 
20129ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
202bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
20383b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
204e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
205e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
206e592488cSAndi Kleen 					ab->addr_width + 1, dl->line_nr);
207e592488cSAndi Kleen 		else
20883b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
20983b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
21026270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
211bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width - cycles_width + 1);
21283b1f2aaSArnaldo Carvalho de Melo 	} else {
21329ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
21483b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
215aca7a94dSNamhyung Kim 
216e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
217aca7a94dSNamhyung Kim 			addr += ab->start;
218aca7a94dSNamhyung Kim 
219e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
220aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
22161e04b33SArnaldo Carvalho de Melo 		} else {
2227d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
223e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2242402e4a9SArnaldo Carvalho de Melo 					int prev;
2252402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2262402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2272402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2282402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2292402e4a9SArnaldo Carvalho de Melo 											 current_entry);
23026270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
23105e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2322402e4a9SArnaldo Carvalho de Melo 				}
2332402e4a9SArnaldo Carvalho de Melo 
23461e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2352402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
23661e04b33SArnaldo Carvalho de Melo 			} else {
23761e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
23883b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
23961e04b33SArnaldo Carvalho de Melo 			}
24061e04b33SArnaldo Carvalho de Melo 		}
241b793a401SArnaldo Carvalho de Melo 
242aca7a94dSNamhyung Kim 		if (change_color)
24305e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
24426270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
245aca7a94dSNamhyung Kim 		if (change_color)
24605e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
24775b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
24875b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
249e216874cSRavi Bangoria 				bool fwd = dl->ops.target.offset > dl->offset;
25051a0d455SArnaldo Carvalho de Melo 
25105e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
25251a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
25351a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25475b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
25505e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
25688298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25775b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
25805e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2594ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2606ef94929SNaveen N. Rao 			} else {
2616ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2624ea08b52SArnaldo Carvalho de Melo 			}
2636ef94929SNaveen N. Rao 		} else {
2646ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2654ea08b52SArnaldo Carvalho de Melo 		}
2664ea08b52SArnaldo Carvalho de Melo 
267e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
268bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
269aca7a94dSNamhyung Kim 	}
270aca7a94dSNamhyung Kim 
271aca7a94dSNamhyung Kim 	if (current_entry)
27229ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
273aca7a94dSNamhyung Kim }
274aca7a94dSNamhyung Kim 
275865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
276865c66c4SFrederik Deweerdt {
27775b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
278865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
279e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
280e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
281865c66c4SFrederik Deweerdt 		return false;
282865c66c4SFrederik Deweerdt 
283865c66c4SFrederik Deweerdt 	return true;
284865c66c4SFrederik Deweerdt }
285865c66c4SFrederik Deweerdt 
2867e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2877e63a13aSJin Yao {
2887e63a13aSJin Yao 	struct disasm_line *pos = list_prev_entry(cursor, node);
2897e63a13aSJin Yao 	const char *name;
2907e63a13aSJin Yao 
2917e63a13aSJin Yao 	if (!pos)
2927e63a13aSJin Yao 		return false;
2937e63a13aSJin Yao 
2947e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2957e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2967e63a13aSJin Yao 	else
2977e63a13aSJin Yao 		name = pos->ins.name;
2987e63a13aSJin Yao 
2997e63a13aSJin Yao 	if (!name || !cursor->ins.name)
3007e63a13aSJin Yao 		return false;
3017e63a13aSJin Yao 
3027e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
3037e63a13aSJin Yao }
3047e63a13aSJin Yao 
3059d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
306a3f895beSArnaldo Carvalho de Melo {
307a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3089d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
3099d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
31083b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
31132ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
31232ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
313f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
31432ae1efdSNamhyung Kim 
31532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31732ae1efdSNamhyung Kim 		return;
318a3f895beSArnaldo Carvalho de Melo 
319865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
320a3f895beSArnaldo Carvalho de Melo 		return;
321a3f895beSArnaldo Carvalho de Melo 
3229d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
3239d1ef56dSArnaldo Carvalho de Melo 	if (!target)
3249d1ef56dSArnaldo Carvalho de Melo 		return;
3259d1ef56dSArnaldo Carvalho de Melo 
3269d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
3279d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
3289d1ef56dSArnaldo Carvalho de Melo 
329e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3309d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
331a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
332a3f895beSArnaldo Carvalho de Melo 	} else {
3339d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
334a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
335a3f895beSArnaldo Carvalho de Melo 	}
336a3f895beSArnaldo Carvalho de Melo 
33778ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
338c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
339c7e7b610SNamhyung Kim 				 from, to);
3407e63a13aSJin Yao 
3417e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3427e63a13aSJin Yao 		ui_browser__mark_fused(browser,
3437e63a13aSJin Yao 				       pcnt_width + 3 + ab->addr_width,
3447e63a13aSJin Yao 				       from - 1,
3457e63a13aSJin Yao 				       to > from ? true : false);
3467e63a13aSJin Yao 	}
347a3f895beSArnaldo Carvalho de Melo }
348a3f895beSArnaldo Carvalho de Melo 
349a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
350a3f895beSArnaldo Carvalho de Melo {
351c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
352a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
353f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
354a3f895beSArnaldo Carvalho de Melo 
355e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3569d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
357a3f895beSArnaldo Carvalho de Melo 
35883b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
359c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
360a3f895beSArnaldo Carvalho de Melo 	return ret;
361a3f895beSArnaldo Carvalho de Melo }
362a3f895beSArnaldo Carvalho de Melo 
363c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
364c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
365c7e7b610SNamhyung Kim {
366c7e7b610SNamhyung Kim 	int i;
367c7e7b610SNamhyung Kim 
368c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3690c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
370c7e7b610SNamhyung Kim 			continue;
3710c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
372c7e7b610SNamhyung Kim 	}
373c7e7b610SNamhyung Kim 	return 0;
374c7e7b610SNamhyung Kim }
375c7e7b610SNamhyung Kim 
376c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
377c7e7b610SNamhyung Kim 				   int nr_events)
378aca7a94dSNamhyung Kim {
37929ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
380aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
381887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
382aca7a94dSNamhyung Kim 
383aca7a94dSNamhyung Kim 	while (*p != NULL) {
384aca7a94dSNamhyung Kim 		parent = *p;
385887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
386c7e7b610SNamhyung Kim 
387c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
388aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
389aca7a94dSNamhyung Kim 		else
390aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
391aca7a94dSNamhyung Kim 	}
392887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
393887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
394aca7a94dSNamhyung Kim }
395aca7a94dSNamhyung Kim 
39605e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
39729ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
398aca7a94dSNamhyung Kim {
399aca7a94dSNamhyung Kim 	unsigned back;
400aca7a94dSNamhyung Kim 
40105e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
40205e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
40305e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
404aca7a94dSNamhyung Kim 
40505e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
40629ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
407aca7a94dSNamhyung Kim 
40805e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
409aca7a94dSNamhyung Kim 			continue;
410aca7a94dSNamhyung Kim 
41105e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
412aca7a94dSNamhyung Kim 		--back;
413aca7a94dSNamhyung Kim 	}
414aca7a94dSNamhyung Kim 
41505e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
41605e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
417aca7a94dSNamhyung Kim }
418aca7a94dSNamhyung Kim 
419aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
420aca7a94dSNamhyung Kim 					 struct rb_node *nd)
421aca7a94dSNamhyung Kim {
422887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
42329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
424a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
425aca7a94dSNamhyung Kim 
426887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
427887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
428a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
429e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
430a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
431a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
432aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
433aca7a94dSNamhyung Kim }
434aca7a94dSNamhyung Kim 
435aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
436db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
437aca7a94dSNamhyung Kim {
438aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
439aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
440aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
441e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
442e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
443aca7a94dSNamhyung Kim 
444aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
445aca7a94dSNamhyung Kim 
446aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
447aca7a94dSNamhyung Kim 
448aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
449887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
450e64aa75bSNamhyung Kim 		const char *path = NULL;
451c7e7b610SNamhyung Kim 		double max_percent = 0.0;
452c7e7b610SNamhyung Kim 		int i;
453e64aa75bSNamhyung Kim 
454e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
455e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
456e64aa75bSNamhyung Kim 			continue;
457e64aa75bSNamhyung Kim 		}
458e64aa75bSNamhyung Kim 
459e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
460c7e7b610SNamhyung Kim 
461c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
462896bccd3STaeung Song 			struct sym_hist_entry sample;
4630c4a5bceSMartin Liška 
4640c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
465c7e7b610SNamhyung Kim 						evsel->idx + i,
466c7e7b610SNamhyung Kim 						pos->offset,
467c7e7b610SNamhyung Kim 						next ? next->offset : len,
468896bccd3STaeung Song 						&path, &sample);
469bb79a232SArnaldo Carvalho de Melo 			bpos->samples[i].he = sample;
470e64aa75bSNamhyung Kim 
4710c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4720c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
473c7e7b610SNamhyung Kim 		}
474c7e7b610SNamhyung Kim 
47530e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
476887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
477aca7a94dSNamhyung Kim 			continue;
478aca7a94dSNamhyung Kim 		}
479c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
480c7e7b610SNamhyung Kim 				       browser->nr_events);
481aca7a94dSNamhyung Kim 	}
482aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
483aca7a94dSNamhyung Kim 
484aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
485aca7a94dSNamhyung Kim }
486aca7a94dSNamhyung Kim 
487aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
488aca7a94dSNamhyung Kim {
48929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
490887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
491aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
492aca7a94dSNamhyung Kim 
493aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
49429ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
495887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
496aca7a94dSNamhyung Kim 
497e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
498887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
499887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
500aca7a94dSNamhyung Kim 
501aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
502e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
503aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
504887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
505887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
506aca7a94dSNamhyung Kim 	} else {
507887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
508aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
509aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
510aca7a94dSNamhyung Kim 			return false;
511aca7a94dSNamhyung Kim 		}
512aca7a94dSNamhyung Kim 
513887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
514887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
515aca7a94dSNamhyung Kim 
516aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
517e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
518aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
519887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
520887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
521aca7a94dSNamhyung Kim 	}
522aca7a94dSNamhyung Kim 
523aca7a94dSNamhyung Kim 	return true;
524aca7a94dSNamhyung Kim }
525aca7a94dSNamhyung Kim 
526e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
527e9823b21SArnaldo Carvalho de Melo {
528e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
529e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
530e9823b21SArnaldo Carvalho de Melo }
531e9823b21SArnaldo Carvalho de Melo 
53234f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
53334f77abcSAdrian Hunter 
53434f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
53534f77abcSAdrian Hunter 		     size_t sz)
53634f77abcSAdrian Hunter {
53734f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
53834f77abcSAdrian Hunter }
53934f77abcSAdrian Hunter 
540db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
541db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5429783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
543aca7a94dSNamhyung Kim {
544aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
545657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
546aca7a94dSNamhyung Kim 	struct annotation *notes;
5471179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5481179e11bSAdrian Hunter 		.map = ms->map,
5491d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5501179e11bSAdrian Hunter 	};
55134f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
552aca7a94dSNamhyung Kim 
55375b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
554aca7a94dSNamhyung Kim 		return false;
555aca7a94dSNamhyung Kim 
556be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5571d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5581d5077bdSAdrian Hunter 							     target.addr)) !=
5591d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
560aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
561aca7a94dSNamhyung Kim 		return true;
562aca7a94dSNamhyung Kim 	}
563aca7a94dSNamhyung Kim 
5641179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
565aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
566aca7a94dSNamhyung Kim 
5671179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
568aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
569aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5701179e11bSAdrian Hunter 			    target.sym->name);
571aca7a94dSNamhyung Kim 		return true;
572aca7a94dSNamhyung Kim 	}
573aca7a94dSNamhyung Kim 
574aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5751179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5761179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
57734f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
578aca7a94dSNamhyung Kim 	return true;
579aca7a94dSNamhyung Kim }
580aca7a94dSNamhyung Kim 
58129ed6e76SArnaldo Carvalho de Melo static
58229ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
583aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
584aca7a94dSNamhyung Kim {
585aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
586aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
587aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
58829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
589aca7a94dSNamhyung Kim 
590aca7a94dSNamhyung Kim 	*idx = 0;
591aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
592aca7a94dSNamhyung Kim 		if (pos->offset == offset)
593aca7a94dSNamhyung Kim 			return pos;
59429ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
595aca7a94dSNamhyung Kim 			++*idx;
596aca7a94dSNamhyung Kim 	}
597aca7a94dSNamhyung Kim 
598aca7a94dSNamhyung Kim 	return NULL;
599aca7a94dSNamhyung Kim }
600aca7a94dSNamhyung Kim 
601aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
602aca7a94dSNamhyung Kim {
603657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
6045252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6054f9d0325SArnaldo Carvalho de Melo 	s64 idx;
606aca7a94dSNamhyung Kim 
60775b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
608aca7a94dSNamhyung Kim 		return false;
609aca7a94dSNamhyung Kim 
6105252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6115252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
61229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6135252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
614aca7a94dSNamhyung Kim 		return true;
615aca7a94dSNamhyung Kim 	}
616aca7a94dSNamhyung Kim 
61729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
618aca7a94dSNamhyung Kim 
619aca7a94dSNamhyung Kim 	return true;
620aca7a94dSNamhyung Kim }
621aca7a94dSNamhyung Kim 
62229ed6e76SArnaldo Carvalho de Melo static
62329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
624aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
625aca7a94dSNamhyung Kim {
626aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
627aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
628aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
62929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
630aca7a94dSNamhyung Kim 
631aca7a94dSNamhyung Kim 	*idx = browser->b.index;
632aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
63329ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
634aca7a94dSNamhyung Kim 			continue;
635aca7a94dSNamhyung Kim 
636aca7a94dSNamhyung Kim 		++*idx;
637aca7a94dSNamhyung Kim 
638aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
639aca7a94dSNamhyung Kim 			return pos;
640aca7a94dSNamhyung Kim 	}
641aca7a94dSNamhyung Kim 
642aca7a94dSNamhyung Kim 	return NULL;
643aca7a94dSNamhyung Kim }
644aca7a94dSNamhyung Kim 
645aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
646aca7a94dSNamhyung Kim {
64729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
648aca7a94dSNamhyung Kim 	s64 idx;
649aca7a94dSNamhyung Kim 
65029ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
65129ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
652aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
653aca7a94dSNamhyung Kim 		return false;
654aca7a94dSNamhyung Kim 	}
655aca7a94dSNamhyung Kim 
65629ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
657aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
658aca7a94dSNamhyung Kim 	return true;
659aca7a94dSNamhyung Kim }
660aca7a94dSNamhyung Kim 
66129ed6e76SArnaldo Carvalho de Melo static
66229ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
663aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
664aca7a94dSNamhyung Kim {
665aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
666aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
667aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
66829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
669aca7a94dSNamhyung Kim 
670aca7a94dSNamhyung Kim 	*idx = browser->b.index;
671aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
67229ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
673aca7a94dSNamhyung Kim 			continue;
674aca7a94dSNamhyung Kim 
675aca7a94dSNamhyung Kim 		--*idx;
676aca7a94dSNamhyung Kim 
677aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
678aca7a94dSNamhyung Kim 			return pos;
679aca7a94dSNamhyung Kim 	}
680aca7a94dSNamhyung Kim 
681aca7a94dSNamhyung Kim 	return NULL;
682aca7a94dSNamhyung Kim }
683aca7a94dSNamhyung Kim 
684aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
685aca7a94dSNamhyung Kim {
68629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
687aca7a94dSNamhyung Kim 	s64 idx;
688aca7a94dSNamhyung Kim 
68929ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
69029ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
691aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
692aca7a94dSNamhyung Kim 		return false;
693aca7a94dSNamhyung Kim 	}
694aca7a94dSNamhyung Kim 
69529ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
696aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
697aca7a94dSNamhyung Kim 	return true;
698aca7a94dSNamhyung Kim }
699aca7a94dSNamhyung Kim 
700aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
701aca7a94dSNamhyung Kim 					    int delay_secs)
702aca7a94dSNamhyung Kim {
703aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
704aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
705aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
706aca7a94dSNamhyung Kim 	    !*browser->search_bf)
707aca7a94dSNamhyung Kim 		return false;
708aca7a94dSNamhyung Kim 
709aca7a94dSNamhyung Kim 	return true;
710aca7a94dSNamhyung Kim }
711aca7a94dSNamhyung Kim 
712aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
713aca7a94dSNamhyung Kim {
714aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
715aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
716aca7a94dSNamhyung Kim 
717aca7a94dSNamhyung Kim 	return false;
718aca7a94dSNamhyung Kim }
719aca7a94dSNamhyung Kim 
720aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
721aca7a94dSNamhyung Kim 					      int delay_secs)
722aca7a94dSNamhyung Kim {
723aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
724aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
725aca7a94dSNamhyung Kim 
726aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
727aca7a94dSNamhyung Kim }
728aca7a94dSNamhyung Kim 
729aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
730aca7a94dSNamhyung Kim 					   int delay_secs)
731aca7a94dSNamhyung Kim {
732aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
733aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
734aca7a94dSNamhyung Kim 
735aca7a94dSNamhyung Kim 	return false;
736aca7a94dSNamhyung Kim }
737aca7a94dSNamhyung Kim 
738aca7a94dSNamhyung Kim static
739aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
740aca7a94dSNamhyung Kim 					       int delay_secs)
741aca7a94dSNamhyung Kim {
742aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
743aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
744aca7a94dSNamhyung Kim 
745aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
746aca7a94dSNamhyung Kim }
747aca7a94dSNamhyung Kim 
748e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
749e9823b21SArnaldo Carvalho de Melo {
750e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
751e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
752e9823b21SArnaldo Carvalho de Melo 	else
753e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
754e9823b21SArnaldo Carvalho de Melo 
755e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
756e9823b21SArnaldo Carvalho de Melo 
757e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
758e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
759e9823b21SArnaldo Carvalho de Melo }
760e9823b21SArnaldo Carvalho de Melo 
761db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
762db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7639783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
764aca7a94dSNamhyung Kim {
765aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
76605e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
767aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
76854e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7699783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
770aca7a94dSNamhyung Kim 	int key;
77134f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
772aca7a94dSNamhyung Kim 
77334f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
77434f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
775aca7a94dSNamhyung Kim 		return -1;
776aca7a94dSNamhyung Kim 
777db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
778aca7a94dSNamhyung Kim 
77905e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
78005e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
78105e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
782aca7a94dSNamhyung Kim 	}
783aca7a94dSNamhyung Kim 
78405e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
785aca7a94dSNamhyung Kim 
786aca7a94dSNamhyung Kim 	while (1) {
78705e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
788aca7a94dSNamhyung Kim 
789aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
790db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
791aca7a94dSNamhyung Kim 			/*
792aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
793aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
794aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
795aca7a94dSNamhyung Kim 			 */
796aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
797aca7a94dSNamhyung Kim 				nd = NULL;
798aca7a94dSNamhyung Kim 		}
799aca7a94dSNamhyung Kim 
800aca7a94dSNamhyung Kim 		switch (key) {
801aca7a94dSNamhyung Kim 		case K_TIMER:
8029783adf7SNamhyung Kim 			if (hbt)
8039783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
804aca7a94dSNamhyung Kim 
805aca7a94dSNamhyung Kim 			if (delay_secs != 0)
806db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
807aca7a94dSNamhyung Kim 			continue;
808aca7a94dSNamhyung Kim 		case K_TAB:
809aca7a94dSNamhyung Kim 			if (nd != NULL) {
810aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
811aca7a94dSNamhyung Kim 				if (nd == NULL)
81205e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
813aca7a94dSNamhyung Kim 			} else
81405e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
815aca7a94dSNamhyung Kim 			break;
816aca7a94dSNamhyung Kim 		case K_UNTAB:
817d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
818aca7a94dSNamhyung Kim 				nd = rb_next(nd);
819aca7a94dSNamhyung Kim 				if (nd == NULL)
82005e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
821d4913cbdSMarkus Trippelsdorf 			} else
82205e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
823aca7a94dSNamhyung Kim 			break;
82454e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
825aca7a94dSNamhyung Kim 		case 'h':
82605e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
82754e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
82854e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
82954e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8307727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8317727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
832107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
83354e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
83454e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
83554e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
83654e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
83754e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8380c4a5bceSMartin Liška 		"t             Toggle total period view\n"
83954e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
840e592488cSAndi Kleen 		"k             Toggle line numbers\n"
84179ee47faSFeng Tang 		"r             Run available scripts\n"
842fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
84354e7a4e8SArnaldo Carvalho de Melo 			continue;
84479ee47faSFeng Tang 		case 'r':
84579ee47faSFeng Tang 			{
84679ee47faSFeng Tang 				script_browse(NULL);
84779ee47faSFeng Tang 				continue;
84879ee47faSFeng Tang 			}
849e592488cSAndi Kleen 		case 'k':
850e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
851e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
852e592488cSAndi Kleen 			break;
85354e7a4e8SArnaldo Carvalho de Melo 		case 'H':
85405e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
855aca7a94dSNamhyung Kim 			break;
856aca7a94dSNamhyung Kim 		case 's':
85705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
858aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
859aca7a94dSNamhyung Kim 			continue;
860aca7a94dSNamhyung Kim 		case 'o':
861e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
86205e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
863aca7a94dSNamhyung Kim 			continue;
8649d1ef56dSArnaldo Carvalho de Melo 		case 'j':
865e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8669d1ef56dSArnaldo Carvalho de Melo 			continue;
8672402e4a9SArnaldo Carvalho de Melo 		case 'J':
868e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
86905e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
870e9823b21SArnaldo Carvalho de Melo 			continue;
871aca7a94dSNamhyung Kim 		case '/':
87205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
873aca7a94dSNamhyung Kim show_help:
874aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
875aca7a94dSNamhyung Kim 			}
876aca7a94dSNamhyung Kim 			continue;
877aca7a94dSNamhyung Kim 		case 'n':
87805e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
87905e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
88005e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
881aca7a94dSNamhyung Kim 				goto show_help;
882aca7a94dSNamhyung Kim 			continue;
883aca7a94dSNamhyung Kim 		case '?':
88405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
885aca7a94dSNamhyung Kim 				goto show_help;
886aca7a94dSNamhyung Kim 			continue;
887e9823b21SArnaldo Carvalho de Melo 		case 'D': {
888e9823b21SArnaldo Carvalho de Melo 			static int seq;
889e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
890e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
89105e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
89205e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
89305e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
89405e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
89505e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
896e9823b21SArnaldo Carvalho de Melo 		}
897e9823b21SArnaldo Carvalho de Melo 			continue;
898aca7a94dSNamhyung Kim 		case K_ENTER:
899aca7a94dSNamhyung Kim 		case K_RIGHT:
90005e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
901aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
90205e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
903aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
90475b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
905c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
90675b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
907c4cceae3SArnaldo Carvalho de Melo 				goto out;
9086ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
909db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
910c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9116ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
912c4cceae3SArnaldo Carvalho de Melo 			}
913aca7a94dSNamhyung Kim 			continue;
9140c4a5bceSMartin Liška 		case 't':
9150c4a5bceSMartin Liška 			annotate_browser__opts.show_total_period =
9160c4a5bceSMartin Liška 			  !annotate_browser__opts.show_total_period;
9170c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9180c4a5bceSMartin Liška 			continue;
919aca7a94dSNamhyung Kim 		case K_LEFT:
920aca7a94dSNamhyung Kim 		case K_ESC:
921aca7a94dSNamhyung Kim 		case 'q':
922aca7a94dSNamhyung Kim 		case CTRL('c'):
923aca7a94dSNamhyung Kim 			goto out;
924aca7a94dSNamhyung Kim 		default:
925aca7a94dSNamhyung Kim 			continue;
926aca7a94dSNamhyung Kim 		}
927aca7a94dSNamhyung Kim 
928aca7a94dSNamhyung Kim 		if (nd != NULL)
92905e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
930aca7a94dSNamhyung Kim 	}
931aca7a94dSNamhyung Kim out:
93205e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
933aca7a94dSNamhyung Kim 	return key;
934aca7a94dSNamhyung Kim }
935aca7a94dSNamhyung Kim 
936d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
937d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
938d5dbc518SArnaldo Carvalho de Melo {
939*9cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9400c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9410c4a5bceSMartin Liška 		symbol_conf.show_total_period;
942*9cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
943*9cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9440c4a5bceSMartin Liška 
945d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
946d5dbc518SArnaldo Carvalho de Melo }
947d5dbc518SArnaldo Carvalho de Melo 
948db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9499783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
950aca7a94dSNamhyung Kim {
951ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
952ed426915SNamhyung Kim 	SLang_reset_tty();
953ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
954ed426915SNamhyung Kim 
955d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
956aca7a94dSNamhyung Kim }
957aca7a94dSNamhyung Kim 
95830e863bbSAndi Kleen 
95930e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
96030e863bbSAndi Kleen {
96130e863bbSAndi Kleen 	unsigned n_insn = 0;
96230e863bbSAndi Kleen 	u64 offset;
96330e863bbSAndi Kleen 
96430e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
96530e863bbSAndi Kleen 		if (browser->offsets[offset])
96630e863bbSAndi Kleen 			n_insn++;
96730e863bbSAndi Kleen 	}
96830e863bbSAndi Kleen 	return n_insn;
96930e863bbSAndi Kleen }
97030e863bbSAndi Kleen 
97130e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
97230e863bbSAndi Kleen 			   struct cyc_hist *ch)
97330e863bbSAndi Kleen {
97430e863bbSAndi Kleen 	unsigned n_insn;
97530e863bbSAndi Kleen 	u64 offset;
97630e863bbSAndi Kleen 
97730e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
97830e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
97930e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
98030e863bbSAndi Kleen 
98130e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
98230e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
98330e863bbSAndi Kleen 			return;
98430e863bbSAndi Kleen 
98530e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
98630e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
98730e863bbSAndi Kleen 
98830e863bbSAndi Kleen 			if (dl)
98930e863bbSAndi Kleen 				dl->ipc = ipc;
99030e863bbSAndi Kleen 		}
99130e863bbSAndi Kleen 	}
99230e863bbSAndi Kleen }
99330e863bbSAndi Kleen 
99430e863bbSAndi Kleen /*
99530e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
99630e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
99730e863bbSAndi Kleen  * which are only here.
99830e863bbSAndi Kleen  */
99930e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
100030e863bbSAndi Kleen 			   struct symbol *sym)
100130e863bbSAndi Kleen {
100230e863bbSAndi Kleen 	u64 offset;
100330e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
100430e863bbSAndi Kleen 
100530e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
100630e863bbSAndi Kleen 		return;
100730e863bbSAndi Kleen 
100830e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
100930e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
101030e863bbSAndi Kleen 		struct cyc_hist *ch;
101130e863bbSAndi Kleen 
101230e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
101330e863bbSAndi Kleen 		if (ch && ch->cycles) {
101430e863bbSAndi Kleen 			struct disasm_line *dl;
101530e863bbSAndi Kleen 
101630e863bbSAndi Kleen 			if (ch->have_start)
101730e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
101830e863bbSAndi Kleen 			dl = browser->offsets[offset];
101930e863bbSAndi Kleen 			if (dl && ch->num_aggr)
102030e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
102130e863bbSAndi Kleen 			browser->have_cycles = true;
102230e863bbSAndi Kleen 		}
102330e863bbSAndi Kleen 	}
102430e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
102530e863bbSAndi Kleen }
102630e863bbSAndi Kleen 
1027b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1028b793a401SArnaldo Carvalho de Melo 						size_t size)
1029b793a401SArnaldo Carvalho de Melo {
1030b793a401SArnaldo Carvalho de Melo 	u64 offset;
103132ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
103232ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
103332ae1efdSNamhyung Kim 
103432ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
103532ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
103632ae1efdSNamhyung Kim 		return;
1037b793a401SArnaldo Carvalho de Melo 
1038b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1039b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
1040b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
1041b793a401SArnaldo Carvalho de Melo 
1042865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1043b793a401SArnaldo Carvalho de Melo 			continue;
1044b793a401SArnaldo Carvalho de Melo 
104544d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10469481ede9SArnaldo Carvalho de Melo 		/*
10479481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10489481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10499481ede9SArnaldo Carvalho de Melo  		 */
10509481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10519481ede9SArnaldo Carvalho de Melo 			continue;
10529481ede9SArnaldo Carvalho de Melo 
1053b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
10542402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10552402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10562402e4a9SArnaldo Carvalho de Melo 
10572402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1058b793a401SArnaldo Carvalho de Melo 	}
1059b793a401SArnaldo Carvalho de Melo }
1060b793a401SArnaldo Carvalho de Melo 
10612402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10622402e4a9SArnaldo Carvalho de Melo {
10632402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10642402e4a9SArnaldo Carvalho de Melo 		return 5;
10652402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10662402e4a9SArnaldo Carvalho de Melo 		return 2;
10672402e4a9SArnaldo Carvalho de Melo 	return 1;
10682402e4a9SArnaldo Carvalho de Melo }
10692402e4a9SArnaldo Carvalho de Melo 
1070db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1071db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10729783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1073aca7a94dSNamhyung Kim {
107429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1075aca7a94dSNamhyung Kim 	struct annotation *notes;
1076c0a58fb2SSamuel Liao 	size_t size;
1077aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1078aca7a94dSNamhyung Kim 		.map = map,
1079aca7a94dSNamhyung Kim 		.sym = sym,
1080aca7a94dSNamhyung Kim 	};
1081aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1082aca7a94dSNamhyung Kim 		.b = {
1083a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1084aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1085aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
108629ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1087aca7a94dSNamhyung Kim 			.priv	 = &ms,
1088aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1089aca7a94dSNamhyung Kim 		},
1090aca7a94dSNamhyung Kim 	};
1091ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1092c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1093c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1094aca7a94dSNamhyung Kim 
1095aca7a94dSNamhyung Kim 	if (sym == NULL)
1096aca7a94dSNamhyung Kim 		return -1;
1097aca7a94dSNamhyung Kim 
1098c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1099c0a58fb2SSamuel Liao 
1100aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1101aca7a94dSNamhyung Kim 		return -1;
1102aca7a94dSNamhyung Kim 
1103b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1104b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1105b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1106b793a401SArnaldo Carvalho de Melo 		return -1;
1107b793a401SArnaldo Carvalho de Melo 	}
1108b793a401SArnaldo Carvalho de Melo 
1109c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1110c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
11110c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
11120c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1113c7e7b610SNamhyung Kim 	}
1114c7e7b610SNamhyung Kim 
1115dcaa3948SJin Yao 	err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
111669fb09f6SJin Yao 				  sizeof_bdl, &browser.arch,
111769fb09f6SJin Yao 				  perf_evsel__env_cpuid(evsel));
1118ee51d851SArnaldo Carvalho de Melo 	if (err) {
1119ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1120ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1121ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1122b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1123aca7a94dSNamhyung Kim 	}
1124aca7a94dSNamhyung Kim 
11257727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1126aca7a94dSNamhyung Kim 
1127aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1128aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1129aca7a94dSNamhyung Kim 
1130aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1131887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1132aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1133aca7a94dSNamhyung Kim 
1134aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1135aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1136887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1137887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1138b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1139887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
114097148a97SArnaldo Carvalho de Melo 			/*
114197148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
114297148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
114397148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
114497148a97SArnaldo Carvalho de Melo 			 *
114597148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
114697148a97SArnaldo Carvalho de Melo  			 */
114797148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1148b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1149b793a401SArnaldo Carvalho de Melo 		} else
1150887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1151aca7a94dSNamhyung Kim 	}
1152aca7a94dSNamhyung Kim 
1153b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
115430e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1155b793a401SArnaldo Carvalho de Melo 
11562402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
115783b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11582402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1159c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1160aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1161aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1162aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1163e9823b21SArnaldo Carvalho de Melo 
1164e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1165e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1166e9823b21SArnaldo Carvalho de Melo 
1167e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1168e9823b21SArnaldo Carvalho de Melo 
1169db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1170aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1171aca7a94dSNamhyung Kim 		list_del(&pos->node);
117229ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1173aca7a94dSNamhyung Kim 	}
1174b793a401SArnaldo Carvalho de Melo 
1175b793a401SArnaldo Carvalho de Melo out_free_offsets:
1176b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1177aca7a94dSNamhyung Kim 	return ret;
1178aca7a94dSNamhyung Kim }
1179c323cf04SArnaldo Carvalho de Melo 
1180c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1181c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1182c323cf04SArnaldo Carvalho de Melo 
1183c323cf04SArnaldo Carvalho de Melo /*
1184c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1185c323cf04SArnaldo Carvalho de Melo  */
11867c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1187c323cf04SArnaldo Carvalho de Melo 	const char *name;
1188c323cf04SArnaldo Carvalho de Melo 	bool *value;
1189c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1190c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1191c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1192e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1193c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
1194*9cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
11950c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
119639ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1197c323cf04SArnaldo Carvalho de Melo };
1198c323cf04SArnaldo Carvalho de Melo 
1199c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1200c323cf04SArnaldo Carvalho de Melo 
1201c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1202c323cf04SArnaldo Carvalho de Melo {
12037c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1204c323cf04SArnaldo Carvalho de Melo 
1205c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1206c323cf04SArnaldo Carvalho de Melo }
1207c323cf04SArnaldo Carvalho de Melo 
12081d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
12091d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1210c323cf04SArnaldo Carvalho de Melo {
12117c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1212c323cf04SArnaldo Carvalho de Melo 	const char *name;
1213c323cf04SArnaldo Carvalho de Melo 
12148e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1215c323cf04SArnaldo Carvalho de Melo 		return 0;
1216c323cf04SArnaldo Carvalho de Melo 
1217c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1218c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12197c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1220c323cf04SArnaldo Carvalho de Melo 
1221c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1222f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1223f06cff7cSArnaldo Carvalho de Melo 	else
1224c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1225c323cf04SArnaldo Carvalho de Melo 	return 0;
1226c323cf04SArnaldo Carvalho de Melo }
1227c323cf04SArnaldo Carvalho de Melo 
1228c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1229c323cf04SArnaldo Carvalho de Melo {
1230c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1231c323cf04SArnaldo Carvalho de Melo }
1232