xref: /linux/tools/perf/ui/browsers/annotate.c (revision 5b12adc849be011fd6d99a16e39d83afee43c0a0)
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 	u32				idx;
30b793a401SArnaldo Carvalho de Melo 	int				idx_asm;
317d5b12f5SArnaldo Carvalho de Melo 	int				jump_sources;
32c7e7b610SNamhyung Kim 	/*
33c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
34c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
35c7e7b610SNamhyung Kim 	 */
360c4a5bceSMartin Liška 	struct disasm_line_samples	samples[1];
37b793a401SArnaldo Carvalho de Melo };
38b793a401SArnaldo Carvalho de Melo 
39e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
40e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
41e9823b21SArnaldo Carvalho de Melo 	     use_offset,
42e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
43e592488cSAndi Kleen 	     show_linenr,
440c4a5bceSMartin Liška 	     show_nr_jumps,
459cef4b0bSTaeung Song 	     show_nr_samples,
460c4a5bceSMartin Liška 	     show_total_period;
47e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
48e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
49e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
50e9823b21SArnaldo Carvalho de Melo };
51e9823b21SArnaldo Carvalho de Melo 
52dcaa3948SJin Yao struct arch;
53dcaa3948SJin Yao 
54aca7a94dSNamhyung Kim struct annotate_browser {
55aca7a94dSNamhyung Kim 	struct ui_browser b;
56aca7a94dSNamhyung Kim 	struct rb_root	  entries;
57aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
5829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
59b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
60dcaa3948SJin Yao 	struct arch	    *arch;
61c7e7b610SNamhyung Kim 	int		    nr_events;
62aca7a94dSNamhyung Kim 	u64		    start;
63aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
64aca7a94dSNamhyung Kim 	int		    nr_entries;
652402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
662402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
67aca7a94dSNamhyung Kim 	bool		    searching_backwards;
6830e863bbSAndi Kleen 	bool		    have_cycles;
6983b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
702402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
712402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
7283b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
7383b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
74aca7a94dSNamhyung Kim 	char		    search_bf[128];
75aca7a94dSNamhyung Kim };
76aca7a94dSNamhyung Kim 
77887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
78aca7a94dSNamhyung Kim {
79887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
80aca7a94dSNamhyung Kim }
81aca7a94dSNamhyung Kim 
821d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
831d037ca1SIrina Tirdea 				void *entry)
84aca7a94dSNamhyung Kim {
85e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
86d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
87d5490b96SJiri Olsa 
88d5490b96SJiri Olsa 		return al->offset == -1;
89aca7a94dSNamhyung Kim 	}
90aca7a94dSNamhyung Kim 
91aca7a94dSNamhyung Kim 	return false;
92aca7a94dSNamhyung Kim }
93aca7a94dSNamhyung Kim 
942402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
952402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
962402e4a9SArnaldo Carvalho de Melo {
972402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
982402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
992402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
1002402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
1012402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
1022402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
1032402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
1042402e4a9SArnaldo Carvalho de Melo }
1052402e4a9SArnaldo Carvalho de Melo 
1062402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
1072402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1082402e4a9SArnaldo Carvalho de Melo {
1092402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1102402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1112402e4a9SArnaldo Carvalho de Melo }
1122402e4a9SArnaldo Carvalho de Melo 
113f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
114f8f4aaeaSAndi Kleen {
1153861c4a4SArnaldo Carvalho de Melo 	return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events;
116bc1e5d60SArnaldo Carvalho de Melo }
117f8f4aaeaSAndi Kleen 
118bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab)
119bc1e5d60SArnaldo Carvalho de Melo {
120bc1e5d60SArnaldo Carvalho de Melo 	return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
121f8f4aaeaSAndi Kleen }
122f8f4aaeaSAndi Kleen 
12305e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
124aca7a94dSNamhyung Kim {
12505e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
126a17c4ca0SJiri Olsa 	struct disasm_line *dl = list_entry(entry, struct disasm_line, al.node);
127b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
12805e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
129e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
13005e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
13105e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
13205e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
133bc1e5d60SArnaldo Carvalho de Melo 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
134bc1e5d60SArnaldo Carvalho de Melo 	       cycles_width = annotate_browser__cycles_width(ab);
135c7e7b610SNamhyung Kim 	double percent_max = 0.0;
13683b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
137ec27ae18SJin Yao 	bool show_title = false;
138aca7a94dSNamhyung Kim 
139c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1400c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1410c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
142c7e7b610SNamhyung Kim 	}
143c7e7b610SNamhyung Kim 
144d5490b96SJiri Olsa 	if ((row == 0) && (dl->al.offset == -1 || percent_max == 0.0)) {
145ec27ae18SJin Yao 		if (ab->have_cycles) {
14637236d5eSJiri Olsa 			if (dl->al.ipc == 0.0 && dl->al.cycles == 0)
147ec27ae18SJin Yao 				show_title = true;
148ec27ae18SJin Yao 		} else
149ec27ae18SJin Yao 			show_title = true;
150ec27ae18SJin Yao 	}
151ec27ae18SJin Yao 
152d5490b96SJiri Olsa 	if (dl->al.offset != -1 && percent_max != 0.0) {
153c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1540c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1550c4a5bceSMartin Liška 						bdl->samples[i].percent,
156c7e7b610SNamhyung Kim 						current_entry);
157517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
1583861c4a4SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%11" PRIu64 " ",
15929dc267fSTaeung Song 						   bdl->samples[i].he.period);
1609cef4b0bSTaeung Song 			} else if (annotate_browser__opts.show_nr_samples) {
1619cef4b0bSTaeung Song 				ui_browser__printf(browser, "%6" PRIu64 " ",
1629cef4b0bSTaeung Song 						   bdl->samples[i].he.nr_samples);
163517dfdb3SArnaldo Carvalho de Melo 			} else {
164517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
165517dfdb3SArnaldo Carvalho de Melo 						   bdl->samples[i].percent);
166517dfdb3SArnaldo Carvalho de Melo 			}
167c7e7b610SNamhyung Kim 		}
168aca7a94dSNamhyung Kim 	} else {
16905e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
170ec27ae18SJin Yao 
171ec27ae18SJin Yao 		if (!show_title)
172bc1e5d60SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", pcnt_width);
1733861c4a4SArnaldo Carvalho de Melo 		else {
1743861c4a4SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s", pcnt_width,
1759cef4b0bSTaeung Song 					   annotate_browser__opts.show_total_period ? "Period" :
1769cef4b0bSTaeung Song 					   annotate_browser__opts.show_nr_samples ? "Samples" : "Percent");
1773861c4a4SArnaldo Carvalho de Melo 		}
178f8f4aaeaSAndi Kleen 	}
179f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
18037236d5eSJiri Olsa 		if (dl->al.ipc)
18137236d5eSJiri Olsa 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->al.ipc);
182ec27ae18SJin Yao 		else if (!show_title)
18326270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
184ec27ae18SJin Yao 		else
185ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
186ec27ae18SJin Yao 
18737236d5eSJiri Olsa 		if (dl->al.cycles)
188517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
18937236d5eSJiri Olsa 					   CYCLES_WIDTH - 1, dl->al.cycles);
190ec27ae18SJin Yao 		else if (!show_title)
19126270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
192ec27ae18SJin Yao 		else
193ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
194aca7a94dSNamhyung Kim 	}
195aca7a94dSNamhyung Kim 
196cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
197aca7a94dSNamhyung Kim 
198aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
19905e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
200aca7a94dSNamhyung Kim 		width += 1;
201aca7a94dSNamhyung Kim 
202d5490b96SJiri Olsa 	if (!*dl->al.line)
203bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
204d5490b96SJiri Olsa 	else if (dl->al.offset == -1) {
205d5490b96SJiri Olsa 		if (dl->al.line_nr && annotate_browser__opts.show_linenr)
206e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
207d5490b96SJiri Olsa 					ab->addr_width + 1, dl->al.line_nr);
208e592488cSAndi Kleen 		else
20983b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
21083b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
21126270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
212d5490b96SJiri Olsa 		ui_browser__write_nstring(browser, dl->al.line, width - printed - pcnt_width - cycles_width + 1);
21383b1f2aaSArnaldo Carvalho de Melo 	} else {
214d5490b96SJiri Olsa 		u64 addr = dl->al.offset;
21583b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
216aca7a94dSNamhyung Kim 
217e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
218aca7a94dSNamhyung Kim 			addr += ab->start;
219aca7a94dSNamhyung Kim 
220e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
221aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
22261e04b33SArnaldo Carvalho de Melo 		} else {
2237d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
224e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2252402e4a9SArnaldo Carvalho de Melo 					int prev;
2262402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2272402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2282402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2292402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2302402e4a9SArnaldo Carvalho de Melo 											 current_entry);
23126270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
23205e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2332402e4a9SArnaldo Carvalho de Melo 				}
2342402e4a9SArnaldo Carvalho de Melo 
23561e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2362402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
23761e04b33SArnaldo Carvalho de Melo 			} else {
23861e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
23983b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
24061e04b33SArnaldo Carvalho de Melo 			}
24161e04b33SArnaldo Carvalho de Melo 		}
242b793a401SArnaldo Carvalho de Melo 
243aca7a94dSNamhyung Kim 		if (change_color)
24405e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
24526270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
246aca7a94dSNamhyung Kim 		if (change_color)
24705e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
24875b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
24975b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
250d5490b96SJiri Olsa 				bool fwd = dl->ops.target.offset > dl->al.offset;
25151a0d455SArnaldo Carvalho de Melo 
25205e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
25351a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
25451a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25575b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
25605e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
25788298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25875b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
25905e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2604ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2616ef94929SNaveen N. Rao 			} else {
2626ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2634ea08b52SArnaldo Carvalho de Melo 			}
2646ef94929SNaveen N. Rao 		} else {
2656ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2664ea08b52SArnaldo Carvalho de Melo 		}
2674ea08b52SArnaldo Carvalho de Melo 
268e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
269bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
270aca7a94dSNamhyung Kim 	}
271aca7a94dSNamhyung Kim 
272aca7a94dSNamhyung Kim 	if (current_entry)
27329ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
274aca7a94dSNamhyung Kim }
275aca7a94dSNamhyung Kim 
276865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
277865c66c4SFrederik Deweerdt {
27875b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
279865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
280e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
281e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
282865c66c4SFrederik Deweerdt 		return false;
283865c66c4SFrederik Deweerdt 
284865c66c4SFrederik Deweerdt 	return true;
285865c66c4SFrederik Deweerdt }
286865c66c4SFrederik Deweerdt 
2877e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2887e63a13aSJin Yao {
289a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2907e63a13aSJin Yao 	const char *name;
2917e63a13aSJin Yao 
2927e63a13aSJin Yao 	if (!pos)
2937e63a13aSJin Yao 		return false;
2947e63a13aSJin Yao 
2957e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2967e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2977e63a13aSJin Yao 	else
2987e63a13aSJin Yao 		name = pos->ins.name;
2997e63a13aSJin Yao 
3007e63a13aSJin Yao 	if (!name || !cursor->ins.name)
3017e63a13aSJin Yao 		return false;
3027e63a13aSJin Yao 
3037e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
3047e63a13aSJin Yao }
3057e63a13aSJin Yao 
3069d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
307a3f895beSArnaldo Carvalho de Melo {
308a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3099d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
3109d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
31183b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
31232ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
31332ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
314f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
31532ae1efdSNamhyung Kim 
31632ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31732ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31832ae1efdSNamhyung Kim 		return;
319a3f895beSArnaldo Carvalho de Melo 
320865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
321a3f895beSArnaldo Carvalho de Melo 		return;
322a3f895beSArnaldo Carvalho de Melo 
3239d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
3249d1ef56dSArnaldo Carvalho de Melo 	if (!target)
3259d1ef56dSArnaldo Carvalho de Melo 		return;
3269d1ef56dSArnaldo Carvalho de Melo 
3279d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
3289d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
3299d1ef56dSArnaldo Carvalho de Melo 
330e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3319d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
332a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
333a3f895beSArnaldo Carvalho de Melo 	} else {
3349d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
335a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
336a3f895beSArnaldo Carvalho de Melo 	}
337a3f895beSArnaldo Carvalho de Melo 
33878ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
339c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
340c7e7b610SNamhyung Kim 				 from, to);
3417e63a13aSJin Yao 
3427e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3437e63a13aSJin Yao 		ui_browser__mark_fused(browser,
3447e63a13aSJin Yao 				       pcnt_width + 3 + ab->addr_width,
3457e63a13aSJin Yao 				       from - 1,
3467e63a13aSJin Yao 				       to > from ? true : false);
3477e63a13aSJin Yao 	}
348a3f895beSArnaldo Carvalho de Melo }
349a3f895beSArnaldo Carvalho de Melo 
350a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
351a3f895beSArnaldo Carvalho de Melo {
352c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
353a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
354f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
355a3f895beSArnaldo Carvalho de Melo 
356e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3579d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
358a3f895beSArnaldo Carvalho de Melo 
35983b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
360c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
361a3f895beSArnaldo Carvalho de Melo 	return ret;
362a3f895beSArnaldo Carvalho de Melo }
363a3f895beSArnaldo Carvalho de Melo 
364*5b12adc8SJiri Olsa static int disasm__cmp(struct disasm_line *da,
365*5b12adc8SJiri Olsa 		       struct disasm_line *db, int nr_pcnt)
366c7e7b610SNamhyung Kim {
367*5b12adc8SJiri Olsa 	struct browser_disasm_line *a = disasm_line__browser(da);
368*5b12adc8SJiri Olsa 	struct browser_disasm_line *b = disasm_line__browser(db);
369c7e7b610SNamhyung Kim 	int i;
370c7e7b610SNamhyung Kim 
371c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3720c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
373c7e7b610SNamhyung Kim 			continue;
3740c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
375c7e7b610SNamhyung Kim 	}
376c7e7b610SNamhyung Kim 	return 0;
377c7e7b610SNamhyung Kim }
378c7e7b610SNamhyung Kim 
379*5b12adc8SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct disasm_line *dl,
380c7e7b610SNamhyung Kim 				   int nr_events)
381aca7a94dSNamhyung Kim {
38229ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
383aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
384*5b12adc8SJiri Olsa 	struct disasm_line *l;
385aca7a94dSNamhyung Kim 
386aca7a94dSNamhyung Kim 	while (*p != NULL) {
387aca7a94dSNamhyung Kim 		parent = *p;
388*5b12adc8SJiri Olsa 		l = rb_entry(parent, struct disasm_line, al.rb_node);
389c7e7b610SNamhyung Kim 
390*5b12adc8SJiri Olsa 		if (disasm__cmp(dl, l, nr_events))
391aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
392aca7a94dSNamhyung Kim 		else
393aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
394aca7a94dSNamhyung Kim 	}
395*5b12adc8SJiri Olsa 	rb_link_node(&dl->al.rb_node, parent, p);
396*5b12adc8SJiri Olsa 	rb_insert_color(&dl->al.rb_node, root);
397aca7a94dSNamhyung Kim }
398aca7a94dSNamhyung Kim 
39905e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
40029ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
401aca7a94dSNamhyung Kim {
402aca7a94dSNamhyung Kim 	unsigned back;
403aca7a94dSNamhyung Kim 
40405e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
40505e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
40605e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
407aca7a94dSNamhyung Kim 
40805e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
409a17c4ca0SJiri Olsa 		pos = list_entry(pos->al.node.prev, struct disasm_line, al.node);
410aca7a94dSNamhyung Kim 
411a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
412aca7a94dSNamhyung Kim 			continue;
413aca7a94dSNamhyung Kim 
41405e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
415aca7a94dSNamhyung Kim 		--back;
416aca7a94dSNamhyung Kim 	}
417aca7a94dSNamhyung Kim 
418a17c4ca0SJiri Olsa 	browser->b.top = &pos->al;
41905e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
420aca7a94dSNamhyung Kim }
421aca7a94dSNamhyung Kim 
422aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
423aca7a94dSNamhyung Kim 					 struct rb_node *nd)
424aca7a94dSNamhyung Kim {
425887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
42629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
427a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
428aca7a94dSNamhyung Kim 
429*5b12adc8SJiri Olsa 	pos = rb_entry(nd, struct disasm_line, al.rb_node);
430*5b12adc8SJiri Olsa 	bpos = disasm_line__browser(pos);
431*5b12adc8SJiri Olsa 
432a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
433e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
434a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
435a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
436aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
437aca7a94dSNamhyung Kim }
438aca7a94dSNamhyung Kim 
439aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
440db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
441aca7a94dSNamhyung Kim {
442aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
443aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
444aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
445c4c72436SJiri Olsa 	struct annotation_line *next;
446c4c72436SJiri Olsa 	struct disasm_line *pos;
447e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
448aca7a94dSNamhyung Kim 
449aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
450aca7a94dSNamhyung Kim 
451aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
452aca7a94dSNamhyung Kim 
453a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
454887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
455e64aa75bSNamhyung Kim 		const char *path = NULL;
456c7e7b610SNamhyung Kim 		double max_percent = 0.0;
457c7e7b610SNamhyung Kim 		int i;
458e64aa75bSNamhyung Kim 
459d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
460*5b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
461e64aa75bSNamhyung Kim 			continue;
462e64aa75bSNamhyung Kim 		}
463e64aa75bSNamhyung Kim 
464c4c72436SJiri Olsa 		next = annotation_line__next(&pos->al, &notes->src->source);
465c7e7b610SNamhyung Kim 
466c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
467896bccd3STaeung Song 			struct sym_hist_entry sample;
4680c4a5bceSMartin Liška 
4690c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
470c7e7b610SNamhyung Kim 						evsel->idx + i,
471d5490b96SJiri Olsa 						pos->al.offset,
472c4c72436SJiri Olsa 						next ? next->offset : len,
473896bccd3STaeung Song 						&path, &sample);
474bb79a232SArnaldo Carvalho de Melo 			bpos->samples[i].he = sample;
475e64aa75bSNamhyung Kim 
4760c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4770c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
478c7e7b610SNamhyung Kim 		}
479c7e7b610SNamhyung Kim 
48037236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
481*5b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
482aca7a94dSNamhyung Kim 			continue;
483aca7a94dSNamhyung Kim 		}
484*5b12adc8SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, pos,
485c7e7b610SNamhyung Kim 				       browser->nr_events);
486aca7a94dSNamhyung Kim 	}
487aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
488aca7a94dSNamhyung Kim 
489aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
490aca7a94dSNamhyung Kim }
491aca7a94dSNamhyung Kim 
492aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
493aca7a94dSNamhyung Kim {
49429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
495887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
496aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
497aca7a94dSNamhyung Kim 
498aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
499a17c4ca0SJiri Olsa 	dl = list_entry(browser->b.top, struct disasm_line, al.node);
500887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
501aca7a94dSNamhyung Kim 
502e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
503887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
504887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
505aca7a94dSNamhyung Kim 
506aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
507e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
508aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
509887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
510887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
511aca7a94dSNamhyung Kim 	} else {
512887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
513aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
514aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
515aca7a94dSNamhyung Kim 			return false;
516aca7a94dSNamhyung Kim 		}
517aca7a94dSNamhyung Kim 
518887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
519887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
520aca7a94dSNamhyung Kim 
521aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
522e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
523aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
524887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
525887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
526aca7a94dSNamhyung Kim 	}
527aca7a94dSNamhyung Kim 
528aca7a94dSNamhyung Kim 	return true;
529aca7a94dSNamhyung Kim }
530aca7a94dSNamhyung Kim 
531e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
532e9823b21SArnaldo Carvalho de Melo {
533e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
534e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
535e9823b21SArnaldo Carvalho de Melo }
536e9823b21SArnaldo Carvalho de Melo 
53734f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
53834f77abcSAdrian Hunter 
53934f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
54034f77abcSAdrian Hunter 		     size_t sz)
54134f77abcSAdrian Hunter {
54234f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
54334f77abcSAdrian Hunter }
54434f77abcSAdrian Hunter 
545db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
546db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5479783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
548aca7a94dSNamhyung Kim {
549aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
550657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
551aca7a94dSNamhyung Kim 	struct annotation *notes;
5521179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5531179e11bSAdrian Hunter 		.map = ms->map,
5541d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5551179e11bSAdrian Hunter 	};
55634f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
557aca7a94dSNamhyung Kim 
55875b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
559aca7a94dSNamhyung Kim 		return false;
560aca7a94dSNamhyung Kim 
561be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5621d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5631d5077bdSAdrian Hunter 							     target.addr)) !=
5641d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
565aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
566aca7a94dSNamhyung Kim 		return true;
567aca7a94dSNamhyung Kim 	}
568aca7a94dSNamhyung Kim 
5691179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
570aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
571aca7a94dSNamhyung Kim 
5721179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
573aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
574aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5751179e11bSAdrian Hunter 			    target.sym->name);
576aca7a94dSNamhyung Kim 		return true;
577aca7a94dSNamhyung Kim 	}
578aca7a94dSNamhyung Kim 
579aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5801179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5811179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
58234f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
583aca7a94dSNamhyung Kim 	return true;
584aca7a94dSNamhyung Kim }
585aca7a94dSNamhyung Kim 
58629ed6e76SArnaldo Carvalho de Melo static
58729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
588aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
589aca7a94dSNamhyung Kim {
590aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
591aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
592aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
59329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
594aca7a94dSNamhyung Kim 
595aca7a94dSNamhyung Kim 	*idx = 0;
596a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
597d5490b96SJiri Olsa 		if (pos->al.offset == offset)
598aca7a94dSNamhyung Kim 			return pos;
599a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
600aca7a94dSNamhyung Kim 			++*idx;
601aca7a94dSNamhyung Kim 	}
602aca7a94dSNamhyung Kim 
603aca7a94dSNamhyung Kim 	return NULL;
604aca7a94dSNamhyung Kim }
605aca7a94dSNamhyung Kim 
606aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
607aca7a94dSNamhyung Kim {
608657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
6095252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6104f9d0325SArnaldo Carvalho de Melo 	s64 idx;
611aca7a94dSNamhyung Kim 
61275b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
613aca7a94dSNamhyung Kim 		return false;
614aca7a94dSNamhyung Kim 
6155252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6165252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
61729ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6185252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
619aca7a94dSNamhyung Kim 		return true;
620aca7a94dSNamhyung Kim 	}
621aca7a94dSNamhyung Kim 
62229ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
623aca7a94dSNamhyung Kim 
624aca7a94dSNamhyung Kim 	return true;
625aca7a94dSNamhyung Kim }
626aca7a94dSNamhyung Kim 
62729ed6e76SArnaldo Carvalho de Melo static
62829ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
629aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
630aca7a94dSNamhyung Kim {
631aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
632aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
633aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
63429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
635aca7a94dSNamhyung Kim 
636aca7a94dSNamhyung Kim 	*idx = browser->b.index;
637a17c4ca0SJiri Olsa 	list_for_each_entry_continue(pos, &notes->src->source, al.node) {
638a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
639aca7a94dSNamhyung Kim 			continue;
640aca7a94dSNamhyung Kim 
641aca7a94dSNamhyung Kim 		++*idx;
642aca7a94dSNamhyung Kim 
643d5490b96SJiri Olsa 		if (pos->al.line && strstr(pos->al.line, s) != NULL)
644aca7a94dSNamhyung Kim 			return pos;
645aca7a94dSNamhyung Kim 	}
646aca7a94dSNamhyung Kim 
647aca7a94dSNamhyung Kim 	return NULL;
648aca7a94dSNamhyung Kim }
649aca7a94dSNamhyung Kim 
650aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
651aca7a94dSNamhyung Kim {
65229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
653aca7a94dSNamhyung Kim 	s64 idx;
654aca7a94dSNamhyung Kim 
65529ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
65629ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
657aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
658aca7a94dSNamhyung Kim 		return false;
659aca7a94dSNamhyung Kim 	}
660aca7a94dSNamhyung Kim 
66129ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
662aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
663aca7a94dSNamhyung Kim 	return true;
664aca7a94dSNamhyung Kim }
665aca7a94dSNamhyung Kim 
66629ed6e76SArnaldo Carvalho de Melo static
66729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
668aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
669aca7a94dSNamhyung Kim {
670aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
671aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
672aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
67329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
674aca7a94dSNamhyung Kim 
675aca7a94dSNamhyung Kim 	*idx = browser->b.index;
676a17c4ca0SJiri Olsa 	list_for_each_entry_continue_reverse(pos, &notes->src->source, al.node) {
677a17c4ca0SJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->al.node))
678aca7a94dSNamhyung Kim 			continue;
679aca7a94dSNamhyung Kim 
680aca7a94dSNamhyung Kim 		--*idx;
681aca7a94dSNamhyung Kim 
682d5490b96SJiri Olsa 		if (pos->al.line && strstr(pos->al.line, s) != NULL)
683aca7a94dSNamhyung Kim 			return pos;
684aca7a94dSNamhyung Kim 	}
685aca7a94dSNamhyung Kim 
686aca7a94dSNamhyung Kim 	return NULL;
687aca7a94dSNamhyung Kim }
688aca7a94dSNamhyung Kim 
689aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
690aca7a94dSNamhyung Kim {
69129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
692aca7a94dSNamhyung Kim 	s64 idx;
693aca7a94dSNamhyung Kim 
69429ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
69529ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
696aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
697aca7a94dSNamhyung Kim 		return false;
698aca7a94dSNamhyung Kim 	}
699aca7a94dSNamhyung Kim 
70029ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
701aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
702aca7a94dSNamhyung Kim 	return true;
703aca7a94dSNamhyung Kim }
704aca7a94dSNamhyung Kim 
705aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
706aca7a94dSNamhyung Kim 					    int delay_secs)
707aca7a94dSNamhyung Kim {
708aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
709aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
710aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
711aca7a94dSNamhyung Kim 	    !*browser->search_bf)
712aca7a94dSNamhyung Kim 		return false;
713aca7a94dSNamhyung Kim 
714aca7a94dSNamhyung Kim 	return true;
715aca7a94dSNamhyung Kim }
716aca7a94dSNamhyung Kim 
717aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
718aca7a94dSNamhyung Kim {
719aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
720aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
721aca7a94dSNamhyung Kim 
722aca7a94dSNamhyung Kim 	return false;
723aca7a94dSNamhyung Kim }
724aca7a94dSNamhyung Kim 
725aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
726aca7a94dSNamhyung Kim 					      int delay_secs)
727aca7a94dSNamhyung Kim {
728aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
729aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
730aca7a94dSNamhyung Kim 
731aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
732aca7a94dSNamhyung Kim }
733aca7a94dSNamhyung Kim 
734aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
735aca7a94dSNamhyung Kim 					   int delay_secs)
736aca7a94dSNamhyung Kim {
737aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
738aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
739aca7a94dSNamhyung Kim 
740aca7a94dSNamhyung Kim 	return false;
741aca7a94dSNamhyung Kim }
742aca7a94dSNamhyung Kim 
743aca7a94dSNamhyung Kim static
744aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
745aca7a94dSNamhyung Kim 					       int delay_secs)
746aca7a94dSNamhyung Kim {
747aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
748aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
749aca7a94dSNamhyung Kim 
750aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
751aca7a94dSNamhyung Kim }
752aca7a94dSNamhyung Kim 
753e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
754e9823b21SArnaldo Carvalho de Melo {
755e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
756e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
757e9823b21SArnaldo Carvalho de Melo 	else
758e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
759e9823b21SArnaldo Carvalho de Melo 
760e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
761e9823b21SArnaldo Carvalho de Melo 
762e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
763e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
764e9823b21SArnaldo Carvalho de Melo }
765e9823b21SArnaldo Carvalho de Melo 
766db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
767db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7689783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
769aca7a94dSNamhyung Kim {
770aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
77105e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
772aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
77354e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7749783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
775aca7a94dSNamhyung Kim 	int key;
77634f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
777aca7a94dSNamhyung Kim 
77834f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
77934f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
780aca7a94dSNamhyung Kim 		return -1;
781aca7a94dSNamhyung Kim 
782db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
783aca7a94dSNamhyung Kim 
78405e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
78505e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
78605e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
787aca7a94dSNamhyung Kim 	}
788aca7a94dSNamhyung Kim 
78905e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
790aca7a94dSNamhyung Kim 
791aca7a94dSNamhyung Kim 	while (1) {
79205e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
793aca7a94dSNamhyung Kim 
794aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
795db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
796aca7a94dSNamhyung Kim 			/*
797aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
798aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
799aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
800aca7a94dSNamhyung Kim 			 */
801aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
802aca7a94dSNamhyung Kim 				nd = NULL;
803aca7a94dSNamhyung Kim 		}
804aca7a94dSNamhyung Kim 
805aca7a94dSNamhyung Kim 		switch (key) {
806aca7a94dSNamhyung Kim 		case K_TIMER:
8079783adf7SNamhyung Kim 			if (hbt)
8089783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
809aca7a94dSNamhyung Kim 
810aca7a94dSNamhyung Kim 			if (delay_secs != 0)
811db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
812aca7a94dSNamhyung Kim 			continue;
813aca7a94dSNamhyung Kim 		case K_TAB:
814aca7a94dSNamhyung Kim 			if (nd != NULL) {
815aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
816aca7a94dSNamhyung Kim 				if (nd == NULL)
81705e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
818aca7a94dSNamhyung Kim 			} else
81905e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
820aca7a94dSNamhyung Kim 			break;
821aca7a94dSNamhyung Kim 		case K_UNTAB:
822d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
823aca7a94dSNamhyung Kim 				nd = rb_next(nd);
824aca7a94dSNamhyung Kim 				if (nd == NULL)
82505e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
826d4913cbdSMarkus Trippelsdorf 			} else
82705e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
828aca7a94dSNamhyung Kim 			break;
82954e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
830aca7a94dSNamhyung Kim 		case 'h':
83105e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
83254e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
83354e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
83454e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8357727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8367727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
837eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
838eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
83954e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
84054e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
84154e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
84254e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
84354e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8443a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
84554e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
846e592488cSAndi Kleen 		"k             Toggle line numbers\n"
84779ee47faSFeng Tang 		"r             Run available scripts\n"
848fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
84954e7a4e8SArnaldo Carvalho de Melo 			continue;
85079ee47faSFeng Tang 		case 'r':
85179ee47faSFeng Tang 			{
85279ee47faSFeng Tang 				script_browse(NULL);
85379ee47faSFeng Tang 				continue;
85479ee47faSFeng Tang 			}
855e592488cSAndi Kleen 		case 'k':
856e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
857e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
858e592488cSAndi Kleen 			break;
85954e7a4e8SArnaldo Carvalho de Melo 		case 'H':
86005e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
861aca7a94dSNamhyung Kim 			break;
862aca7a94dSNamhyung Kim 		case 's':
86305e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
864aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
865aca7a94dSNamhyung Kim 			continue;
866aca7a94dSNamhyung Kim 		case 'o':
867e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
86805e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
869aca7a94dSNamhyung Kim 			continue;
8709d1ef56dSArnaldo Carvalho de Melo 		case 'j':
871e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8729d1ef56dSArnaldo Carvalho de Melo 			continue;
8732402e4a9SArnaldo Carvalho de Melo 		case 'J':
874e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
87505e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
876e9823b21SArnaldo Carvalho de Melo 			continue;
877aca7a94dSNamhyung Kim 		case '/':
87805e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
879aca7a94dSNamhyung Kim show_help:
880aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
881aca7a94dSNamhyung Kim 			}
882aca7a94dSNamhyung Kim 			continue;
883aca7a94dSNamhyung Kim 		case 'n':
88405e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
88505e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
88605e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
887aca7a94dSNamhyung Kim 				goto show_help;
888aca7a94dSNamhyung Kim 			continue;
889aca7a94dSNamhyung Kim 		case '?':
89005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
891aca7a94dSNamhyung Kim 				goto show_help;
892aca7a94dSNamhyung Kim 			continue;
893e9823b21SArnaldo Carvalho de Melo 		case 'D': {
894e9823b21SArnaldo Carvalho de Melo 			static int seq;
895e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
896e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
89705e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
89805e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
89905e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
90005e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
90105e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
902e9823b21SArnaldo Carvalho de Melo 		}
903e9823b21SArnaldo Carvalho de Melo 			continue;
904aca7a94dSNamhyung Kim 		case K_ENTER:
905aca7a94dSNamhyung Kim 		case K_RIGHT:
90605e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
907aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
908d5490b96SJiri Olsa 			else if (browser->selection->al.offset == -1)
909aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
91075b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
911c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
91275b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
913c4cceae3SArnaldo Carvalho de Melo 				goto out;
9146ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
915db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
916c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9176ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
918c4cceae3SArnaldo Carvalho de Melo 			}
919aca7a94dSNamhyung Kim 			continue;
9200c4a5bceSMartin Liška 		case 't':
9213a555c77STaeung Song 			if (annotate_browser__opts.show_total_period) {
9223a555c77STaeung Song 				annotate_browser__opts.show_total_period = false;
9233a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = true;
9243a555c77STaeung Song 			} else if (annotate_browser__opts.show_nr_samples)
9253a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = false;
9263a555c77STaeung Song 			else
9273a555c77STaeung Song 				annotate_browser__opts.show_total_period = true;
9280c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9290c4a5bceSMartin Liška 			continue;
930aca7a94dSNamhyung Kim 		case K_LEFT:
931aca7a94dSNamhyung Kim 		case K_ESC:
932aca7a94dSNamhyung Kim 		case 'q':
933aca7a94dSNamhyung Kim 		case CTRL('c'):
934aca7a94dSNamhyung Kim 			goto out;
935aca7a94dSNamhyung Kim 		default:
936aca7a94dSNamhyung Kim 			continue;
937aca7a94dSNamhyung Kim 		}
938aca7a94dSNamhyung Kim 
939aca7a94dSNamhyung Kim 		if (nd != NULL)
94005e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
941aca7a94dSNamhyung Kim 	}
942aca7a94dSNamhyung Kim out:
94305e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
944aca7a94dSNamhyung Kim 	return key;
945aca7a94dSNamhyung Kim }
946aca7a94dSNamhyung Kim 
947d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
948d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
949d5dbc518SArnaldo Carvalho de Melo {
9509cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9510c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9520c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9539cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9549cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9550c4a5bceSMartin Liška 
956d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
957d5dbc518SArnaldo Carvalho de Melo }
958d5dbc518SArnaldo Carvalho de Melo 
959db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9609783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
961aca7a94dSNamhyung Kim {
962ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
963ed426915SNamhyung Kim 	SLang_reset_tty();
964ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
965ed426915SNamhyung Kim 
966d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
967aca7a94dSNamhyung Kim }
968aca7a94dSNamhyung Kim 
96930e863bbSAndi Kleen 
97030e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
97130e863bbSAndi Kleen {
97230e863bbSAndi Kleen 	unsigned n_insn = 0;
97330e863bbSAndi Kleen 	u64 offset;
97430e863bbSAndi Kleen 
97530e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
97630e863bbSAndi Kleen 		if (browser->offsets[offset])
97730e863bbSAndi Kleen 			n_insn++;
97830e863bbSAndi Kleen 	}
97930e863bbSAndi Kleen 	return n_insn;
98030e863bbSAndi Kleen }
98130e863bbSAndi Kleen 
98230e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
98330e863bbSAndi Kleen 			   struct cyc_hist *ch)
98430e863bbSAndi Kleen {
98530e863bbSAndi Kleen 	unsigned n_insn;
98630e863bbSAndi Kleen 	u64 offset;
98730e863bbSAndi Kleen 
98830e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
98930e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
99030e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
99130e863bbSAndi Kleen 
99230e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
99330e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
99430e863bbSAndi Kleen 			return;
99530e863bbSAndi Kleen 
99630e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
99730e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
99830e863bbSAndi Kleen 
99930e863bbSAndi Kleen 			if (dl)
100037236d5eSJiri Olsa 				dl->al.ipc = ipc;
100130e863bbSAndi Kleen 		}
100230e863bbSAndi Kleen 	}
100330e863bbSAndi Kleen }
100430e863bbSAndi Kleen 
100530e863bbSAndi Kleen /*
100630e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
100730e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
100830e863bbSAndi Kleen  * which are only here.
100930e863bbSAndi Kleen  */
101030e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
101130e863bbSAndi Kleen 			   struct symbol *sym)
101230e863bbSAndi Kleen {
101330e863bbSAndi Kleen 	u64 offset;
101430e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
101530e863bbSAndi Kleen 
101630e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
101730e863bbSAndi Kleen 		return;
101830e863bbSAndi Kleen 
101930e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
102030e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
102130e863bbSAndi Kleen 		struct cyc_hist *ch;
102230e863bbSAndi Kleen 
102330e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
102430e863bbSAndi Kleen 		if (ch && ch->cycles) {
102530e863bbSAndi Kleen 			struct disasm_line *dl;
102630e863bbSAndi Kleen 
102730e863bbSAndi Kleen 			if (ch->have_start)
102830e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
102930e863bbSAndi Kleen 			dl = browser->offsets[offset];
103030e863bbSAndi Kleen 			if (dl && ch->num_aggr)
103137236d5eSJiri Olsa 				dl->al.cycles = ch->cycles_aggr / ch->num_aggr;
103230e863bbSAndi Kleen 			browser->have_cycles = true;
103330e863bbSAndi Kleen 		}
103430e863bbSAndi Kleen 	}
103530e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
103630e863bbSAndi Kleen }
103730e863bbSAndi Kleen 
1038b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1039b793a401SArnaldo Carvalho de Melo 						size_t size)
1040b793a401SArnaldo Carvalho de Melo {
1041b793a401SArnaldo Carvalho de Melo 	u64 offset;
104232ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
104332ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
104432ae1efdSNamhyung Kim 
104532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
104632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
104732ae1efdSNamhyung Kim 		return;
1048b793a401SArnaldo Carvalho de Melo 
1049b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1050b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
1051b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
1052b793a401SArnaldo Carvalho de Melo 
1053865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1054b793a401SArnaldo Carvalho de Melo 			continue;
1055b793a401SArnaldo Carvalho de Melo 
105644d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10579481ede9SArnaldo Carvalho de Melo 		/*
10589481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10599481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10609481ede9SArnaldo Carvalho de Melo  		 */
10619481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10629481ede9SArnaldo Carvalho de Melo 			continue;
10639481ede9SArnaldo Carvalho de Melo 
1064b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
10652402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10662402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10672402e4a9SArnaldo Carvalho de Melo 
10682402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1069b793a401SArnaldo Carvalho de Melo 	}
1070b793a401SArnaldo Carvalho de Melo }
1071b793a401SArnaldo Carvalho de Melo 
10722402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10732402e4a9SArnaldo Carvalho de Melo {
10742402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10752402e4a9SArnaldo Carvalho de Melo 		return 5;
10762402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10772402e4a9SArnaldo Carvalho de Melo 		return 2;
10782402e4a9SArnaldo Carvalho de Melo 	return 1;
10792402e4a9SArnaldo Carvalho de Melo }
10802402e4a9SArnaldo Carvalho de Melo 
1081db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1082db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10839783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1084aca7a94dSNamhyung Kim {
108529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1086aca7a94dSNamhyung Kim 	struct annotation *notes;
1087c0a58fb2SSamuel Liao 	size_t size;
1088aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1089aca7a94dSNamhyung Kim 		.map = map,
1090aca7a94dSNamhyung Kim 		.sym = sym,
1091aca7a94dSNamhyung Kim 	};
1092aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1093aca7a94dSNamhyung Kim 		.b = {
1094a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1095aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1096aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
109729ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1098aca7a94dSNamhyung Kim 			.priv	 = &ms,
1099aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1100aca7a94dSNamhyung Kim 		},
1101aca7a94dSNamhyung Kim 	};
1102ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1103c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1104c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1105aca7a94dSNamhyung Kim 
1106aca7a94dSNamhyung Kim 	if (sym == NULL)
1107aca7a94dSNamhyung Kim 		return -1;
1108aca7a94dSNamhyung Kim 
1109c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1110c0a58fb2SSamuel Liao 
1111aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1112aca7a94dSNamhyung Kim 		return -1;
1113aca7a94dSNamhyung Kim 
1114b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1115b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1116b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1117b793a401SArnaldo Carvalho de Melo 		return -1;
1118b793a401SArnaldo Carvalho de Melo 	}
1119b793a401SArnaldo Carvalho de Melo 
1120c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1121c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
11220c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
11230c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1124c7e7b610SNamhyung Kim 	}
1125c7e7b610SNamhyung Kim 
1126d03a686eSJiri Olsa 	err = symbol__annotate(sym, map, evsel,
112769fb09f6SJin Yao 			       sizeof_bdl, &browser.arch,
112869fb09f6SJin Yao 			       perf_evsel__env_cpuid(evsel));
1129ee51d851SArnaldo Carvalho de Melo 	if (err) {
1130ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1131ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1132ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1133b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1134aca7a94dSNamhyung Kim 	}
1135aca7a94dSNamhyung Kim 
11367727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1137aca7a94dSNamhyung Kim 
1138aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1139aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1140aca7a94dSNamhyung Kim 
1141a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
1142887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1143d5490b96SJiri Olsa 		size_t line_len = strlen(pos->al.line);
1144aca7a94dSNamhyung Kim 
1145aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1146aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1147887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1148887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1149d5490b96SJiri Olsa 		if (pos->al.offset != -1) {
1150887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
115197148a97SArnaldo Carvalho de Melo 			/*
115297148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
115397148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
115497148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
115597148a97SArnaldo Carvalho de Melo 			 *
115697148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
115797148a97SArnaldo Carvalho de Melo  			 */
1158d5490b96SJiri Olsa 			if (pos->al.offset < (s64)size)
1159d5490b96SJiri Olsa 				browser.offsets[pos->al.offset] = pos;
1160b793a401SArnaldo Carvalho de Melo 		} else
1161887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1162aca7a94dSNamhyung Kim 	}
1163aca7a94dSNamhyung Kim 
1164b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
116530e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1166b793a401SArnaldo Carvalho de Melo 
11672402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
116883b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11692402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1170c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1171aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1172aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1173aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1174e9823b21SArnaldo Carvalho de Melo 
1175e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1176e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1177e9823b21SArnaldo Carvalho de Melo 
1178e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1179e9823b21SArnaldo Carvalho de Melo 
1180db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1181a17c4ca0SJiri Olsa 	list_for_each_entry_safe(pos, n, &notes->src->source, al.node) {
1182a17c4ca0SJiri Olsa 		list_del(&pos->al.node);
118329ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1184aca7a94dSNamhyung Kim 	}
1185b793a401SArnaldo Carvalho de Melo 
1186b793a401SArnaldo Carvalho de Melo out_free_offsets:
1187b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1188aca7a94dSNamhyung Kim 	return ret;
1189aca7a94dSNamhyung Kim }
1190c323cf04SArnaldo Carvalho de Melo 
1191c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1192c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1193c323cf04SArnaldo Carvalho de Melo 
1194c323cf04SArnaldo Carvalho de Melo /*
1195c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1196c323cf04SArnaldo Carvalho de Melo  */
11977c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1198c323cf04SArnaldo Carvalho de Melo 	const char *name;
1199c323cf04SArnaldo Carvalho de Melo 	bool *value;
1200c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1201c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1202c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1203e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1204c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
12059cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
12060c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
120739ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1208c323cf04SArnaldo Carvalho de Melo };
1209c323cf04SArnaldo Carvalho de Melo 
1210c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1211c323cf04SArnaldo Carvalho de Melo 
1212c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1213c323cf04SArnaldo Carvalho de Melo {
12147c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1215c323cf04SArnaldo Carvalho de Melo 
1216c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1217c323cf04SArnaldo Carvalho de Melo }
1218c323cf04SArnaldo Carvalho de Melo 
12191d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
12201d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1221c323cf04SArnaldo Carvalho de Melo {
12227c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1223c323cf04SArnaldo Carvalho de Melo 	const char *name;
1224c323cf04SArnaldo Carvalho de Melo 
12258e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1226c323cf04SArnaldo Carvalho de Melo 		return 0;
1227c323cf04SArnaldo Carvalho de Melo 
1228c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1229c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12307c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1231c323cf04SArnaldo Carvalho de Melo 
1232c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1233f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1234f06cff7cSArnaldo Carvalho de Melo 	else
1235c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1236c323cf04SArnaldo Carvalho de Melo 	return 0;
1237c323cf04SArnaldo Carvalho de Melo }
1238c323cf04SArnaldo Carvalho de Melo 
1239c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1240c323cf04SArnaldo Carvalho de Melo {
1241c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1242c323cf04SArnaldo Carvalho de Melo }
1243