xref: /linux/tools/perf/ui/browsers/annotate.c (revision 37236d5e0b6a765319dec3e64d828cb44ebecac6)
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 
28b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
29b793a401SArnaldo Carvalho de Melo 	struct rb_node			rb_node;
30b793a401SArnaldo Carvalho de Melo 	u32				idx;
31b793a401SArnaldo Carvalho de Melo 	int				idx_asm;
327d5b12f5SArnaldo Carvalho de Melo 	int				jump_sources;
33c7e7b610SNamhyung Kim 	/*
34c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
35c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
36c7e7b610SNamhyung Kim 	 */
370c4a5bceSMartin Liška 	struct disasm_line_samples	samples[1];
38b793a401SArnaldo Carvalho de Melo };
39b793a401SArnaldo Carvalho de Melo 
40e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
41e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
42e9823b21SArnaldo Carvalho de Melo 	     use_offset,
43e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
44e592488cSAndi Kleen 	     show_linenr,
450c4a5bceSMartin Liška 	     show_nr_jumps,
469cef4b0bSTaeung Song 	     show_nr_samples,
470c4a5bceSMartin Liška 	     show_total_period;
48e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
49e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
50e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
51e9823b21SArnaldo Carvalho de Melo };
52e9823b21SArnaldo Carvalho de Melo 
53dcaa3948SJin Yao struct arch;
54dcaa3948SJin Yao 
55aca7a94dSNamhyung Kim struct annotate_browser {
56aca7a94dSNamhyung Kim 	struct ui_browser b;
57aca7a94dSNamhyung Kim 	struct rb_root	  entries;
58aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
5929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
60b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
61dcaa3948SJin Yao 	struct arch	    *arch;
62c7e7b610SNamhyung Kim 	int		    nr_events;
63aca7a94dSNamhyung Kim 	u64		    start;
64aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
65aca7a94dSNamhyung Kim 	int		    nr_entries;
662402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
672402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
68aca7a94dSNamhyung Kim 	bool		    searching_backwards;
6930e863bbSAndi Kleen 	bool		    have_cycles;
7083b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
712402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
722402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
7383b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
7483b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
75aca7a94dSNamhyung Kim 	char		    search_bf[128];
76aca7a94dSNamhyung Kim };
77aca7a94dSNamhyung Kim 
78887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
79aca7a94dSNamhyung Kim {
80887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
81aca7a94dSNamhyung Kim }
82aca7a94dSNamhyung Kim 
831d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
841d037ca1SIrina Tirdea 				void *entry)
85aca7a94dSNamhyung Kim {
86e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
87d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
88d5490b96SJiri Olsa 
89d5490b96SJiri Olsa 		return al->offset == -1;
90aca7a94dSNamhyung Kim 	}
91aca7a94dSNamhyung Kim 
92aca7a94dSNamhyung Kim 	return false;
93aca7a94dSNamhyung Kim }
94aca7a94dSNamhyung Kim 
952402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
962402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
972402e4a9SArnaldo Carvalho de Melo {
982402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
992402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
1002402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
1012402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
1022402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
1032402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
1042402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
1052402e4a9SArnaldo Carvalho de Melo }
1062402e4a9SArnaldo Carvalho de Melo 
1072402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
1082402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1092402e4a9SArnaldo Carvalho de Melo {
1102402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1112402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1122402e4a9SArnaldo Carvalho de Melo }
1132402e4a9SArnaldo Carvalho de Melo 
114f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
115f8f4aaeaSAndi Kleen {
1163861c4a4SArnaldo Carvalho de Melo 	return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events;
117bc1e5d60SArnaldo Carvalho de Melo }
118f8f4aaeaSAndi Kleen 
119bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab)
120bc1e5d60SArnaldo Carvalho de Melo {
121bc1e5d60SArnaldo Carvalho de Melo 	return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
122f8f4aaeaSAndi Kleen }
123f8f4aaeaSAndi Kleen 
12405e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
125aca7a94dSNamhyung Kim {
12605e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
127a17c4ca0SJiri Olsa 	struct disasm_line *dl = list_entry(entry, struct disasm_line, al.node);
128b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
12905e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
130e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
13105e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
13205e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
13305e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
134bc1e5d60SArnaldo Carvalho de Melo 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
135bc1e5d60SArnaldo Carvalho de Melo 	       cycles_width = annotate_browser__cycles_width(ab);
136c7e7b610SNamhyung Kim 	double percent_max = 0.0;
13783b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
138ec27ae18SJin Yao 	bool show_title = false;
139aca7a94dSNamhyung Kim 
140c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1410c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1420c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
143c7e7b610SNamhyung Kim 	}
144c7e7b610SNamhyung Kim 
145d5490b96SJiri Olsa 	if ((row == 0) && (dl->al.offset == -1 || percent_max == 0.0)) {
146ec27ae18SJin Yao 		if (ab->have_cycles) {
147*37236d5eSJiri Olsa 			if (dl->al.ipc == 0.0 && dl->al.cycles == 0)
148ec27ae18SJin Yao 				show_title = true;
149ec27ae18SJin Yao 		} else
150ec27ae18SJin Yao 			show_title = true;
151ec27ae18SJin Yao 	}
152ec27ae18SJin Yao 
153d5490b96SJiri Olsa 	if (dl->al.offset != -1 && percent_max != 0.0) {
154c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1550c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1560c4a5bceSMartin Liška 						bdl->samples[i].percent,
157c7e7b610SNamhyung Kim 						current_entry);
158517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
1593861c4a4SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%11" PRIu64 " ",
16029dc267fSTaeung Song 						   bdl->samples[i].he.period);
1619cef4b0bSTaeung Song 			} else if (annotate_browser__opts.show_nr_samples) {
1629cef4b0bSTaeung Song 				ui_browser__printf(browser, "%6" PRIu64 " ",
1639cef4b0bSTaeung Song 						   bdl->samples[i].he.nr_samples);
164517dfdb3SArnaldo Carvalho de Melo 			} else {
165517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
166517dfdb3SArnaldo Carvalho de Melo 						   bdl->samples[i].percent);
167517dfdb3SArnaldo Carvalho de Melo 			}
168c7e7b610SNamhyung Kim 		}
169aca7a94dSNamhyung Kim 	} else {
17005e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
171ec27ae18SJin Yao 
172ec27ae18SJin Yao 		if (!show_title)
173bc1e5d60SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", pcnt_width);
1743861c4a4SArnaldo Carvalho de Melo 		else {
1753861c4a4SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s", pcnt_width,
1769cef4b0bSTaeung Song 					   annotate_browser__opts.show_total_period ? "Period" :
1779cef4b0bSTaeung Song 					   annotate_browser__opts.show_nr_samples ? "Samples" : "Percent");
1783861c4a4SArnaldo Carvalho de Melo 		}
179f8f4aaeaSAndi Kleen 	}
180f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
181*37236d5eSJiri Olsa 		if (dl->al.ipc)
182*37236d5eSJiri Olsa 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->al.ipc);
183ec27ae18SJin Yao 		else if (!show_title)
18426270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
185ec27ae18SJin Yao 		else
186ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
187ec27ae18SJin Yao 
188*37236d5eSJiri Olsa 		if (dl->al.cycles)
189517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
190*37236d5eSJiri Olsa 					   CYCLES_WIDTH - 1, dl->al.cycles);
191ec27ae18SJin Yao 		else if (!show_title)
19226270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
193ec27ae18SJin Yao 		else
194ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
195aca7a94dSNamhyung Kim 	}
196aca7a94dSNamhyung Kim 
197cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
198aca7a94dSNamhyung Kim 
199aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
20005e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
201aca7a94dSNamhyung Kim 		width += 1;
202aca7a94dSNamhyung Kim 
203d5490b96SJiri Olsa 	if (!*dl->al.line)
204bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
205d5490b96SJiri Olsa 	else if (dl->al.offset == -1) {
206d5490b96SJiri Olsa 		if (dl->al.line_nr && annotate_browser__opts.show_linenr)
207e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
208d5490b96SJiri Olsa 					ab->addr_width + 1, dl->al.line_nr);
209e592488cSAndi Kleen 		else
21083b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
21183b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
21226270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
213d5490b96SJiri Olsa 		ui_browser__write_nstring(browser, dl->al.line, width - printed - pcnt_width - cycles_width + 1);
21483b1f2aaSArnaldo Carvalho de Melo 	} else {
215d5490b96SJiri Olsa 		u64 addr = dl->al.offset;
21683b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
217aca7a94dSNamhyung Kim 
218e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
219aca7a94dSNamhyung Kim 			addr += ab->start;
220aca7a94dSNamhyung Kim 
221e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
222aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
22361e04b33SArnaldo Carvalho de Melo 		} else {
2247d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
225e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2262402e4a9SArnaldo Carvalho de Melo 					int prev;
2272402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2282402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2292402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2302402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2312402e4a9SArnaldo Carvalho de Melo 											 current_entry);
23226270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
23305e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2342402e4a9SArnaldo Carvalho de Melo 				}
2352402e4a9SArnaldo Carvalho de Melo 
23661e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2372402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
23861e04b33SArnaldo Carvalho de Melo 			} else {
23961e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
24083b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
24161e04b33SArnaldo Carvalho de Melo 			}
24261e04b33SArnaldo Carvalho de Melo 		}
243b793a401SArnaldo Carvalho de Melo 
244aca7a94dSNamhyung Kim 		if (change_color)
24505e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
24626270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
247aca7a94dSNamhyung Kim 		if (change_color)
24805e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
24975b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
25075b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
251d5490b96SJiri Olsa 				bool fwd = dl->ops.target.offset > dl->al.offset;
25251a0d455SArnaldo Carvalho de Melo 
25305e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
25451a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
25551a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25675b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
25705e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
25888298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25975b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
26005e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2614ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2626ef94929SNaveen N. Rao 			} else {
2636ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2644ea08b52SArnaldo Carvalho de Melo 			}
2656ef94929SNaveen N. Rao 		} else {
2666ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2674ea08b52SArnaldo Carvalho de Melo 		}
2684ea08b52SArnaldo Carvalho de Melo 
269e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
270bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
271aca7a94dSNamhyung Kim 	}
272aca7a94dSNamhyung Kim 
273aca7a94dSNamhyung Kim 	if (current_entry)
27429ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
275aca7a94dSNamhyung Kim }
276aca7a94dSNamhyung Kim 
277865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
278865c66c4SFrederik Deweerdt {
27975b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
280865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
281e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
282e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
283865c66c4SFrederik Deweerdt 		return false;
284865c66c4SFrederik Deweerdt 
285865c66c4SFrederik Deweerdt 	return true;
286865c66c4SFrederik Deweerdt }
287865c66c4SFrederik Deweerdt 
2887e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2897e63a13aSJin Yao {
290a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2917e63a13aSJin Yao 	const char *name;
2927e63a13aSJin Yao 
2937e63a13aSJin Yao 	if (!pos)
2947e63a13aSJin Yao 		return false;
2957e63a13aSJin Yao 
2967e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2977e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2987e63a13aSJin Yao 	else
2997e63a13aSJin Yao 		name = pos->ins.name;
3007e63a13aSJin Yao 
3017e63a13aSJin Yao 	if (!name || !cursor->ins.name)
3027e63a13aSJin Yao 		return false;
3037e63a13aSJin Yao 
3047e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
3057e63a13aSJin Yao }
3067e63a13aSJin Yao 
3079d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
308a3f895beSArnaldo Carvalho de Melo {
309a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3109d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
3119d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
31283b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
31332ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
31432ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
315f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
31632ae1efdSNamhyung Kim 
31732ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31832ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31932ae1efdSNamhyung Kim 		return;
320a3f895beSArnaldo Carvalho de Melo 
321865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
322a3f895beSArnaldo Carvalho de Melo 		return;
323a3f895beSArnaldo Carvalho de Melo 
3249d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
3259d1ef56dSArnaldo Carvalho de Melo 	if (!target)
3269d1ef56dSArnaldo Carvalho de Melo 		return;
3279d1ef56dSArnaldo Carvalho de Melo 
3289d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
3299d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
3309d1ef56dSArnaldo Carvalho de Melo 
331e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3329d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
333a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
334a3f895beSArnaldo Carvalho de Melo 	} else {
3359d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
336a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
337a3f895beSArnaldo Carvalho de Melo 	}
338a3f895beSArnaldo Carvalho de Melo 
33978ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
340c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
341c7e7b610SNamhyung Kim 				 from, to);
3427e63a13aSJin Yao 
3437e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3447e63a13aSJin Yao 		ui_browser__mark_fused(browser,
3457e63a13aSJin Yao 				       pcnt_width + 3 + ab->addr_width,
3467e63a13aSJin Yao 				       from - 1,
3477e63a13aSJin Yao 				       to > from ? true : false);
3487e63a13aSJin Yao 	}
349a3f895beSArnaldo Carvalho de Melo }
350a3f895beSArnaldo Carvalho de Melo 
351a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
352a3f895beSArnaldo Carvalho de Melo {
353c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
354a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
355f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
356a3f895beSArnaldo Carvalho de Melo 
357e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3589d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
359a3f895beSArnaldo Carvalho de Melo 
36083b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
361c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
362a3f895beSArnaldo Carvalho de Melo 	return ret;
363a3f895beSArnaldo Carvalho de Melo }
364a3f895beSArnaldo Carvalho de Melo 
365c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
366c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
367c7e7b610SNamhyung Kim {
368c7e7b610SNamhyung Kim 	int i;
369c7e7b610SNamhyung Kim 
370c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3710c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
372c7e7b610SNamhyung Kim 			continue;
3730c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
374c7e7b610SNamhyung Kim 	}
375c7e7b610SNamhyung Kim 	return 0;
376c7e7b610SNamhyung Kim }
377c7e7b610SNamhyung Kim 
378c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
379c7e7b610SNamhyung Kim 				   int nr_events)
380aca7a94dSNamhyung Kim {
38129ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
382aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
383887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
384aca7a94dSNamhyung Kim 
385aca7a94dSNamhyung Kim 	while (*p != NULL) {
386aca7a94dSNamhyung Kim 		parent = *p;
387887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
388c7e7b610SNamhyung Kim 
389c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
390aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
391aca7a94dSNamhyung Kim 		else
392aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
393aca7a94dSNamhyung Kim 	}
394887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
395887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
396aca7a94dSNamhyung Kim }
397aca7a94dSNamhyung Kim 
39805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
39929ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
400aca7a94dSNamhyung Kim {
401aca7a94dSNamhyung Kim 	unsigned back;
402aca7a94dSNamhyung Kim 
40305e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
40405e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
40505e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
406aca7a94dSNamhyung Kim 
40705e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
408a17c4ca0SJiri Olsa 		pos = list_entry(pos->al.node.prev, struct disasm_line, al.node);
409aca7a94dSNamhyung Kim 
410a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
411aca7a94dSNamhyung Kim 			continue;
412aca7a94dSNamhyung Kim 
41305e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
414aca7a94dSNamhyung Kim 		--back;
415aca7a94dSNamhyung Kim 	}
416aca7a94dSNamhyung Kim 
417a17c4ca0SJiri Olsa 	browser->b.top = &pos->al;
41805e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
419aca7a94dSNamhyung Kim }
420aca7a94dSNamhyung Kim 
421aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
422aca7a94dSNamhyung Kim 					 struct rb_node *nd)
423aca7a94dSNamhyung Kim {
424887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
42529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
426a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
427aca7a94dSNamhyung Kim 
428887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
429887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
430a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
431e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
432a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
433a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
434aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
435aca7a94dSNamhyung Kim }
436aca7a94dSNamhyung Kim 
437aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
438db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
439aca7a94dSNamhyung Kim {
440aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
441aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
442aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
443e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
444e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
445aca7a94dSNamhyung Kim 
446aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
447aca7a94dSNamhyung Kim 
448aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
449aca7a94dSNamhyung Kim 
450a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
451887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
452e64aa75bSNamhyung Kim 		const char *path = NULL;
453c7e7b610SNamhyung Kim 		double max_percent = 0.0;
454c7e7b610SNamhyung Kim 		int i;
455e64aa75bSNamhyung Kim 
456d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
457e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
458e64aa75bSNamhyung Kim 			continue;
459e64aa75bSNamhyung Kim 		}
460e64aa75bSNamhyung Kim 
461e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
462c7e7b610SNamhyung Kim 
463c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
464896bccd3STaeung Song 			struct sym_hist_entry sample;
4650c4a5bceSMartin Liška 
4660c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
467c7e7b610SNamhyung Kim 						evsel->idx + i,
468d5490b96SJiri Olsa 						pos->al.offset,
469d5490b96SJiri Olsa 						next ? next->al.offset : len,
470896bccd3STaeung Song 						&path, &sample);
471bb79a232SArnaldo Carvalho de Melo 			bpos->samples[i].he = sample;
472e64aa75bSNamhyung Kim 
4730c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4740c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
475c7e7b610SNamhyung Kim 		}
476c7e7b610SNamhyung Kim 
477*37236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
478887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
479aca7a94dSNamhyung Kim 			continue;
480aca7a94dSNamhyung Kim 		}
481c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
482c7e7b610SNamhyung Kim 				       browser->nr_events);
483aca7a94dSNamhyung Kim 	}
484aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
485aca7a94dSNamhyung Kim 
486aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
487aca7a94dSNamhyung Kim }
488aca7a94dSNamhyung Kim 
489aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
490aca7a94dSNamhyung Kim {
49129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
492887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
493aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
494aca7a94dSNamhyung Kim 
495aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
496a17c4ca0SJiri Olsa 	dl = list_entry(browser->b.top, struct disasm_line, al.node);
497887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
498aca7a94dSNamhyung Kim 
499e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
500887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
501887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
502aca7a94dSNamhyung Kim 
503aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
504e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
505aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
506887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
507887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
508aca7a94dSNamhyung Kim 	} else {
509887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
510aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
511aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
512aca7a94dSNamhyung Kim 			return false;
513aca7a94dSNamhyung Kim 		}
514aca7a94dSNamhyung Kim 
515887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
516887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
517aca7a94dSNamhyung Kim 
518aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
519e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
520aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
521887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
522887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
523aca7a94dSNamhyung Kim 	}
524aca7a94dSNamhyung Kim 
525aca7a94dSNamhyung Kim 	return true;
526aca7a94dSNamhyung Kim }
527aca7a94dSNamhyung Kim 
528e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
529e9823b21SArnaldo Carvalho de Melo {
530e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
531e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
532e9823b21SArnaldo Carvalho de Melo }
533e9823b21SArnaldo Carvalho de Melo 
53434f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
53534f77abcSAdrian Hunter 
53634f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
53734f77abcSAdrian Hunter 		     size_t sz)
53834f77abcSAdrian Hunter {
53934f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
54034f77abcSAdrian Hunter }
54134f77abcSAdrian Hunter 
542db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
543db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5449783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
545aca7a94dSNamhyung Kim {
546aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
547657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
548aca7a94dSNamhyung Kim 	struct annotation *notes;
5491179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5501179e11bSAdrian Hunter 		.map = ms->map,
5511d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5521179e11bSAdrian Hunter 	};
55334f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
554aca7a94dSNamhyung Kim 
55575b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
556aca7a94dSNamhyung Kim 		return false;
557aca7a94dSNamhyung Kim 
558be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5591d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5601d5077bdSAdrian Hunter 							     target.addr)) !=
5611d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
562aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
563aca7a94dSNamhyung Kim 		return true;
564aca7a94dSNamhyung Kim 	}
565aca7a94dSNamhyung Kim 
5661179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
567aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
568aca7a94dSNamhyung Kim 
5691179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
570aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
571aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5721179e11bSAdrian Hunter 			    target.sym->name);
573aca7a94dSNamhyung Kim 		return true;
574aca7a94dSNamhyung Kim 	}
575aca7a94dSNamhyung Kim 
576aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5771179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5781179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
57934f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
580aca7a94dSNamhyung Kim 	return true;
581aca7a94dSNamhyung Kim }
582aca7a94dSNamhyung Kim 
58329ed6e76SArnaldo Carvalho de Melo static
58429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
585aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
586aca7a94dSNamhyung Kim {
587aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
588aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
589aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
59029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
591aca7a94dSNamhyung Kim 
592aca7a94dSNamhyung Kim 	*idx = 0;
593a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
594d5490b96SJiri Olsa 		if (pos->al.offset == offset)
595aca7a94dSNamhyung Kim 			return pos;
596a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
597aca7a94dSNamhyung Kim 			++*idx;
598aca7a94dSNamhyung Kim 	}
599aca7a94dSNamhyung Kim 
600aca7a94dSNamhyung Kim 	return NULL;
601aca7a94dSNamhyung Kim }
602aca7a94dSNamhyung Kim 
603aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
604aca7a94dSNamhyung Kim {
605657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
6065252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6074f9d0325SArnaldo Carvalho de Melo 	s64 idx;
608aca7a94dSNamhyung Kim 
60975b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
610aca7a94dSNamhyung Kim 		return false;
611aca7a94dSNamhyung Kim 
6125252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6135252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
61429ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6155252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
616aca7a94dSNamhyung Kim 		return true;
617aca7a94dSNamhyung Kim 	}
618aca7a94dSNamhyung Kim 
61929ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
620aca7a94dSNamhyung Kim 
621aca7a94dSNamhyung Kim 	return true;
622aca7a94dSNamhyung Kim }
623aca7a94dSNamhyung Kim 
62429ed6e76SArnaldo Carvalho de Melo static
62529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
626aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
627aca7a94dSNamhyung Kim {
628aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
629aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
630aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
63129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
632aca7a94dSNamhyung Kim 
633aca7a94dSNamhyung Kim 	*idx = browser->b.index;
634a17c4ca0SJiri Olsa 	list_for_each_entry_continue(pos, &notes->src->source, al.node) {
635a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
636aca7a94dSNamhyung Kim 			continue;
637aca7a94dSNamhyung Kim 
638aca7a94dSNamhyung Kim 		++*idx;
639aca7a94dSNamhyung Kim 
640d5490b96SJiri Olsa 		if (pos->al.line && strstr(pos->al.line, s) != NULL)
641aca7a94dSNamhyung Kim 			return pos;
642aca7a94dSNamhyung Kim 	}
643aca7a94dSNamhyung Kim 
644aca7a94dSNamhyung Kim 	return NULL;
645aca7a94dSNamhyung Kim }
646aca7a94dSNamhyung Kim 
647aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
648aca7a94dSNamhyung Kim {
64929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
650aca7a94dSNamhyung Kim 	s64 idx;
651aca7a94dSNamhyung Kim 
65229ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
65329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
654aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
655aca7a94dSNamhyung Kim 		return false;
656aca7a94dSNamhyung Kim 	}
657aca7a94dSNamhyung Kim 
65829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
659aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
660aca7a94dSNamhyung Kim 	return true;
661aca7a94dSNamhyung Kim }
662aca7a94dSNamhyung Kim 
66329ed6e76SArnaldo Carvalho de Melo static
66429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
665aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
666aca7a94dSNamhyung Kim {
667aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
668aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
669aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
67029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
671aca7a94dSNamhyung Kim 
672aca7a94dSNamhyung Kim 	*idx = browser->b.index;
673a17c4ca0SJiri Olsa 	list_for_each_entry_continue_reverse(pos, &notes->src->source, al.node) {
674a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
675aca7a94dSNamhyung Kim 			continue;
676aca7a94dSNamhyung Kim 
677aca7a94dSNamhyung Kim 		--*idx;
678aca7a94dSNamhyung Kim 
679d5490b96SJiri Olsa 		if (pos->al.line && strstr(pos->al.line, s) != NULL)
680aca7a94dSNamhyung Kim 			return pos;
681aca7a94dSNamhyung Kim 	}
682aca7a94dSNamhyung Kim 
683aca7a94dSNamhyung Kim 	return NULL;
684aca7a94dSNamhyung Kim }
685aca7a94dSNamhyung Kim 
686aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
687aca7a94dSNamhyung Kim {
68829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
689aca7a94dSNamhyung Kim 	s64 idx;
690aca7a94dSNamhyung Kim 
69129ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
69229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
693aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
694aca7a94dSNamhyung Kim 		return false;
695aca7a94dSNamhyung Kim 	}
696aca7a94dSNamhyung Kim 
69729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
698aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
699aca7a94dSNamhyung Kim 	return true;
700aca7a94dSNamhyung Kim }
701aca7a94dSNamhyung Kim 
702aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
703aca7a94dSNamhyung Kim 					    int delay_secs)
704aca7a94dSNamhyung Kim {
705aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
706aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
707aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
708aca7a94dSNamhyung Kim 	    !*browser->search_bf)
709aca7a94dSNamhyung Kim 		return false;
710aca7a94dSNamhyung Kim 
711aca7a94dSNamhyung Kim 	return true;
712aca7a94dSNamhyung Kim }
713aca7a94dSNamhyung Kim 
714aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
715aca7a94dSNamhyung Kim {
716aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
717aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
718aca7a94dSNamhyung Kim 
719aca7a94dSNamhyung Kim 	return false;
720aca7a94dSNamhyung Kim }
721aca7a94dSNamhyung Kim 
722aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
723aca7a94dSNamhyung Kim 					      int delay_secs)
724aca7a94dSNamhyung Kim {
725aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
726aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
727aca7a94dSNamhyung Kim 
728aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
729aca7a94dSNamhyung Kim }
730aca7a94dSNamhyung Kim 
731aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
732aca7a94dSNamhyung Kim 					   int delay_secs)
733aca7a94dSNamhyung Kim {
734aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
735aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
736aca7a94dSNamhyung Kim 
737aca7a94dSNamhyung Kim 	return false;
738aca7a94dSNamhyung Kim }
739aca7a94dSNamhyung Kim 
740aca7a94dSNamhyung Kim static
741aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
742aca7a94dSNamhyung Kim 					       int delay_secs)
743aca7a94dSNamhyung Kim {
744aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
745aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
746aca7a94dSNamhyung Kim 
747aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
748aca7a94dSNamhyung Kim }
749aca7a94dSNamhyung Kim 
750e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
751e9823b21SArnaldo Carvalho de Melo {
752e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
753e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
754e9823b21SArnaldo Carvalho de Melo 	else
755e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
756e9823b21SArnaldo Carvalho de Melo 
757e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
758e9823b21SArnaldo Carvalho de Melo 
759e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
760e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
761e9823b21SArnaldo Carvalho de Melo }
762e9823b21SArnaldo Carvalho de Melo 
763db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
764db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7659783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
766aca7a94dSNamhyung Kim {
767aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
76805e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
769aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
77054e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7719783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
772aca7a94dSNamhyung Kim 	int key;
77334f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
774aca7a94dSNamhyung Kim 
77534f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
77634f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
777aca7a94dSNamhyung Kim 		return -1;
778aca7a94dSNamhyung Kim 
779db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
780aca7a94dSNamhyung Kim 
78105e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
78205e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
78305e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
784aca7a94dSNamhyung Kim 	}
785aca7a94dSNamhyung Kim 
78605e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
787aca7a94dSNamhyung Kim 
788aca7a94dSNamhyung Kim 	while (1) {
78905e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
790aca7a94dSNamhyung Kim 
791aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
792db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
793aca7a94dSNamhyung Kim 			/*
794aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
795aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
796aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
797aca7a94dSNamhyung Kim 			 */
798aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
799aca7a94dSNamhyung Kim 				nd = NULL;
800aca7a94dSNamhyung Kim 		}
801aca7a94dSNamhyung Kim 
802aca7a94dSNamhyung Kim 		switch (key) {
803aca7a94dSNamhyung Kim 		case K_TIMER:
8049783adf7SNamhyung Kim 			if (hbt)
8059783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
806aca7a94dSNamhyung Kim 
807aca7a94dSNamhyung Kim 			if (delay_secs != 0)
808db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
809aca7a94dSNamhyung Kim 			continue;
810aca7a94dSNamhyung Kim 		case K_TAB:
811aca7a94dSNamhyung Kim 			if (nd != NULL) {
812aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
813aca7a94dSNamhyung Kim 				if (nd == NULL)
81405e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
815aca7a94dSNamhyung Kim 			} else
81605e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
817aca7a94dSNamhyung Kim 			break;
818aca7a94dSNamhyung Kim 		case K_UNTAB:
819d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
820aca7a94dSNamhyung Kim 				nd = rb_next(nd);
821aca7a94dSNamhyung Kim 				if (nd == NULL)
82205e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
823d4913cbdSMarkus Trippelsdorf 			} else
82405e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
825aca7a94dSNamhyung Kim 			break;
82654e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
827aca7a94dSNamhyung Kim 		case 'h':
82805e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
82954e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
83054e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
83154e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8327727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8337727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
834eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
835eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
83654e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
83754e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
83854e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
83954e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
84054e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8413a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
84254e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
843e592488cSAndi Kleen 		"k             Toggle line numbers\n"
84479ee47faSFeng Tang 		"r             Run available scripts\n"
845fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
84654e7a4e8SArnaldo Carvalho de Melo 			continue;
84779ee47faSFeng Tang 		case 'r':
84879ee47faSFeng Tang 			{
84979ee47faSFeng Tang 				script_browse(NULL);
85079ee47faSFeng Tang 				continue;
85179ee47faSFeng Tang 			}
852e592488cSAndi Kleen 		case 'k':
853e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
854e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
855e592488cSAndi Kleen 			break;
85654e7a4e8SArnaldo Carvalho de Melo 		case 'H':
85705e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
858aca7a94dSNamhyung Kim 			break;
859aca7a94dSNamhyung Kim 		case 's':
86005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
861aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
862aca7a94dSNamhyung Kim 			continue;
863aca7a94dSNamhyung Kim 		case 'o':
864e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
86505e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
866aca7a94dSNamhyung Kim 			continue;
8679d1ef56dSArnaldo Carvalho de Melo 		case 'j':
868e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8699d1ef56dSArnaldo Carvalho de Melo 			continue;
8702402e4a9SArnaldo Carvalho de Melo 		case 'J':
871e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
87205e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
873e9823b21SArnaldo Carvalho de Melo 			continue;
874aca7a94dSNamhyung Kim 		case '/':
87505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
876aca7a94dSNamhyung Kim show_help:
877aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
878aca7a94dSNamhyung Kim 			}
879aca7a94dSNamhyung Kim 			continue;
880aca7a94dSNamhyung Kim 		case 'n':
88105e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
88205e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
88305e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
884aca7a94dSNamhyung Kim 				goto show_help;
885aca7a94dSNamhyung Kim 			continue;
886aca7a94dSNamhyung Kim 		case '?':
88705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
888aca7a94dSNamhyung Kim 				goto show_help;
889aca7a94dSNamhyung Kim 			continue;
890e9823b21SArnaldo Carvalho de Melo 		case 'D': {
891e9823b21SArnaldo Carvalho de Melo 			static int seq;
892e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
893e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
89405e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
89505e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
89605e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
89705e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
89805e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
899e9823b21SArnaldo Carvalho de Melo 		}
900e9823b21SArnaldo Carvalho de Melo 			continue;
901aca7a94dSNamhyung Kim 		case K_ENTER:
902aca7a94dSNamhyung Kim 		case K_RIGHT:
90305e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
904aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
905d5490b96SJiri Olsa 			else if (browser->selection->al.offset == -1)
906aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
90775b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
908c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
90975b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
910c4cceae3SArnaldo Carvalho de Melo 				goto out;
9116ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
912db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
913c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9146ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
915c4cceae3SArnaldo Carvalho de Melo 			}
916aca7a94dSNamhyung Kim 			continue;
9170c4a5bceSMartin Liška 		case 't':
9183a555c77STaeung Song 			if (annotate_browser__opts.show_total_period) {
9193a555c77STaeung Song 				annotate_browser__opts.show_total_period = false;
9203a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = true;
9213a555c77STaeung Song 			} else if (annotate_browser__opts.show_nr_samples)
9223a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = false;
9233a555c77STaeung Song 			else
9243a555c77STaeung Song 				annotate_browser__opts.show_total_period = true;
9250c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9260c4a5bceSMartin Liška 			continue;
927aca7a94dSNamhyung Kim 		case K_LEFT:
928aca7a94dSNamhyung Kim 		case K_ESC:
929aca7a94dSNamhyung Kim 		case 'q':
930aca7a94dSNamhyung Kim 		case CTRL('c'):
931aca7a94dSNamhyung Kim 			goto out;
932aca7a94dSNamhyung Kim 		default:
933aca7a94dSNamhyung Kim 			continue;
934aca7a94dSNamhyung Kim 		}
935aca7a94dSNamhyung Kim 
936aca7a94dSNamhyung Kim 		if (nd != NULL)
93705e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
938aca7a94dSNamhyung Kim 	}
939aca7a94dSNamhyung Kim out:
94005e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
941aca7a94dSNamhyung Kim 	return key;
942aca7a94dSNamhyung Kim }
943aca7a94dSNamhyung Kim 
944d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
945d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
946d5dbc518SArnaldo Carvalho de Melo {
9479cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9480c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9490c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9509cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9519cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9520c4a5bceSMartin Liška 
953d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
954d5dbc518SArnaldo Carvalho de Melo }
955d5dbc518SArnaldo Carvalho de Melo 
956db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9579783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
958aca7a94dSNamhyung Kim {
959ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
960ed426915SNamhyung Kim 	SLang_reset_tty();
961ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
962ed426915SNamhyung Kim 
963d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
964aca7a94dSNamhyung Kim }
965aca7a94dSNamhyung Kim 
96630e863bbSAndi Kleen 
96730e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
96830e863bbSAndi Kleen {
96930e863bbSAndi Kleen 	unsigned n_insn = 0;
97030e863bbSAndi Kleen 	u64 offset;
97130e863bbSAndi Kleen 
97230e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
97330e863bbSAndi Kleen 		if (browser->offsets[offset])
97430e863bbSAndi Kleen 			n_insn++;
97530e863bbSAndi Kleen 	}
97630e863bbSAndi Kleen 	return n_insn;
97730e863bbSAndi Kleen }
97830e863bbSAndi Kleen 
97930e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
98030e863bbSAndi Kleen 			   struct cyc_hist *ch)
98130e863bbSAndi Kleen {
98230e863bbSAndi Kleen 	unsigned n_insn;
98330e863bbSAndi Kleen 	u64 offset;
98430e863bbSAndi Kleen 
98530e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
98630e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
98730e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
98830e863bbSAndi Kleen 
98930e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
99030e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
99130e863bbSAndi Kleen 			return;
99230e863bbSAndi Kleen 
99330e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
99430e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
99530e863bbSAndi Kleen 
99630e863bbSAndi Kleen 			if (dl)
997*37236d5eSJiri Olsa 				dl->al.ipc = ipc;
99830e863bbSAndi Kleen 		}
99930e863bbSAndi Kleen 	}
100030e863bbSAndi Kleen }
100130e863bbSAndi Kleen 
100230e863bbSAndi Kleen /*
100330e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
100430e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
100530e863bbSAndi Kleen  * which are only here.
100630e863bbSAndi Kleen  */
100730e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
100830e863bbSAndi Kleen 			   struct symbol *sym)
100930e863bbSAndi Kleen {
101030e863bbSAndi Kleen 	u64 offset;
101130e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
101230e863bbSAndi Kleen 
101330e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
101430e863bbSAndi Kleen 		return;
101530e863bbSAndi Kleen 
101630e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
101730e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
101830e863bbSAndi Kleen 		struct cyc_hist *ch;
101930e863bbSAndi Kleen 
102030e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
102130e863bbSAndi Kleen 		if (ch && ch->cycles) {
102230e863bbSAndi Kleen 			struct disasm_line *dl;
102330e863bbSAndi Kleen 
102430e863bbSAndi Kleen 			if (ch->have_start)
102530e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
102630e863bbSAndi Kleen 			dl = browser->offsets[offset];
102730e863bbSAndi Kleen 			if (dl && ch->num_aggr)
1028*37236d5eSJiri Olsa 				dl->al.cycles = ch->cycles_aggr / ch->num_aggr;
102930e863bbSAndi Kleen 			browser->have_cycles = true;
103030e863bbSAndi Kleen 		}
103130e863bbSAndi Kleen 	}
103230e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
103330e863bbSAndi Kleen }
103430e863bbSAndi Kleen 
1035b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1036b793a401SArnaldo Carvalho de Melo 						size_t size)
1037b793a401SArnaldo Carvalho de Melo {
1038b793a401SArnaldo Carvalho de Melo 	u64 offset;
103932ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
104032ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
104132ae1efdSNamhyung Kim 
104232ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
104332ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
104432ae1efdSNamhyung Kim 		return;
1045b793a401SArnaldo Carvalho de Melo 
1046b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1047b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
1048b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
1049b793a401SArnaldo Carvalho de Melo 
1050865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1051b793a401SArnaldo Carvalho de Melo 			continue;
1052b793a401SArnaldo Carvalho de Melo 
105344d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10549481ede9SArnaldo Carvalho de Melo 		/*
10559481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10569481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10579481ede9SArnaldo Carvalho de Melo  		 */
10589481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10599481ede9SArnaldo Carvalho de Melo 			continue;
10609481ede9SArnaldo Carvalho de Melo 
1061b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
10622402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10632402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10642402e4a9SArnaldo Carvalho de Melo 
10652402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1066b793a401SArnaldo Carvalho de Melo 	}
1067b793a401SArnaldo Carvalho de Melo }
1068b793a401SArnaldo Carvalho de Melo 
10692402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10702402e4a9SArnaldo Carvalho de Melo {
10712402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10722402e4a9SArnaldo Carvalho de Melo 		return 5;
10732402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10742402e4a9SArnaldo Carvalho de Melo 		return 2;
10752402e4a9SArnaldo Carvalho de Melo 	return 1;
10762402e4a9SArnaldo Carvalho de Melo }
10772402e4a9SArnaldo Carvalho de Melo 
1078db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1079db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10809783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1081aca7a94dSNamhyung Kim {
108229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1083aca7a94dSNamhyung Kim 	struct annotation *notes;
1084c0a58fb2SSamuel Liao 	size_t size;
1085aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1086aca7a94dSNamhyung Kim 		.map = map,
1087aca7a94dSNamhyung Kim 		.sym = sym,
1088aca7a94dSNamhyung Kim 	};
1089aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1090aca7a94dSNamhyung Kim 		.b = {
1091a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1092aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1093aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
109429ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1095aca7a94dSNamhyung Kim 			.priv	 = &ms,
1096aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1097aca7a94dSNamhyung Kim 		},
1098aca7a94dSNamhyung Kim 	};
1099ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1100c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1101c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1102aca7a94dSNamhyung Kim 
1103aca7a94dSNamhyung Kim 	if (sym == NULL)
1104aca7a94dSNamhyung Kim 		return -1;
1105aca7a94dSNamhyung Kim 
1106c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1107c0a58fb2SSamuel Liao 
1108aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1109aca7a94dSNamhyung Kim 		return -1;
1110aca7a94dSNamhyung Kim 
1111b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1112b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1113b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1114b793a401SArnaldo Carvalho de Melo 		return -1;
1115b793a401SArnaldo Carvalho de Melo 	}
1116b793a401SArnaldo Carvalho de Melo 
1117c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1118c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
11190c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
11200c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1121c7e7b610SNamhyung Kim 	}
1122c7e7b610SNamhyung Kim 
1123dcaa3948SJin Yao 	err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
112469fb09f6SJin Yao 				  sizeof_bdl, &browser.arch,
112569fb09f6SJin Yao 				  perf_evsel__env_cpuid(evsel));
1126ee51d851SArnaldo Carvalho de Melo 	if (err) {
1127ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1128ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1129ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1130b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1131aca7a94dSNamhyung Kim 	}
1132aca7a94dSNamhyung Kim 
11337727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1134aca7a94dSNamhyung Kim 
1135aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1136aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1137aca7a94dSNamhyung Kim 
1138a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
1139887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1140d5490b96SJiri Olsa 		size_t line_len = strlen(pos->al.line);
1141aca7a94dSNamhyung Kim 
1142aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1143aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1144887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1145887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1146d5490b96SJiri Olsa 		if (pos->al.offset != -1) {
1147887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
114897148a97SArnaldo Carvalho de Melo 			/*
114997148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
115097148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
115197148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
115297148a97SArnaldo Carvalho de Melo 			 *
115397148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
115497148a97SArnaldo Carvalho de Melo  			 */
1155d5490b96SJiri Olsa 			if (pos->al.offset < (s64)size)
1156d5490b96SJiri Olsa 				browser.offsets[pos->al.offset] = pos;
1157b793a401SArnaldo Carvalho de Melo 		} else
1158887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1159aca7a94dSNamhyung Kim 	}
1160aca7a94dSNamhyung Kim 
1161b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
116230e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1163b793a401SArnaldo Carvalho de Melo 
11642402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
116583b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11662402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1167c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1168aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1169aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1170aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1171e9823b21SArnaldo Carvalho de Melo 
1172e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1173e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1174e9823b21SArnaldo Carvalho de Melo 
1175e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1176e9823b21SArnaldo Carvalho de Melo 
1177db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1178a17c4ca0SJiri Olsa 	list_for_each_entry_safe(pos, n, &notes->src->source, al.node) {
1179a17c4ca0SJiri Olsa 		list_del(&pos->al.node);
118029ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1181aca7a94dSNamhyung Kim 	}
1182b793a401SArnaldo Carvalho de Melo 
1183b793a401SArnaldo Carvalho de Melo out_free_offsets:
1184b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1185aca7a94dSNamhyung Kim 	return ret;
1186aca7a94dSNamhyung Kim }
1187c323cf04SArnaldo Carvalho de Melo 
1188c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1189c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1190c323cf04SArnaldo Carvalho de Melo 
1191c323cf04SArnaldo Carvalho de Melo /*
1192c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1193c323cf04SArnaldo Carvalho de Melo  */
11947c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1195c323cf04SArnaldo Carvalho de Melo 	const char *name;
1196c323cf04SArnaldo Carvalho de Melo 	bool *value;
1197c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1198c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1199c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1200e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1201c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
12029cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
12030c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
120439ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1205c323cf04SArnaldo Carvalho de Melo };
1206c323cf04SArnaldo Carvalho de Melo 
1207c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1208c323cf04SArnaldo Carvalho de Melo 
1209c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1210c323cf04SArnaldo Carvalho de Melo {
12117c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1212c323cf04SArnaldo Carvalho de Melo 
1213c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1214c323cf04SArnaldo Carvalho de Melo }
1215c323cf04SArnaldo Carvalho de Melo 
12161d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
12171d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1218c323cf04SArnaldo Carvalho de Melo {
12197c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1220c323cf04SArnaldo Carvalho de Melo 	const char *name;
1221c323cf04SArnaldo Carvalho de Melo 
12228e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1223c323cf04SArnaldo Carvalho de Melo 		return 0;
1224c323cf04SArnaldo Carvalho de Melo 
1225c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1226c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12277c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1228c323cf04SArnaldo Carvalho de Melo 
1229c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1230f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1231f06cff7cSArnaldo Carvalho de Melo 	else
1232c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1233c323cf04SArnaldo Carvalho de Melo 	return 0;
1234c323cf04SArnaldo Carvalho de Melo }
1235c323cf04SArnaldo Carvalho de Melo 
1236c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1237c323cf04SArnaldo Carvalho de Melo {
1238c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1239c323cf04SArnaldo Carvalho de Melo }
1240