xref: /linux/tools/perf/ui/browsers/annotate.c (revision ec27ae1892f7f8119ce82535ffcc2889ea3bb3d8)
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"
12fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
13aca7a94dSNamhyung Kim #include <pthread.h>
14877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
15b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h>
16aca7a94dSNamhyung Kim 
170c4a5bceSMartin Liška struct disasm_line_samples {
180c4a5bceSMartin Liška 	double		percent;
190c4a5bceSMartin Liška 	u64		nr;
200c4a5bceSMartin Liška };
210c4a5bceSMartin Liška 
22f8f4aaeaSAndi Kleen #define IPC_WIDTH 6
23f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6
24f8f4aaeaSAndi Kleen 
25b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
26b793a401SArnaldo Carvalho de Melo 	struct rb_node			rb_node;
27b793a401SArnaldo Carvalho de Melo 	u32				idx;
28b793a401SArnaldo Carvalho de Melo 	int				idx_asm;
297d5b12f5SArnaldo Carvalho de Melo 	int				jump_sources;
30c7e7b610SNamhyung Kim 	/*
31c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
32c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
33c7e7b610SNamhyung Kim 	 */
340c4a5bceSMartin Liška 	struct disasm_line_samples	samples[1];
35b793a401SArnaldo Carvalho de Melo };
36b793a401SArnaldo Carvalho de Melo 
37e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
38e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
39e9823b21SArnaldo Carvalho de Melo 	     use_offset,
40e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
41e592488cSAndi Kleen 	     show_linenr,
420c4a5bceSMartin Liška 	     show_nr_jumps,
430c4a5bceSMartin Liška 	     show_total_period;
44e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
45e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
46e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
47e9823b21SArnaldo Carvalho de Melo };
48e9823b21SArnaldo Carvalho de Melo 
49aca7a94dSNamhyung Kim struct annotate_browser {
50aca7a94dSNamhyung Kim 	struct ui_browser b;
51aca7a94dSNamhyung Kim 	struct rb_root	  entries;
52aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
5329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
54b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
55c7e7b610SNamhyung Kim 	int		    nr_events;
56aca7a94dSNamhyung Kim 	u64		    start;
57aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
58aca7a94dSNamhyung Kim 	int		    nr_entries;
592402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
602402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
61aca7a94dSNamhyung Kim 	bool		    searching_backwards;
6230e863bbSAndi Kleen 	bool		    have_cycles;
6383b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
642402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
652402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
6683b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
6783b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
68aca7a94dSNamhyung Kim 	char		    search_bf[128];
69aca7a94dSNamhyung Kim };
70aca7a94dSNamhyung Kim 
71887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
72aca7a94dSNamhyung Kim {
73887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
74aca7a94dSNamhyung Kim }
75aca7a94dSNamhyung Kim 
761d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
771d037ca1SIrina Tirdea 				void *entry)
78aca7a94dSNamhyung Kim {
79e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
8029ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
8129ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
82aca7a94dSNamhyung Kim 	}
83aca7a94dSNamhyung Kim 
84aca7a94dSNamhyung Kim 	return false;
85aca7a94dSNamhyung Kim }
86aca7a94dSNamhyung Kim 
872402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
882402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
892402e4a9SArnaldo Carvalho de Melo {
902402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
912402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
922402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
932402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
942402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
952402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
962402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
972402e4a9SArnaldo Carvalho de Melo }
982402e4a9SArnaldo Carvalho de Melo 
992402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
1002402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1012402e4a9SArnaldo Carvalho de Melo {
1022402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1032402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1042402e4a9SArnaldo Carvalho de Melo }
1052402e4a9SArnaldo Carvalho de Melo 
106f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
107f8f4aaeaSAndi Kleen {
108f8f4aaeaSAndi Kleen 	int w = 7 * ab->nr_events;
109f8f4aaeaSAndi Kleen 
110f8f4aaeaSAndi Kleen 	if (ab->have_cycles)
111f8f4aaeaSAndi Kleen 		w += IPC_WIDTH + CYCLES_WIDTH;
112f8f4aaeaSAndi Kleen 	return w;
113f8f4aaeaSAndi Kleen }
114f8f4aaeaSAndi Kleen 
11505e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
116aca7a94dSNamhyung Kim {
11705e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
11829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
119b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
12005e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
121e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
12205e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
12305e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
12405e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
125f8f4aaeaSAndi Kleen 	int i, pcnt_width = annotate_browser__pcnt_width(ab);
126c7e7b610SNamhyung Kim 	double percent_max = 0.0;
12783b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
128*ec27ae18SJin Yao 	bool show_title = false;
129aca7a94dSNamhyung Kim 
130c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1310c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1320c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
133c7e7b610SNamhyung Kim 	}
134c7e7b610SNamhyung Kim 
135*ec27ae18SJin Yao 	if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) {
136*ec27ae18SJin Yao 		if (ab->have_cycles) {
137*ec27ae18SJin Yao 			if (dl->ipc == 0.0 && dl->cycles == 0)
138*ec27ae18SJin Yao 				show_title = true;
139*ec27ae18SJin Yao 		} else
140*ec27ae18SJin Yao 			show_title = true;
141*ec27ae18SJin Yao 	}
142*ec27ae18SJin Yao 
143c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
144c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1450c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1460c4a5bceSMartin Liška 						bdl->samples[i].percent,
147c7e7b610SNamhyung Kim 						current_entry);
148517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
149517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6" PRIu64 " ",
1500c4a5bceSMartin Liška 						   bdl->samples[i].nr);
151517dfdb3SArnaldo Carvalho de Melo 			} else {
152517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
153517dfdb3SArnaldo Carvalho de Melo 						   bdl->samples[i].percent);
154517dfdb3SArnaldo Carvalho de Melo 			}
155c7e7b610SNamhyung Kim 		}
156aca7a94dSNamhyung Kim 	} else {
15705e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
158*ec27ae18SJin Yao 
159*ec27ae18SJin Yao 		if (!show_title)
16026270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
161*ec27ae18SJin Yao 		else
162*ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s", 7, "Percent");
163f8f4aaeaSAndi Kleen 	}
164f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
165f8f4aaeaSAndi Kleen 		if (dl->ipc)
166517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
167*ec27ae18SJin Yao 		else if (!show_title)
16826270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
169*ec27ae18SJin Yao 		else
170*ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
171*ec27ae18SJin Yao 
172f8f4aaeaSAndi Kleen 		if (dl->cycles)
173517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
174f8f4aaeaSAndi Kleen 					   CYCLES_WIDTH - 1, dl->cycles);
175*ec27ae18SJin Yao 		else if (!show_title)
17626270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
177*ec27ae18SJin Yao 		else
178*ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
179aca7a94dSNamhyung Kim 	}
180aca7a94dSNamhyung Kim 
181cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
182aca7a94dSNamhyung Kim 
183aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
18405e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
185aca7a94dSNamhyung Kim 		width += 1;
186aca7a94dSNamhyung Kim 
18729ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
18826270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width);
18983b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
190e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
191e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
192e592488cSAndi Kleen 					ab->addr_width + 1, dl->line_nr);
193e592488cSAndi Kleen 		else
19483b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
19583b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
19626270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
19726270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
19883b1f2aaSArnaldo Carvalho de Melo 	} else {
19929ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
20083b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
201aca7a94dSNamhyung Kim 
202e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
203aca7a94dSNamhyung Kim 			addr += ab->start;
204aca7a94dSNamhyung Kim 
205e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
206aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
20761e04b33SArnaldo Carvalho de Melo 		} else {
2087d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
209e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2102402e4a9SArnaldo Carvalho de Melo 					int prev;
2112402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2122402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2132402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2142402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2152402e4a9SArnaldo Carvalho de Melo 											 current_entry);
21626270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
21705e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2182402e4a9SArnaldo Carvalho de Melo 				}
2192402e4a9SArnaldo Carvalho de Melo 
22061e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2212402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
22261e04b33SArnaldo Carvalho de Melo 			} else {
22361e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
22483b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
22561e04b33SArnaldo Carvalho de Melo 			}
22661e04b33SArnaldo Carvalho de Melo 		}
227b793a401SArnaldo Carvalho de Melo 
228aca7a94dSNamhyung Kim 		if (change_color)
22905e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
23026270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
231aca7a94dSNamhyung Kim 		if (change_color)
23205e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
23375b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
23475b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
235e216874cSRavi Bangoria 				bool fwd = dl->ops.target.offset > dl->offset;
23651a0d455SArnaldo Carvalho de Melo 
23705e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
23851a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
23951a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
24075b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
24105e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
24288298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
24375b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
24405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2454ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2466ef94929SNaveen N. Rao 			} else {
2476ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2484ea08b52SArnaldo Carvalho de Melo 			}
2496ef94929SNaveen N. Rao 		} else {
2506ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2514ea08b52SArnaldo Carvalho de Melo 		}
2524ea08b52SArnaldo Carvalho de Melo 
253e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
25426270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
255aca7a94dSNamhyung Kim 	}
256aca7a94dSNamhyung Kim 
257aca7a94dSNamhyung Kim 	if (current_entry)
25829ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
259aca7a94dSNamhyung Kim }
260aca7a94dSNamhyung Kim 
261865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
262865c66c4SFrederik Deweerdt {
26375b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
264865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
265e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
266e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
267865c66c4SFrederik Deweerdt 		return false;
268865c66c4SFrederik Deweerdt 
269865c66c4SFrederik Deweerdt 	return true;
270865c66c4SFrederik Deweerdt }
271865c66c4SFrederik Deweerdt 
2729d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
273a3f895beSArnaldo Carvalho de Melo {
274a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
2759d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
2769d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
27783b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
27832ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
27932ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
280f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
28132ae1efdSNamhyung Kim 
28232ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
28332ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
28432ae1efdSNamhyung Kim 		return;
285a3f895beSArnaldo Carvalho de Melo 
286865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
287a3f895beSArnaldo Carvalho de Melo 		return;
288a3f895beSArnaldo Carvalho de Melo 
2899d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
2909d1ef56dSArnaldo Carvalho de Melo 	if (!target)
2919d1ef56dSArnaldo Carvalho de Melo 		return;
2929d1ef56dSArnaldo Carvalho de Melo 
2939d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2949d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2959d1ef56dSArnaldo Carvalho de Melo 
296e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2979d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
298a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
299a3f895beSArnaldo Carvalho de Melo 	} else {
3009d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
301a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
302a3f895beSArnaldo Carvalho de Melo 	}
303a3f895beSArnaldo Carvalho de Melo 
30478ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
305c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
306c7e7b610SNamhyung Kim 				 from, to);
307a3f895beSArnaldo Carvalho de Melo }
308a3f895beSArnaldo Carvalho de Melo 
309a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
310a3f895beSArnaldo Carvalho de Melo {
311c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
312a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
313f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
314a3f895beSArnaldo Carvalho de Melo 
315e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3169d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
317a3f895beSArnaldo Carvalho de Melo 
31883b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
319c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
320a3f895beSArnaldo Carvalho de Melo 	return ret;
321a3f895beSArnaldo Carvalho de Melo }
322a3f895beSArnaldo Carvalho de Melo 
323c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
324c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
325c7e7b610SNamhyung Kim {
326c7e7b610SNamhyung Kim 	int i;
327c7e7b610SNamhyung Kim 
328c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3290c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
330c7e7b610SNamhyung Kim 			continue;
3310c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
332c7e7b610SNamhyung Kim 	}
333c7e7b610SNamhyung Kim 	return 0;
334c7e7b610SNamhyung Kim }
335c7e7b610SNamhyung Kim 
336c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
337c7e7b610SNamhyung Kim 				   int nr_events)
338aca7a94dSNamhyung Kim {
33929ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
340aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
341887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
342aca7a94dSNamhyung Kim 
343aca7a94dSNamhyung Kim 	while (*p != NULL) {
344aca7a94dSNamhyung Kim 		parent = *p;
345887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
346c7e7b610SNamhyung Kim 
347c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
348aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
349aca7a94dSNamhyung Kim 		else
350aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
351aca7a94dSNamhyung Kim 	}
352887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
353887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
354aca7a94dSNamhyung Kim }
355aca7a94dSNamhyung Kim 
35605e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
35729ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
358aca7a94dSNamhyung Kim {
359aca7a94dSNamhyung Kim 	unsigned back;
360aca7a94dSNamhyung Kim 
36105e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
36205e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
36305e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
364aca7a94dSNamhyung Kim 
36505e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
36629ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
367aca7a94dSNamhyung Kim 
36805e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
369aca7a94dSNamhyung Kim 			continue;
370aca7a94dSNamhyung Kim 
37105e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
372aca7a94dSNamhyung Kim 		--back;
373aca7a94dSNamhyung Kim 	}
374aca7a94dSNamhyung Kim 
37505e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
37605e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
377aca7a94dSNamhyung Kim }
378aca7a94dSNamhyung Kim 
379aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
380aca7a94dSNamhyung Kim 					 struct rb_node *nd)
381aca7a94dSNamhyung Kim {
382887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
38329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
384a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
385aca7a94dSNamhyung Kim 
386887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
387887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
388a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
389e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
390a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
391a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
392aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
393aca7a94dSNamhyung Kim }
394aca7a94dSNamhyung Kim 
395aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
396db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
397aca7a94dSNamhyung Kim {
398aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
399aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
400aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
401e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
402e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
403aca7a94dSNamhyung Kim 
404aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
405aca7a94dSNamhyung Kim 
406aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
407aca7a94dSNamhyung Kim 
408aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
409887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
410e64aa75bSNamhyung Kim 		const char *path = NULL;
411c7e7b610SNamhyung Kim 		double max_percent = 0.0;
412c7e7b610SNamhyung Kim 		int i;
413e64aa75bSNamhyung Kim 
414e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
415e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
416e64aa75bSNamhyung Kim 			continue;
417e64aa75bSNamhyung Kim 		}
418e64aa75bSNamhyung Kim 
419e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
420c7e7b610SNamhyung Kim 
421c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
4220c4a5bceSMartin Liška 			u64 nr_samples;
4230c4a5bceSMartin Liška 
4240c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
425c7e7b610SNamhyung Kim 						evsel->idx + i,
426c7e7b610SNamhyung Kim 						pos->offset,
427c7e7b610SNamhyung Kim 						next ? next->offset : len,
4280c4a5bceSMartin Liška 						&path, &nr_samples);
4290c4a5bceSMartin Liška 			bpos->samples[i].nr = nr_samples;
430e64aa75bSNamhyung Kim 
4310c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4320c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
433c7e7b610SNamhyung Kim 		}
434c7e7b610SNamhyung Kim 
43530e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
436887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
437aca7a94dSNamhyung Kim 			continue;
438aca7a94dSNamhyung Kim 		}
439c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
440c7e7b610SNamhyung Kim 				       browser->nr_events);
441aca7a94dSNamhyung Kim 	}
442aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
443aca7a94dSNamhyung Kim 
444aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
445aca7a94dSNamhyung Kim }
446aca7a94dSNamhyung Kim 
447aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
448aca7a94dSNamhyung Kim {
44929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
450887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
451aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
452aca7a94dSNamhyung Kim 
453aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
45429ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
455887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
456aca7a94dSNamhyung Kim 
457e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
458887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
459887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
460aca7a94dSNamhyung Kim 
461aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
462e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
463aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
464887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
465887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
466aca7a94dSNamhyung Kim 	} else {
467887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
468aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
469aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
470aca7a94dSNamhyung Kim 			return false;
471aca7a94dSNamhyung Kim 		}
472aca7a94dSNamhyung Kim 
473887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
474887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
475aca7a94dSNamhyung Kim 
476aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
477e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
478aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
479887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
480887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
481aca7a94dSNamhyung Kim 	}
482aca7a94dSNamhyung Kim 
483aca7a94dSNamhyung Kim 	return true;
484aca7a94dSNamhyung Kim }
485aca7a94dSNamhyung Kim 
486e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
487e9823b21SArnaldo Carvalho de Melo {
488e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
489e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
490e9823b21SArnaldo Carvalho de Melo }
491e9823b21SArnaldo Carvalho de Melo 
49234f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
49334f77abcSAdrian Hunter 
49434f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
49534f77abcSAdrian Hunter 		     size_t sz)
49634f77abcSAdrian Hunter {
49734f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
49834f77abcSAdrian Hunter }
49934f77abcSAdrian Hunter 
500db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
501db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5029783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
503aca7a94dSNamhyung Kim {
504aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
505657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
506aca7a94dSNamhyung Kim 	struct annotation *notes;
5071179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5081179e11bSAdrian Hunter 		.map = ms->map,
5091d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5101179e11bSAdrian Hunter 	};
51134f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
512aca7a94dSNamhyung Kim 
51375b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
514aca7a94dSNamhyung Kim 		return false;
515aca7a94dSNamhyung Kim 
516be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5171d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5181d5077bdSAdrian Hunter 							     target.addr)) !=
5191d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
520aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
521aca7a94dSNamhyung Kim 		return true;
522aca7a94dSNamhyung Kim 	}
523aca7a94dSNamhyung Kim 
5241179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
525aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
526aca7a94dSNamhyung Kim 
5271179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
528aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
529aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5301179e11bSAdrian Hunter 			    target.sym->name);
531aca7a94dSNamhyung Kim 		return true;
532aca7a94dSNamhyung Kim 	}
533aca7a94dSNamhyung Kim 
534aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5351179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5361179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
53734f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
538aca7a94dSNamhyung Kim 	return true;
539aca7a94dSNamhyung Kim }
540aca7a94dSNamhyung Kim 
54129ed6e76SArnaldo Carvalho de Melo static
54229ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
543aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
544aca7a94dSNamhyung Kim {
545aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
546aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
547aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
54829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
549aca7a94dSNamhyung Kim 
550aca7a94dSNamhyung Kim 	*idx = 0;
551aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
552aca7a94dSNamhyung Kim 		if (pos->offset == offset)
553aca7a94dSNamhyung Kim 			return pos;
55429ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
555aca7a94dSNamhyung Kim 			++*idx;
556aca7a94dSNamhyung Kim 	}
557aca7a94dSNamhyung Kim 
558aca7a94dSNamhyung Kim 	return NULL;
559aca7a94dSNamhyung Kim }
560aca7a94dSNamhyung Kim 
561aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
562aca7a94dSNamhyung Kim {
563657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
5645252b1aeSArnaldo Carvalho de Melo 	u64 offset;
5654f9d0325SArnaldo Carvalho de Melo 	s64 idx;
566aca7a94dSNamhyung Kim 
56775b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
568aca7a94dSNamhyung Kim 		return false;
569aca7a94dSNamhyung Kim 
5705252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
5715252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
57229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
5735252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
574aca7a94dSNamhyung Kim 		return true;
575aca7a94dSNamhyung Kim 	}
576aca7a94dSNamhyung Kim 
57729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
578aca7a94dSNamhyung Kim 
579aca7a94dSNamhyung Kim 	return true;
580aca7a94dSNamhyung Kim }
581aca7a94dSNamhyung Kim 
58229ed6e76SArnaldo Carvalho de Melo static
58329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
584aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
585aca7a94dSNamhyung Kim {
586aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
587aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
588aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
58929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
590aca7a94dSNamhyung Kim 
591aca7a94dSNamhyung Kim 	*idx = browser->b.index;
592aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
59329ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
594aca7a94dSNamhyung Kim 			continue;
595aca7a94dSNamhyung Kim 
596aca7a94dSNamhyung Kim 		++*idx;
597aca7a94dSNamhyung Kim 
598aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
599aca7a94dSNamhyung Kim 			return pos;
600aca7a94dSNamhyung Kim 	}
601aca7a94dSNamhyung Kim 
602aca7a94dSNamhyung Kim 	return NULL;
603aca7a94dSNamhyung Kim }
604aca7a94dSNamhyung Kim 
605aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
606aca7a94dSNamhyung Kim {
60729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
608aca7a94dSNamhyung Kim 	s64 idx;
609aca7a94dSNamhyung Kim 
61029ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
61129ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
612aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
613aca7a94dSNamhyung Kim 		return false;
614aca7a94dSNamhyung Kim 	}
615aca7a94dSNamhyung Kim 
61629ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
617aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
618aca7a94dSNamhyung Kim 	return true;
619aca7a94dSNamhyung Kim }
620aca7a94dSNamhyung Kim 
62129ed6e76SArnaldo Carvalho de Melo static
62229ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
623aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
624aca7a94dSNamhyung Kim {
625aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
626aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
627aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
62829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
629aca7a94dSNamhyung Kim 
630aca7a94dSNamhyung Kim 	*idx = browser->b.index;
631aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
63229ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
633aca7a94dSNamhyung Kim 			continue;
634aca7a94dSNamhyung Kim 
635aca7a94dSNamhyung Kim 		--*idx;
636aca7a94dSNamhyung Kim 
637aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
638aca7a94dSNamhyung Kim 			return pos;
639aca7a94dSNamhyung Kim 	}
640aca7a94dSNamhyung Kim 
641aca7a94dSNamhyung Kim 	return NULL;
642aca7a94dSNamhyung Kim }
643aca7a94dSNamhyung Kim 
644aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
645aca7a94dSNamhyung Kim {
64629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
647aca7a94dSNamhyung Kim 	s64 idx;
648aca7a94dSNamhyung Kim 
64929ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
65029ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
651aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
652aca7a94dSNamhyung Kim 		return false;
653aca7a94dSNamhyung Kim 	}
654aca7a94dSNamhyung Kim 
65529ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
656aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
657aca7a94dSNamhyung Kim 	return true;
658aca7a94dSNamhyung Kim }
659aca7a94dSNamhyung Kim 
660aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
661aca7a94dSNamhyung Kim 					    int delay_secs)
662aca7a94dSNamhyung Kim {
663aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
664aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
665aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
666aca7a94dSNamhyung Kim 	    !*browser->search_bf)
667aca7a94dSNamhyung Kim 		return false;
668aca7a94dSNamhyung Kim 
669aca7a94dSNamhyung Kim 	return true;
670aca7a94dSNamhyung Kim }
671aca7a94dSNamhyung Kim 
672aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
673aca7a94dSNamhyung Kim {
674aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
675aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
676aca7a94dSNamhyung Kim 
677aca7a94dSNamhyung Kim 	return false;
678aca7a94dSNamhyung Kim }
679aca7a94dSNamhyung Kim 
680aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
681aca7a94dSNamhyung Kim 					      int delay_secs)
682aca7a94dSNamhyung Kim {
683aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
684aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
685aca7a94dSNamhyung Kim 
686aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
687aca7a94dSNamhyung Kim }
688aca7a94dSNamhyung Kim 
689aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
690aca7a94dSNamhyung Kim 					   int delay_secs)
691aca7a94dSNamhyung Kim {
692aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
693aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
694aca7a94dSNamhyung Kim 
695aca7a94dSNamhyung Kim 	return false;
696aca7a94dSNamhyung Kim }
697aca7a94dSNamhyung Kim 
698aca7a94dSNamhyung Kim static
699aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
700aca7a94dSNamhyung Kim 					       int delay_secs)
701aca7a94dSNamhyung Kim {
702aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
703aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
704aca7a94dSNamhyung Kim 
705aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
706aca7a94dSNamhyung Kim }
707aca7a94dSNamhyung Kim 
708e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
709e9823b21SArnaldo Carvalho de Melo {
710e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
711e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
712e9823b21SArnaldo Carvalho de Melo 	else
713e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
714e9823b21SArnaldo Carvalho de Melo 
715e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
716e9823b21SArnaldo Carvalho de Melo 
717e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
718e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
719e9823b21SArnaldo Carvalho de Melo }
720e9823b21SArnaldo Carvalho de Melo 
721db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
722db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7239783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
724aca7a94dSNamhyung Kim {
725aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
72605e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
727aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
72854e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7299783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
730aca7a94dSNamhyung Kim 	int key;
73134f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
732aca7a94dSNamhyung Kim 
73334f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
73434f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
735aca7a94dSNamhyung Kim 		return -1;
736aca7a94dSNamhyung Kim 
737db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
738aca7a94dSNamhyung Kim 
73905e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
74005e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
74105e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
742aca7a94dSNamhyung Kim 	}
743aca7a94dSNamhyung Kim 
74405e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
745aca7a94dSNamhyung Kim 
746aca7a94dSNamhyung Kim 	while (1) {
74705e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
748aca7a94dSNamhyung Kim 
749aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
750db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
751aca7a94dSNamhyung Kim 			/*
752aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
753aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
754aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
755aca7a94dSNamhyung Kim 			 */
756aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
757aca7a94dSNamhyung Kim 				nd = NULL;
758aca7a94dSNamhyung Kim 		}
759aca7a94dSNamhyung Kim 
760aca7a94dSNamhyung Kim 		switch (key) {
761aca7a94dSNamhyung Kim 		case K_TIMER:
7629783adf7SNamhyung Kim 			if (hbt)
7639783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
764aca7a94dSNamhyung Kim 
765aca7a94dSNamhyung Kim 			if (delay_secs != 0)
766db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
767aca7a94dSNamhyung Kim 			continue;
768aca7a94dSNamhyung Kim 		case K_TAB:
769aca7a94dSNamhyung Kim 			if (nd != NULL) {
770aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
771aca7a94dSNamhyung Kim 				if (nd == NULL)
77205e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
773aca7a94dSNamhyung Kim 			} else
77405e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
775aca7a94dSNamhyung Kim 			break;
776aca7a94dSNamhyung Kim 		case K_UNTAB:
777d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
778aca7a94dSNamhyung Kim 				nd = rb_next(nd);
779aca7a94dSNamhyung Kim 				if (nd == NULL)
78005e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
781d4913cbdSMarkus Trippelsdorf 			} else
78205e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
783aca7a94dSNamhyung Kim 			break;
78454e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
785aca7a94dSNamhyung Kim 		case 'h':
78605e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
78754e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
78854e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
78954e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
7907727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
7917727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
792107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
79354e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
79454e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
79554e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
79654e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
79754e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
7980c4a5bceSMartin Liška 		"t             Toggle total period view\n"
79954e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
800e592488cSAndi Kleen 		"k             Toggle line numbers\n"
80179ee47faSFeng Tang 		"r             Run available scripts\n"
802fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
80354e7a4e8SArnaldo Carvalho de Melo 			continue;
80479ee47faSFeng Tang 		case 'r':
80579ee47faSFeng Tang 			{
80679ee47faSFeng Tang 				script_browse(NULL);
80779ee47faSFeng Tang 				continue;
80879ee47faSFeng Tang 			}
809e592488cSAndi Kleen 		case 'k':
810e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
811e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
812e592488cSAndi Kleen 			break;
81354e7a4e8SArnaldo Carvalho de Melo 		case 'H':
81405e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
815aca7a94dSNamhyung Kim 			break;
816aca7a94dSNamhyung Kim 		case 's':
81705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
818aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
819aca7a94dSNamhyung Kim 			continue;
820aca7a94dSNamhyung Kim 		case 'o':
821e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
82205e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
823aca7a94dSNamhyung Kim 			continue;
8249d1ef56dSArnaldo Carvalho de Melo 		case 'j':
825e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8269d1ef56dSArnaldo Carvalho de Melo 			continue;
8272402e4a9SArnaldo Carvalho de Melo 		case 'J':
828e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
82905e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
830e9823b21SArnaldo Carvalho de Melo 			continue;
831aca7a94dSNamhyung Kim 		case '/':
83205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
833aca7a94dSNamhyung Kim show_help:
834aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
835aca7a94dSNamhyung Kim 			}
836aca7a94dSNamhyung Kim 			continue;
837aca7a94dSNamhyung Kim 		case 'n':
83805e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
83905e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
84005e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
841aca7a94dSNamhyung Kim 				goto show_help;
842aca7a94dSNamhyung Kim 			continue;
843aca7a94dSNamhyung Kim 		case '?':
84405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
845aca7a94dSNamhyung Kim 				goto show_help;
846aca7a94dSNamhyung Kim 			continue;
847e9823b21SArnaldo Carvalho de Melo 		case 'D': {
848e9823b21SArnaldo Carvalho de Melo 			static int seq;
849e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
850e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
85105e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
85205e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
85305e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
85405e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
85505e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
856e9823b21SArnaldo Carvalho de Melo 		}
857e9823b21SArnaldo Carvalho de Melo 			continue;
858aca7a94dSNamhyung Kim 		case K_ENTER:
859aca7a94dSNamhyung Kim 		case K_RIGHT:
86005e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
861aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
86205e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
863aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
86475b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
865c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
86675b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
867c4cceae3SArnaldo Carvalho de Melo 				goto out;
8686ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
869db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
870c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
8716ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
872c4cceae3SArnaldo Carvalho de Melo 			}
873aca7a94dSNamhyung Kim 			continue;
8740c4a5bceSMartin Liška 		case 't':
8750c4a5bceSMartin Liška 			annotate_browser__opts.show_total_period =
8760c4a5bceSMartin Liška 			  !annotate_browser__opts.show_total_period;
8770c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
8780c4a5bceSMartin Liška 			continue;
879aca7a94dSNamhyung Kim 		case K_LEFT:
880aca7a94dSNamhyung Kim 		case K_ESC:
881aca7a94dSNamhyung Kim 		case 'q':
882aca7a94dSNamhyung Kim 		case CTRL('c'):
883aca7a94dSNamhyung Kim 			goto out;
884aca7a94dSNamhyung Kim 		default:
885aca7a94dSNamhyung Kim 			continue;
886aca7a94dSNamhyung Kim 		}
887aca7a94dSNamhyung Kim 
888aca7a94dSNamhyung Kim 		if (nd != NULL)
88905e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
890aca7a94dSNamhyung Kim 	}
891aca7a94dSNamhyung Kim out:
89205e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
893aca7a94dSNamhyung Kim 	return key;
894aca7a94dSNamhyung Kim }
895aca7a94dSNamhyung Kim 
896d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
897d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
898d5dbc518SArnaldo Carvalho de Melo {
8990c4a5bceSMartin Liška 	/* Set default value for show_total_period.  */
9000c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9010c4a5bceSMartin Liška 	  symbol_conf.show_total_period;
9020c4a5bceSMartin Liška 
903d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
904d5dbc518SArnaldo Carvalho de Melo }
905d5dbc518SArnaldo Carvalho de Melo 
906db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9079783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
908aca7a94dSNamhyung Kim {
909ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
910ed426915SNamhyung Kim 	SLang_reset_tty();
911ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
912ed426915SNamhyung Kim 
913d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
914aca7a94dSNamhyung Kim }
915aca7a94dSNamhyung Kim 
91630e863bbSAndi Kleen 
91730e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
91830e863bbSAndi Kleen {
91930e863bbSAndi Kleen 	unsigned n_insn = 0;
92030e863bbSAndi Kleen 	u64 offset;
92130e863bbSAndi Kleen 
92230e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
92330e863bbSAndi Kleen 		if (browser->offsets[offset])
92430e863bbSAndi Kleen 			n_insn++;
92530e863bbSAndi Kleen 	}
92630e863bbSAndi Kleen 	return n_insn;
92730e863bbSAndi Kleen }
92830e863bbSAndi Kleen 
92930e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
93030e863bbSAndi Kleen 			   struct cyc_hist *ch)
93130e863bbSAndi Kleen {
93230e863bbSAndi Kleen 	unsigned n_insn;
93330e863bbSAndi Kleen 	u64 offset;
93430e863bbSAndi Kleen 
93530e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
93630e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
93730e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
93830e863bbSAndi Kleen 
93930e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
94030e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
94130e863bbSAndi Kleen 			return;
94230e863bbSAndi Kleen 
94330e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
94430e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
94530e863bbSAndi Kleen 
94630e863bbSAndi Kleen 			if (dl)
94730e863bbSAndi Kleen 				dl->ipc = ipc;
94830e863bbSAndi Kleen 		}
94930e863bbSAndi Kleen 	}
95030e863bbSAndi Kleen }
95130e863bbSAndi Kleen 
95230e863bbSAndi Kleen /*
95330e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
95430e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
95530e863bbSAndi Kleen  * which are only here.
95630e863bbSAndi Kleen  */
95730e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
95830e863bbSAndi Kleen 			   struct symbol *sym)
95930e863bbSAndi Kleen {
96030e863bbSAndi Kleen 	u64 offset;
96130e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
96230e863bbSAndi Kleen 
96330e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
96430e863bbSAndi Kleen 		return;
96530e863bbSAndi Kleen 
96630e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
96730e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
96830e863bbSAndi Kleen 		struct cyc_hist *ch;
96930e863bbSAndi Kleen 
97030e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
97130e863bbSAndi Kleen 		if (ch && ch->cycles) {
97230e863bbSAndi Kleen 			struct disasm_line *dl;
97330e863bbSAndi Kleen 
97430e863bbSAndi Kleen 			if (ch->have_start)
97530e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
97630e863bbSAndi Kleen 			dl = browser->offsets[offset];
97730e863bbSAndi Kleen 			if (dl && ch->num_aggr)
97830e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
97930e863bbSAndi Kleen 			browser->have_cycles = true;
98030e863bbSAndi Kleen 		}
98130e863bbSAndi Kleen 	}
98230e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
98330e863bbSAndi Kleen }
98430e863bbSAndi Kleen 
985b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
986b793a401SArnaldo Carvalho de Melo 						size_t size)
987b793a401SArnaldo Carvalho de Melo {
988b793a401SArnaldo Carvalho de Melo 	u64 offset;
98932ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
99032ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
99132ae1efdSNamhyung Kim 
99232ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
99332ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
99432ae1efdSNamhyung Kim 		return;
995b793a401SArnaldo Carvalho de Melo 
996b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
997b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
998b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
999b793a401SArnaldo Carvalho de Melo 
1000865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1001b793a401SArnaldo Carvalho de Melo 			continue;
1002b793a401SArnaldo Carvalho de Melo 
100344d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10049481ede9SArnaldo Carvalho de Melo 		/*
10059481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10069481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10079481ede9SArnaldo Carvalho de Melo  		 */
10089481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10099481ede9SArnaldo Carvalho de Melo 			continue;
10109481ede9SArnaldo Carvalho de Melo 
1011b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
10122402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10132402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10142402e4a9SArnaldo Carvalho de Melo 
10152402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1016b793a401SArnaldo Carvalho de Melo 	}
1017b793a401SArnaldo Carvalho de Melo }
1018b793a401SArnaldo Carvalho de Melo 
10192402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10202402e4a9SArnaldo Carvalho de Melo {
10212402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10222402e4a9SArnaldo Carvalho de Melo 		return 5;
10232402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10242402e4a9SArnaldo Carvalho de Melo 		return 2;
10252402e4a9SArnaldo Carvalho de Melo 	return 1;
10262402e4a9SArnaldo Carvalho de Melo }
10272402e4a9SArnaldo Carvalho de Melo 
1028db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1029db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10309783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1031aca7a94dSNamhyung Kim {
103229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1033aca7a94dSNamhyung Kim 	struct annotation *notes;
1034c0a58fb2SSamuel Liao 	size_t size;
1035aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1036aca7a94dSNamhyung Kim 		.map = map,
1037aca7a94dSNamhyung Kim 		.sym = sym,
1038aca7a94dSNamhyung Kim 	};
1039aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1040aca7a94dSNamhyung Kim 		.b = {
1041a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1042aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1043aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
104429ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1045aca7a94dSNamhyung Kim 			.priv	 = &ms,
1046aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1047aca7a94dSNamhyung Kim 		},
1048aca7a94dSNamhyung Kim 	};
1049ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1050c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1051c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1052aca7a94dSNamhyung Kim 
1053aca7a94dSNamhyung Kim 	if (sym == NULL)
1054aca7a94dSNamhyung Kim 		return -1;
1055aca7a94dSNamhyung Kim 
1056c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1057c0a58fb2SSamuel Liao 
1058aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1059aca7a94dSNamhyung Kim 		return -1;
1060aca7a94dSNamhyung Kim 
1061b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1062b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1063b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1064b793a401SArnaldo Carvalho de Melo 		return -1;
1065b793a401SArnaldo Carvalho de Melo 	}
1066b793a401SArnaldo Carvalho de Melo 
1067c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1068c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
10690c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
10700c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1071c7e7b610SNamhyung Kim 	}
1072c7e7b610SNamhyung Kim 
1073786c1b51SArnaldo Carvalho de Melo 	err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl);
1074ee51d851SArnaldo Carvalho de Melo 	if (err) {
1075ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1076ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1077ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1078b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1079aca7a94dSNamhyung Kim 	}
1080aca7a94dSNamhyung Kim 
10817727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1082aca7a94dSNamhyung Kim 
1083aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1084aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1085aca7a94dSNamhyung Kim 
1086aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1087887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1088aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1089aca7a94dSNamhyung Kim 
1090aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1091aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1092887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1093887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1094b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1095887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
109697148a97SArnaldo Carvalho de Melo 			/*
109797148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
109897148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
109997148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
110097148a97SArnaldo Carvalho de Melo 			 *
110197148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
110297148a97SArnaldo Carvalho de Melo  			 */
110397148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1104b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1105b793a401SArnaldo Carvalho de Melo 		} else
1106887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1107aca7a94dSNamhyung Kim 	}
1108aca7a94dSNamhyung Kim 
1109b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
111030e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1111b793a401SArnaldo Carvalho de Melo 
11122402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
111383b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11142402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1115c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1116aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1117aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1118aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1119e9823b21SArnaldo Carvalho de Melo 
1120e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1121e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1122e9823b21SArnaldo Carvalho de Melo 
1123e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1124e9823b21SArnaldo Carvalho de Melo 
1125db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1126aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1127aca7a94dSNamhyung Kim 		list_del(&pos->node);
112829ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1129aca7a94dSNamhyung Kim 	}
1130b793a401SArnaldo Carvalho de Melo 
1131b793a401SArnaldo Carvalho de Melo out_free_offsets:
1132b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1133aca7a94dSNamhyung Kim 	return ret;
1134aca7a94dSNamhyung Kim }
1135c323cf04SArnaldo Carvalho de Melo 
1136c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1137c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1138c323cf04SArnaldo Carvalho de Melo 
1139c323cf04SArnaldo Carvalho de Melo /*
1140c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1141c323cf04SArnaldo Carvalho de Melo  */
11427c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1143c323cf04SArnaldo Carvalho de Melo 	const char *name;
1144c323cf04SArnaldo Carvalho de Melo 	bool *value;
1145c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1146c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1147c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1148e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1149c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11500c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
115139ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1152c323cf04SArnaldo Carvalho de Melo };
1153c323cf04SArnaldo Carvalho de Melo 
1154c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1155c323cf04SArnaldo Carvalho de Melo 
1156c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1157c323cf04SArnaldo Carvalho de Melo {
11587c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1159c323cf04SArnaldo Carvalho de Melo 
1160c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1161c323cf04SArnaldo Carvalho de Melo }
1162c323cf04SArnaldo Carvalho de Melo 
11631d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11641d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1165c323cf04SArnaldo Carvalho de Melo {
11667c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1167c323cf04SArnaldo Carvalho de Melo 	const char *name;
1168c323cf04SArnaldo Carvalho de Melo 
1169c323cf04SArnaldo Carvalho de Melo 	if (prefixcmp(var, "annotate.") != 0)
1170c323cf04SArnaldo Carvalho de Melo 		return 0;
1171c323cf04SArnaldo Carvalho de Melo 
1172c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1173c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
11747c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1175c323cf04SArnaldo Carvalho de Melo 
1176c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1177f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1178f06cff7cSArnaldo Carvalho de Melo 	else
1179c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1180c323cf04SArnaldo Carvalho de Melo 	return 0;
1181c323cf04SArnaldo Carvalho de Melo }
1182c323cf04SArnaldo Carvalho de Melo 
1183c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1184c323cf04SArnaldo Carvalho de Melo {
1185c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1186c323cf04SArnaldo Carvalho de Melo }
1187