xref: /linux/tools/perf/ui/browsers/annotate.c (revision bc1e5d60cebb711ca3783a87a969d18db376d357)
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,
450c4a5bceSMartin Liška 	     show_total_period;
46e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
47e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
48e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
49e9823b21SArnaldo Carvalho de Melo };
50e9823b21SArnaldo Carvalho de Melo 
51dcaa3948SJin Yao struct arch;
52dcaa3948SJin Yao 
53aca7a94dSNamhyung Kim struct annotate_browser {
54aca7a94dSNamhyung Kim 	struct ui_browser b;
55aca7a94dSNamhyung Kim 	struct rb_root	  entries;
56aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
5729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
58b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
59dcaa3948SJin Yao 	struct arch	    *arch;
60c7e7b610SNamhyung Kim 	int		    nr_events;
61aca7a94dSNamhyung Kim 	u64		    start;
62aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
63aca7a94dSNamhyung Kim 	int		    nr_entries;
642402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
652402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
66aca7a94dSNamhyung Kim 	bool		    searching_backwards;
6730e863bbSAndi Kleen 	bool		    have_cycles;
6883b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
692402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
702402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
7183b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
7283b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
73aca7a94dSNamhyung Kim 	char		    search_bf[128];
74aca7a94dSNamhyung Kim };
75aca7a94dSNamhyung Kim 
76887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
77aca7a94dSNamhyung Kim {
78887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
79aca7a94dSNamhyung Kim }
80aca7a94dSNamhyung Kim 
811d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
821d037ca1SIrina Tirdea 				void *entry)
83aca7a94dSNamhyung Kim {
84e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
8529ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
8629ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
87aca7a94dSNamhyung Kim 	}
88aca7a94dSNamhyung Kim 
89aca7a94dSNamhyung Kim 	return false;
90aca7a94dSNamhyung Kim }
91aca7a94dSNamhyung Kim 
922402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
932402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
942402e4a9SArnaldo Carvalho de Melo {
952402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
962402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
972402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
982402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
992402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
1002402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
1012402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
1022402e4a9SArnaldo Carvalho de Melo }
1032402e4a9SArnaldo Carvalho de Melo 
1042402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
1052402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1062402e4a9SArnaldo Carvalho de Melo {
1072402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1082402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1092402e4a9SArnaldo Carvalho de Melo }
1102402e4a9SArnaldo Carvalho de Melo 
111f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
112f8f4aaeaSAndi Kleen {
113*bc1e5d60SArnaldo Carvalho de Melo 	return 7 * ab->nr_events;
114*bc1e5d60SArnaldo Carvalho de Melo }
115f8f4aaeaSAndi Kleen 
116*bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab)
117*bc1e5d60SArnaldo Carvalho de Melo {
118*bc1e5d60SArnaldo Carvalho de Melo 	return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
119f8f4aaeaSAndi Kleen }
120f8f4aaeaSAndi Kleen 
12105e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
122aca7a94dSNamhyung Kim {
12305e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
12429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
125b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
12605e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
127e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
12805e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
12905e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
13005e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
131*bc1e5d60SArnaldo Carvalho de Melo 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
132*bc1e5d60SArnaldo Carvalho de Melo 	       cycles_width = annotate_browser__cycles_width(ab);
133c7e7b610SNamhyung Kim 	double percent_max = 0.0;
13483b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
135ec27ae18SJin Yao 	bool show_title = false;
136aca7a94dSNamhyung Kim 
137c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1380c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1390c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
140c7e7b610SNamhyung Kim 	}
141c7e7b610SNamhyung Kim 
142ec27ae18SJin Yao 	if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) {
143ec27ae18SJin Yao 		if (ab->have_cycles) {
144ec27ae18SJin Yao 			if (dl->ipc == 0.0 && dl->cycles == 0)
145ec27ae18SJin Yao 				show_title = true;
146ec27ae18SJin Yao 		} else
147ec27ae18SJin Yao 			show_title = true;
148ec27ae18SJin Yao 	}
149ec27ae18SJin Yao 
150c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
151c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1520c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1530c4a5bceSMartin Liška 						bdl->samples[i].percent,
154c7e7b610SNamhyung Kim 						current_entry);
155517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
156517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6" PRIu64 " ",
15729dc267fSTaeung Song 						   bdl->samples[i].he.period);
158517dfdb3SArnaldo Carvalho de Melo 			} else {
159517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
160517dfdb3SArnaldo Carvalho de Melo 						   bdl->samples[i].percent);
161517dfdb3SArnaldo Carvalho de Melo 			}
162c7e7b610SNamhyung Kim 		}
163aca7a94dSNamhyung Kim 	} else {
16405e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
165ec27ae18SJin Yao 
166ec27ae18SJin Yao 		if (!show_title)
167*bc1e5d60SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", pcnt_width);
168ec27ae18SJin Yao 		else
169ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s", 7, "Percent");
170f8f4aaeaSAndi Kleen 	}
171f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
172f8f4aaeaSAndi Kleen 		if (dl->ipc)
173517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
174ec27ae18SJin Yao 		else if (!show_title)
17526270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
176ec27ae18SJin Yao 		else
177ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
178ec27ae18SJin Yao 
179f8f4aaeaSAndi Kleen 		if (dl->cycles)
180517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
181f8f4aaeaSAndi Kleen 					   CYCLES_WIDTH - 1, dl->cycles);
182ec27ae18SJin Yao 		else if (!show_title)
18326270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
184ec27ae18SJin Yao 		else
185ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
186aca7a94dSNamhyung Kim 	}
187aca7a94dSNamhyung Kim 
188cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
189aca7a94dSNamhyung Kim 
190aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
19105e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
192aca7a94dSNamhyung Kim 		width += 1;
193aca7a94dSNamhyung Kim 
19429ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
195*bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
19683b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
197e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
198e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
199e592488cSAndi Kleen 					ab->addr_width + 1, dl->line_nr);
200e592488cSAndi Kleen 		else
20183b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
20283b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
20326270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
204*bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width - cycles_width + 1);
20583b1f2aaSArnaldo Carvalho de Melo 	} else {
20629ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
20783b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
208aca7a94dSNamhyung Kim 
209e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
210aca7a94dSNamhyung Kim 			addr += ab->start;
211aca7a94dSNamhyung Kim 
212e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
213aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
21461e04b33SArnaldo Carvalho de Melo 		} else {
2157d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
216e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2172402e4a9SArnaldo Carvalho de Melo 					int prev;
2182402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2192402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2202402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2212402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2222402e4a9SArnaldo Carvalho de Melo 											 current_entry);
22326270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
22405e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2252402e4a9SArnaldo Carvalho de Melo 				}
2262402e4a9SArnaldo Carvalho de Melo 
22761e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2282402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
22961e04b33SArnaldo Carvalho de Melo 			} else {
23061e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
23183b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
23261e04b33SArnaldo Carvalho de Melo 			}
23361e04b33SArnaldo Carvalho de Melo 		}
234b793a401SArnaldo Carvalho de Melo 
235aca7a94dSNamhyung Kim 		if (change_color)
23605e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
23726270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
238aca7a94dSNamhyung Kim 		if (change_color)
23905e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
24075b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
24175b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
242e216874cSRavi Bangoria 				bool fwd = dl->ops.target.offset > dl->offset;
24351a0d455SArnaldo Carvalho de Melo 
24405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
24551a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
24651a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
24775b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
24805e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
24988298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25075b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
25105e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2524ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2536ef94929SNaveen N. Rao 			} else {
2546ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2554ea08b52SArnaldo Carvalho de Melo 			}
2566ef94929SNaveen N. Rao 		} else {
2576ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2584ea08b52SArnaldo Carvalho de Melo 		}
2594ea08b52SArnaldo Carvalho de Melo 
260e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
261*bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
262aca7a94dSNamhyung Kim 	}
263aca7a94dSNamhyung Kim 
264aca7a94dSNamhyung Kim 	if (current_entry)
26529ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
266aca7a94dSNamhyung Kim }
267aca7a94dSNamhyung Kim 
268865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
269865c66c4SFrederik Deweerdt {
27075b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
271865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
272e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
273e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
274865c66c4SFrederik Deweerdt 		return false;
275865c66c4SFrederik Deweerdt 
276865c66c4SFrederik Deweerdt 	return true;
277865c66c4SFrederik Deweerdt }
278865c66c4SFrederik Deweerdt 
2797e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2807e63a13aSJin Yao {
2817e63a13aSJin Yao 	struct disasm_line *pos = list_prev_entry(cursor, node);
2827e63a13aSJin Yao 	const char *name;
2837e63a13aSJin Yao 
2847e63a13aSJin Yao 	if (!pos)
2857e63a13aSJin Yao 		return false;
2867e63a13aSJin Yao 
2877e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2887e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2897e63a13aSJin Yao 	else
2907e63a13aSJin Yao 		name = pos->ins.name;
2917e63a13aSJin Yao 
2927e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2937e63a13aSJin Yao 		return false;
2947e63a13aSJin Yao 
2957e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
2967e63a13aSJin Yao }
2977e63a13aSJin Yao 
2989d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
299a3f895beSArnaldo Carvalho de Melo {
300a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3019d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
3029d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
30383b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
30432ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
30532ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
306f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
30732ae1efdSNamhyung Kim 
30832ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
30932ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31032ae1efdSNamhyung Kim 		return;
311a3f895beSArnaldo Carvalho de Melo 
312865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
313a3f895beSArnaldo Carvalho de Melo 		return;
314a3f895beSArnaldo Carvalho de Melo 
3159d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
3169d1ef56dSArnaldo Carvalho de Melo 	if (!target)
3179d1ef56dSArnaldo Carvalho de Melo 		return;
3189d1ef56dSArnaldo Carvalho de Melo 
3199d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
3209d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
3219d1ef56dSArnaldo Carvalho de Melo 
322e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3239d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
324a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
325a3f895beSArnaldo Carvalho de Melo 	} else {
3269d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
327a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
328a3f895beSArnaldo Carvalho de Melo 	}
329a3f895beSArnaldo Carvalho de Melo 
33078ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
331c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
332c7e7b610SNamhyung Kim 				 from, to);
3337e63a13aSJin Yao 
3347e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3357e63a13aSJin Yao 		ui_browser__mark_fused(browser,
3367e63a13aSJin Yao 				       pcnt_width + 3 + ab->addr_width,
3377e63a13aSJin Yao 				       from - 1,
3387e63a13aSJin Yao 				       to > from ? true : false);
3397e63a13aSJin Yao 	}
340a3f895beSArnaldo Carvalho de Melo }
341a3f895beSArnaldo Carvalho de Melo 
342a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
343a3f895beSArnaldo Carvalho de Melo {
344c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
345a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
346f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
347a3f895beSArnaldo Carvalho de Melo 
348e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3499d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
350a3f895beSArnaldo Carvalho de Melo 
35183b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
352c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
353a3f895beSArnaldo Carvalho de Melo 	return ret;
354a3f895beSArnaldo Carvalho de Melo }
355a3f895beSArnaldo Carvalho de Melo 
356c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
357c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
358c7e7b610SNamhyung Kim {
359c7e7b610SNamhyung Kim 	int i;
360c7e7b610SNamhyung Kim 
361c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3620c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
363c7e7b610SNamhyung Kim 			continue;
3640c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
365c7e7b610SNamhyung Kim 	}
366c7e7b610SNamhyung Kim 	return 0;
367c7e7b610SNamhyung Kim }
368c7e7b610SNamhyung Kim 
369c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
370c7e7b610SNamhyung Kim 				   int nr_events)
371aca7a94dSNamhyung Kim {
37229ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
373aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
374887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
375aca7a94dSNamhyung Kim 
376aca7a94dSNamhyung Kim 	while (*p != NULL) {
377aca7a94dSNamhyung Kim 		parent = *p;
378887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
379c7e7b610SNamhyung Kim 
380c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
381aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
382aca7a94dSNamhyung Kim 		else
383aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
384aca7a94dSNamhyung Kim 	}
385887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
386887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
387aca7a94dSNamhyung Kim }
388aca7a94dSNamhyung Kim 
38905e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
39029ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
391aca7a94dSNamhyung Kim {
392aca7a94dSNamhyung Kim 	unsigned back;
393aca7a94dSNamhyung Kim 
39405e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
39505e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
39605e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
397aca7a94dSNamhyung Kim 
39805e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
39929ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
400aca7a94dSNamhyung Kim 
40105e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
402aca7a94dSNamhyung Kim 			continue;
403aca7a94dSNamhyung Kim 
40405e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
405aca7a94dSNamhyung Kim 		--back;
406aca7a94dSNamhyung Kim 	}
407aca7a94dSNamhyung Kim 
40805e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
40905e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
410aca7a94dSNamhyung Kim }
411aca7a94dSNamhyung Kim 
412aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
413aca7a94dSNamhyung Kim 					 struct rb_node *nd)
414aca7a94dSNamhyung Kim {
415887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
41629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
417a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
418aca7a94dSNamhyung Kim 
419887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
420887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
421a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
422e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
423a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
424a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
425aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
426aca7a94dSNamhyung Kim }
427aca7a94dSNamhyung Kim 
428aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
429db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
430aca7a94dSNamhyung Kim {
431aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
432aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
433aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
434e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
435e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
436aca7a94dSNamhyung Kim 
437aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
438aca7a94dSNamhyung Kim 
439aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
440aca7a94dSNamhyung Kim 
441aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
442887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
443e64aa75bSNamhyung Kim 		const char *path = NULL;
444c7e7b610SNamhyung Kim 		double max_percent = 0.0;
445c7e7b610SNamhyung Kim 		int i;
446e64aa75bSNamhyung Kim 
447e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
448e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
449e64aa75bSNamhyung Kim 			continue;
450e64aa75bSNamhyung Kim 		}
451e64aa75bSNamhyung Kim 
452e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
453c7e7b610SNamhyung Kim 
454c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
455896bccd3STaeung Song 			struct sym_hist_entry sample;
4560c4a5bceSMartin Liška 
4570c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
458c7e7b610SNamhyung Kim 						evsel->idx + i,
459c7e7b610SNamhyung Kim 						pos->offset,
460c7e7b610SNamhyung Kim 						next ? next->offset : len,
461896bccd3STaeung Song 						&path, &sample);
462bb79a232SArnaldo Carvalho de Melo 			bpos->samples[i].he = sample;
463e64aa75bSNamhyung Kim 
4640c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4650c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
466c7e7b610SNamhyung Kim 		}
467c7e7b610SNamhyung Kim 
46830e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
469887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
470aca7a94dSNamhyung Kim 			continue;
471aca7a94dSNamhyung Kim 		}
472c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
473c7e7b610SNamhyung Kim 				       browser->nr_events);
474aca7a94dSNamhyung Kim 	}
475aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
476aca7a94dSNamhyung Kim 
477aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
478aca7a94dSNamhyung Kim }
479aca7a94dSNamhyung Kim 
480aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
481aca7a94dSNamhyung Kim {
48229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
483887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
484aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
485aca7a94dSNamhyung Kim 
486aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
48729ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
488887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
489aca7a94dSNamhyung Kim 
490e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
491887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
492887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
493aca7a94dSNamhyung Kim 
494aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
495e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
496aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
497887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
498887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
499aca7a94dSNamhyung Kim 	} else {
500887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
501aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
502aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
503aca7a94dSNamhyung Kim 			return false;
504aca7a94dSNamhyung Kim 		}
505aca7a94dSNamhyung Kim 
506887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
507887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
508aca7a94dSNamhyung Kim 
509aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
510e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
511aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
512887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
513887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
514aca7a94dSNamhyung Kim 	}
515aca7a94dSNamhyung Kim 
516aca7a94dSNamhyung Kim 	return true;
517aca7a94dSNamhyung Kim }
518aca7a94dSNamhyung Kim 
519e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
520e9823b21SArnaldo Carvalho de Melo {
521e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
522e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
523e9823b21SArnaldo Carvalho de Melo }
524e9823b21SArnaldo Carvalho de Melo 
52534f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
52634f77abcSAdrian Hunter 
52734f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
52834f77abcSAdrian Hunter 		     size_t sz)
52934f77abcSAdrian Hunter {
53034f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
53134f77abcSAdrian Hunter }
53234f77abcSAdrian Hunter 
533db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
534db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5359783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
536aca7a94dSNamhyung Kim {
537aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
538657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
539aca7a94dSNamhyung Kim 	struct annotation *notes;
5401179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5411179e11bSAdrian Hunter 		.map = ms->map,
5421d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5431179e11bSAdrian Hunter 	};
54434f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
545aca7a94dSNamhyung Kim 
54675b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
547aca7a94dSNamhyung Kim 		return false;
548aca7a94dSNamhyung Kim 
549be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5501d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5511d5077bdSAdrian Hunter 							     target.addr)) !=
5521d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
553aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
554aca7a94dSNamhyung Kim 		return true;
555aca7a94dSNamhyung Kim 	}
556aca7a94dSNamhyung Kim 
5571179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
558aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
559aca7a94dSNamhyung Kim 
5601179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
561aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
562aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5631179e11bSAdrian Hunter 			    target.sym->name);
564aca7a94dSNamhyung Kim 		return true;
565aca7a94dSNamhyung Kim 	}
566aca7a94dSNamhyung Kim 
567aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5681179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5691179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
57034f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
571aca7a94dSNamhyung Kim 	return true;
572aca7a94dSNamhyung Kim }
573aca7a94dSNamhyung Kim 
57429ed6e76SArnaldo Carvalho de Melo static
57529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
576aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
577aca7a94dSNamhyung Kim {
578aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
579aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
580aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
58129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
582aca7a94dSNamhyung Kim 
583aca7a94dSNamhyung Kim 	*idx = 0;
584aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
585aca7a94dSNamhyung Kim 		if (pos->offset == offset)
586aca7a94dSNamhyung Kim 			return pos;
58729ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
588aca7a94dSNamhyung Kim 			++*idx;
589aca7a94dSNamhyung Kim 	}
590aca7a94dSNamhyung Kim 
591aca7a94dSNamhyung Kim 	return NULL;
592aca7a94dSNamhyung Kim }
593aca7a94dSNamhyung Kim 
594aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
595aca7a94dSNamhyung Kim {
596657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
5975252b1aeSArnaldo Carvalho de Melo 	u64 offset;
5984f9d0325SArnaldo Carvalho de Melo 	s64 idx;
599aca7a94dSNamhyung Kim 
60075b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
601aca7a94dSNamhyung Kim 		return false;
602aca7a94dSNamhyung Kim 
6035252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6045252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
60529ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6065252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
607aca7a94dSNamhyung Kim 		return true;
608aca7a94dSNamhyung Kim 	}
609aca7a94dSNamhyung Kim 
61029ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
611aca7a94dSNamhyung Kim 
612aca7a94dSNamhyung Kim 	return true;
613aca7a94dSNamhyung Kim }
614aca7a94dSNamhyung Kim 
61529ed6e76SArnaldo Carvalho de Melo static
61629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
617aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
618aca7a94dSNamhyung Kim {
619aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
620aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
621aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
62229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
623aca7a94dSNamhyung Kim 
624aca7a94dSNamhyung Kim 	*idx = browser->b.index;
625aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
62629ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
627aca7a94dSNamhyung Kim 			continue;
628aca7a94dSNamhyung Kim 
629aca7a94dSNamhyung Kim 		++*idx;
630aca7a94dSNamhyung Kim 
631aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
632aca7a94dSNamhyung Kim 			return pos;
633aca7a94dSNamhyung Kim 	}
634aca7a94dSNamhyung Kim 
635aca7a94dSNamhyung Kim 	return NULL;
636aca7a94dSNamhyung Kim }
637aca7a94dSNamhyung Kim 
638aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
639aca7a94dSNamhyung Kim {
64029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
641aca7a94dSNamhyung Kim 	s64 idx;
642aca7a94dSNamhyung Kim 
64329ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
64429ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
645aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
646aca7a94dSNamhyung Kim 		return false;
647aca7a94dSNamhyung Kim 	}
648aca7a94dSNamhyung Kim 
64929ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
650aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
651aca7a94dSNamhyung Kim 	return true;
652aca7a94dSNamhyung Kim }
653aca7a94dSNamhyung Kim 
65429ed6e76SArnaldo Carvalho de Melo static
65529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
656aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
657aca7a94dSNamhyung Kim {
658aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
659aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
660aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
66129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
662aca7a94dSNamhyung Kim 
663aca7a94dSNamhyung Kim 	*idx = browser->b.index;
664aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
66529ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
666aca7a94dSNamhyung Kim 			continue;
667aca7a94dSNamhyung Kim 
668aca7a94dSNamhyung Kim 		--*idx;
669aca7a94dSNamhyung Kim 
670aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
671aca7a94dSNamhyung Kim 			return pos;
672aca7a94dSNamhyung Kim 	}
673aca7a94dSNamhyung Kim 
674aca7a94dSNamhyung Kim 	return NULL;
675aca7a94dSNamhyung Kim }
676aca7a94dSNamhyung Kim 
677aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
678aca7a94dSNamhyung Kim {
67929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
680aca7a94dSNamhyung Kim 	s64 idx;
681aca7a94dSNamhyung Kim 
68229ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
68329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
684aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
685aca7a94dSNamhyung Kim 		return false;
686aca7a94dSNamhyung Kim 	}
687aca7a94dSNamhyung Kim 
68829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
689aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
690aca7a94dSNamhyung Kim 	return true;
691aca7a94dSNamhyung Kim }
692aca7a94dSNamhyung Kim 
693aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
694aca7a94dSNamhyung Kim 					    int delay_secs)
695aca7a94dSNamhyung Kim {
696aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
697aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
698aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
699aca7a94dSNamhyung Kim 	    !*browser->search_bf)
700aca7a94dSNamhyung Kim 		return false;
701aca7a94dSNamhyung Kim 
702aca7a94dSNamhyung Kim 	return true;
703aca7a94dSNamhyung Kim }
704aca7a94dSNamhyung Kim 
705aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
706aca7a94dSNamhyung Kim {
707aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
708aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
709aca7a94dSNamhyung Kim 
710aca7a94dSNamhyung Kim 	return false;
711aca7a94dSNamhyung Kim }
712aca7a94dSNamhyung Kim 
713aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
714aca7a94dSNamhyung Kim 					      int delay_secs)
715aca7a94dSNamhyung Kim {
716aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
717aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
718aca7a94dSNamhyung Kim 
719aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
720aca7a94dSNamhyung Kim }
721aca7a94dSNamhyung Kim 
722aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
723aca7a94dSNamhyung Kim 					   int delay_secs)
724aca7a94dSNamhyung Kim {
725aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
726aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
727aca7a94dSNamhyung Kim 
728aca7a94dSNamhyung Kim 	return false;
729aca7a94dSNamhyung Kim }
730aca7a94dSNamhyung Kim 
731aca7a94dSNamhyung Kim static
732aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
733aca7a94dSNamhyung Kim 					       int delay_secs)
734aca7a94dSNamhyung Kim {
735aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
736aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
737aca7a94dSNamhyung Kim 
738aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
739aca7a94dSNamhyung Kim }
740aca7a94dSNamhyung Kim 
741e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
742e9823b21SArnaldo Carvalho de Melo {
743e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
744e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
745e9823b21SArnaldo Carvalho de Melo 	else
746e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
747e9823b21SArnaldo Carvalho de Melo 
748e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
749e9823b21SArnaldo Carvalho de Melo 
750e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
751e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
752e9823b21SArnaldo Carvalho de Melo }
753e9823b21SArnaldo Carvalho de Melo 
754db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
755db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7569783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
757aca7a94dSNamhyung Kim {
758aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
75905e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
760aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
76154e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7629783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
763aca7a94dSNamhyung Kim 	int key;
76434f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
765aca7a94dSNamhyung Kim 
76634f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
76734f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
768aca7a94dSNamhyung Kim 		return -1;
769aca7a94dSNamhyung Kim 
770db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
771aca7a94dSNamhyung Kim 
77205e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
77305e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
77405e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
775aca7a94dSNamhyung Kim 	}
776aca7a94dSNamhyung Kim 
77705e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
778aca7a94dSNamhyung Kim 
779aca7a94dSNamhyung Kim 	while (1) {
78005e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
781aca7a94dSNamhyung Kim 
782aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
783db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
784aca7a94dSNamhyung Kim 			/*
785aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
786aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
787aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
788aca7a94dSNamhyung Kim 			 */
789aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
790aca7a94dSNamhyung Kim 				nd = NULL;
791aca7a94dSNamhyung Kim 		}
792aca7a94dSNamhyung Kim 
793aca7a94dSNamhyung Kim 		switch (key) {
794aca7a94dSNamhyung Kim 		case K_TIMER:
7959783adf7SNamhyung Kim 			if (hbt)
7969783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
797aca7a94dSNamhyung Kim 
798aca7a94dSNamhyung Kim 			if (delay_secs != 0)
799db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
800aca7a94dSNamhyung Kim 			continue;
801aca7a94dSNamhyung Kim 		case K_TAB:
802aca7a94dSNamhyung Kim 			if (nd != NULL) {
803aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
804aca7a94dSNamhyung Kim 				if (nd == NULL)
80505e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
806aca7a94dSNamhyung Kim 			} else
80705e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
808aca7a94dSNamhyung Kim 			break;
809aca7a94dSNamhyung Kim 		case K_UNTAB:
810d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
811aca7a94dSNamhyung Kim 				nd = rb_next(nd);
812aca7a94dSNamhyung Kim 				if (nd == NULL)
81305e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
814d4913cbdSMarkus Trippelsdorf 			} else
81505e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
816aca7a94dSNamhyung Kim 			break;
81754e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
818aca7a94dSNamhyung Kim 		case 'h':
81905e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
82054e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
82154e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
82254e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8237727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8247727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
825107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
82654e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
82754e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
82854e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
82954e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
83054e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8310c4a5bceSMartin Liška 		"t             Toggle total period view\n"
83254e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
833e592488cSAndi Kleen 		"k             Toggle line numbers\n"
83479ee47faSFeng Tang 		"r             Run available scripts\n"
835fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
83654e7a4e8SArnaldo Carvalho de Melo 			continue;
83779ee47faSFeng Tang 		case 'r':
83879ee47faSFeng Tang 			{
83979ee47faSFeng Tang 				script_browse(NULL);
84079ee47faSFeng Tang 				continue;
84179ee47faSFeng Tang 			}
842e592488cSAndi Kleen 		case 'k':
843e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
844e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
845e592488cSAndi Kleen 			break;
84654e7a4e8SArnaldo Carvalho de Melo 		case 'H':
84705e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
848aca7a94dSNamhyung Kim 			break;
849aca7a94dSNamhyung Kim 		case 's':
85005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
851aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
852aca7a94dSNamhyung Kim 			continue;
853aca7a94dSNamhyung Kim 		case 'o':
854e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
85505e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
856aca7a94dSNamhyung Kim 			continue;
8579d1ef56dSArnaldo Carvalho de Melo 		case 'j':
858e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8599d1ef56dSArnaldo Carvalho de Melo 			continue;
8602402e4a9SArnaldo Carvalho de Melo 		case 'J':
861e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
86205e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
863e9823b21SArnaldo Carvalho de Melo 			continue;
864aca7a94dSNamhyung Kim 		case '/':
86505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
866aca7a94dSNamhyung Kim show_help:
867aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
868aca7a94dSNamhyung Kim 			}
869aca7a94dSNamhyung Kim 			continue;
870aca7a94dSNamhyung Kim 		case 'n':
87105e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
87205e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
87305e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
874aca7a94dSNamhyung Kim 				goto show_help;
875aca7a94dSNamhyung Kim 			continue;
876aca7a94dSNamhyung Kim 		case '?':
87705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
878aca7a94dSNamhyung Kim 				goto show_help;
879aca7a94dSNamhyung Kim 			continue;
880e9823b21SArnaldo Carvalho de Melo 		case 'D': {
881e9823b21SArnaldo Carvalho de Melo 			static int seq;
882e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
883e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
88405e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
88505e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
88605e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
88705e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
88805e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
889e9823b21SArnaldo Carvalho de Melo 		}
890e9823b21SArnaldo Carvalho de Melo 			continue;
891aca7a94dSNamhyung Kim 		case K_ENTER:
892aca7a94dSNamhyung Kim 		case K_RIGHT:
89305e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
894aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
89505e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
896aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
89775b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
898c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
89975b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
900c4cceae3SArnaldo Carvalho de Melo 				goto out;
9016ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
902db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
903c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9046ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
905c4cceae3SArnaldo Carvalho de Melo 			}
906aca7a94dSNamhyung Kim 			continue;
9070c4a5bceSMartin Liška 		case 't':
9080c4a5bceSMartin Liška 			annotate_browser__opts.show_total_period =
9090c4a5bceSMartin Liška 			  !annotate_browser__opts.show_total_period;
9100c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9110c4a5bceSMartin Liška 			continue;
912aca7a94dSNamhyung Kim 		case K_LEFT:
913aca7a94dSNamhyung Kim 		case K_ESC:
914aca7a94dSNamhyung Kim 		case 'q':
915aca7a94dSNamhyung Kim 		case CTRL('c'):
916aca7a94dSNamhyung Kim 			goto out;
917aca7a94dSNamhyung Kim 		default:
918aca7a94dSNamhyung Kim 			continue;
919aca7a94dSNamhyung Kim 		}
920aca7a94dSNamhyung Kim 
921aca7a94dSNamhyung Kim 		if (nd != NULL)
92205e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
923aca7a94dSNamhyung Kim 	}
924aca7a94dSNamhyung Kim out:
92505e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
926aca7a94dSNamhyung Kim 	return key;
927aca7a94dSNamhyung Kim }
928aca7a94dSNamhyung Kim 
929d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
930d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
931d5dbc518SArnaldo Carvalho de Melo {
9320c4a5bceSMartin Liška 	/* Set default value for show_total_period.  */
9330c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9340c4a5bceSMartin Liška 	  symbol_conf.show_total_period;
9350c4a5bceSMartin Liška 
936d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
937d5dbc518SArnaldo Carvalho de Melo }
938d5dbc518SArnaldo Carvalho de Melo 
939db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9409783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
941aca7a94dSNamhyung Kim {
942ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
943ed426915SNamhyung Kim 	SLang_reset_tty();
944ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
945ed426915SNamhyung Kim 
946d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
947aca7a94dSNamhyung Kim }
948aca7a94dSNamhyung Kim 
94930e863bbSAndi Kleen 
95030e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
95130e863bbSAndi Kleen {
95230e863bbSAndi Kleen 	unsigned n_insn = 0;
95330e863bbSAndi Kleen 	u64 offset;
95430e863bbSAndi Kleen 
95530e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
95630e863bbSAndi Kleen 		if (browser->offsets[offset])
95730e863bbSAndi Kleen 			n_insn++;
95830e863bbSAndi Kleen 	}
95930e863bbSAndi Kleen 	return n_insn;
96030e863bbSAndi Kleen }
96130e863bbSAndi Kleen 
96230e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
96330e863bbSAndi Kleen 			   struct cyc_hist *ch)
96430e863bbSAndi Kleen {
96530e863bbSAndi Kleen 	unsigned n_insn;
96630e863bbSAndi Kleen 	u64 offset;
96730e863bbSAndi Kleen 
96830e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
96930e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
97030e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
97130e863bbSAndi Kleen 
97230e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
97330e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
97430e863bbSAndi Kleen 			return;
97530e863bbSAndi Kleen 
97630e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
97730e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
97830e863bbSAndi Kleen 
97930e863bbSAndi Kleen 			if (dl)
98030e863bbSAndi Kleen 				dl->ipc = ipc;
98130e863bbSAndi Kleen 		}
98230e863bbSAndi Kleen 	}
98330e863bbSAndi Kleen }
98430e863bbSAndi Kleen 
98530e863bbSAndi Kleen /*
98630e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
98730e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
98830e863bbSAndi Kleen  * which are only here.
98930e863bbSAndi Kleen  */
99030e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
99130e863bbSAndi Kleen 			   struct symbol *sym)
99230e863bbSAndi Kleen {
99330e863bbSAndi Kleen 	u64 offset;
99430e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
99530e863bbSAndi Kleen 
99630e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
99730e863bbSAndi Kleen 		return;
99830e863bbSAndi Kleen 
99930e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
100030e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
100130e863bbSAndi Kleen 		struct cyc_hist *ch;
100230e863bbSAndi Kleen 
100330e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
100430e863bbSAndi Kleen 		if (ch && ch->cycles) {
100530e863bbSAndi Kleen 			struct disasm_line *dl;
100630e863bbSAndi Kleen 
100730e863bbSAndi Kleen 			if (ch->have_start)
100830e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
100930e863bbSAndi Kleen 			dl = browser->offsets[offset];
101030e863bbSAndi Kleen 			if (dl && ch->num_aggr)
101130e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
101230e863bbSAndi Kleen 			browser->have_cycles = true;
101330e863bbSAndi Kleen 		}
101430e863bbSAndi Kleen 	}
101530e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
101630e863bbSAndi Kleen }
101730e863bbSAndi Kleen 
1018b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1019b793a401SArnaldo Carvalho de Melo 						size_t size)
1020b793a401SArnaldo Carvalho de Melo {
1021b793a401SArnaldo Carvalho de Melo 	u64 offset;
102232ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
102332ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
102432ae1efdSNamhyung Kim 
102532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
102632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
102732ae1efdSNamhyung Kim 		return;
1028b793a401SArnaldo Carvalho de Melo 
1029b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1030b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
1031b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
1032b793a401SArnaldo Carvalho de Melo 
1033865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1034b793a401SArnaldo Carvalho de Melo 			continue;
1035b793a401SArnaldo Carvalho de Melo 
103644d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10379481ede9SArnaldo Carvalho de Melo 		/*
10389481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10399481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10409481ede9SArnaldo Carvalho de Melo  		 */
10419481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10429481ede9SArnaldo Carvalho de Melo 			continue;
10439481ede9SArnaldo Carvalho de Melo 
1044b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
10452402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10462402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10472402e4a9SArnaldo Carvalho de Melo 
10482402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1049b793a401SArnaldo Carvalho de Melo 	}
1050b793a401SArnaldo Carvalho de Melo }
1051b793a401SArnaldo Carvalho de Melo 
10522402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10532402e4a9SArnaldo Carvalho de Melo {
10542402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10552402e4a9SArnaldo Carvalho de Melo 		return 5;
10562402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10572402e4a9SArnaldo Carvalho de Melo 		return 2;
10582402e4a9SArnaldo Carvalho de Melo 	return 1;
10592402e4a9SArnaldo Carvalho de Melo }
10602402e4a9SArnaldo Carvalho de Melo 
1061db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1062db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10639783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1064aca7a94dSNamhyung Kim {
106529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1066aca7a94dSNamhyung Kim 	struct annotation *notes;
1067c0a58fb2SSamuel Liao 	size_t size;
1068aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1069aca7a94dSNamhyung Kim 		.map = map,
1070aca7a94dSNamhyung Kim 		.sym = sym,
1071aca7a94dSNamhyung Kim 	};
1072aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1073aca7a94dSNamhyung Kim 		.b = {
1074a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1075aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1076aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
107729ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1078aca7a94dSNamhyung Kim 			.priv	 = &ms,
1079aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1080aca7a94dSNamhyung Kim 		},
1081aca7a94dSNamhyung Kim 	};
1082ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1083c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1084c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1085aca7a94dSNamhyung Kim 
1086aca7a94dSNamhyung Kim 	if (sym == NULL)
1087aca7a94dSNamhyung Kim 		return -1;
1088aca7a94dSNamhyung Kim 
1089c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1090c0a58fb2SSamuel Liao 
1091aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1092aca7a94dSNamhyung Kim 		return -1;
1093aca7a94dSNamhyung Kim 
1094b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1095b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1096b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1097b793a401SArnaldo Carvalho de Melo 		return -1;
1098b793a401SArnaldo Carvalho de Melo 	}
1099b793a401SArnaldo Carvalho de Melo 
1100c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1101c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
11020c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
11030c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1104c7e7b610SNamhyung Kim 	}
1105c7e7b610SNamhyung Kim 
1106dcaa3948SJin Yao 	err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
110769fb09f6SJin Yao 				  sizeof_bdl, &browser.arch,
110869fb09f6SJin Yao 				  perf_evsel__env_cpuid(evsel));
1109ee51d851SArnaldo Carvalho de Melo 	if (err) {
1110ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1111ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1112ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1113b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1114aca7a94dSNamhyung Kim 	}
1115aca7a94dSNamhyung Kim 
11167727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1117aca7a94dSNamhyung Kim 
1118aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1119aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1120aca7a94dSNamhyung Kim 
1121aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1122887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1123aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1124aca7a94dSNamhyung Kim 
1125aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1126aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1127887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1128887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1129b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1130887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
113197148a97SArnaldo Carvalho de Melo 			/*
113297148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
113397148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
113497148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
113597148a97SArnaldo Carvalho de Melo 			 *
113697148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
113797148a97SArnaldo Carvalho de Melo  			 */
113897148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1139b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1140b793a401SArnaldo Carvalho de Melo 		} else
1141887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1142aca7a94dSNamhyung Kim 	}
1143aca7a94dSNamhyung Kim 
1144b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
114530e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1146b793a401SArnaldo Carvalho de Melo 
11472402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
114883b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11492402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1150c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1151aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1152aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1153aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1154e9823b21SArnaldo Carvalho de Melo 
1155e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1156e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1157e9823b21SArnaldo Carvalho de Melo 
1158e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1159e9823b21SArnaldo Carvalho de Melo 
1160db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1161aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1162aca7a94dSNamhyung Kim 		list_del(&pos->node);
116329ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1164aca7a94dSNamhyung Kim 	}
1165b793a401SArnaldo Carvalho de Melo 
1166b793a401SArnaldo Carvalho de Melo out_free_offsets:
1167b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1168aca7a94dSNamhyung Kim 	return ret;
1169aca7a94dSNamhyung Kim }
1170c323cf04SArnaldo Carvalho de Melo 
1171c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1172c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1173c323cf04SArnaldo Carvalho de Melo 
1174c323cf04SArnaldo Carvalho de Melo /*
1175c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1176c323cf04SArnaldo Carvalho de Melo  */
11777c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1178c323cf04SArnaldo Carvalho de Melo 	const char *name;
1179c323cf04SArnaldo Carvalho de Melo 	bool *value;
1180c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1181c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1182c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1183e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1184c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11850c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
118639ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1187c323cf04SArnaldo Carvalho de Melo };
1188c323cf04SArnaldo Carvalho de Melo 
1189c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1190c323cf04SArnaldo Carvalho de Melo 
1191c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1192c323cf04SArnaldo Carvalho de Melo {
11937c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1194c323cf04SArnaldo Carvalho de Melo 
1195c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1196c323cf04SArnaldo Carvalho de Melo }
1197c323cf04SArnaldo Carvalho de Melo 
11981d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11991d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1200c323cf04SArnaldo Carvalho de Melo {
12017c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1202c323cf04SArnaldo Carvalho de Melo 	const char *name;
1203c323cf04SArnaldo Carvalho de Melo 
12048e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1205c323cf04SArnaldo Carvalho de Melo 		return 0;
1206c323cf04SArnaldo Carvalho de Melo 
1207c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1208c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12097c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1210c323cf04SArnaldo Carvalho de Melo 
1211c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1212f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1213f06cff7cSArnaldo Carvalho de Melo 	else
1214c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1215c323cf04SArnaldo Carvalho de Melo 	return 0;
1216c323cf04SArnaldo Carvalho de Melo }
1217c323cf04SArnaldo Carvalho de Melo 
1218c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1219c323cf04SArnaldo Carvalho de Melo {
1220c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1221c323cf04SArnaldo Carvalho de Melo }
1222