xref: /linux/tools/perf/ui/browsers/annotate.c (revision daf25d4303cbf1795535b6c0b7172ba6f12aa2bd)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2aca7a94dSNamhyung Kim #include "../../util/util.h"
3aca7a94dSNamhyung Kim #include "../browser.h"
4aca7a94dSNamhyung Kim #include "../helpline.h"
5aca7a94dSNamhyung Kim #include "../ui.h"
6aca7a94dSNamhyung Kim #include "../util.h"
7aca7a94dSNamhyung Kim #include "../../util/annotate.h"
8aca7a94dSNamhyung Kim #include "../../util/hist.h"
9aca7a94dSNamhyung Kim #include "../../util/sort.h"
10aca7a94dSNamhyung Kim #include "../../util/symbol.h"
11db8fd07aSNamhyung Kim #include "../../util/evsel.h"
1241840d21STaeung Song #include "../../util/config.h"
1369fb09f6SJin Yao #include "../../util/evlist.h"
14fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
15aca7a94dSNamhyung Kim #include <pthread.h>
16877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
178e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h>
18b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h>
19aca7a94dSNamhyung Kim 
200c4a5bceSMartin Liška struct disasm_line_samples {
210c4a5bceSMartin Liška 	double		      percent;
22bb79a232SArnaldo Carvalho de Melo 	struct sym_hist_entry he;
230c4a5bceSMartin Liška };
240c4a5bceSMartin Liška 
25f8f4aaeaSAndi Kleen #define IPC_WIDTH 6
26f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6
27f8f4aaeaSAndi Kleen 
280d957970SJiri Olsa struct browser_line {
29b793a401SArnaldo Carvalho de Melo 	u32	idx;
30b793a401SArnaldo Carvalho de Melo 	int	idx_asm;
317d5b12f5SArnaldo Carvalho de Melo 	int	jump_sources;
32b793a401SArnaldo Carvalho de Melo };
33b793a401SArnaldo Carvalho de Melo 
34e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
35e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
36e9823b21SArnaldo Carvalho de Melo 	     use_offset,
37e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
38e592488cSAndi Kleen 	     show_linenr,
390c4a5bceSMartin Liška 	     show_nr_jumps,
409cef4b0bSTaeung Song 	     show_nr_samples,
410c4a5bceSMartin Liška 	     show_total_period;
42e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
43e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
44e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
45e9823b21SArnaldo Carvalho de Melo };
46e9823b21SArnaldo Carvalho de Melo 
47dcaa3948SJin Yao struct arch;
48dcaa3948SJin Yao 
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;
55dcaa3948SJin Yao 	struct arch	    *arch;
56c7e7b610SNamhyung Kim 	int		    nr_events;
57aca7a94dSNamhyung Kim 	u64		    start;
58aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
59aca7a94dSNamhyung Kim 	int		    nr_entries;
602402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
612402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
62aca7a94dSNamhyung Kim 	bool		    searching_backwards;
6330e863bbSAndi Kleen 	bool		    have_cycles;
6483b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
652402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
662402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
6783b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
6883b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
69aca7a94dSNamhyung Kim 	char		    search_bf[128];
70aca7a94dSNamhyung Kim };
71aca7a94dSNamhyung Kim 
72*daf25d43SJiri Olsa static inline struct browser_line *browser_line(struct disasm_line *dl)
73aca7a94dSNamhyung Kim {
740d957970SJiri Olsa 	return (void *) dl - sizeof(struct browser_line);
75aca7a94dSNamhyung Kim }
76aca7a94dSNamhyung Kim 
771d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
781d037ca1SIrina Tirdea 				void *entry)
79aca7a94dSNamhyung Kim {
80e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
81d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
82d5490b96SJiri Olsa 
83d5490b96SJiri Olsa 		return al->offset == -1;
84aca7a94dSNamhyung Kim 	}
85aca7a94dSNamhyung Kim 
86aca7a94dSNamhyung Kim 	return false;
87aca7a94dSNamhyung Kim }
88aca7a94dSNamhyung Kim 
892402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
902402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
912402e4a9SArnaldo Carvalho de Melo {
922402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
932402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
942402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
952402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
962402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
972402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
982402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
992402e4a9SArnaldo Carvalho de Melo }
1002402e4a9SArnaldo Carvalho de Melo 
1012402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
1022402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1032402e4a9SArnaldo Carvalho de Melo {
1042402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1052402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1062402e4a9SArnaldo Carvalho de Melo }
1072402e4a9SArnaldo Carvalho de Melo 
108f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
109f8f4aaeaSAndi Kleen {
1103861c4a4SArnaldo Carvalho de Melo 	return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events;
111bc1e5d60SArnaldo Carvalho de Melo }
112f8f4aaeaSAndi Kleen 
113bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab)
114bc1e5d60SArnaldo Carvalho de Melo {
115bc1e5d60SArnaldo Carvalho de Melo 	return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
116f8f4aaeaSAndi Kleen }
117f8f4aaeaSAndi Kleen 
11805e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
119aca7a94dSNamhyung Kim {
12005e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
121a17c4ca0SJiri Olsa 	struct disasm_line *dl = list_entry(entry, struct disasm_line, al.node);
122*daf25d43SJiri Olsa 	struct browser_line *bdl = browser_line(dl);
12305e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
124e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
12505e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
12605e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
12705e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
128bc1e5d60SArnaldo Carvalho de Melo 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
129bc1e5d60SArnaldo Carvalho de Melo 	       cycles_width = annotate_browser__cycles_width(ab);
130c7e7b610SNamhyung Kim 	double percent_max = 0.0;
13183b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
132ec27ae18SJin Yao 	bool show_title = false;
133aca7a94dSNamhyung Kim 
134c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1353ab6db8dSJiri Olsa 		if (dl->al.samples[i].percent > percent_max)
1363ab6db8dSJiri Olsa 			percent_max = dl->al.samples[i].percent;
137c7e7b610SNamhyung Kim 	}
138c7e7b610SNamhyung Kim 
139d5490b96SJiri Olsa 	if ((row == 0) && (dl->al.offset == -1 || percent_max == 0.0)) {
140ec27ae18SJin Yao 		if (ab->have_cycles) {
14137236d5eSJiri Olsa 			if (dl->al.ipc == 0.0 && dl->al.cycles == 0)
142ec27ae18SJin Yao 				show_title = true;
143ec27ae18SJin Yao 		} else
144ec27ae18SJin Yao 			show_title = true;
145ec27ae18SJin Yao 	}
146ec27ae18SJin Yao 
147d5490b96SJiri Olsa 	if (dl->al.offset != -1 && percent_max != 0.0) {
148c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1490c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1503ab6db8dSJiri Olsa 						dl->al.samples[i].percent,
151c7e7b610SNamhyung Kim 						current_entry);
152517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
1533861c4a4SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%11" PRIu64 " ",
1543ab6db8dSJiri Olsa 						   dl->al.samples[i].he.period);
1559cef4b0bSTaeung Song 			} else if (annotate_browser__opts.show_nr_samples) {
1569cef4b0bSTaeung Song 				ui_browser__printf(browser, "%6" PRIu64 " ",
1573ab6db8dSJiri Olsa 						   dl->al.samples[i].he.nr_samples);
158517dfdb3SArnaldo Carvalho de Melo 			} else {
159517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
1603ab6db8dSJiri Olsa 						   dl->al.samples[i].percent);
161517dfdb3SArnaldo Carvalho de Melo 			}
162c7e7b610SNamhyung Kim 		}
163aca7a94dSNamhyung Kim 	} else {
16405e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
165ec27ae18SJin Yao 
166ec27ae18SJin Yao 		if (!show_title)
167bc1e5d60SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", pcnt_width);
1683861c4a4SArnaldo Carvalho de Melo 		else {
1693861c4a4SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s", pcnt_width,
1709cef4b0bSTaeung Song 					   annotate_browser__opts.show_total_period ? "Period" :
1719cef4b0bSTaeung Song 					   annotate_browser__opts.show_nr_samples ? "Samples" : "Percent");
1723861c4a4SArnaldo Carvalho de Melo 		}
173f8f4aaeaSAndi Kleen 	}
174f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
17537236d5eSJiri Olsa 		if (dl->al.ipc)
17637236d5eSJiri Olsa 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->al.ipc);
177ec27ae18SJin Yao 		else if (!show_title)
17826270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
179ec27ae18SJin Yao 		else
180ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
181ec27ae18SJin Yao 
18237236d5eSJiri Olsa 		if (dl->al.cycles)
183517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
18437236d5eSJiri Olsa 					   CYCLES_WIDTH - 1, dl->al.cycles);
185ec27ae18SJin Yao 		else if (!show_title)
18626270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
187ec27ae18SJin Yao 		else
188ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
189aca7a94dSNamhyung Kim 	}
190aca7a94dSNamhyung Kim 
191cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
192aca7a94dSNamhyung Kim 
193aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
19405e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
195aca7a94dSNamhyung Kim 		width += 1;
196aca7a94dSNamhyung Kim 
197d5490b96SJiri Olsa 	if (!*dl->al.line)
198bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
199d5490b96SJiri Olsa 	else if (dl->al.offset == -1) {
200d5490b96SJiri Olsa 		if (dl->al.line_nr && annotate_browser__opts.show_linenr)
201e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
202d5490b96SJiri Olsa 					ab->addr_width + 1, dl->al.line_nr);
203e592488cSAndi Kleen 		else
20483b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
20583b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
20626270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
207d5490b96SJiri Olsa 		ui_browser__write_nstring(browser, dl->al.line, width - printed - pcnt_width - cycles_width + 1);
20883b1f2aaSArnaldo Carvalho de Melo 	} else {
209d5490b96SJiri Olsa 		u64 addr = dl->al.offset;
21083b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
211aca7a94dSNamhyung Kim 
212e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
213aca7a94dSNamhyung Kim 			addr += ab->start;
214aca7a94dSNamhyung Kim 
215e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
216aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
21761e04b33SArnaldo Carvalho de Melo 		} else {
2187d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
219e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2202402e4a9SArnaldo Carvalho de Melo 					int prev;
2212402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2222402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2232402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2242402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2252402e4a9SArnaldo Carvalho de Melo 											 current_entry);
22626270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
22705e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2282402e4a9SArnaldo Carvalho de Melo 				}
2292402e4a9SArnaldo Carvalho de Melo 
23061e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2312402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
23261e04b33SArnaldo Carvalho de Melo 			} else {
23361e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
23483b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
23561e04b33SArnaldo Carvalho de Melo 			}
23661e04b33SArnaldo Carvalho de Melo 		}
237b793a401SArnaldo Carvalho de Melo 
238aca7a94dSNamhyung Kim 		if (change_color)
23905e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
24026270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
241aca7a94dSNamhyung Kim 		if (change_color)
24205e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
24375b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
24475b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
245d5490b96SJiri Olsa 				bool fwd = dl->ops.target.offset > dl->al.offset;
24651a0d455SArnaldo Carvalho de Melo 
24705e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
24851a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
24951a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25075b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
25105e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
25288298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25375b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
25405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2554ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2566ef94929SNaveen N. Rao 			} else {
2576ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2584ea08b52SArnaldo Carvalho de Melo 			}
2596ef94929SNaveen N. Rao 		} else {
2606ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2614ea08b52SArnaldo Carvalho de Melo 		}
2624ea08b52SArnaldo Carvalho de Melo 
263e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
264bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
265aca7a94dSNamhyung Kim 	}
266aca7a94dSNamhyung Kim 
267aca7a94dSNamhyung Kim 	if (current_entry)
26829ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
269aca7a94dSNamhyung Kim }
270aca7a94dSNamhyung Kim 
271865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
272865c66c4SFrederik Deweerdt {
27375b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
274865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
275e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
276e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
277865c66c4SFrederik Deweerdt 		return false;
278865c66c4SFrederik Deweerdt 
279865c66c4SFrederik Deweerdt 	return true;
280865c66c4SFrederik Deweerdt }
281865c66c4SFrederik Deweerdt 
2827e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2837e63a13aSJin Yao {
284a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2857e63a13aSJin Yao 	const char *name;
2867e63a13aSJin Yao 
2877e63a13aSJin Yao 	if (!pos)
2887e63a13aSJin Yao 		return false;
2897e63a13aSJin Yao 
2907e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2917e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2927e63a13aSJin Yao 	else
2937e63a13aSJin Yao 		name = pos->ins.name;
2947e63a13aSJin Yao 
2957e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2967e63a13aSJin Yao 		return false;
2977e63a13aSJin Yao 
2987e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
2997e63a13aSJin Yao }
3007e63a13aSJin Yao 
3019d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
302a3f895beSArnaldo Carvalho de Melo {
303a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3049d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
3050d957970SJiri Olsa 	struct browser_line *btarget, *bcursor;
30683b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
30732ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
30832ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
309f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
31032ae1efdSNamhyung Kim 
31132ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31232ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31332ae1efdSNamhyung Kim 		return;
314a3f895beSArnaldo Carvalho de Melo 
315865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
316a3f895beSArnaldo Carvalho de Melo 		return;
317a3f895beSArnaldo Carvalho de Melo 
3189d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
3199d1ef56dSArnaldo Carvalho de Melo 	if (!target)
3209d1ef56dSArnaldo Carvalho de Melo 		return;
3219d1ef56dSArnaldo Carvalho de Melo 
322*daf25d43SJiri Olsa 	bcursor = browser_line(cursor);
323*daf25d43SJiri Olsa 	btarget = browser_line(target);
3249d1ef56dSArnaldo Carvalho de Melo 
325e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3269d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
327a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
328a3f895beSArnaldo Carvalho de Melo 	} else {
3299d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
330a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
331a3f895beSArnaldo Carvalho de Melo 	}
332a3f895beSArnaldo Carvalho de Melo 
33378ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
334c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
335c7e7b610SNamhyung Kim 				 from, to);
3367e63a13aSJin Yao 
3377e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3387e63a13aSJin Yao 		ui_browser__mark_fused(browser,
3397e63a13aSJin Yao 				       pcnt_width + 3 + ab->addr_width,
3407e63a13aSJin Yao 				       from - 1,
3417e63a13aSJin Yao 				       to > from ? true : false);
3427e63a13aSJin Yao 	}
343a3f895beSArnaldo Carvalho de Melo }
344a3f895beSArnaldo Carvalho de Melo 
345a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
346a3f895beSArnaldo Carvalho de Melo {
347c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
348a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
349f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
350a3f895beSArnaldo Carvalho de Melo 
351e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3529d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
353a3f895beSArnaldo Carvalho de Melo 
35483b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
355c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
356a3f895beSArnaldo Carvalho de Melo 	return ret;
357a3f895beSArnaldo Carvalho de Melo }
358a3f895beSArnaldo Carvalho de Melo 
359b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
360c7e7b610SNamhyung Kim {
361c7e7b610SNamhyung Kim 	int i;
362c7e7b610SNamhyung Kim 
363b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
3640c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
365c7e7b610SNamhyung Kim 			continue;
3660c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
367c7e7b610SNamhyung Kim 	}
368c7e7b610SNamhyung Kim 	return 0;
369c7e7b610SNamhyung Kim }
370c7e7b610SNamhyung Kim 
371b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
372aca7a94dSNamhyung Kim {
37329ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
374aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
3753ab6db8dSJiri Olsa 	struct annotation_line *l;
376aca7a94dSNamhyung Kim 
377aca7a94dSNamhyung Kim 	while (*p != NULL) {
378aca7a94dSNamhyung Kim 		parent = *p;
3793ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
380c7e7b610SNamhyung Kim 
381b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
382aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
383aca7a94dSNamhyung Kim 		else
384aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
385aca7a94dSNamhyung Kim 	}
3863ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
3873ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
388aca7a94dSNamhyung Kim }
389aca7a94dSNamhyung Kim 
39005e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
39129ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
392aca7a94dSNamhyung Kim {
393aca7a94dSNamhyung Kim 	unsigned back;
394aca7a94dSNamhyung Kim 
39505e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
39605e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
39705e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
398aca7a94dSNamhyung Kim 
39905e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
400a17c4ca0SJiri Olsa 		pos = list_entry(pos->al.node.prev, struct disasm_line, al.node);
401aca7a94dSNamhyung Kim 
402a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
403aca7a94dSNamhyung Kim 			continue;
404aca7a94dSNamhyung Kim 
40505e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
406aca7a94dSNamhyung Kim 		--back;
407aca7a94dSNamhyung Kim 	}
408aca7a94dSNamhyung Kim 
409a17c4ca0SJiri Olsa 	browser->b.top = &pos->al;
41005e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
411aca7a94dSNamhyung Kim }
412aca7a94dSNamhyung Kim 
413aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
414aca7a94dSNamhyung Kim 					 struct rb_node *nd)
415aca7a94dSNamhyung Kim {
4160d957970SJiri Olsa 	struct browser_line *bpos;
41729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
418a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
419aca7a94dSNamhyung Kim 
4205b12adc8SJiri Olsa 	pos = rb_entry(nd, struct disasm_line, al.rb_node);
421*daf25d43SJiri Olsa 	bpos = browser_line(pos);
4225b12adc8SJiri Olsa 
423a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
424e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
425a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
426a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
427aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
428aca7a94dSNamhyung Kim }
429aca7a94dSNamhyung Kim 
430aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
431db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
432aca7a94dSNamhyung Kim {
433aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
434aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
435aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
436c4c72436SJiri Olsa 	struct disasm_line *pos;
437aca7a94dSNamhyung Kim 
438aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
439aca7a94dSNamhyung Kim 
440aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
441aca7a94dSNamhyung Kim 
442e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
443e425da6cSJiri Olsa 
444a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
445c7e7b610SNamhyung Kim 		double max_percent = 0.0;
446c7e7b610SNamhyung Kim 		int i;
447e64aa75bSNamhyung Kim 
448d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
4495b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
450e64aa75bSNamhyung Kim 			continue;
451e64aa75bSNamhyung Kim 		}
452e64aa75bSNamhyung Kim 
453b15636c6SJiri Olsa 		for (i = 0; i < pos->al.samples_nr; i++) {
454e425da6cSJiri Olsa 			struct annotation_data *sample = &pos->al.samples[i];
4550c4a5bceSMartin Liška 
4563ab6db8dSJiri Olsa 			if (max_percent < sample->percent)
4573ab6db8dSJiri Olsa 				max_percent = sample->percent;
458c7e7b610SNamhyung Kim 		}
459c7e7b610SNamhyung Kim 
46037236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
4615b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
462aca7a94dSNamhyung Kim 			continue;
463aca7a94dSNamhyung Kim 		}
464b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
465aca7a94dSNamhyung Kim 	}
466aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
467aca7a94dSNamhyung Kim 
468aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
469aca7a94dSNamhyung Kim }
470aca7a94dSNamhyung Kim 
471aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
472aca7a94dSNamhyung Kim {
47329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
4740d957970SJiri Olsa 	struct browser_line *bdl;
475aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
476aca7a94dSNamhyung Kim 
477aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
478a17c4ca0SJiri Olsa 	dl = list_entry(browser->b.top, struct disasm_line, al.node);
479*daf25d43SJiri Olsa 	bdl = browser_line(dl);
480aca7a94dSNamhyung Kim 
481e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
482887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
483887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
484aca7a94dSNamhyung Kim 
485aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
486e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
487aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
488887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
489887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
490aca7a94dSNamhyung Kim 	} else {
491887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
492aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
493aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
494aca7a94dSNamhyung Kim 			return false;
495aca7a94dSNamhyung Kim 		}
496aca7a94dSNamhyung Kim 
497887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
498887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
499aca7a94dSNamhyung Kim 
500aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
501e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
502aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
503887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
504887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
505aca7a94dSNamhyung Kim 	}
506aca7a94dSNamhyung Kim 
507aca7a94dSNamhyung Kim 	return true;
508aca7a94dSNamhyung Kim }
509aca7a94dSNamhyung Kim 
510e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
511e9823b21SArnaldo Carvalho de Melo {
512e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
513e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
514e9823b21SArnaldo Carvalho de Melo }
515e9823b21SArnaldo Carvalho de Melo 
51634f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
51734f77abcSAdrian Hunter 
51834f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
51934f77abcSAdrian Hunter 		     size_t sz)
52034f77abcSAdrian Hunter {
52134f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
52234f77abcSAdrian Hunter }
52334f77abcSAdrian Hunter 
524db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
525db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5269783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
527aca7a94dSNamhyung Kim {
528aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
529657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
530aca7a94dSNamhyung Kim 	struct annotation *notes;
5311179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5321179e11bSAdrian Hunter 		.map = ms->map,
5331d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5341179e11bSAdrian Hunter 	};
53534f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
536aca7a94dSNamhyung Kim 
53775b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
538aca7a94dSNamhyung Kim 		return false;
539aca7a94dSNamhyung Kim 
540be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5411d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5421d5077bdSAdrian Hunter 							     target.addr)) !=
5431d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
544aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
545aca7a94dSNamhyung Kim 		return true;
546aca7a94dSNamhyung Kim 	}
547aca7a94dSNamhyung Kim 
5481179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
549aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
550aca7a94dSNamhyung Kim 
5511179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
552aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
553aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5541179e11bSAdrian Hunter 			    target.sym->name);
555aca7a94dSNamhyung Kim 		return true;
556aca7a94dSNamhyung Kim 	}
557aca7a94dSNamhyung Kim 
558aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5591179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5601179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
56134f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
562aca7a94dSNamhyung Kim 	return true;
563aca7a94dSNamhyung Kim }
564aca7a94dSNamhyung Kim 
56529ed6e76SArnaldo Carvalho de Melo static
56629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
567aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
568aca7a94dSNamhyung Kim {
569aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
570aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
571aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
57229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
573aca7a94dSNamhyung Kim 
574aca7a94dSNamhyung Kim 	*idx = 0;
575a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
576d5490b96SJiri Olsa 		if (pos->al.offset == offset)
577aca7a94dSNamhyung Kim 			return pos;
578a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
579aca7a94dSNamhyung Kim 			++*idx;
580aca7a94dSNamhyung Kim 	}
581aca7a94dSNamhyung Kim 
582aca7a94dSNamhyung Kim 	return NULL;
583aca7a94dSNamhyung Kim }
584aca7a94dSNamhyung Kim 
585aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
586aca7a94dSNamhyung Kim {
587657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
5885252b1aeSArnaldo Carvalho de Melo 	u64 offset;
5894f9d0325SArnaldo Carvalho de Melo 	s64 idx;
590aca7a94dSNamhyung Kim 
59175b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
592aca7a94dSNamhyung Kim 		return false;
593aca7a94dSNamhyung Kim 
5945252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
5955252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
59629ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
5975252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
598aca7a94dSNamhyung Kim 		return true;
599aca7a94dSNamhyung Kim 	}
600aca7a94dSNamhyung Kim 
60129ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
602aca7a94dSNamhyung Kim 
603aca7a94dSNamhyung Kim 	return true;
604aca7a94dSNamhyung Kim }
605aca7a94dSNamhyung Kim 
60629ed6e76SArnaldo Carvalho de Melo static
60729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
608aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
609aca7a94dSNamhyung Kim {
610aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
611aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
612aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
61329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
614aca7a94dSNamhyung Kim 
615aca7a94dSNamhyung Kim 	*idx = browser->b.index;
616a17c4ca0SJiri Olsa 	list_for_each_entry_continue(pos, &notes->src->source, al.node) {
617a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
618aca7a94dSNamhyung Kim 			continue;
619aca7a94dSNamhyung Kim 
620aca7a94dSNamhyung Kim 		++*idx;
621aca7a94dSNamhyung Kim 
622d5490b96SJiri Olsa 		if (pos->al.line && strstr(pos->al.line, s) != NULL)
623aca7a94dSNamhyung Kim 			return pos;
624aca7a94dSNamhyung Kim 	}
625aca7a94dSNamhyung Kim 
626aca7a94dSNamhyung Kim 	return NULL;
627aca7a94dSNamhyung Kim }
628aca7a94dSNamhyung Kim 
629aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
630aca7a94dSNamhyung Kim {
63129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
632aca7a94dSNamhyung Kim 	s64 idx;
633aca7a94dSNamhyung Kim 
63429ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
63529ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
636aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
637aca7a94dSNamhyung Kim 		return false;
638aca7a94dSNamhyung Kim 	}
639aca7a94dSNamhyung Kim 
64029ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
641aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
642aca7a94dSNamhyung Kim 	return true;
643aca7a94dSNamhyung Kim }
644aca7a94dSNamhyung Kim 
64529ed6e76SArnaldo Carvalho de Melo static
64629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
647aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
648aca7a94dSNamhyung Kim {
649aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
650aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
651aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
65229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
653aca7a94dSNamhyung Kim 
654aca7a94dSNamhyung Kim 	*idx = browser->b.index;
655a17c4ca0SJiri Olsa 	list_for_each_entry_continue_reverse(pos, &notes->src->source, al.node) {
656a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
657aca7a94dSNamhyung Kim 			continue;
658aca7a94dSNamhyung Kim 
659aca7a94dSNamhyung Kim 		--*idx;
660aca7a94dSNamhyung Kim 
661d5490b96SJiri Olsa 		if (pos->al.line && strstr(pos->al.line, s) != NULL)
662aca7a94dSNamhyung Kim 			return pos;
663aca7a94dSNamhyung Kim 	}
664aca7a94dSNamhyung Kim 
665aca7a94dSNamhyung Kim 	return NULL;
666aca7a94dSNamhyung Kim }
667aca7a94dSNamhyung Kim 
668aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
669aca7a94dSNamhyung Kim {
67029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
671aca7a94dSNamhyung Kim 	s64 idx;
672aca7a94dSNamhyung Kim 
67329ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
67429ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
675aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
676aca7a94dSNamhyung Kim 		return false;
677aca7a94dSNamhyung Kim 	}
678aca7a94dSNamhyung Kim 
67929ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
680aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
681aca7a94dSNamhyung Kim 	return true;
682aca7a94dSNamhyung Kim }
683aca7a94dSNamhyung Kim 
684aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
685aca7a94dSNamhyung Kim 					    int delay_secs)
686aca7a94dSNamhyung Kim {
687aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
688aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
689aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
690aca7a94dSNamhyung Kim 	    !*browser->search_bf)
691aca7a94dSNamhyung Kim 		return false;
692aca7a94dSNamhyung Kim 
693aca7a94dSNamhyung Kim 	return true;
694aca7a94dSNamhyung Kim }
695aca7a94dSNamhyung Kim 
696aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
697aca7a94dSNamhyung Kim {
698aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
699aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
700aca7a94dSNamhyung Kim 
701aca7a94dSNamhyung Kim 	return false;
702aca7a94dSNamhyung Kim }
703aca7a94dSNamhyung Kim 
704aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
705aca7a94dSNamhyung Kim 					      int delay_secs)
706aca7a94dSNamhyung Kim {
707aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
708aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
709aca7a94dSNamhyung Kim 
710aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
711aca7a94dSNamhyung Kim }
712aca7a94dSNamhyung Kim 
713aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
714aca7a94dSNamhyung Kim 					   int delay_secs)
715aca7a94dSNamhyung Kim {
716aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
717aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
718aca7a94dSNamhyung Kim 
719aca7a94dSNamhyung Kim 	return false;
720aca7a94dSNamhyung Kim }
721aca7a94dSNamhyung Kim 
722aca7a94dSNamhyung Kim static
723aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
724aca7a94dSNamhyung Kim 					       int delay_secs)
725aca7a94dSNamhyung Kim {
726aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
727aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
728aca7a94dSNamhyung Kim 
729aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
730aca7a94dSNamhyung Kim }
731aca7a94dSNamhyung Kim 
732e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
733e9823b21SArnaldo Carvalho de Melo {
734e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
735e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
736e9823b21SArnaldo Carvalho de Melo 	else
737e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
738e9823b21SArnaldo Carvalho de Melo 
739e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
740e9823b21SArnaldo Carvalho de Melo 
741e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
742e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
743e9823b21SArnaldo Carvalho de Melo }
744e9823b21SArnaldo Carvalho de Melo 
745db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
746db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7479783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
748aca7a94dSNamhyung Kim {
749aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
75005e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
751aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
75254e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7539783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
754aca7a94dSNamhyung Kim 	int key;
75534f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
756aca7a94dSNamhyung Kim 
75734f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
75834f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
759aca7a94dSNamhyung Kim 		return -1;
760aca7a94dSNamhyung Kim 
761db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
762aca7a94dSNamhyung Kim 
76305e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
76405e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
76505e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
766aca7a94dSNamhyung Kim 	}
767aca7a94dSNamhyung Kim 
76805e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
769aca7a94dSNamhyung Kim 
770aca7a94dSNamhyung Kim 	while (1) {
77105e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
772aca7a94dSNamhyung Kim 
773aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
774db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
775aca7a94dSNamhyung Kim 			/*
776aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
777aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
778aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
779aca7a94dSNamhyung Kim 			 */
780aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
781aca7a94dSNamhyung Kim 				nd = NULL;
782aca7a94dSNamhyung Kim 		}
783aca7a94dSNamhyung Kim 
784aca7a94dSNamhyung Kim 		switch (key) {
785aca7a94dSNamhyung Kim 		case K_TIMER:
7869783adf7SNamhyung Kim 			if (hbt)
7879783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
788aca7a94dSNamhyung Kim 
789aca7a94dSNamhyung Kim 			if (delay_secs != 0)
790db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
791aca7a94dSNamhyung Kim 			continue;
792aca7a94dSNamhyung Kim 		case K_TAB:
793aca7a94dSNamhyung Kim 			if (nd != NULL) {
794aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
795aca7a94dSNamhyung Kim 				if (nd == NULL)
79605e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
797aca7a94dSNamhyung Kim 			} else
79805e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
799aca7a94dSNamhyung Kim 			break;
800aca7a94dSNamhyung Kim 		case K_UNTAB:
801d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
802aca7a94dSNamhyung Kim 				nd = rb_next(nd);
803aca7a94dSNamhyung Kim 				if (nd == NULL)
80405e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
805d4913cbdSMarkus Trippelsdorf 			} else
80605e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
807aca7a94dSNamhyung Kim 			break;
80854e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
809aca7a94dSNamhyung Kim 		case 'h':
81005e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
81154e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
81254e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
81354e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8147727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8157727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
816eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
817eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
81854e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
81954e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
82054e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
82154e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
82254e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8233a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
82454e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
825e592488cSAndi Kleen 		"k             Toggle line numbers\n"
82679ee47faSFeng Tang 		"r             Run available scripts\n"
827fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
82854e7a4e8SArnaldo Carvalho de Melo 			continue;
82979ee47faSFeng Tang 		case 'r':
83079ee47faSFeng Tang 			{
83179ee47faSFeng Tang 				script_browse(NULL);
83279ee47faSFeng Tang 				continue;
83379ee47faSFeng Tang 			}
834e592488cSAndi Kleen 		case 'k':
835e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
836e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
837e592488cSAndi Kleen 			break;
83854e7a4e8SArnaldo Carvalho de Melo 		case 'H':
83905e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
840aca7a94dSNamhyung Kim 			break;
841aca7a94dSNamhyung Kim 		case 's':
84205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
843aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
844aca7a94dSNamhyung Kim 			continue;
845aca7a94dSNamhyung Kim 		case 'o':
846e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
84705e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
848aca7a94dSNamhyung Kim 			continue;
8499d1ef56dSArnaldo Carvalho de Melo 		case 'j':
850e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8519d1ef56dSArnaldo Carvalho de Melo 			continue;
8522402e4a9SArnaldo Carvalho de Melo 		case 'J':
853e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
85405e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
855e9823b21SArnaldo Carvalho de Melo 			continue;
856aca7a94dSNamhyung Kim 		case '/':
85705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
858aca7a94dSNamhyung Kim show_help:
859aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
860aca7a94dSNamhyung Kim 			}
861aca7a94dSNamhyung Kim 			continue;
862aca7a94dSNamhyung Kim 		case 'n':
86305e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
86405e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
86505e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
866aca7a94dSNamhyung Kim 				goto show_help;
867aca7a94dSNamhyung Kim 			continue;
868aca7a94dSNamhyung Kim 		case '?':
86905e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
870aca7a94dSNamhyung Kim 				goto show_help;
871aca7a94dSNamhyung Kim 			continue;
872e9823b21SArnaldo Carvalho de Melo 		case 'D': {
873e9823b21SArnaldo Carvalho de Melo 			static int seq;
874e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
875e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
87605e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
87705e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
87805e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
87905e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
88005e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
881e9823b21SArnaldo Carvalho de Melo 		}
882e9823b21SArnaldo Carvalho de Melo 			continue;
883aca7a94dSNamhyung Kim 		case K_ENTER:
884aca7a94dSNamhyung Kim 		case K_RIGHT:
88505e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
886aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
887d5490b96SJiri Olsa 			else if (browser->selection->al.offset == -1)
888aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
88975b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
890c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
89175b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
892c4cceae3SArnaldo Carvalho de Melo 				goto out;
8936ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
894db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
895c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
8966ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
897c4cceae3SArnaldo Carvalho de Melo 			}
898aca7a94dSNamhyung Kim 			continue;
8990c4a5bceSMartin Liška 		case 't':
9003a555c77STaeung Song 			if (annotate_browser__opts.show_total_period) {
9013a555c77STaeung Song 				annotate_browser__opts.show_total_period = false;
9023a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = true;
9033a555c77STaeung Song 			} else if (annotate_browser__opts.show_nr_samples)
9043a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = false;
9053a555c77STaeung Song 			else
9063a555c77STaeung Song 				annotate_browser__opts.show_total_period = true;
9070c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9080c4a5bceSMartin Liška 			continue;
909aca7a94dSNamhyung Kim 		case K_LEFT:
910aca7a94dSNamhyung Kim 		case K_ESC:
911aca7a94dSNamhyung Kim 		case 'q':
912aca7a94dSNamhyung Kim 		case CTRL('c'):
913aca7a94dSNamhyung Kim 			goto out;
914aca7a94dSNamhyung Kim 		default:
915aca7a94dSNamhyung Kim 			continue;
916aca7a94dSNamhyung Kim 		}
917aca7a94dSNamhyung Kim 
918aca7a94dSNamhyung Kim 		if (nd != NULL)
91905e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
920aca7a94dSNamhyung Kim 	}
921aca7a94dSNamhyung Kim out:
92205e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
923aca7a94dSNamhyung Kim 	return key;
924aca7a94dSNamhyung Kim }
925aca7a94dSNamhyung Kim 
926d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
927d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
928d5dbc518SArnaldo Carvalho de Melo {
9299cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9300c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9310c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9329cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9339cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9340c4a5bceSMartin Liška 
935d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
936d5dbc518SArnaldo Carvalho de Melo }
937d5dbc518SArnaldo Carvalho de Melo 
938db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9399783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
940aca7a94dSNamhyung Kim {
941ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
942ed426915SNamhyung Kim 	SLang_reset_tty();
943ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
944ed426915SNamhyung Kim 
945d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
946aca7a94dSNamhyung Kim }
947aca7a94dSNamhyung Kim 
94830e863bbSAndi Kleen 
94930e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
95030e863bbSAndi Kleen {
95130e863bbSAndi Kleen 	unsigned n_insn = 0;
95230e863bbSAndi Kleen 	u64 offset;
95330e863bbSAndi Kleen 
95430e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
95530e863bbSAndi Kleen 		if (browser->offsets[offset])
95630e863bbSAndi Kleen 			n_insn++;
95730e863bbSAndi Kleen 	}
95830e863bbSAndi Kleen 	return n_insn;
95930e863bbSAndi Kleen }
96030e863bbSAndi Kleen 
96130e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
96230e863bbSAndi Kleen 			   struct cyc_hist *ch)
96330e863bbSAndi Kleen {
96430e863bbSAndi Kleen 	unsigned n_insn;
96530e863bbSAndi Kleen 	u64 offset;
96630e863bbSAndi Kleen 
96730e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
96830e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
96930e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
97030e863bbSAndi Kleen 
97130e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
97230e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
97330e863bbSAndi Kleen 			return;
97430e863bbSAndi Kleen 
97530e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
97630e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
97730e863bbSAndi Kleen 
97830e863bbSAndi Kleen 			if (dl)
97937236d5eSJiri Olsa 				dl->al.ipc = ipc;
98030e863bbSAndi Kleen 		}
98130e863bbSAndi Kleen 	}
98230e863bbSAndi Kleen }
98330e863bbSAndi Kleen 
98430e863bbSAndi Kleen /*
98530e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
98630e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
98730e863bbSAndi Kleen  * which are only here.
98830e863bbSAndi Kleen  */
98930e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
99030e863bbSAndi Kleen 			   struct symbol *sym)
99130e863bbSAndi Kleen {
99230e863bbSAndi Kleen 	u64 offset;
99330e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
99430e863bbSAndi Kleen 
99530e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
99630e863bbSAndi Kleen 		return;
99730e863bbSAndi Kleen 
99830e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
99930e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
100030e863bbSAndi Kleen 		struct cyc_hist *ch;
100130e863bbSAndi Kleen 
100230e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
100330e863bbSAndi Kleen 		if (ch && ch->cycles) {
100430e863bbSAndi Kleen 			struct disasm_line *dl;
100530e863bbSAndi Kleen 
100630e863bbSAndi Kleen 			if (ch->have_start)
100730e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
100830e863bbSAndi Kleen 			dl = browser->offsets[offset];
100930e863bbSAndi Kleen 			if (dl && ch->num_aggr)
101037236d5eSJiri Olsa 				dl->al.cycles = ch->cycles_aggr / ch->num_aggr;
101130e863bbSAndi Kleen 			browser->have_cycles = true;
101230e863bbSAndi Kleen 		}
101330e863bbSAndi Kleen 	}
101430e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
101530e863bbSAndi Kleen }
101630e863bbSAndi Kleen 
1017b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1018b793a401SArnaldo Carvalho de Melo 						size_t size)
1019b793a401SArnaldo Carvalho de Melo {
1020b793a401SArnaldo Carvalho de Melo 	u64 offset;
102132ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
102232ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
102332ae1efdSNamhyung Kim 
102432ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
102532ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
102632ae1efdSNamhyung Kim 		return;
1027b793a401SArnaldo Carvalho de Melo 
1028b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1029b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
10300d957970SJiri Olsa 		struct browser_line *bdlt;
1031b793a401SArnaldo Carvalho de Melo 
1032865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1033b793a401SArnaldo Carvalho de Melo 			continue;
1034b793a401SArnaldo Carvalho de Melo 
103544d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10369481ede9SArnaldo Carvalho de Melo 		/*
10379481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10389481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10399481ede9SArnaldo Carvalho de Melo  		 */
10409481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10419481ede9SArnaldo Carvalho de Melo 			continue;
10429481ede9SArnaldo Carvalho de Melo 
1043*daf25d43SJiri Olsa 		bdlt = browser_line(dlt);
10442402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10452402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10462402e4a9SArnaldo Carvalho de Melo 
10472402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1048b793a401SArnaldo Carvalho de Melo 	}
1049b793a401SArnaldo Carvalho de Melo }
1050b793a401SArnaldo Carvalho de Melo 
10512402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10522402e4a9SArnaldo Carvalho de Melo {
10532402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10542402e4a9SArnaldo Carvalho de Melo 		return 5;
10552402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10562402e4a9SArnaldo Carvalho de Melo 		return 2;
10572402e4a9SArnaldo Carvalho de Melo 	return 1;
10582402e4a9SArnaldo Carvalho de Melo }
10592402e4a9SArnaldo Carvalho de Melo 
1060db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1061db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10629783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1063aca7a94dSNamhyung Kim {
1064f8eb37bdSJiri Olsa 	struct disasm_line *pos;
1065aca7a94dSNamhyung Kim 	struct annotation *notes;
1066c0a58fb2SSamuel Liao 	size_t size;
1067aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1068aca7a94dSNamhyung Kim 		.map = map,
1069aca7a94dSNamhyung Kim 		.sym = sym,
1070aca7a94dSNamhyung Kim 	};
1071aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1072aca7a94dSNamhyung Kim 		.b = {
1073a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1074aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1075aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
107629ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1077aca7a94dSNamhyung Kim 			.priv	 = &ms,
1078aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1079aca7a94dSNamhyung Kim 		},
1080aca7a94dSNamhyung Kim 	};
1081ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1082c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
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 
10983ab6db8dSJiri Olsa 	if (perf_evsel__is_group_event(evsel))
1099c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
1100c7e7b610SNamhyung Kim 
1101d03a686eSJiri Olsa 	err = symbol__annotate(sym, map, evsel,
11020d957970SJiri Olsa 			       sizeof(struct browser_line), &browser.arch,
110369fb09f6SJin Yao 			       perf_evsel__env_cpuid(evsel));
1104ee51d851SArnaldo Carvalho de Melo 	if (err) {
1105ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1106ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1107ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1108b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1109aca7a94dSNamhyung Kim 	}
1110aca7a94dSNamhyung Kim 
11117727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1112aca7a94dSNamhyung Kim 
1113aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1114aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1115aca7a94dSNamhyung Kim 
1116a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
11170d957970SJiri Olsa 		struct browser_line *bpos;
1118d5490b96SJiri Olsa 		size_t line_len = strlen(pos->al.line);
1119aca7a94dSNamhyung Kim 
1120aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1121aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1122*daf25d43SJiri Olsa 		bpos = browser_line(pos);
1123887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1124d5490b96SJiri Olsa 		if (pos->al.offset != -1) {
1125887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
112697148a97SArnaldo Carvalho de Melo 			/*
112797148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
112897148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
112997148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
113097148a97SArnaldo Carvalho de Melo 			 *
113197148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
113297148a97SArnaldo Carvalho de Melo  			 */
1133d5490b96SJiri Olsa 			if (pos->al.offset < (s64)size)
1134d5490b96SJiri Olsa 				browser.offsets[pos->al.offset] = pos;
1135b793a401SArnaldo Carvalho de Melo 		} else
1136887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1137aca7a94dSNamhyung Kim 	}
1138aca7a94dSNamhyung Kim 
1139b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
114030e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1141b793a401SArnaldo Carvalho de Melo 
11422402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
114383b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11442402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1145c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1146aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1147aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1148aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1149e9823b21SArnaldo Carvalho de Melo 
1150e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1151e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1152e9823b21SArnaldo Carvalho de Melo 
1153e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1154e9823b21SArnaldo Carvalho de Melo 
1155db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1156f8eb37bdSJiri Olsa 
1157f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
1158b793a401SArnaldo Carvalho de Melo 
1159b793a401SArnaldo Carvalho de Melo out_free_offsets:
1160b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1161aca7a94dSNamhyung Kim 	return ret;
1162aca7a94dSNamhyung Kim }
1163c323cf04SArnaldo Carvalho de Melo 
1164c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1165c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1166c323cf04SArnaldo Carvalho de Melo 
1167c323cf04SArnaldo Carvalho de Melo /*
1168c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1169c323cf04SArnaldo Carvalho de Melo  */
11707c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1171c323cf04SArnaldo Carvalho de Melo 	const char *name;
1172c323cf04SArnaldo Carvalho de Melo 	bool *value;
1173c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1174c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1175c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1176e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1177c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11789cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
11790c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
118039ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1181c323cf04SArnaldo Carvalho de Melo };
1182c323cf04SArnaldo Carvalho de Melo 
1183c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1184c323cf04SArnaldo Carvalho de Melo 
1185c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1186c323cf04SArnaldo Carvalho de Melo {
11877c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1188c323cf04SArnaldo Carvalho de Melo 
1189c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1190c323cf04SArnaldo Carvalho de Melo }
1191c323cf04SArnaldo Carvalho de Melo 
11921d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11931d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1194c323cf04SArnaldo Carvalho de Melo {
11957c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1196c323cf04SArnaldo Carvalho de Melo 	const char *name;
1197c323cf04SArnaldo Carvalho de Melo 
11988e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1199c323cf04SArnaldo Carvalho de Melo 		return 0;
1200c323cf04SArnaldo Carvalho de Melo 
1201c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1202c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12037c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1204c323cf04SArnaldo Carvalho de Melo 
1205c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1206f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1207f06cff7cSArnaldo Carvalho de Melo 	else
1208c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1209c323cf04SArnaldo Carvalho de Melo 	return 0;
1210c323cf04SArnaldo Carvalho de Melo }
1211c323cf04SArnaldo Carvalho de Melo 
1212c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1213c323cf04SArnaldo Carvalho de Melo {
1214c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1215c323cf04SArnaldo Carvalho de Melo }
1216