xref: /linux/tools/perf/ui/browsers/annotate.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
1*b2441318SGreg 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) {
8729ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
8829ed6e76SArnaldo Carvalho de Melo 		return dl->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);
12629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, 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 
144ec27ae18SJin Yao 	if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) {
145ec27ae18SJin Yao 		if (ab->have_cycles) {
146ec27ae18SJin Yao 			if (dl->ipc == 0.0 && dl->cycles == 0)
147ec27ae18SJin Yao 				show_title = true;
148ec27ae18SJin Yao 		} else
149ec27ae18SJin Yao 			show_title = true;
150ec27ae18SJin Yao 	}
151ec27ae18SJin Yao 
152c7e7b610SNamhyung Kim 	if (dl->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) {
180f8f4aaeaSAndi Kleen 		if (dl->ipc)
181517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->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 
187f8f4aaeaSAndi Kleen 		if (dl->cycles)
188517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
189f8f4aaeaSAndi Kleen 					   CYCLES_WIDTH - 1, dl->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 
20229ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
203bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
20483b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
205e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
206e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
207e592488cSAndi Kleen 					ab->addr_width + 1, dl->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);
212bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width - cycles_width + 1);
21383b1f2aaSArnaldo Carvalho de Melo 	} else {
21429ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->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)) {
250e216874cSRavi Bangoria 				bool fwd = dl->ops.target.offset > dl->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 {
2897e63a13aSJin Yao 	struct disasm_line *pos = list_prev_entry(cursor, 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 
364c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
365c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
366c7e7b610SNamhyung Kim {
367c7e7b610SNamhyung Kim 	int i;
368c7e7b610SNamhyung Kim 
369c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3700c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
371c7e7b610SNamhyung Kim 			continue;
3720c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
373c7e7b610SNamhyung Kim 	}
374c7e7b610SNamhyung Kim 	return 0;
375c7e7b610SNamhyung Kim }
376c7e7b610SNamhyung Kim 
377c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
378c7e7b610SNamhyung Kim 				   int nr_events)
379aca7a94dSNamhyung Kim {
38029ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
381aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
382887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
383aca7a94dSNamhyung Kim 
384aca7a94dSNamhyung Kim 	while (*p != NULL) {
385aca7a94dSNamhyung Kim 		parent = *p;
386887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
387c7e7b610SNamhyung Kim 
388c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
389aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
390aca7a94dSNamhyung Kim 		else
391aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
392aca7a94dSNamhyung Kim 	}
393887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
394887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
395aca7a94dSNamhyung Kim }
396aca7a94dSNamhyung Kim 
39705e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
39829ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
399aca7a94dSNamhyung Kim {
400aca7a94dSNamhyung Kim 	unsigned back;
401aca7a94dSNamhyung Kim 
40205e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
40305e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
40405e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
405aca7a94dSNamhyung Kim 
40605e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
40729ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
408aca7a94dSNamhyung Kim 
40905e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
410aca7a94dSNamhyung Kim 			continue;
411aca7a94dSNamhyung Kim 
41205e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
413aca7a94dSNamhyung Kim 		--back;
414aca7a94dSNamhyung Kim 	}
415aca7a94dSNamhyung Kim 
41605e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
41705e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
418aca7a94dSNamhyung Kim }
419aca7a94dSNamhyung Kim 
420aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
421aca7a94dSNamhyung Kim 					 struct rb_node *nd)
422aca7a94dSNamhyung Kim {
423887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
42429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
425a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
426aca7a94dSNamhyung Kim 
427887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
428887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
429a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
430e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
431a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
432a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
433aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
434aca7a94dSNamhyung Kim }
435aca7a94dSNamhyung Kim 
436aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
437db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
438aca7a94dSNamhyung Kim {
439aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
440aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
441aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
442e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
443e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
444aca7a94dSNamhyung Kim 
445aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
446aca7a94dSNamhyung Kim 
447aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
448aca7a94dSNamhyung Kim 
449aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
450887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
451e64aa75bSNamhyung Kim 		const char *path = NULL;
452c7e7b610SNamhyung Kim 		double max_percent = 0.0;
453c7e7b610SNamhyung Kim 		int i;
454e64aa75bSNamhyung Kim 
455e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
456e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
457e64aa75bSNamhyung Kim 			continue;
458e64aa75bSNamhyung Kim 		}
459e64aa75bSNamhyung Kim 
460e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
461c7e7b610SNamhyung Kim 
462c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
463896bccd3STaeung Song 			struct sym_hist_entry sample;
4640c4a5bceSMartin Liška 
4650c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
466c7e7b610SNamhyung Kim 						evsel->idx + i,
467c7e7b610SNamhyung Kim 						pos->offset,
468c7e7b610SNamhyung Kim 						next ? next->offset : len,
469896bccd3STaeung Song 						&path, &sample);
470bb79a232SArnaldo Carvalho de Melo 			bpos->samples[i].he = sample;
471e64aa75bSNamhyung Kim 
4720c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4730c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
474c7e7b610SNamhyung Kim 		}
475c7e7b610SNamhyung Kim 
47630e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
477887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
478aca7a94dSNamhyung Kim 			continue;
479aca7a94dSNamhyung Kim 		}
480c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
481c7e7b610SNamhyung Kim 				       browser->nr_events);
482aca7a94dSNamhyung Kim 	}
483aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
484aca7a94dSNamhyung Kim 
485aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
486aca7a94dSNamhyung Kim }
487aca7a94dSNamhyung Kim 
488aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
489aca7a94dSNamhyung Kim {
49029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
491887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
492aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
493aca7a94dSNamhyung Kim 
494aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
49529ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
496887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
497aca7a94dSNamhyung Kim 
498e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
499887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
500887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
501aca7a94dSNamhyung Kim 
502aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
503e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
504aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
505887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
506887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
507aca7a94dSNamhyung Kim 	} else {
508887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
509aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
510aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
511aca7a94dSNamhyung Kim 			return false;
512aca7a94dSNamhyung Kim 		}
513aca7a94dSNamhyung Kim 
514887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
515887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
516aca7a94dSNamhyung Kim 
517aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
518e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
519aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
520887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
521887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
522aca7a94dSNamhyung Kim 	}
523aca7a94dSNamhyung Kim 
524aca7a94dSNamhyung Kim 	return true;
525aca7a94dSNamhyung Kim }
526aca7a94dSNamhyung Kim 
527e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
528e9823b21SArnaldo Carvalho de Melo {
529e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
530e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
531e9823b21SArnaldo Carvalho de Melo }
532e9823b21SArnaldo Carvalho de Melo 
53334f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
53434f77abcSAdrian Hunter 
53534f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
53634f77abcSAdrian Hunter 		     size_t sz)
53734f77abcSAdrian Hunter {
53834f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
53934f77abcSAdrian Hunter }
54034f77abcSAdrian Hunter 
541db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
542db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5439783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
544aca7a94dSNamhyung Kim {
545aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
546657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
547aca7a94dSNamhyung Kim 	struct annotation *notes;
5481179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5491179e11bSAdrian Hunter 		.map = ms->map,
5501d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5511179e11bSAdrian Hunter 	};
55234f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
553aca7a94dSNamhyung Kim 
55475b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
555aca7a94dSNamhyung Kim 		return false;
556aca7a94dSNamhyung Kim 
557be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5581d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5591d5077bdSAdrian Hunter 							     target.addr)) !=
5601d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
561aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
562aca7a94dSNamhyung Kim 		return true;
563aca7a94dSNamhyung Kim 	}
564aca7a94dSNamhyung Kim 
5651179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
566aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
567aca7a94dSNamhyung Kim 
5681179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
569aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
570aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5711179e11bSAdrian Hunter 			    target.sym->name);
572aca7a94dSNamhyung Kim 		return true;
573aca7a94dSNamhyung Kim 	}
574aca7a94dSNamhyung Kim 
575aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5761179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5771179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
57834f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
579aca7a94dSNamhyung Kim 	return true;
580aca7a94dSNamhyung Kim }
581aca7a94dSNamhyung Kim 
58229ed6e76SArnaldo Carvalho de Melo static
58329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
584aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
585aca7a94dSNamhyung Kim {
586aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
587aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
588aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
58929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
590aca7a94dSNamhyung Kim 
591aca7a94dSNamhyung Kim 	*idx = 0;
592aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
593aca7a94dSNamhyung Kim 		if (pos->offset == offset)
594aca7a94dSNamhyung Kim 			return pos;
59529ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
596aca7a94dSNamhyung Kim 			++*idx;
597aca7a94dSNamhyung Kim 	}
598aca7a94dSNamhyung Kim 
599aca7a94dSNamhyung Kim 	return NULL;
600aca7a94dSNamhyung Kim }
601aca7a94dSNamhyung Kim 
602aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
603aca7a94dSNamhyung Kim {
604657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
6055252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6064f9d0325SArnaldo Carvalho de Melo 	s64 idx;
607aca7a94dSNamhyung Kim 
60875b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
609aca7a94dSNamhyung Kim 		return false;
610aca7a94dSNamhyung Kim 
6115252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6125252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
61329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6145252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
615aca7a94dSNamhyung Kim 		return true;
616aca7a94dSNamhyung Kim 	}
617aca7a94dSNamhyung Kim 
61829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
619aca7a94dSNamhyung Kim 
620aca7a94dSNamhyung Kim 	return true;
621aca7a94dSNamhyung Kim }
622aca7a94dSNamhyung Kim 
62329ed6e76SArnaldo Carvalho de Melo static
62429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
625aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
626aca7a94dSNamhyung Kim {
627aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
628aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
629aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
63029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
631aca7a94dSNamhyung Kim 
632aca7a94dSNamhyung Kim 	*idx = browser->b.index;
633aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
63429ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
635aca7a94dSNamhyung Kim 			continue;
636aca7a94dSNamhyung Kim 
637aca7a94dSNamhyung Kim 		++*idx;
638aca7a94dSNamhyung Kim 
639aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
640aca7a94dSNamhyung Kim 			return pos;
641aca7a94dSNamhyung Kim 	}
642aca7a94dSNamhyung Kim 
643aca7a94dSNamhyung Kim 	return NULL;
644aca7a94dSNamhyung Kim }
645aca7a94dSNamhyung Kim 
646aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
647aca7a94dSNamhyung Kim {
64829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
649aca7a94dSNamhyung Kim 	s64 idx;
650aca7a94dSNamhyung Kim 
65129ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
65229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
653aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
654aca7a94dSNamhyung Kim 		return false;
655aca7a94dSNamhyung Kim 	}
656aca7a94dSNamhyung Kim 
65729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
658aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
659aca7a94dSNamhyung Kim 	return true;
660aca7a94dSNamhyung Kim }
661aca7a94dSNamhyung Kim 
66229ed6e76SArnaldo Carvalho de Melo static
66329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
664aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
665aca7a94dSNamhyung Kim {
666aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
667aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
668aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
66929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
670aca7a94dSNamhyung Kim 
671aca7a94dSNamhyung Kim 	*idx = browser->b.index;
672aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
67329ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
674aca7a94dSNamhyung Kim 			continue;
675aca7a94dSNamhyung Kim 
676aca7a94dSNamhyung Kim 		--*idx;
677aca7a94dSNamhyung Kim 
678aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
679aca7a94dSNamhyung Kim 			return pos;
680aca7a94dSNamhyung Kim 	}
681aca7a94dSNamhyung Kim 
682aca7a94dSNamhyung Kim 	return NULL;
683aca7a94dSNamhyung Kim }
684aca7a94dSNamhyung Kim 
685aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
686aca7a94dSNamhyung Kim {
68729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
688aca7a94dSNamhyung Kim 	s64 idx;
689aca7a94dSNamhyung Kim 
69029ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
69129ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
692aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
693aca7a94dSNamhyung Kim 		return false;
694aca7a94dSNamhyung Kim 	}
695aca7a94dSNamhyung Kim 
69629ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
697aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
698aca7a94dSNamhyung Kim 	return true;
699aca7a94dSNamhyung Kim }
700aca7a94dSNamhyung Kim 
701aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
702aca7a94dSNamhyung Kim 					    int delay_secs)
703aca7a94dSNamhyung Kim {
704aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
705aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
706aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
707aca7a94dSNamhyung Kim 	    !*browser->search_bf)
708aca7a94dSNamhyung Kim 		return false;
709aca7a94dSNamhyung Kim 
710aca7a94dSNamhyung Kim 	return true;
711aca7a94dSNamhyung Kim }
712aca7a94dSNamhyung Kim 
713aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
714aca7a94dSNamhyung Kim {
715aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
716aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
717aca7a94dSNamhyung Kim 
718aca7a94dSNamhyung Kim 	return false;
719aca7a94dSNamhyung Kim }
720aca7a94dSNamhyung Kim 
721aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
722aca7a94dSNamhyung Kim 					      int delay_secs)
723aca7a94dSNamhyung Kim {
724aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
725aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
726aca7a94dSNamhyung Kim 
727aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
728aca7a94dSNamhyung Kim }
729aca7a94dSNamhyung Kim 
730aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
731aca7a94dSNamhyung Kim 					   int delay_secs)
732aca7a94dSNamhyung Kim {
733aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
734aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
735aca7a94dSNamhyung Kim 
736aca7a94dSNamhyung Kim 	return false;
737aca7a94dSNamhyung Kim }
738aca7a94dSNamhyung Kim 
739aca7a94dSNamhyung Kim static
740aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
741aca7a94dSNamhyung Kim 					       int delay_secs)
742aca7a94dSNamhyung Kim {
743aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
744aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
745aca7a94dSNamhyung Kim 
746aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
747aca7a94dSNamhyung Kim }
748aca7a94dSNamhyung Kim 
749e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
750e9823b21SArnaldo Carvalho de Melo {
751e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
752e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
753e9823b21SArnaldo Carvalho de Melo 	else
754e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
755e9823b21SArnaldo Carvalho de Melo 
756e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
757e9823b21SArnaldo Carvalho de Melo 
758e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
759e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
760e9823b21SArnaldo Carvalho de Melo }
761e9823b21SArnaldo Carvalho de Melo 
762db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
763db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7649783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
765aca7a94dSNamhyung Kim {
766aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
76705e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
768aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
76954e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7709783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
771aca7a94dSNamhyung Kim 	int key;
77234f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
773aca7a94dSNamhyung Kim 
77434f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
77534f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
776aca7a94dSNamhyung Kim 		return -1;
777aca7a94dSNamhyung Kim 
778db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
779aca7a94dSNamhyung Kim 
78005e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
78105e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
78205e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
783aca7a94dSNamhyung Kim 	}
784aca7a94dSNamhyung Kim 
78505e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
786aca7a94dSNamhyung Kim 
787aca7a94dSNamhyung Kim 	while (1) {
78805e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
789aca7a94dSNamhyung Kim 
790aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
791db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
792aca7a94dSNamhyung Kim 			/*
793aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
794aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
795aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
796aca7a94dSNamhyung Kim 			 */
797aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
798aca7a94dSNamhyung Kim 				nd = NULL;
799aca7a94dSNamhyung Kim 		}
800aca7a94dSNamhyung Kim 
801aca7a94dSNamhyung Kim 		switch (key) {
802aca7a94dSNamhyung Kim 		case K_TIMER:
8039783adf7SNamhyung Kim 			if (hbt)
8049783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
805aca7a94dSNamhyung Kim 
806aca7a94dSNamhyung Kim 			if (delay_secs != 0)
807db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
808aca7a94dSNamhyung Kim 			continue;
809aca7a94dSNamhyung Kim 		case K_TAB:
810aca7a94dSNamhyung Kim 			if (nd != NULL) {
811aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
812aca7a94dSNamhyung Kim 				if (nd == NULL)
81305e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
814aca7a94dSNamhyung Kim 			} else
81505e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
816aca7a94dSNamhyung Kim 			break;
817aca7a94dSNamhyung Kim 		case K_UNTAB:
818d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
819aca7a94dSNamhyung Kim 				nd = rb_next(nd);
820aca7a94dSNamhyung Kim 				if (nd == NULL)
82105e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
822d4913cbdSMarkus Trippelsdorf 			} else
82305e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
824aca7a94dSNamhyung Kim 			break;
82554e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
826aca7a94dSNamhyung Kim 		case 'h':
82705e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
82854e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
82954e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
83054e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8317727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8327727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
833eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
834eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
83554e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
83654e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
83754e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
83854e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
83954e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8403a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
84154e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
842e592488cSAndi Kleen 		"k             Toggle line numbers\n"
84379ee47faSFeng Tang 		"r             Run available scripts\n"
844fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
84554e7a4e8SArnaldo Carvalho de Melo 			continue;
84679ee47faSFeng Tang 		case 'r':
84779ee47faSFeng Tang 			{
84879ee47faSFeng Tang 				script_browse(NULL);
84979ee47faSFeng Tang 				continue;
85079ee47faSFeng Tang 			}
851e592488cSAndi Kleen 		case 'k':
852e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
853e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
854e592488cSAndi Kleen 			break;
85554e7a4e8SArnaldo Carvalho de Melo 		case 'H':
85605e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
857aca7a94dSNamhyung Kim 			break;
858aca7a94dSNamhyung Kim 		case 's':
85905e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
860aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
861aca7a94dSNamhyung Kim 			continue;
862aca7a94dSNamhyung Kim 		case 'o':
863e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
86405e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
865aca7a94dSNamhyung Kim 			continue;
8669d1ef56dSArnaldo Carvalho de Melo 		case 'j':
867e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8689d1ef56dSArnaldo Carvalho de Melo 			continue;
8692402e4a9SArnaldo Carvalho de Melo 		case 'J':
870e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
87105e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
872e9823b21SArnaldo Carvalho de Melo 			continue;
873aca7a94dSNamhyung Kim 		case '/':
87405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
875aca7a94dSNamhyung Kim show_help:
876aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
877aca7a94dSNamhyung Kim 			}
878aca7a94dSNamhyung Kim 			continue;
879aca7a94dSNamhyung Kim 		case 'n':
88005e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
88105e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
88205e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
883aca7a94dSNamhyung Kim 				goto show_help;
884aca7a94dSNamhyung Kim 			continue;
885aca7a94dSNamhyung Kim 		case '?':
88605e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
887aca7a94dSNamhyung Kim 				goto show_help;
888aca7a94dSNamhyung Kim 			continue;
889e9823b21SArnaldo Carvalho de Melo 		case 'D': {
890e9823b21SArnaldo Carvalho de Melo 			static int seq;
891e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
892e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
89305e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
89405e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
89505e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
89605e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
89705e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
898e9823b21SArnaldo Carvalho de Melo 		}
899e9823b21SArnaldo Carvalho de Melo 			continue;
900aca7a94dSNamhyung Kim 		case K_ENTER:
901aca7a94dSNamhyung Kim 		case K_RIGHT:
90205e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
903aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
90405e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
905aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
90675b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
907c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
90875b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
909c4cceae3SArnaldo Carvalho de Melo 				goto out;
9106ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
911db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
912c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9136ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
914c4cceae3SArnaldo Carvalho de Melo 			}
915aca7a94dSNamhyung Kim 			continue;
9160c4a5bceSMartin Liška 		case 't':
9173a555c77STaeung Song 			if (annotate_browser__opts.show_total_period) {
9183a555c77STaeung Song 				annotate_browser__opts.show_total_period = false;
9193a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = true;
9203a555c77STaeung Song 			} else if (annotate_browser__opts.show_nr_samples)
9213a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = false;
9223a555c77STaeung Song 			else
9233a555c77STaeung Song 				annotate_browser__opts.show_total_period = true;
9240c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9250c4a5bceSMartin Liška 			continue;
926aca7a94dSNamhyung Kim 		case K_LEFT:
927aca7a94dSNamhyung Kim 		case K_ESC:
928aca7a94dSNamhyung Kim 		case 'q':
929aca7a94dSNamhyung Kim 		case CTRL('c'):
930aca7a94dSNamhyung Kim 			goto out;
931aca7a94dSNamhyung Kim 		default:
932aca7a94dSNamhyung Kim 			continue;
933aca7a94dSNamhyung Kim 		}
934aca7a94dSNamhyung Kim 
935aca7a94dSNamhyung Kim 		if (nd != NULL)
93605e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
937aca7a94dSNamhyung Kim 	}
938aca7a94dSNamhyung Kim out:
93905e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
940aca7a94dSNamhyung Kim 	return key;
941aca7a94dSNamhyung Kim }
942aca7a94dSNamhyung Kim 
943d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
944d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
945d5dbc518SArnaldo Carvalho de Melo {
9469cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9470c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9480c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9499cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9509cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9510c4a5bceSMartin Liška 
952d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
953d5dbc518SArnaldo Carvalho de Melo }
954d5dbc518SArnaldo Carvalho de Melo 
955db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9569783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
957aca7a94dSNamhyung Kim {
958ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
959ed426915SNamhyung Kim 	SLang_reset_tty();
960ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
961ed426915SNamhyung Kim 
962d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
963aca7a94dSNamhyung Kim }
964aca7a94dSNamhyung Kim 
96530e863bbSAndi Kleen 
96630e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
96730e863bbSAndi Kleen {
96830e863bbSAndi Kleen 	unsigned n_insn = 0;
96930e863bbSAndi Kleen 	u64 offset;
97030e863bbSAndi Kleen 
97130e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
97230e863bbSAndi Kleen 		if (browser->offsets[offset])
97330e863bbSAndi Kleen 			n_insn++;
97430e863bbSAndi Kleen 	}
97530e863bbSAndi Kleen 	return n_insn;
97630e863bbSAndi Kleen }
97730e863bbSAndi Kleen 
97830e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
97930e863bbSAndi Kleen 			   struct cyc_hist *ch)
98030e863bbSAndi Kleen {
98130e863bbSAndi Kleen 	unsigned n_insn;
98230e863bbSAndi Kleen 	u64 offset;
98330e863bbSAndi Kleen 
98430e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
98530e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
98630e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
98730e863bbSAndi Kleen 
98830e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
98930e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
99030e863bbSAndi Kleen 			return;
99130e863bbSAndi Kleen 
99230e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
99330e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
99430e863bbSAndi Kleen 
99530e863bbSAndi Kleen 			if (dl)
99630e863bbSAndi Kleen 				dl->ipc = ipc;
99730e863bbSAndi Kleen 		}
99830e863bbSAndi Kleen 	}
99930e863bbSAndi Kleen }
100030e863bbSAndi Kleen 
100130e863bbSAndi Kleen /*
100230e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
100330e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
100430e863bbSAndi Kleen  * which are only here.
100530e863bbSAndi Kleen  */
100630e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
100730e863bbSAndi Kleen 			   struct symbol *sym)
100830e863bbSAndi Kleen {
100930e863bbSAndi Kleen 	u64 offset;
101030e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
101130e863bbSAndi Kleen 
101230e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
101330e863bbSAndi Kleen 		return;
101430e863bbSAndi Kleen 
101530e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
101630e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
101730e863bbSAndi Kleen 		struct cyc_hist *ch;
101830e863bbSAndi Kleen 
101930e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
102030e863bbSAndi Kleen 		if (ch && ch->cycles) {
102130e863bbSAndi Kleen 			struct disasm_line *dl;
102230e863bbSAndi Kleen 
102330e863bbSAndi Kleen 			if (ch->have_start)
102430e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
102530e863bbSAndi Kleen 			dl = browser->offsets[offset];
102630e863bbSAndi Kleen 			if (dl && ch->num_aggr)
102730e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
102830e863bbSAndi Kleen 			browser->have_cycles = true;
102930e863bbSAndi Kleen 		}
103030e863bbSAndi Kleen 	}
103130e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
103230e863bbSAndi Kleen }
103330e863bbSAndi Kleen 
1034b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1035b793a401SArnaldo Carvalho de Melo 						size_t size)
1036b793a401SArnaldo Carvalho de Melo {
1037b793a401SArnaldo Carvalho de Melo 	u64 offset;
103832ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
103932ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
104032ae1efdSNamhyung Kim 
104132ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
104232ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
104332ae1efdSNamhyung Kim 		return;
1044b793a401SArnaldo Carvalho de Melo 
1045b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1046b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
1047b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
1048b793a401SArnaldo Carvalho de Melo 
1049865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1050b793a401SArnaldo Carvalho de Melo 			continue;
1051b793a401SArnaldo Carvalho de Melo 
105244d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
10539481ede9SArnaldo Carvalho de Melo 		/*
10549481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10559481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10569481ede9SArnaldo Carvalho de Melo  		 */
10579481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
10589481ede9SArnaldo Carvalho de Melo 			continue;
10599481ede9SArnaldo Carvalho de Melo 
1060b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
10612402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
10622402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
10632402e4a9SArnaldo Carvalho de Melo 
10642402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1065b793a401SArnaldo Carvalho de Melo 	}
1066b793a401SArnaldo Carvalho de Melo }
1067b793a401SArnaldo Carvalho de Melo 
10682402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10692402e4a9SArnaldo Carvalho de Melo {
10702402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10712402e4a9SArnaldo Carvalho de Melo 		return 5;
10722402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10732402e4a9SArnaldo Carvalho de Melo 		return 2;
10742402e4a9SArnaldo Carvalho de Melo 	return 1;
10752402e4a9SArnaldo Carvalho de Melo }
10762402e4a9SArnaldo Carvalho de Melo 
1077db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1078db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10799783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1080aca7a94dSNamhyung Kim {
108129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1082aca7a94dSNamhyung Kim 	struct annotation *notes;
1083c0a58fb2SSamuel Liao 	size_t size;
1084aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1085aca7a94dSNamhyung Kim 		.map = map,
1086aca7a94dSNamhyung Kim 		.sym = sym,
1087aca7a94dSNamhyung Kim 	};
1088aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1089aca7a94dSNamhyung Kim 		.b = {
1090a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1091aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1092aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
109329ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1094aca7a94dSNamhyung Kim 			.priv	 = &ms,
1095aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1096aca7a94dSNamhyung Kim 		},
1097aca7a94dSNamhyung Kim 	};
1098ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1099c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1100c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1101aca7a94dSNamhyung Kim 
1102aca7a94dSNamhyung Kim 	if (sym == NULL)
1103aca7a94dSNamhyung Kim 		return -1;
1104aca7a94dSNamhyung Kim 
1105c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1106c0a58fb2SSamuel Liao 
1107aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1108aca7a94dSNamhyung Kim 		return -1;
1109aca7a94dSNamhyung Kim 
1110b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1111b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1112b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1113b793a401SArnaldo Carvalho de Melo 		return -1;
1114b793a401SArnaldo Carvalho de Melo 	}
1115b793a401SArnaldo Carvalho de Melo 
1116c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1117c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
11180c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
11190c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1120c7e7b610SNamhyung Kim 	}
1121c7e7b610SNamhyung Kim 
1122dcaa3948SJin Yao 	err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
112369fb09f6SJin Yao 				  sizeof_bdl, &browser.arch,
112469fb09f6SJin Yao 				  perf_evsel__env_cpuid(evsel));
1125ee51d851SArnaldo Carvalho de Melo 	if (err) {
1126ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1127ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1128ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1129b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1130aca7a94dSNamhyung Kim 	}
1131aca7a94dSNamhyung Kim 
11327727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1133aca7a94dSNamhyung Kim 
1134aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1135aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1136aca7a94dSNamhyung Kim 
1137aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1138887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1139aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1140aca7a94dSNamhyung Kim 
1141aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1142aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1143887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1144887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1145b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1146887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
114797148a97SArnaldo Carvalho de Melo 			/*
114897148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
114997148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
115097148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
115197148a97SArnaldo Carvalho de Melo 			 *
115297148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
115397148a97SArnaldo Carvalho de Melo  			 */
115497148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1155b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1156b793a401SArnaldo Carvalho de Melo 		} else
1157887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1158aca7a94dSNamhyung Kim 	}
1159aca7a94dSNamhyung Kim 
1160b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
116130e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1162b793a401SArnaldo Carvalho de Melo 
11632402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
116483b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11652402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1166c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1167aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1168aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1169aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1170e9823b21SArnaldo Carvalho de Melo 
1171e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1172e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1173e9823b21SArnaldo Carvalho de Melo 
1174e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1175e9823b21SArnaldo Carvalho de Melo 
1176db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1177aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1178aca7a94dSNamhyung Kim 		list_del(&pos->node);
117929ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1180aca7a94dSNamhyung Kim 	}
1181b793a401SArnaldo Carvalho de Melo 
1182b793a401SArnaldo Carvalho de Melo out_free_offsets:
1183b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1184aca7a94dSNamhyung Kim 	return ret;
1185aca7a94dSNamhyung Kim }
1186c323cf04SArnaldo Carvalho de Melo 
1187c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1188c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1189c323cf04SArnaldo Carvalho de Melo 
1190c323cf04SArnaldo Carvalho de Melo /*
1191c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1192c323cf04SArnaldo Carvalho de Melo  */
11937c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1194c323cf04SArnaldo Carvalho de Melo 	const char *name;
1195c323cf04SArnaldo Carvalho de Melo 	bool *value;
1196c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1197c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1198c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1199e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1200c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
12019cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
12020c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
120339ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1204c323cf04SArnaldo Carvalho de Melo };
1205c323cf04SArnaldo Carvalho de Melo 
1206c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1207c323cf04SArnaldo Carvalho de Melo 
1208c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1209c323cf04SArnaldo Carvalho de Melo {
12107c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1211c323cf04SArnaldo Carvalho de Melo 
1212c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1213c323cf04SArnaldo Carvalho de Melo }
1214c323cf04SArnaldo Carvalho de Melo 
12151d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
12161d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1217c323cf04SArnaldo Carvalho de Melo {
12187c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1219c323cf04SArnaldo Carvalho de Melo 	const char *name;
1220c323cf04SArnaldo Carvalho de Melo 
12218e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1222c323cf04SArnaldo Carvalho de Melo 		return 0;
1223c323cf04SArnaldo Carvalho de Melo 
1224c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1225c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12267c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1227c323cf04SArnaldo Carvalho de Melo 
1228c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1229f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1230f06cff7cSArnaldo Carvalho de Melo 	else
1231c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1232c323cf04SArnaldo Carvalho de Melo 	return 0;
1233c323cf04SArnaldo Carvalho de Melo }
1234c323cf04SArnaldo Carvalho de Melo 
1235c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1236c323cf04SArnaldo Carvalho de Melo {
1237c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1238c323cf04SArnaldo Carvalho de Melo }
1239