xref: /linux/tools/perf/ui/browsers/annotate.c (revision 896bccd3cb8d95cbc565687715516009c5169e71)
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;
210c4a5bceSMartin Liška 	u64		nr;
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 {
113f8f4aaeaSAndi Kleen 	int w = 7 * ab->nr_events;
114f8f4aaeaSAndi Kleen 
115f8f4aaeaSAndi Kleen 	if (ab->have_cycles)
116f8f4aaeaSAndi Kleen 		w += IPC_WIDTH + CYCLES_WIDTH;
117f8f4aaeaSAndi Kleen 	return w;
118f8f4aaeaSAndi Kleen }
119f8f4aaeaSAndi Kleen 
12005e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
121aca7a94dSNamhyung Kim {
12205e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
12329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
124b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
12505e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
126e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
12705e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
12805e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
12905e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
130f8f4aaeaSAndi Kleen 	int i, pcnt_width = annotate_browser__pcnt_width(ab);
131c7e7b610SNamhyung Kim 	double percent_max = 0.0;
13283b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
133ec27ae18SJin Yao 	bool show_title = false;
134aca7a94dSNamhyung Kim 
135c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1360c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1370c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
138c7e7b610SNamhyung Kim 	}
139c7e7b610SNamhyung Kim 
140ec27ae18SJin Yao 	if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) {
141ec27ae18SJin Yao 		if (ab->have_cycles) {
142ec27ae18SJin Yao 			if (dl->ipc == 0.0 && dl->cycles == 0)
143ec27ae18SJin Yao 				show_title = true;
144ec27ae18SJin Yao 		} else
145ec27ae18SJin Yao 			show_title = true;
146ec27ae18SJin Yao 	}
147ec27ae18SJin Yao 
148c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
149c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1500c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1510c4a5bceSMartin Liška 						bdl->samples[i].percent,
152c7e7b610SNamhyung Kim 						current_entry);
153517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
154517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6" PRIu64 " ",
1550c4a5bceSMartin Liška 						   bdl->samples[i].nr);
156517dfdb3SArnaldo Carvalho de Melo 			} else {
157517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
158517dfdb3SArnaldo Carvalho de Melo 						   bdl->samples[i].percent);
159517dfdb3SArnaldo Carvalho de Melo 			}
160c7e7b610SNamhyung Kim 		}
161aca7a94dSNamhyung Kim 	} else {
16205e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
163ec27ae18SJin Yao 
164ec27ae18SJin Yao 		if (!show_title)
16526270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
166ec27ae18SJin Yao 		else
167ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s", 7, "Percent");
168f8f4aaeaSAndi Kleen 	}
169f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
170f8f4aaeaSAndi Kleen 		if (dl->ipc)
171517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
172ec27ae18SJin Yao 		else if (!show_title)
17326270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
174ec27ae18SJin Yao 		else
175ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
176ec27ae18SJin Yao 
177f8f4aaeaSAndi Kleen 		if (dl->cycles)
178517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
179f8f4aaeaSAndi Kleen 					   CYCLES_WIDTH - 1, dl->cycles);
180ec27ae18SJin Yao 		else if (!show_title)
18126270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
182ec27ae18SJin Yao 		else
183ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
184aca7a94dSNamhyung Kim 	}
185aca7a94dSNamhyung Kim 
186cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
187aca7a94dSNamhyung Kim 
188aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
18905e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
190aca7a94dSNamhyung Kim 		width += 1;
191aca7a94dSNamhyung Kim 
19229ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
19326270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width);
19483b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
195e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
196e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
197e592488cSAndi Kleen 					ab->addr_width + 1, dl->line_nr);
198e592488cSAndi Kleen 		else
19983b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
20083b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
20126270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
20226270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
20383b1f2aaSArnaldo Carvalho de Melo 	} else {
20429ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
20583b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
206aca7a94dSNamhyung Kim 
207e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
208aca7a94dSNamhyung Kim 			addr += ab->start;
209aca7a94dSNamhyung Kim 
210e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
211aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
21261e04b33SArnaldo Carvalho de Melo 		} else {
2137d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
214e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2152402e4a9SArnaldo Carvalho de Melo 					int prev;
2162402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2172402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2182402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2192402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2202402e4a9SArnaldo Carvalho de Melo 											 current_entry);
22126270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
22205e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2232402e4a9SArnaldo Carvalho de Melo 				}
2242402e4a9SArnaldo Carvalho de Melo 
22561e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2262402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
22761e04b33SArnaldo Carvalho de Melo 			} else {
22861e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
22983b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
23061e04b33SArnaldo Carvalho de Melo 			}
23161e04b33SArnaldo Carvalho de Melo 		}
232b793a401SArnaldo Carvalho de Melo 
233aca7a94dSNamhyung Kim 		if (change_color)
23405e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
23526270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
236aca7a94dSNamhyung Kim 		if (change_color)
23705e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
23875b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
23975b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
240e216874cSRavi Bangoria 				bool fwd = dl->ops.target.offset > dl->offset;
24151a0d455SArnaldo Carvalho de Melo 
24205e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
24351a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
24451a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
24575b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
24605e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
24788298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
24875b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
24905e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2504ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2516ef94929SNaveen N. Rao 			} else {
2526ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2534ea08b52SArnaldo Carvalho de Melo 			}
2546ef94929SNaveen N. Rao 		} else {
2556ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2564ea08b52SArnaldo Carvalho de Melo 		}
2574ea08b52SArnaldo Carvalho de Melo 
258e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
25926270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
260aca7a94dSNamhyung Kim 	}
261aca7a94dSNamhyung Kim 
262aca7a94dSNamhyung Kim 	if (current_entry)
26329ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
264aca7a94dSNamhyung Kim }
265aca7a94dSNamhyung Kim 
266865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
267865c66c4SFrederik Deweerdt {
26875b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
269865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
270e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
271e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
272865c66c4SFrederik Deweerdt 		return false;
273865c66c4SFrederik Deweerdt 
274865c66c4SFrederik Deweerdt 	return true;
275865c66c4SFrederik Deweerdt }
276865c66c4SFrederik Deweerdt 
2777e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2787e63a13aSJin Yao {
2797e63a13aSJin Yao 	struct disasm_line *pos = list_prev_entry(cursor, node);
2807e63a13aSJin Yao 	const char *name;
2817e63a13aSJin Yao 
2827e63a13aSJin Yao 	if (!pos)
2837e63a13aSJin Yao 		return false;
2847e63a13aSJin Yao 
2857e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2867e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2877e63a13aSJin Yao 	else
2887e63a13aSJin Yao 		name = pos->ins.name;
2897e63a13aSJin Yao 
2907e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2917e63a13aSJin Yao 		return false;
2927e63a13aSJin Yao 
2937e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
2947e63a13aSJin Yao }
2957e63a13aSJin Yao 
2969d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
297a3f895beSArnaldo Carvalho de Melo {
298a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
2999d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
3009d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
30183b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
30232ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
30332ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
304f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
30532ae1efdSNamhyung Kim 
30632ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
30732ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
30832ae1efdSNamhyung Kim 		return;
309a3f895beSArnaldo Carvalho de Melo 
310865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
311a3f895beSArnaldo Carvalho de Melo 		return;
312a3f895beSArnaldo Carvalho de Melo 
3139d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
3149d1ef56dSArnaldo Carvalho de Melo 	if (!target)
3159d1ef56dSArnaldo Carvalho de Melo 		return;
3169d1ef56dSArnaldo Carvalho de Melo 
3179d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
3189d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
3199d1ef56dSArnaldo Carvalho de Melo 
320e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3219d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
322a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
323a3f895beSArnaldo Carvalho de Melo 	} else {
3249d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
325a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
326a3f895beSArnaldo Carvalho de Melo 	}
327a3f895beSArnaldo Carvalho de Melo 
32878ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
329c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
330c7e7b610SNamhyung Kim 				 from, to);
3317e63a13aSJin Yao 
3327e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3337e63a13aSJin Yao 		ui_browser__mark_fused(browser,
3347e63a13aSJin Yao 				       pcnt_width + 3 + ab->addr_width,
3357e63a13aSJin Yao 				       from - 1,
3367e63a13aSJin Yao 				       to > from ? true : false);
3377e63a13aSJin Yao 	}
338a3f895beSArnaldo Carvalho de Melo }
339a3f895beSArnaldo Carvalho de Melo 
340a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
341a3f895beSArnaldo Carvalho de Melo {
342c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
343a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
344f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
345a3f895beSArnaldo Carvalho de Melo 
346e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3479d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
348a3f895beSArnaldo Carvalho de Melo 
34983b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
350c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
351a3f895beSArnaldo Carvalho de Melo 	return ret;
352a3f895beSArnaldo Carvalho de Melo }
353a3f895beSArnaldo Carvalho de Melo 
354c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
355c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
356c7e7b610SNamhyung Kim {
357c7e7b610SNamhyung Kim 	int i;
358c7e7b610SNamhyung Kim 
359c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3600c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
361c7e7b610SNamhyung Kim 			continue;
3620c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
363c7e7b610SNamhyung Kim 	}
364c7e7b610SNamhyung Kim 	return 0;
365c7e7b610SNamhyung Kim }
366c7e7b610SNamhyung Kim 
367c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
368c7e7b610SNamhyung Kim 				   int nr_events)
369aca7a94dSNamhyung Kim {
37029ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
371aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
372887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
373aca7a94dSNamhyung Kim 
374aca7a94dSNamhyung Kim 	while (*p != NULL) {
375aca7a94dSNamhyung Kim 		parent = *p;
376887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
377c7e7b610SNamhyung Kim 
378c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
379aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
380aca7a94dSNamhyung Kim 		else
381aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
382aca7a94dSNamhyung Kim 	}
383887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
384887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
385aca7a94dSNamhyung Kim }
386aca7a94dSNamhyung Kim 
38705e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
38829ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
389aca7a94dSNamhyung Kim {
390aca7a94dSNamhyung Kim 	unsigned back;
391aca7a94dSNamhyung Kim 
39205e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
39305e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
39405e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
395aca7a94dSNamhyung Kim 
39605e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
39729ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
398aca7a94dSNamhyung Kim 
39905e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
400aca7a94dSNamhyung Kim 			continue;
401aca7a94dSNamhyung Kim 
40205e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
403aca7a94dSNamhyung Kim 		--back;
404aca7a94dSNamhyung Kim 	}
405aca7a94dSNamhyung Kim 
40605e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
40705e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
408aca7a94dSNamhyung Kim }
409aca7a94dSNamhyung Kim 
410aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
411aca7a94dSNamhyung Kim 					 struct rb_node *nd)
412aca7a94dSNamhyung Kim {
413887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
41429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
415a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
416aca7a94dSNamhyung Kim 
417887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
418887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
419a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
420e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
421a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
422a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
423aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
424aca7a94dSNamhyung Kim }
425aca7a94dSNamhyung Kim 
426aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
427db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
428aca7a94dSNamhyung Kim {
429aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
430aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
431aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
432e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
433e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
434aca7a94dSNamhyung Kim 
435aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
436aca7a94dSNamhyung Kim 
437aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
438aca7a94dSNamhyung Kim 
439aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
440887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
441e64aa75bSNamhyung Kim 		const char *path = NULL;
442c7e7b610SNamhyung Kim 		double max_percent = 0.0;
443c7e7b610SNamhyung Kim 		int i;
444e64aa75bSNamhyung Kim 
445e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
446e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
447e64aa75bSNamhyung Kim 			continue;
448e64aa75bSNamhyung Kim 		}
449e64aa75bSNamhyung Kim 
450e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
451c7e7b610SNamhyung Kim 
452c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
453*896bccd3STaeung Song 			struct sym_hist_entry sample;
4540c4a5bceSMartin Liška 
4550c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
456c7e7b610SNamhyung Kim 						evsel->idx + i,
457c7e7b610SNamhyung Kim 						pos->offset,
458c7e7b610SNamhyung Kim 						next ? next->offset : len,
459*896bccd3STaeung Song 						&path, &sample);
460*896bccd3STaeung Song 			bpos->samples[i].nr = sample.nr_samples;
461e64aa75bSNamhyung Kim 
4620c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4630c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
464c7e7b610SNamhyung Kim 		}
465c7e7b610SNamhyung Kim 
46630e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
467887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
468aca7a94dSNamhyung Kim 			continue;
469aca7a94dSNamhyung Kim 		}
470c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
471c7e7b610SNamhyung Kim 				       browser->nr_events);
472aca7a94dSNamhyung Kim 	}
473aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
474aca7a94dSNamhyung Kim 
475aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
476aca7a94dSNamhyung Kim }
477aca7a94dSNamhyung Kim 
478aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
479aca7a94dSNamhyung Kim {
48029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
481887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
482aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
483aca7a94dSNamhyung Kim 
484aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
48529ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
486887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
487aca7a94dSNamhyung Kim 
488e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
489887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
490887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
491aca7a94dSNamhyung Kim 
492aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
493e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
494aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
495887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
496887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
497aca7a94dSNamhyung Kim 	} else {
498887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
499aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
500aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
501aca7a94dSNamhyung Kim 			return false;
502aca7a94dSNamhyung Kim 		}
503aca7a94dSNamhyung Kim 
504887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
505887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
506aca7a94dSNamhyung Kim 
507aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
508e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
509aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
510887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
511887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
512aca7a94dSNamhyung Kim 	}
513aca7a94dSNamhyung Kim 
514aca7a94dSNamhyung Kim 	return true;
515aca7a94dSNamhyung Kim }
516aca7a94dSNamhyung Kim 
517e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
518e9823b21SArnaldo Carvalho de Melo {
519e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
520e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
521e9823b21SArnaldo Carvalho de Melo }
522e9823b21SArnaldo Carvalho de Melo 
52334f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
52434f77abcSAdrian Hunter 
52534f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
52634f77abcSAdrian Hunter 		     size_t sz)
52734f77abcSAdrian Hunter {
52834f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
52934f77abcSAdrian Hunter }
53034f77abcSAdrian Hunter 
531db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
532db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5339783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
534aca7a94dSNamhyung Kim {
535aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
536657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
537aca7a94dSNamhyung Kim 	struct annotation *notes;
5381179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5391179e11bSAdrian Hunter 		.map = ms->map,
5401d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5411179e11bSAdrian Hunter 	};
54234f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
543aca7a94dSNamhyung Kim 
54475b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
545aca7a94dSNamhyung Kim 		return false;
546aca7a94dSNamhyung Kim 
547be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5481d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5491d5077bdSAdrian Hunter 							     target.addr)) !=
5501d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
551aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
552aca7a94dSNamhyung Kim 		return true;
553aca7a94dSNamhyung Kim 	}
554aca7a94dSNamhyung Kim 
5551179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
556aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
557aca7a94dSNamhyung Kim 
5581179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
559aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
560aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5611179e11bSAdrian Hunter 			    target.sym->name);
562aca7a94dSNamhyung Kim 		return true;
563aca7a94dSNamhyung Kim 	}
564aca7a94dSNamhyung Kim 
565aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5661179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5671179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
56834f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
569aca7a94dSNamhyung Kim 	return true;
570aca7a94dSNamhyung Kim }
571aca7a94dSNamhyung Kim 
57229ed6e76SArnaldo Carvalho de Melo static
57329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
574aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
575aca7a94dSNamhyung Kim {
576aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
577aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
578aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
57929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
580aca7a94dSNamhyung Kim 
581aca7a94dSNamhyung Kim 	*idx = 0;
582aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
583aca7a94dSNamhyung Kim 		if (pos->offset == offset)
584aca7a94dSNamhyung Kim 			return pos;
58529ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
586aca7a94dSNamhyung Kim 			++*idx;
587aca7a94dSNamhyung Kim 	}
588aca7a94dSNamhyung Kim 
589aca7a94dSNamhyung Kim 	return NULL;
590aca7a94dSNamhyung Kim }
591aca7a94dSNamhyung Kim 
592aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
593aca7a94dSNamhyung Kim {
594657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
5955252b1aeSArnaldo Carvalho de Melo 	u64 offset;
5964f9d0325SArnaldo Carvalho de Melo 	s64 idx;
597aca7a94dSNamhyung Kim 
59875b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
599aca7a94dSNamhyung Kim 		return false;
600aca7a94dSNamhyung Kim 
6015252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6025252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
60329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6045252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
605aca7a94dSNamhyung Kim 		return true;
606aca7a94dSNamhyung Kim 	}
607aca7a94dSNamhyung Kim 
60829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
609aca7a94dSNamhyung Kim 
610aca7a94dSNamhyung Kim 	return true;
611aca7a94dSNamhyung Kim }
612aca7a94dSNamhyung Kim 
61329ed6e76SArnaldo Carvalho de Melo static
61429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
615aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
616aca7a94dSNamhyung Kim {
617aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
618aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
619aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
62029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
621aca7a94dSNamhyung Kim 
622aca7a94dSNamhyung Kim 	*idx = browser->b.index;
623aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
62429ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
625aca7a94dSNamhyung Kim 			continue;
626aca7a94dSNamhyung Kim 
627aca7a94dSNamhyung Kim 		++*idx;
628aca7a94dSNamhyung Kim 
629aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
630aca7a94dSNamhyung Kim 			return pos;
631aca7a94dSNamhyung Kim 	}
632aca7a94dSNamhyung Kim 
633aca7a94dSNamhyung Kim 	return NULL;
634aca7a94dSNamhyung Kim }
635aca7a94dSNamhyung Kim 
636aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
637aca7a94dSNamhyung Kim {
63829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
639aca7a94dSNamhyung Kim 	s64 idx;
640aca7a94dSNamhyung Kim 
64129ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
64229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
643aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
644aca7a94dSNamhyung Kim 		return false;
645aca7a94dSNamhyung Kim 	}
646aca7a94dSNamhyung Kim 
64729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
648aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
649aca7a94dSNamhyung Kim 	return true;
650aca7a94dSNamhyung Kim }
651aca7a94dSNamhyung Kim 
65229ed6e76SArnaldo Carvalho de Melo static
65329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
654aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
655aca7a94dSNamhyung Kim {
656aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
657aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
658aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
65929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
660aca7a94dSNamhyung Kim 
661aca7a94dSNamhyung Kim 	*idx = browser->b.index;
662aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
66329ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
664aca7a94dSNamhyung Kim 			continue;
665aca7a94dSNamhyung Kim 
666aca7a94dSNamhyung Kim 		--*idx;
667aca7a94dSNamhyung Kim 
668aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
669aca7a94dSNamhyung Kim 			return pos;
670aca7a94dSNamhyung Kim 	}
671aca7a94dSNamhyung Kim 
672aca7a94dSNamhyung Kim 	return NULL;
673aca7a94dSNamhyung Kim }
674aca7a94dSNamhyung Kim 
675aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
676aca7a94dSNamhyung Kim {
67729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
678aca7a94dSNamhyung Kim 	s64 idx;
679aca7a94dSNamhyung Kim 
68029ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
68129ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
682aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
683aca7a94dSNamhyung Kim 		return false;
684aca7a94dSNamhyung Kim 	}
685aca7a94dSNamhyung Kim 
68629ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
687aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
688aca7a94dSNamhyung Kim 	return true;
689aca7a94dSNamhyung Kim }
690aca7a94dSNamhyung Kim 
691aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
692aca7a94dSNamhyung Kim 					    int delay_secs)
693aca7a94dSNamhyung Kim {
694aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
695aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
696aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
697aca7a94dSNamhyung Kim 	    !*browser->search_bf)
698aca7a94dSNamhyung Kim 		return false;
699aca7a94dSNamhyung Kim 
700aca7a94dSNamhyung Kim 	return true;
701aca7a94dSNamhyung Kim }
702aca7a94dSNamhyung Kim 
703aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
704aca7a94dSNamhyung Kim {
705aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
706aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
707aca7a94dSNamhyung Kim 
708aca7a94dSNamhyung Kim 	return false;
709aca7a94dSNamhyung Kim }
710aca7a94dSNamhyung Kim 
711aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
712aca7a94dSNamhyung Kim 					      int delay_secs)
713aca7a94dSNamhyung Kim {
714aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
715aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
716aca7a94dSNamhyung Kim 
717aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
718aca7a94dSNamhyung Kim }
719aca7a94dSNamhyung Kim 
720aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
721aca7a94dSNamhyung Kim 					   int delay_secs)
722aca7a94dSNamhyung Kim {
723aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
724aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
725aca7a94dSNamhyung Kim 
726aca7a94dSNamhyung Kim 	return false;
727aca7a94dSNamhyung Kim }
728aca7a94dSNamhyung Kim 
729aca7a94dSNamhyung Kim static
730aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
731aca7a94dSNamhyung Kim 					       int delay_secs)
732aca7a94dSNamhyung Kim {
733aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
734aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
735aca7a94dSNamhyung Kim 
736aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
737aca7a94dSNamhyung Kim }
738aca7a94dSNamhyung Kim 
739e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
740e9823b21SArnaldo Carvalho de Melo {
741e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
742e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
743e9823b21SArnaldo Carvalho de Melo 	else
744e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
745e9823b21SArnaldo Carvalho de Melo 
746e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
747e9823b21SArnaldo Carvalho de Melo 
748e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
749e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
750e9823b21SArnaldo Carvalho de Melo }
751e9823b21SArnaldo Carvalho de Melo 
752db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
753db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7549783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
755aca7a94dSNamhyung Kim {
756aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
75705e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
758aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
75954e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7609783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
761aca7a94dSNamhyung Kim 	int key;
76234f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
763aca7a94dSNamhyung Kim 
76434f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
76534f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
766aca7a94dSNamhyung Kim 		return -1;
767aca7a94dSNamhyung Kim 
768db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
769aca7a94dSNamhyung Kim 
77005e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
77105e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
77205e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
773aca7a94dSNamhyung Kim 	}
774aca7a94dSNamhyung Kim 
77505e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
776aca7a94dSNamhyung Kim 
777aca7a94dSNamhyung Kim 	while (1) {
77805e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
779aca7a94dSNamhyung Kim 
780aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
781db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
782aca7a94dSNamhyung Kim 			/*
783aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
784aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
785aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
786aca7a94dSNamhyung Kim 			 */
787aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
788aca7a94dSNamhyung Kim 				nd = NULL;
789aca7a94dSNamhyung Kim 		}
790aca7a94dSNamhyung Kim 
791aca7a94dSNamhyung Kim 		switch (key) {
792aca7a94dSNamhyung Kim 		case K_TIMER:
7939783adf7SNamhyung Kim 			if (hbt)
7949783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
795aca7a94dSNamhyung Kim 
796aca7a94dSNamhyung Kim 			if (delay_secs != 0)
797db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
798aca7a94dSNamhyung Kim 			continue;
799aca7a94dSNamhyung Kim 		case K_TAB:
800aca7a94dSNamhyung Kim 			if (nd != NULL) {
801aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
802aca7a94dSNamhyung Kim 				if (nd == NULL)
80305e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
804aca7a94dSNamhyung Kim 			} else
80505e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
806aca7a94dSNamhyung Kim 			break;
807aca7a94dSNamhyung Kim 		case K_UNTAB:
808d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
809aca7a94dSNamhyung Kim 				nd = rb_next(nd);
810aca7a94dSNamhyung Kim 				if (nd == NULL)
81105e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
812d4913cbdSMarkus Trippelsdorf 			} else
81305e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
814aca7a94dSNamhyung Kim 			break;
81554e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
816aca7a94dSNamhyung Kim 		case 'h':
81705e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
81854e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
81954e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
82054e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8217727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8227727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
823107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
82454e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
82554e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
82654e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
82754e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
82854e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8290c4a5bceSMartin Liška 		"t             Toggle total period view\n"
83054e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
831e592488cSAndi Kleen 		"k             Toggle line numbers\n"
83279ee47faSFeng Tang 		"r             Run available scripts\n"
833fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
83454e7a4e8SArnaldo Carvalho de Melo 			continue;
83579ee47faSFeng Tang 		case 'r':
83679ee47faSFeng Tang 			{
83779ee47faSFeng Tang 				script_browse(NULL);
83879ee47faSFeng Tang 				continue;
83979ee47faSFeng Tang 			}
840e592488cSAndi Kleen 		case 'k':
841e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
842e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
843e592488cSAndi Kleen 			break;
84454e7a4e8SArnaldo Carvalho de Melo 		case 'H':
84505e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
846aca7a94dSNamhyung Kim 			break;
847aca7a94dSNamhyung Kim 		case 's':
84805e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
849aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
850aca7a94dSNamhyung Kim 			continue;
851aca7a94dSNamhyung Kim 		case 'o':
852e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
85305e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
854aca7a94dSNamhyung Kim 			continue;
8559d1ef56dSArnaldo Carvalho de Melo 		case 'j':
856e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8579d1ef56dSArnaldo Carvalho de Melo 			continue;
8582402e4a9SArnaldo Carvalho de Melo 		case 'J':
859e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
86005e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
861e9823b21SArnaldo Carvalho de Melo 			continue;
862aca7a94dSNamhyung Kim 		case '/':
86305e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
864aca7a94dSNamhyung Kim show_help:
865aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
866aca7a94dSNamhyung Kim 			}
867aca7a94dSNamhyung Kim 			continue;
868aca7a94dSNamhyung Kim 		case 'n':
86905e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
87005e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
87105e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
872aca7a94dSNamhyung Kim 				goto show_help;
873aca7a94dSNamhyung Kim 			continue;
874aca7a94dSNamhyung Kim 		case '?':
87505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
876aca7a94dSNamhyung Kim 				goto show_help;
877aca7a94dSNamhyung Kim 			continue;
878e9823b21SArnaldo Carvalho de Melo 		case 'D': {
879e9823b21SArnaldo Carvalho de Melo 			static int seq;
880e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
881e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
88205e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
88305e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
88405e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
88505e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
88605e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
887e9823b21SArnaldo Carvalho de Melo 		}
888e9823b21SArnaldo Carvalho de Melo 			continue;
889aca7a94dSNamhyung Kim 		case K_ENTER:
890aca7a94dSNamhyung Kim 		case K_RIGHT:
89105e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
892aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
89305e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
894aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
89575b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
896c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
89775b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
898c4cceae3SArnaldo Carvalho de Melo 				goto out;
8996ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
900db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
901c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9026ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
903c4cceae3SArnaldo Carvalho de Melo 			}
904aca7a94dSNamhyung Kim 			continue;
9050c4a5bceSMartin Liška 		case 't':
9060c4a5bceSMartin Liška 			annotate_browser__opts.show_total_period =
9070c4a5bceSMartin Liška 			  !annotate_browser__opts.show_total_period;
9080c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9090c4a5bceSMartin Liška 			continue;
910aca7a94dSNamhyung Kim 		case K_LEFT:
911aca7a94dSNamhyung Kim 		case K_ESC:
912aca7a94dSNamhyung Kim 		case 'q':
913aca7a94dSNamhyung Kim 		case CTRL('c'):
914aca7a94dSNamhyung Kim 			goto out;
915aca7a94dSNamhyung Kim 		default:
916aca7a94dSNamhyung Kim 			continue;
917aca7a94dSNamhyung Kim 		}
918aca7a94dSNamhyung Kim 
919aca7a94dSNamhyung Kim 		if (nd != NULL)
92005e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
921aca7a94dSNamhyung Kim 	}
922aca7a94dSNamhyung Kim out:
92305e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
924aca7a94dSNamhyung Kim 	return key;
925aca7a94dSNamhyung Kim }
926aca7a94dSNamhyung Kim 
927d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
928d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
929d5dbc518SArnaldo Carvalho de Melo {
9300c4a5bceSMartin Liška 	/* Set default value for show_total_period.  */
9310c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9320c4a5bceSMartin Liška 	  symbol_conf.show_total_period;
9330c4a5bceSMartin Liška 
934d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
935d5dbc518SArnaldo Carvalho de Melo }
936d5dbc518SArnaldo Carvalho de Melo 
937db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9389783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
939aca7a94dSNamhyung Kim {
940ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
941ed426915SNamhyung Kim 	SLang_reset_tty();
942ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
943ed426915SNamhyung Kim 
944d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
945aca7a94dSNamhyung Kim }
946aca7a94dSNamhyung Kim 
94730e863bbSAndi Kleen 
94830e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
94930e863bbSAndi Kleen {
95030e863bbSAndi Kleen 	unsigned n_insn = 0;
95130e863bbSAndi Kleen 	u64 offset;
95230e863bbSAndi Kleen 
95330e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
95430e863bbSAndi Kleen 		if (browser->offsets[offset])
95530e863bbSAndi Kleen 			n_insn++;
95630e863bbSAndi Kleen 	}
95730e863bbSAndi Kleen 	return n_insn;
95830e863bbSAndi Kleen }
95930e863bbSAndi Kleen 
96030e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
96130e863bbSAndi Kleen 			   struct cyc_hist *ch)
96230e863bbSAndi Kleen {
96330e863bbSAndi Kleen 	unsigned n_insn;
96430e863bbSAndi Kleen 	u64 offset;
96530e863bbSAndi Kleen 
96630e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
96730e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
96830e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
96930e863bbSAndi Kleen 
97030e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
97130e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
97230e863bbSAndi Kleen 			return;
97330e863bbSAndi Kleen 
97430e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
97530e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
97630e863bbSAndi Kleen 
97730e863bbSAndi Kleen 			if (dl)
97830e863bbSAndi Kleen 				dl->ipc = ipc;
97930e863bbSAndi Kleen 		}
98030e863bbSAndi Kleen 	}
98130e863bbSAndi Kleen }
98230e863bbSAndi Kleen 
98330e863bbSAndi Kleen /*
98430e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
98530e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
98630e863bbSAndi Kleen  * which are only here.
98730e863bbSAndi Kleen  */
98830e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
98930e863bbSAndi Kleen 			   struct symbol *sym)
99030e863bbSAndi Kleen {
99130e863bbSAndi Kleen 	u64 offset;
99230e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
99330e863bbSAndi Kleen 
99430e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
99530e863bbSAndi Kleen 		return;
99630e863bbSAndi Kleen 
99730e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
99830e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
99930e863bbSAndi Kleen 		struct cyc_hist *ch;
100030e863bbSAndi Kleen 
100130e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
100230e863bbSAndi Kleen 		if (ch && ch->cycles) {
100330e863bbSAndi Kleen 			struct disasm_line *dl;
100430e863bbSAndi Kleen 
100530e863bbSAndi Kleen 			if (ch->have_start)
100630e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
100730e863bbSAndi Kleen 			dl = browser->offsets[offset];
100830e863bbSAndi Kleen 			if (dl && ch->num_aggr)
100930e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
101030e863bbSAndi Kleen 			browser->have_cycles = true;
101130e863bbSAndi Kleen 		}
101230e863bbSAndi Kleen 	}
101330e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
101430e863bbSAndi Kleen }
101530e863bbSAndi Kleen 
1016b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1017b793a401SArnaldo Carvalho de Melo 						size_t size)
1018b793a401SArnaldo Carvalho de Melo {
1019b793a401SArnaldo Carvalho de Melo 	u64 offset;
102032ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
102132ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
102232ae1efdSNamhyung Kim 
102332ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
102432ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
102532ae1efdSNamhyung Kim 		return;
1026b793a401SArnaldo Carvalho de Melo 
1027b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1028b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
1029b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
1030b793a401SArnaldo Carvalho de Melo 
1031865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1032b793a401SArnaldo Carvalho de Melo 			continue;
1033b793a401SArnaldo Carvalho de Melo 
103444d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10359481ede9SArnaldo Carvalho de Melo 		/*
10369481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10379481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10389481ede9SArnaldo Carvalho de Melo  		 */
10399481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10409481ede9SArnaldo Carvalho de Melo 			continue;
10419481ede9SArnaldo Carvalho de Melo 
1042b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
10432402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10442402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10452402e4a9SArnaldo Carvalho de Melo 
10462402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1047b793a401SArnaldo Carvalho de Melo 	}
1048b793a401SArnaldo Carvalho de Melo }
1049b793a401SArnaldo Carvalho de Melo 
10502402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10512402e4a9SArnaldo Carvalho de Melo {
10522402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10532402e4a9SArnaldo Carvalho de Melo 		return 5;
10542402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10552402e4a9SArnaldo Carvalho de Melo 		return 2;
10562402e4a9SArnaldo Carvalho de Melo 	return 1;
10572402e4a9SArnaldo Carvalho de Melo }
10582402e4a9SArnaldo Carvalho de Melo 
1059db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1060db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10619783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1062aca7a94dSNamhyung Kim {
106329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1064aca7a94dSNamhyung Kim 	struct annotation *notes;
1065c0a58fb2SSamuel Liao 	size_t size;
1066aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1067aca7a94dSNamhyung Kim 		.map = map,
1068aca7a94dSNamhyung Kim 		.sym = sym,
1069aca7a94dSNamhyung Kim 	};
1070aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1071aca7a94dSNamhyung Kim 		.b = {
1072a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1073aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1074aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
107529ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1076aca7a94dSNamhyung Kim 			.priv	 = &ms,
1077aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1078aca7a94dSNamhyung Kim 		},
1079aca7a94dSNamhyung Kim 	};
1080ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1081c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1082c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1083aca7a94dSNamhyung Kim 
1084aca7a94dSNamhyung Kim 	if (sym == NULL)
1085aca7a94dSNamhyung Kim 		return -1;
1086aca7a94dSNamhyung Kim 
1087c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1088c0a58fb2SSamuel Liao 
1089aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1090aca7a94dSNamhyung Kim 		return -1;
1091aca7a94dSNamhyung Kim 
1092b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1093b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1094b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1095b793a401SArnaldo Carvalho de Melo 		return -1;
1096b793a401SArnaldo Carvalho de Melo 	}
1097b793a401SArnaldo Carvalho de Melo 
1098c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1099c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
11000c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
11010c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1102c7e7b610SNamhyung Kim 	}
1103c7e7b610SNamhyung Kim 
1104dcaa3948SJin Yao 	err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
110569fb09f6SJin Yao 				  sizeof_bdl, &browser.arch,
110669fb09f6SJin Yao 				  perf_evsel__env_cpuid(evsel));
1107ee51d851SArnaldo Carvalho de Melo 	if (err) {
1108ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1109ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1110ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1111b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1112aca7a94dSNamhyung Kim 	}
1113aca7a94dSNamhyung Kim 
11147727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1115aca7a94dSNamhyung Kim 
1116aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1117aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1118aca7a94dSNamhyung Kim 
1119aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1120887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1121aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1122aca7a94dSNamhyung Kim 
1123aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1124aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1125887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1126887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1127b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1128887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
112997148a97SArnaldo Carvalho de Melo 			/*
113097148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
113197148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
113297148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
113397148a97SArnaldo Carvalho de Melo 			 *
113497148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
113597148a97SArnaldo Carvalho de Melo  			 */
113697148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1137b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1138b793a401SArnaldo Carvalho de Melo 		} else
1139887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1140aca7a94dSNamhyung Kim 	}
1141aca7a94dSNamhyung Kim 
1142b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
114330e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1144b793a401SArnaldo Carvalho de Melo 
11452402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
114683b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11472402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1148c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1149aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1150aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1151aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1152e9823b21SArnaldo Carvalho de Melo 
1153e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1154e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1155e9823b21SArnaldo Carvalho de Melo 
1156e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1157e9823b21SArnaldo Carvalho de Melo 
1158db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1159aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1160aca7a94dSNamhyung Kim 		list_del(&pos->node);
116129ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1162aca7a94dSNamhyung Kim 	}
1163b793a401SArnaldo Carvalho de Melo 
1164b793a401SArnaldo Carvalho de Melo out_free_offsets:
1165b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1166aca7a94dSNamhyung Kim 	return ret;
1167aca7a94dSNamhyung Kim }
1168c323cf04SArnaldo Carvalho de Melo 
1169c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1170c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1171c323cf04SArnaldo Carvalho de Melo 
1172c323cf04SArnaldo Carvalho de Melo /*
1173c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1174c323cf04SArnaldo Carvalho de Melo  */
11757c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1176c323cf04SArnaldo Carvalho de Melo 	const char *name;
1177c323cf04SArnaldo Carvalho de Melo 	bool *value;
1178c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1179c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1180c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1181e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1182c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11830c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
118439ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1185c323cf04SArnaldo Carvalho de Melo };
1186c323cf04SArnaldo Carvalho de Melo 
1187c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1188c323cf04SArnaldo Carvalho de Melo 
1189c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1190c323cf04SArnaldo Carvalho de Melo {
11917c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1192c323cf04SArnaldo Carvalho de Melo 
1193c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1194c323cf04SArnaldo Carvalho de Melo }
1195c323cf04SArnaldo Carvalho de Melo 
11961d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11971d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1198c323cf04SArnaldo Carvalho de Melo {
11997c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1200c323cf04SArnaldo Carvalho de Melo 	const char *name;
1201c323cf04SArnaldo Carvalho de Melo 
12028e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1203c323cf04SArnaldo Carvalho de Melo 		return 0;
1204c323cf04SArnaldo Carvalho de Melo 
1205c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1206c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12077c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1208c323cf04SArnaldo Carvalho de Melo 
1209c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1210f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1211f06cff7cSArnaldo Carvalho de Melo 	else
1212c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1213c323cf04SArnaldo Carvalho de Melo 	return 0;
1214c323cf04SArnaldo Carvalho de Melo }
1215c323cf04SArnaldo Carvalho de Melo 
1216c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1217c323cf04SArnaldo Carvalho de Melo {
1218c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1219c323cf04SArnaldo Carvalho de Melo }
1220