xref: /linux/tools/perf/ui/browsers/annotate.c (revision ec03a77d7d28a2c2de246f67322c5d916852dd9d)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2aca7a94dSNamhyung Kim #include "../../util/util.h"
3aca7a94dSNamhyung Kim #include "../browser.h"
4aca7a94dSNamhyung Kim #include "../helpline.h"
5aca7a94dSNamhyung Kim #include "../ui.h"
6aca7a94dSNamhyung Kim #include "../util.h"
7aca7a94dSNamhyung Kim #include "../../util/annotate.h"
8aca7a94dSNamhyung Kim #include "../../util/hist.h"
9aca7a94dSNamhyung Kim #include "../../util/sort.h"
10aca7a94dSNamhyung Kim #include "../../util/symbol.h"
11db8fd07aSNamhyung Kim #include "../../util/evsel.h"
1241840d21STaeung Song #include "../../util/config.h"
1369fb09f6SJin Yao #include "../../util/evlist.h"
14fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
15aca7a94dSNamhyung Kim #include <pthread.h>
16877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
178e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h>
18b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h>
19aca7a94dSNamhyung Kim 
200c4a5bceSMartin Liška struct disasm_line_samples {
210c4a5bceSMartin Liška 	double		      percent;
22bb79a232SArnaldo Carvalho de Melo 	struct sym_hist_entry he;
230c4a5bceSMartin Liška };
240c4a5bceSMartin Liška 
25f8f4aaeaSAndi Kleen #define IPC_WIDTH 6
26f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6
27f8f4aaeaSAndi Kleen 
280d957970SJiri Olsa struct browser_line {
29b793a401SArnaldo Carvalho de Melo 	u32	idx;
30b793a401SArnaldo Carvalho de Melo 	int	idx_asm;
317d5b12f5SArnaldo Carvalho de Melo 	int	jump_sources;
32b793a401SArnaldo Carvalho de Melo };
33b793a401SArnaldo Carvalho de Melo 
34e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
35e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
36e9823b21SArnaldo Carvalho de Melo 	     use_offset,
37e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
38e592488cSAndi Kleen 	     show_linenr,
390c4a5bceSMartin Liška 	     show_nr_jumps,
409cef4b0bSTaeung Song 	     show_nr_samples,
410c4a5bceSMartin Liška 	     show_total_period;
42e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
43e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
44e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
45e9823b21SArnaldo Carvalho de Melo };
46e9823b21SArnaldo Carvalho de Melo 
47dcaa3948SJin Yao struct arch;
48dcaa3948SJin Yao 
49aca7a94dSNamhyung Kim struct annotate_browser {
50aca7a94dSNamhyung Kim 	struct ui_browser	    b;
51aca7a94dSNamhyung Kim 	struct rb_root		    entries;
52aca7a94dSNamhyung Kim 	struct rb_node		   *curr_hot;
537bcbcd58SJiri Olsa 	struct annotation_line	   *selection;
54e1b60b5bSJiri Olsa 	struct annotation_line	  **offsets;
55dcaa3948SJin Yao 	struct arch		   *arch;
56c7e7b610SNamhyung Kim 	int			    nr_events;
57aca7a94dSNamhyung Kim 	u64			    start;
58aca7a94dSNamhyung Kim 	int			    nr_asm_entries;
59aca7a94dSNamhyung Kim 	int			    nr_entries;
602402e4a9SArnaldo Carvalho de Melo 	int			    max_jump_sources;
612402e4a9SArnaldo Carvalho de Melo 	int			    nr_jumps;
62aca7a94dSNamhyung Kim 	bool			    searching_backwards;
6330e863bbSAndi Kleen 	bool			    have_cycles;
6483b1f2aaSArnaldo Carvalho de Melo 	u8			    addr_width;
652402e4a9SArnaldo Carvalho de Melo 	u8			    jumps_width;
662402e4a9SArnaldo Carvalho de Melo 	u8			    target_width;
6783b1f2aaSArnaldo Carvalho de Melo 	u8			    min_addr_width;
6883b1f2aaSArnaldo Carvalho de Melo 	u8			    max_addr_width;
69aca7a94dSNamhyung Kim 	char			    search_bf[128];
70aca7a94dSNamhyung Kim };
71aca7a94dSNamhyung Kim 
72a5ef2702SJiri Olsa static inline struct browser_line *browser_line(struct annotation_line *al)
73aca7a94dSNamhyung Kim {
74a5ef2702SJiri Olsa 	void *ptr = al;
75a5ef2702SJiri Olsa 
76a5ef2702SJiri Olsa 	ptr = container_of(al, struct disasm_line, al);
77a5ef2702SJiri Olsa 	return ptr - sizeof(struct browser_line);
78aca7a94dSNamhyung Kim }
79aca7a94dSNamhyung Kim 
801d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
811d037ca1SIrina Tirdea 				void *entry)
82aca7a94dSNamhyung Kim {
83e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
84d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
85d5490b96SJiri Olsa 
86d5490b96SJiri Olsa 		return al->offset == -1;
87aca7a94dSNamhyung Kim 	}
88aca7a94dSNamhyung Kim 
89aca7a94dSNamhyung Kim 	return false;
90aca7a94dSNamhyung Kim }
91aca7a94dSNamhyung Kim 
922402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
932402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
942402e4a9SArnaldo Carvalho de Melo {
952402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
962402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
972402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
982402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
992402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
1002402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
1012402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
1022402e4a9SArnaldo Carvalho de Melo }
1032402e4a9SArnaldo Carvalho de Melo 
1042402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
1052402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1062402e4a9SArnaldo Carvalho de Melo {
1072402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1082402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1092402e4a9SArnaldo Carvalho de Melo }
1102402e4a9SArnaldo Carvalho de Melo 
111f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
112f8f4aaeaSAndi Kleen {
1133861c4a4SArnaldo Carvalho de Melo 	return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events;
114bc1e5d60SArnaldo Carvalho de Melo }
115f8f4aaeaSAndi Kleen 
116bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab)
117bc1e5d60SArnaldo Carvalho de Melo {
118bc1e5d60SArnaldo Carvalho de Melo 	return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
119f8f4aaeaSAndi Kleen }
120f8f4aaeaSAndi Kleen 
12105e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
122aca7a94dSNamhyung Kim {
12305e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
124a17c4ca0SJiri Olsa 	struct disasm_line *dl = list_entry(entry, struct disasm_line, al.node);
125a5ef2702SJiri Olsa 	struct browser_line *bdl = browser_line(&dl->al);
12605e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
127e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
12805e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
12905e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
13005e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
131bc1e5d60SArnaldo Carvalho de Melo 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
132bc1e5d60SArnaldo Carvalho de Melo 	       cycles_width = annotate_browser__cycles_width(ab);
133c7e7b610SNamhyung Kim 	double percent_max = 0.0;
13483b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
135ec27ae18SJin Yao 	bool show_title = false;
136aca7a94dSNamhyung Kim 
137c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1383ab6db8dSJiri Olsa 		if (dl->al.samples[i].percent > percent_max)
1393ab6db8dSJiri Olsa 			percent_max = dl->al.samples[i].percent;
140c7e7b610SNamhyung Kim 	}
141c7e7b610SNamhyung Kim 
142d5490b96SJiri Olsa 	if ((row == 0) && (dl->al.offset == -1 || percent_max == 0.0)) {
143ec27ae18SJin Yao 		if (ab->have_cycles) {
14437236d5eSJiri Olsa 			if (dl->al.ipc == 0.0 && dl->al.cycles == 0)
145ec27ae18SJin Yao 				show_title = true;
146ec27ae18SJin Yao 		} else
147ec27ae18SJin Yao 			show_title = true;
148ec27ae18SJin Yao 	}
149ec27ae18SJin Yao 
150d5490b96SJiri Olsa 	if (dl->al.offset != -1 && percent_max != 0.0) {
151c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1520c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1533ab6db8dSJiri Olsa 						dl->al.samples[i].percent,
154c7e7b610SNamhyung Kim 						current_entry);
155517dfdb3SArnaldo Carvalho de Melo 			if (annotate_browser__opts.show_total_period) {
1563861c4a4SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%11" PRIu64 " ",
1573ab6db8dSJiri Olsa 						   dl->al.samples[i].he.period);
1589cef4b0bSTaeung Song 			} else if (annotate_browser__opts.show_nr_samples) {
1599cef4b0bSTaeung Song 				ui_browser__printf(browser, "%6" PRIu64 " ",
1603ab6db8dSJiri Olsa 						   dl->al.samples[i].he.nr_samples);
161517dfdb3SArnaldo Carvalho de Melo 			} else {
162517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(browser, "%6.2f ",
1633ab6db8dSJiri Olsa 						   dl->al.samples[i].percent);
164517dfdb3SArnaldo Carvalho de Melo 			}
165c7e7b610SNamhyung Kim 		}
166aca7a94dSNamhyung Kim 	} else {
16705e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
168ec27ae18SJin Yao 
169ec27ae18SJin Yao 		if (!show_title)
170bc1e5d60SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", pcnt_width);
1713861c4a4SArnaldo Carvalho de Melo 		else {
1723861c4a4SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s", pcnt_width,
1739cef4b0bSTaeung Song 					   annotate_browser__opts.show_total_period ? "Period" :
1749cef4b0bSTaeung Song 					   annotate_browser__opts.show_nr_samples ? "Samples" : "Percent");
1753861c4a4SArnaldo Carvalho de Melo 		}
176f8f4aaeaSAndi Kleen 	}
177f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
17837236d5eSJiri Olsa 		if (dl->al.ipc)
17937236d5eSJiri Olsa 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->al.ipc);
180ec27ae18SJin Yao 		else if (!show_title)
18126270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
182ec27ae18SJin Yao 		else
183ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
184ec27ae18SJin Yao 
18537236d5eSJiri Olsa 		if (dl->al.cycles)
186517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
18737236d5eSJiri Olsa 					   CYCLES_WIDTH - 1, dl->al.cycles);
188ec27ae18SJin Yao 		else if (!show_title)
18926270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
190ec27ae18SJin Yao 		else
191ec27ae18SJin Yao 			ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle");
192aca7a94dSNamhyung Kim 	}
193aca7a94dSNamhyung Kim 
194cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
195aca7a94dSNamhyung Kim 
196aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
19705e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
198aca7a94dSNamhyung Kim 		width += 1;
199aca7a94dSNamhyung Kim 
200d5490b96SJiri Olsa 	if (!*dl->al.line)
201bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
202d5490b96SJiri Olsa 	else if (dl->al.offset == -1) {
203d5490b96SJiri Olsa 		if (dl->al.line_nr && annotate_browser__opts.show_linenr)
204e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
205d5490b96SJiri Olsa 					ab->addr_width + 1, dl->al.line_nr);
206e592488cSAndi Kleen 		else
20783b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
20883b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
20926270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
210d5490b96SJiri Olsa 		ui_browser__write_nstring(browser, dl->al.line, width - printed - pcnt_width - cycles_width + 1);
21183b1f2aaSArnaldo Carvalho de Melo 	} else {
212d5490b96SJiri Olsa 		u64 addr = dl->al.offset;
21383b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
214aca7a94dSNamhyung Kim 
215e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
216aca7a94dSNamhyung Kim 			addr += ab->start;
217aca7a94dSNamhyung Kim 
218e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
219aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
22061e04b33SArnaldo Carvalho de Melo 		} else {
2217d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
222e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
2232402e4a9SArnaldo Carvalho de Melo 					int prev;
2242402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
2252402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
2262402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
2272402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
2282402e4a9SArnaldo Carvalho de Melo 											 current_entry);
22926270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
23005e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2312402e4a9SArnaldo Carvalho de Melo 				}
2322402e4a9SArnaldo Carvalho de Melo 
23361e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2342402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
23561e04b33SArnaldo Carvalho de Melo 			} else {
23661e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
23783b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
23861e04b33SArnaldo Carvalho de Melo 			}
23961e04b33SArnaldo Carvalho de Melo 		}
240b793a401SArnaldo Carvalho de Melo 
241aca7a94dSNamhyung Kim 		if (change_color)
24205e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
24326270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
244aca7a94dSNamhyung Kim 		if (change_color)
24505e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
24675b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
24775b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
248d5490b96SJiri Olsa 				bool fwd = dl->ops.target.offset > dl->al.offset;
24951a0d455SArnaldo Carvalho de Melo 
25005e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
25151a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
25251a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25375b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
25405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
25588298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
25675b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
25705e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2584ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2596ef94929SNaveen N. Rao 			} else {
2606ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2614ea08b52SArnaldo Carvalho de Melo 			}
2626ef94929SNaveen N. Rao 		} else {
2636ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2644ea08b52SArnaldo Carvalho de Melo 		}
2654ea08b52SArnaldo Carvalho de Melo 
266e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
267bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
268aca7a94dSNamhyung Kim 	}
269aca7a94dSNamhyung Kim 
270aca7a94dSNamhyung Kim 	if (current_entry)
2717bcbcd58SJiri Olsa 		ab->selection = &dl->al;
272aca7a94dSNamhyung Kim }
273aca7a94dSNamhyung Kim 
274865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
275865c66c4SFrederik Deweerdt {
27675b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
277865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
278e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
279e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
280865c66c4SFrederik Deweerdt 		return false;
281865c66c4SFrederik Deweerdt 
282865c66c4SFrederik Deweerdt 	return true;
283865c66c4SFrederik Deweerdt }
284865c66c4SFrederik Deweerdt 
2857e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2867e63a13aSJin Yao {
287a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2887e63a13aSJin Yao 	const char *name;
2897e63a13aSJin Yao 
2907e63a13aSJin Yao 	if (!pos)
2917e63a13aSJin Yao 		return false;
2927e63a13aSJin Yao 
2937e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2947e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2957e63a13aSJin Yao 	else
2967e63a13aSJin Yao 		name = pos->ins.name;
2977e63a13aSJin Yao 
2987e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2997e63a13aSJin Yao 		return false;
3007e63a13aSJin Yao 
3017e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
3027e63a13aSJin Yao }
3037e63a13aSJin Yao 
3049d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
305a3f895beSArnaldo Carvalho de Melo {
306a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3077bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
308a5ef2702SJiri Olsa 	struct annotation_line *target;
3090d957970SJiri Olsa 	struct browser_line *btarget, *bcursor;
31083b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
31132ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
31232ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
313f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
31432ae1efdSNamhyung Kim 
31532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31732ae1efdSNamhyung Kim 		return;
318a3f895beSArnaldo Carvalho de Melo 
319865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
320a3f895beSArnaldo Carvalho de Melo 		return;
321a3f895beSArnaldo Carvalho de Melo 
322a5ef2702SJiri Olsa 	target = ab->offsets[cursor->ops.target.offset];
3239d1ef56dSArnaldo Carvalho de Melo 
324a5ef2702SJiri Olsa 	bcursor = browser_line(&cursor->al);
325daf25d43SJiri Olsa 	btarget = browser_line(target);
3269d1ef56dSArnaldo Carvalho de Melo 
327e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3289d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
329a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
330a3f895beSArnaldo Carvalho de Melo 	} else {
3319d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
332a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
333a3f895beSArnaldo Carvalho de Melo 	}
334a3f895beSArnaldo Carvalho de Melo 
33578ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
336c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
337c7e7b610SNamhyung Kim 				 from, to);
3387e63a13aSJin Yao 
3397e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3407e63a13aSJin Yao 		ui_browser__mark_fused(browser,
3417e63a13aSJin Yao 				       pcnt_width + 3 + ab->addr_width,
3427e63a13aSJin Yao 				       from - 1,
3437e63a13aSJin Yao 				       to > from ? true : false);
3447e63a13aSJin Yao 	}
345a3f895beSArnaldo Carvalho de Melo }
346a3f895beSArnaldo Carvalho de Melo 
347a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
348a3f895beSArnaldo Carvalho de Melo {
349c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
350a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
351f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
352a3f895beSArnaldo Carvalho de Melo 
353e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3549d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
355a3f895beSArnaldo Carvalho de Melo 
35683b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
357c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
358a3f895beSArnaldo Carvalho de Melo 	return ret;
359a3f895beSArnaldo Carvalho de Melo }
360a3f895beSArnaldo Carvalho de Melo 
361b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
362c7e7b610SNamhyung Kim {
363c7e7b610SNamhyung Kim 	int i;
364c7e7b610SNamhyung Kim 
365b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
3660c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
367c7e7b610SNamhyung Kim 			continue;
3680c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
369c7e7b610SNamhyung Kim 	}
370c7e7b610SNamhyung Kim 	return 0;
371c7e7b610SNamhyung Kim }
372c7e7b610SNamhyung Kim 
373b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
374aca7a94dSNamhyung Kim {
37529ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
376aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
3773ab6db8dSJiri Olsa 	struct annotation_line *l;
378aca7a94dSNamhyung Kim 
379aca7a94dSNamhyung Kim 	while (*p != NULL) {
380aca7a94dSNamhyung Kim 		parent = *p;
3813ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
382c7e7b610SNamhyung Kim 
383b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
384aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
385aca7a94dSNamhyung Kim 		else
386aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
387aca7a94dSNamhyung Kim 	}
3883ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
3893ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
390aca7a94dSNamhyung Kim }
391aca7a94dSNamhyung Kim 
39205e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
393*ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
394aca7a94dSNamhyung Kim {
395aca7a94dSNamhyung Kim 	unsigned back;
396aca7a94dSNamhyung Kim 
39705e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
39805e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
39905e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
400aca7a94dSNamhyung Kim 
40105e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
402*ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
403aca7a94dSNamhyung Kim 
404*ec03a77dSJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->node))
405aca7a94dSNamhyung Kim 			continue;
406aca7a94dSNamhyung Kim 
40705e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
408aca7a94dSNamhyung Kim 		--back;
409aca7a94dSNamhyung Kim 	}
410aca7a94dSNamhyung Kim 
411*ec03a77dSJiri Olsa 	browser->b.top = pos;
41205e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
413aca7a94dSNamhyung Kim }
414aca7a94dSNamhyung Kim 
415aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
416aca7a94dSNamhyung Kim 					 struct rb_node *nd)
417aca7a94dSNamhyung Kim {
4180d957970SJiri Olsa 	struct browser_line *bpos;
419*ec03a77dSJiri Olsa 	struct annotation_line *pos;
420a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
421aca7a94dSNamhyung Kim 
422*ec03a77dSJiri Olsa 	pos = rb_entry(nd, struct annotation_line, rb_node);
423*ec03a77dSJiri Olsa 	bpos = browser_line(pos);
4245b12adc8SJiri Olsa 
425a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
426e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
427a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
428a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
429aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
430aca7a94dSNamhyung Kim }
431aca7a94dSNamhyung Kim 
432aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
433db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
434aca7a94dSNamhyung Kim {
435aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
436aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
437aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
438c4c72436SJiri Olsa 	struct disasm_line *pos;
439aca7a94dSNamhyung Kim 
440aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
441aca7a94dSNamhyung Kim 
442aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
443aca7a94dSNamhyung Kim 
444e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
445e425da6cSJiri Olsa 
446a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
447c7e7b610SNamhyung Kim 		double max_percent = 0.0;
448c7e7b610SNamhyung Kim 		int i;
449e64aa75bSNamhyung Kim 
450d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
4515b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
452e64aa75bSNamhyung Kim 			continue;
453e64aa75bSNamhyung Kim 		}
454e64aa75bSNamhyung Kim 
455b15636c6SJiri Olsa 		for (i = 0; i < pos->al.samples_nr; i++) {
456e425da6cSJiri Olsa 			struct annotation_data *sample = &pos->al.samples[i];
4570c4a5bceSMartin Liška 
4583ab6db8dSJiri Olsa 			if (max_percent < sample->percent)
4593ab6db8dSJiri Olsa 				max_percent = sample->percent;
460c7e7b610SNamhyung Kim 		}
461c7e7b610SNamhyung Kim 
46237236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
4635b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
464aca7a94dSNamhyung Kim 			continue;
465aca7a94dSNamhyung Kim 		}
466b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
467aca7a94dSNamhyung Kim 	}
468aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
469aca7a94dSNamhyung Kim 
470aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
471aca7a94dSNamhyung Kim }
472aca7a94dSNamhyung Kim 
473aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
474aca7a94dSNamhyung Kim {
475*ec03a77dSJiri Olsa 	struct annotation_line *al;
476a5ef2702SJiri Olsa 	struct browser_line *bl;
477aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
478aca7a94dSNamhyung Kim 
479aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
480*ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
481*ec03a77dSJiri Olsa 	bl = browser_line(al);
482aca7a94dSNamhyung Kim 
483e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
484a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
485a5ef2702SJiri Olsa 			offset = bl->idx;
486aca7a94dSNamhyung Kim 
487aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
488e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
489aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
490a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx - offset;
491a5ef2702SJiri Olsa 		browser->b.index = bl->idx;
492aca7a94dSNamhyung Kim 	} else {
493a5ef2702SJiri Olsa 		if (bl->idx_asm < 0) {
494aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
495aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
496aca7a94dSNamhyung Kim 			return false;
497aca7a94dSNamhyung Kim 		}
498aca7a94dSNamhyung Kim 
499a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
500a5ef2702SJiri Olsa 			offset = bl->idx_asm;
501aca7a94dSNamhyung Kim 
502aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
503e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
504aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
505a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx_asm - offset;
506a5ef2702SJiri Olsa 		browser->b.index = bl->idx_asm;
507aca7a94dSNamhyung Kim 	}
508aca7a94dSNamhyung Kim 
509aca7a94dSNamhyung Kim 	return true;
510aca7a94dSNamhyung Kim }
511aca7a94dSNamhyung Kim 
512e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
513e9823b21SArnaldo Carvalho de Melo {
514e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
515e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
516e9823b21SArnaldo Carvalho de Melo }
517e9823b21SArnaldo Carvalho de Melo 
51834f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
51934f77abcSAdrian Hunter 
52034f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
52134f77abcSAdrian Hunter 		     size_t sz)
52234f77abcSAdrian Hunter {
52334f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
52434f77abcSAdrian Hunter }
52534f77abcSAdrian Hunter 
526db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
527db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5289783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
529aca7a94dSNamhyung Kim {
530aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
5317bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
532aca7a94dSNamhyung Kim 	struct annotation *notes;
5331179e11bSAdrian Hunter 	struct addr_map_symbol target = {
5341179e11bSAdrian Hunter 		.map = ms->map,
5351d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
5361179e11bSAdrian Hunter 	};
53734f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
538aca7a94dSNamhyung Kim 
53975b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
540aca7a94dSNamhyung Kim 		return false;
541aca7a94dSNamhyung Kim 
542be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
5431d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5441d5077bdSAdrian Hunter 							     target.addr)) !=
5451d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
546aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
547aca7a94dSNamhyung Kim 		return true;
548aca7a94dSNamhyung Kim 	}
549aca7a94dSNamhyung Kim 
5501179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
551aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
552aca7a94dSNamhyung Kim 
5531179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
554aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
555aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5561179e11bSAdrian Hunter 			    target.sym->name);
557aca7a94dSNamhyung Kim 		return true;
558aca7a94dSNamhyung Kim 	}
559aca7a94dSNamhyung Kim 
560aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5611179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5621179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
56334f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
564aca7a94dSNamhyung Kim 	return true;
565aca7a94dSNamhyung Kim }
566aca7a94dSNamhyung Kim 
56729ed6e76SArnaldo Carvalho de Melo static
56829ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
569aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
570aca7a94dSNamhyung Kim {
571aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
572aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
573aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
57429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
575aca7a94dSNamhyung Kim 
576aca7a94dSNamhyung Kim 	*idx = 0;
577a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
578d5490b96SJiri Olsa 		if (pos->al.offset == offset)
579aca7a94dSNamhyung Kim 			return pos;
580a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
581aca7a94dSNamhyung Kim 			++*idx;
582aca7a94dSNamhyung Kim 	}
583aca7a94dSNamhyung Kim 
584aca7a94dSNamhyung Kim 	return NULL;
585aca7a94dSNamhyung Kim }
586aca7a94dSNamhyung Kim 
587aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
588aca7a94dSNamhyung Kim {
5897bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
5905252b1aeSArnaldo Carvalho de Melo 	u64 offset;
5914f9d0325SArnaldo Carvalho de Melo 	s64 idx;
592aca7a94dSNamhyung Kim 
59375b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
594aca7a94dSNamhyung Kim 		return false;
595aca7a94dSNamhyung Kim 
5965252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
5975252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
59829ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
5995252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
600aca7a94dSNamhyung Kim 		return true;
601aca7a94dSNamhyung Kim 	}
602aca7a94dSNamhyung Kim 
603*ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
604aca7a94dSNamhyung Kim 
605aca7a94dSNamhyung Kim 	return true;
606aca7a94dSNamhyung Kim }
607aca7a94dSNamhyung Kim 
60829ed6e76SArnaldo Carvalho de Melo static
6099213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
610aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
611aca7a94dSNamhyung Kim {
612aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
613aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
614aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
6159213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
616aca7a94dSNamhyung Kim 
617aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6189213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
6199213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
620aca7a94dSNamhyung Kim 			continue;
621aca7a94dSNamhyung Kim 
622aca7a94dSNamhyung Kim 		++*idx;
623aca7a94dSNamhyung Kim 
6249213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6259213afbdSJiri Olsa 			return al;
626aca7a94dSNamhyung Kim 	}
627aca7a94dSNamhyung Kim 
628aca7a94dSNamhyung Kim 	return NULL;
629aca7a94dSNamhyung Kim }
630aca7a94dSNamhyung Kim 
631aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
632aca7a94dSNamhyung Kim {
6339213afbdSJiri Olsa 	struct annotation_line *al;
634aca7a94dSNamhyung Kim 	s64 idx;
635aca7a94dSNamhyung Kim 
6369213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
6379213afbdSJiri Olsa 	if (al == NULL) {
638aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
639aca7a94dSNamhyung Kim 		return false;
640aca7a94dSNamhyung Kim 	}
641aca7a94dSNamhyung Kim 
642*ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
643aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
644aca7a94dSNamhyung Kim 	return true;
645aca7a94dSNamhyung Kim }
646aca7a94dSNamhyung Kim 
64729ed6e76SArnaldo Carvalho de Melo static
6489213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
649aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
650aca7a94dSNamhyung Kim {
651aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
652aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
653aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
6549213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
655aca7a94dSNamhyung Kim 
656aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6579213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
6589213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
659aca7a94dSNamhyung Kim 			continue;
660aca7a94dSNamhyung Kim 
661aca7a94dSNamhyung Kim 		--*idx;
662aca7a94dSNamhyung Kim 
6639213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6649213afbdSJiri Olsa 			return al;
665aca7a94dSNamhyung Kim 	}
666aca7a94dSNamhyung Kim 
667aca7a94dSNamhyung Kim 	return NULL;
668aca7a94dSNamhyung Kim }
669aca7a94dSNamhyung Kim 
670aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
671aca7a94dSNamhyung Kim {
6729213afbdSJiri Olsa 	struct annotation_line *al;
673aca7a94dSNamhyung Kim 	s64 idx;
674aca7a94dSNamhyung Kim 
6759213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
6769213afbdSJiri Olsa 	if (al == NULL) {
677aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
678aca7a94dSNamhyung Kim 		return false;
679aca7a94dSNamhyung Kim 	}
680aca7a94dSNamhyung Kim 
681*ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
682aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
683aca7a94dSNamhyung Kim 	return true;
684aca7a94dSNamhyung Kim }
685aca7a94dSNamhyung Kim 
686aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
687aca7a94dSNamhyung Kim 					    int delay_secs)
688aca7a94dSNamhyung Kim {
689aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
690aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
691aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
692aca7a94dSNamhyung Kim 	    !*browser->search_bf)
693aca7a94dSNamhyung Kim 		return false;
694aca7a94dSNamhyung Kim 
695aca7a94dSNamhyung Kim 	return true;
696aca7a94dSNamhyung Kim }
697aca7a94dSNamhyung Kim 
698aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
699aca7a94dSNamhyung Kim {
700aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
701aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
702aca7a94dSNamhyung Kim 
703aca7a94dSNamhyung Kim 	return false;
704aca7a94dSNamhyung Kim }
705aca7a94dSNamhyung Kim 
706aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
707aca7a94dSNamhyung Kim 					      int delay_secs)
708aca7a94dSNamhyung Kim {
709aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
710aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
711aca7a94dSNamhyung Kim 
712aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
713aca7a94dSNamhyung Kim }
714aca7a94dSNamhyung Kim 
715aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
716aca7a94dSNamhyung Kim 					   int delay_secs)
717aca7a94dSNamhyung Kim {
718aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
719aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
720aca7a94dSNamhyung Kim 
721aca7a94dSNamhyung Kim 	return false;
722aca7a94dSNamhyung Kim }
723aca7a94dSNamhyung Kim 
724aca7a94dSNamhyung Kim static
725aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
726aca7a94dSNamhyung Kim 					       int delay_secs)
727aca7a94dSNamhyung Kim {
728aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
729aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
730aca7a94dSNamhyung Kim 
731aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
732aca7a94dSNamhyung Kim }
733aca7a94dSNamhyung Kim 
734e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
735e9823b21SArnaldo Carvalho de Melo {
736e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
737e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
738e9823b21SArnaldo Carvalho de Melo 	else
739e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
740e9823b21SArnaldo Carvalho de Melo 
741e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
742e9823b21SArnaldo Carvalho de Melo 
743e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
744e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
745e9823b21SArnaldo Carvalho de Melo }
746e9823b21SArnaldo Carvalho de Melo 
747db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
748db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7499783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
750aca7a94dSNamhyung Kim {
751aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
75205e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
753aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
75454e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7559783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
756aca7a94dSNamhyung Kim 	int key;
75734f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
758aca7a94dSNamhyung Kim 
75934f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
76034f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
761aca7a94dSNamhyung Kim 		return -1;
762aca7a94dSNamhyung Kim 
763db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
764aca7a94dSNamhyung Kim 
76505e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
76605e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
76705e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
768aca7a94dSNamhyung Kim 	}
769aca7a94dSNamhyung Kim 
77005e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
771aca7a94dSNamhyung Kim 
772aca7a94dSNamhyung Kim 	while (1) {
77305e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
774aca7a94dSNamhyung Kim 
775aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
776db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
777aca7a94dSNamhyung Kim 			/*
778aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
779aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
780aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
781aca7a94dSNamhyung Kim 			 */
782aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
783aca7a94dSNamhyung Kim 				nd = NULL;
784aca7a94dSNamhyung Kim 		}
785aca7a94dSNamhyung Kim 
786aca7a94dSNamhyung Kim 		switch (key) {
787aca7a94dSNamhyung Kim 		case K_TIMER:
7889783adf7SNamhyung Kim 			if (hbt)
7899783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
790aca7a94dSNamhyung Kim 
791aca7a94dSNamhyung Kim 			if (delay_secs != 0)
792db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
793aca7a94dSNamhyung Kim 			continue;
794aca7a94dSNamhyung Kim 		case K_TAB:
795aca7a94dSNamhyung Kim 			if (nd != NULL) {
796aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
797aca7a94dSNamhyung Kim 				if (nd == NULL)
79805e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
799aca7a94dSNamhyung Kim 			} else
80005e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
801aca7a94dSNamhyung Kim 			break;
802aca7a94dSNamhyung Kim 		case K_UNTAB:
803d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
804aca7a94dSNamhyung Kim 				nd = rb_next(nd);
805aca7a94dSNamhyung Kim 				if (nd == NULL)
80605e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
807d4913cbdSMarkus Trippelsdorf 			} else
80805e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
809aca7a94dSNamhyung Kim 			break;
81054e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
811aca7a94dSNamhyung Kim 		case 'h':
81205e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
81354e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
81454e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
81554e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8167727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8177727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
818eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
819eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
82054e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
82154e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
82254e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
82354e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
82454e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8253a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
82654e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
827e592488cSAndi Kleen 		"k             Toggle line numbers\n"
82879ee47faSFeng Tang 		"r             Run available scripts\n"
829fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
83054e7a4e8SArnaldo Carvalho de Melo 			continue;
83179ee47faSFeng Tang 		case 'r':
83279ee47faSFeng Tang 			{
83379ee47faSFeng Tang 				script_browse(NULL);
83479ee47faSFeng Tang 				continue;
83579ee47faSFeng Tang 			}
836e592488cSAndi Kleen 		case 'k':
837e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
838e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
839e592488cSAndi Kleen 			break;
84054e7a4e8SArnaldo Carvalho de Melo 		case 'H':
84105e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
842aca7a94dSNamhyung Kim 			break;
843aca7a94dSNamhyung Kim 		case 's':
84405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
845aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
846aca7a94dSNamhyung Kim 			continue;
847aca7a94dSNamhyung Kim 		case 'o':
848e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
84905e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
850aca7a94dSNamhyung Kim 			continue;
8519d1ef56dSArnaldo Carvalho de Melo 		case 'j':
852e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8539d1ef56dSArnaldo Carvalho de Melo 			continue;
8542402e4a9SArnaldo Carvalho de Melo 		case 'J':
855e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
85605e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
857e9823b21SArnaldo Carvalho de Melo 			continue;
858aca7a94dSNamhyung Kim 		case '/':
85905e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
860aca7a94dSNamhyung Kim show_help:
861aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
862aca7a94dSNamhyung Kim 			}
863aca7a94dSNamhyung Kim 			continue;
864aca7a94dSNamhyung Kim 		case 'n':
86505e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
86605e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
86705e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
868aca7a94dSNamhyung Kim 				goto show_help;
869aca7a94dSNamhyung Kim 			continue;
870aca7a94dSNamhyung Kim 		case '?':
87105e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
872aca7a94dSNamhyung Kim 				goto show_help;
873aca7a94dSNamhyung Kim 			continue;
874e9823b21SArnaldo Carvalho de Melo 		case 'D': {
875e9823b21SArnaldo Carvalho de Melo 			static int seq;
876e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
877e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
87805e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
87905e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
88005e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
88105e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
88205e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
883e9823b21SArnaldo Carvalho de Melo 		}
884e9823b21SArnaldo Carvalho de Melo 			continue;
885aca7a94dSNamhyung Kim 		case K_ENTER:
886aca7a94dSNamhyung Kim 		case K_RIGHT:
8877bcbcd58SJiri Olsa 		{
8887bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
8897bcbcd58SJiri Olsa 
89005e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
891aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
8927bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
893aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
8947bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
895c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
8967bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
897c4cceae3SArnaldo Carvalho de Melo 				goto out;
8986ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
899db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
900c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9016ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
902c4cceae3SArnaldo Carvalho de Melo 			}
903aca7a94dSNamhyung Kim 			continue;
9047bcbcd58SJiri Olsa 		}
9050c4a5bceSMartin Liška 		case 't':
9063a555c77STaeung Song 			if (annotate_browser__opts.show_total_period) {
9073a555c77STaeung Song 				annotate_browser__opts.show_total_period = false;
9083a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = true;
9093a555c77STaeung Song 			} else if (annotate_browser__opts.show_nr_samples)
9103a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = false;
9113a555c77STaeung Song 			else
9123a555c77STaeung Song 				annotate_browser__opts.show_total_period = true;
9130c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9140c4a5bceSMartin Liška 			continue;
915aca7a94dSNamhyung Kim 		case K_LEFT:
916aca7a94dSNamhyung Kim 		case K_ESC:
917aca7a94dSNamhyung Kim 		case 'q':
918aca7a94dSNamhyung Kim 		case CTRL('c'):
919aca7a94dSNamhyung Kim 			goto out;
920aca7a94dSNamhyung Kim 		default:
921aca7a94dSNamhyung Kim 			continue;
922aca7a94dSNamhyung Kim 		}
923aca7a94dSNamhyung Kim 
924aca7a94dSNamhyung Kim 		if (nd != NULL)
92505e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
926aca7a94dSNamhyung Kim 	}
927aca7a94dSNamhyung Kim out:
92805e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
929aca7a94dSNamhyung Kim 	return key;
930aca7a94dSNamhyung Kim }
931aca7a94dSNamhyung Kim 
932d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
933d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
934d5dbc518SArnaldo Carvalho de Melo {
9359cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9360c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9370c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9389cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9399cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9400c4a5bceSMartin Liška 
941d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
942d5dbc518SArnaldo Carvalho de Melo }
943d5dbc518SArnaldo Carvalho de Melo 
944db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9459783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
946aca7a94dSNamhyung Kim {
947ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
948ed426915SNamhyung Kim 	SLang_reset_tty();
949ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
950ed426915SNamhyung Kim 
951d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
952aca7a94dSNamhyung Kim }
953aca7a94dSNamhyung Kim 
95430e863bbSAndi Kleen 
95530e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
95630e863bbSAndi Kleen {
95730e863bbSAndi Kleen 	unsigned n_insn = 0;
95830e863bbSAndi Kleen 	u64 offset;
95930e863bbSAndi Kleen 
96030e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
96130e863bbSAndi Kleen 		if (browser->offsets[offset])
96230e863bbSAndi Kleen 			n_insn++;
96330e863bbSAndi Kleen 	}
96430e863bbSAndi Kleen 	return n_insn;
96530e863bbSAndi Kleen }
96630e863bbSAndi Kleen 
96730e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
96830e863bbSAndi Kleen 			   struct cyc_hist *ch)
96930e863bbSAndi Kleen {
97030e863bbSAndi Kleen 	unsigned n_insn;
97130e863bbSAndi Kleen 	u64 offset;
97230e863bbSAndi Kleen 
97330e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
97430e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
97530e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
97630e863bbSAndi Kleen 
97730e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
97830e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
97930e863bbSAndi Kleen 			return;
98030e863bbSAndi Kleen 
98130e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
982e1b60b5bSJiri Olsa 			struct annotation_line *al = browser->offsets[offset];
98330e863bbSAndi Kleen 
984e1b60b5bSJiri Olsa 			if (al)
985e1b60b5bSJiri Olsa 				al->ipc = ipc;
98630e863bbSAndi Kleen 		}
98730e863bbSAndi Kleen 	}
98830e863bbSAndi Kleen }
98930e863bbSAndi Kleen 
99030e863bbSAndi Kleen /*
99130e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
99230e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
99330e863bbSAndi Kleen  * which are only here.
99430e863bbSAndi Kleen  */
99530e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
99630e863bbSAndi Kleen 			   struct symbol *sym)
99730e863bbSAndi Kleen {
99830e863bbSAndi Kleen 	u64 offset;
99930e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
100030e863bbSAndi Kleen 
100130e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
100230e863bbSAndi Kleen 		return;
100330e863bbSAndi Kleen 
100430e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
100530e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
100630e863bbSAndi Kleen 		struct cyc_hist *ch;
100730e863bbSAndi Kleen 
100830e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
100930e863bbSAndi Kleen 		if (ch && ch->cycles) {
1010e1b60b5bSJiri Olsa 			struct annotation_line *al;
101130e863bbSAndi Kleen 
101230e863bbSAndi Kleen 			if (ch->have_start)
101330e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
1014e1b60b5bSJiri Olsa 			al = browser->offsets[offset];
1015e1b60b5bSJiri Olsa 			if (al && ch->num_aggr)
1016e1b60b5bSJiri Olsa 				al->cycles = ch->cycles_aggr / ch->num_aggr;
101730e863bbSAndi Kleen 			browser->have_cycles = true;
101830e863bbSAndi Kleen 		}
101930e863bbSAndi Kleen 	}
102030e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
102130e863bbSAndi Kleen }
102230e863bbSAndi Kleen 
1023b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1024b793a401SArnaldo Carvalho de Melo 						size_t size)
1025b793a401SArnaldo Carvalho de Melo {
1026b793a401SArnaldo Carvalho de Melo 	u64 offset;
102732ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
102832ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
102932ae1efdSNamhyung Kim 
103032ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
103132ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
103232ae1efdSNamhyung Kim 		return;
1033b793a401SArnaldo Carvalho de Melo 
1034b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1035e1b60b5bSJiri Olsa 		struct annotation_line *al = browser->offsets[offset];
1036a5ef2702SJiri Olsa 		struct disasm_line *dl;
1037a5ef2702SJiri Olsa 		struct browser_line *blt;
1038b793a401SArnaldo Carvalho de Melo 
1039e1b60b5bSJiri Olsa 		dl = disasm_line(al);
1040e1b60b5bSJiri Olsa 
1041865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1042b793a401SArnaldo Carvalho de Melo 			continue;
1043b793a401SArnaldo Carvalho de Melo 
1044e1b60b5bSJiri Olsa 		al = browser->offsets[dl->ops.target.offset];
1045e1b60b5bSJiri Olsa 
10469481ede9SArnaldo Carvalho de Melo 		/*
10479481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10489481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10499481ede9SArnaldo Carvalho de Melo  		 */
1050a5ef2702SJiri Olsa 		if (al == NULL)
10519481ede9SArnaldo Carvalho de Melo 			continue;
10529481ede9SArnaldo Carvalho de Melo 
1053a5ef2702SJiri Olsa 		blt = browser_line(al);
1054a5ef2702SJiri Olsa 		if (++blt->jump_sources > browser->max_jump_sources)
1055a5ef2702SJiri Olsa 			browser->max_jump_sources = blt->jump_sources;
10562402e4a9SArnaldo Carvalho de Melo 
10572402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1058b793a401SArnaldo Carvalho de Melo 	}
1059b793a401SArnaldo Carvalho de Melo }
1060b793a401SArnaldo Carvalho de Melo 
10612402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10622402e4a9SArnaldo Carvalho de Melo {
10632402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10642402e4a9SArnaldo Carvalho de Melo 		return 5;
10652402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10662402e4a9SArnaldo Carvalho de Melo 		return 2;
10672402e4a9SArnaldo Carvalho de Melo 	return 1;
10682402e4a9SArnaldo Carvalho de Melo }
10692402e4a9SArnaldo Carvalho de Melo 
1070db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1071db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10729783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1073aca7a94dSNamhyung Kim {
1074e1b60b5bSJiri Olsa 	struct annotation_line *al;
1075aca7a94dSNamhyung Kim 	struct annotation *notes;
1076c0a58fb2SSamuel Liao 	size_t size;
1077aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1078aca7a94dSNamhyung Kim 		.map = map,
1079aca7a94dSNamhyung Kim 		.sym = sym,
1080aca7a94dSNamhyung Kim 	};
1081aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1082aca7a94dSNamhyung Kim 		.b = {
1083a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1084aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1085aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
108629ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1087aca7a94dSNamhyung Kim 			.priv	 = &ms,
1088aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1089aca7a94dSNamhyung Kim 		},
1090aca7a94dSNamhyung Kim 	};
1091ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1092c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1093aca7a94dSNamhyung Kim 
1094aca7a94dSNamhyung Kim 	if (sym == NULL)
1095aca7a94dSNamhyung Kim 		return -1;
1096aca7a94dSNamhyung Kim 
1097c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1098c0a58fb2SSamuel Liao 
1099aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1100aca7a94dSNamhyung Kim 		return -1;
1101aca7a94dSNamhyung Kim 
1102e1b60b5bSJiri Olsa 	browser.offsets = zalloc(size * sizeof(struct annotation_line *));
1103b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1104b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1105b793a401SArnaldo Carvalho de Melo 		return -1;
1106b793a401SArnaldo Carvalho de Melo 	}
1107b793a401SArnaldo Carvalho de Melo 
11083ab6db8dSJiri Olsa 	if (perf_evsel__is_group_event(evsel))
1109c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
1110c7e7b610SNamhyung Kim 
1111d03a686eSJiri Olsa 	err = symbol__annotate(sym, map, evsel,
11120d957970SJiri Olsa 			       sizeof(struct browser_line), &browser.arch,
111369fb09f6SJin Yao 			       perf_evsel__env_cpuid(evsel));
1114ee51d851SArnaldo Carvalho de Melo 	if (err) {
1115ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1116ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1117ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1118b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1119aca7a94dSNamhyung Kim 	}
1120aca7a94dSNamhyung Kim 
11217727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1122aca7a94dSNamhyung Kim 
1123aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1124aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1125aca7a94dSNamhyung Kim 
1126e1b60b5bSJiri Olsa 	list_for_each_entry(al, &notes->src->source, node) {
11270d957970SJiri Olsa 		struct browser_line *bpos;
1128e1b60b5bSJiri Olsa 		size_t line_len = strlen(al->line);
1129aca7a94dSNamhyung Kim 
1130aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1131aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1132a5ef2702SJiri Olsa 		bpos = browser_line(al);
1133887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1134e1b60b5bSJiri Olsa 		if (al->offset != -1) {
1135887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
113697148a97SArnaldo Carvalho de Melo 			/*
113797148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
113897148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
113997148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
114097148a97SArnaldo Carvalho de Melo 			 *
114197148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
114297148a97SArnaldo Carvalho de Melo  			 */
1143e1b60b5bSJiri Olsa 			if (al->offset < (s64)size)
1144e1b60b5bSJiri Olsa 				browser.offsets[al->offset] = al;
1145b793a401SArnaldo Carvalho de Melo 		} else
1146887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1147aca7a94dSNamhyung Kim 	}
1148aca7a94dSNamhyung Kim 
1149b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
115030e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1151b793a401SArnaldo Carvalho de Melo 
11522402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
115383b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11542402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1155c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1156aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1157aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1158aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1159e9823b21SArnaldo Carvalho de Melo 
1160e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1161e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1162e9823b21SArnaldo Carvalho de Melo 
1163e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1164e9823b21SArnaldo Carvalho de Melo 
1165db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1166f8eb37bdSJiri Olsa 
1167f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
1168b793a401SArnaldo Carvalho de Melo 
1169b793a401SArnaldo Carvalho de Melo out_free_offsets:
1170b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1171aca7a94dSNamhyung Kim 	return ret;
1172aca7a94dSNamhyung Kim }
1173c323cf04SArnaldo Carvalho de Melo 
1174c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1175c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1176c323cf04SArnaldo Carvalho de Melo 
1177c323cf04SArnaldo Carvalho de Melo /*
1178c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1179c323cf04SArnaldo Carvalho de Melo  */
11807c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1181c323cf04SArnaldo Carvalho de Melo 	const char *name;
1182c323cf04SArnaldo Carvalho de Melo 	bool *value;
1183c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1184c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1185c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1186e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1187c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11889cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
11890c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
119039ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1191c323cf04SArnaldo Carvalho de Melo };
1192c323cf04SArnaldo Carvalho de Melo 
1193c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1194c323cf04SArnaldo Carvalho de Melo 
1195c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1196c323cf04SArnaldo Carvalho de Melo {
11977c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1198c323cf04SArnaldo Carvalho de Melo 
1199c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1200c323cf04SArnaldo Carvalho de Melo }
1201c323cf04SArnaldo Carvalho de Melo 
12021d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
12031d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1204c323cf04SArnaldo Carvalho de Melo {
12057c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1206c323cf04SArnaldo Carvalho de Melo 	const char *name;
1207c323cf04SArnaldo Carvalho de Melo 
12088e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1209c323cf04SArnaldo Carvalho de Melo 		return 0;
1210c323cf04SArnaldo Carvalho de Melo 
1211c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1212c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12137c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1214c323cf04SArnaldo Carvalho de Melo 
1215c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1216f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1217f06cff7cSArnaldo Carvalho de Melo 	else
1218c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1219c323cf04SArnaldo Carvalho de Melo 	return 0;
1220c323cf04SArnaldo Carvalho de Melo }
1221c323cf04SArnaldo Carvalho de Melo 
1222c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1223c323cf04SArnaldo Carvalho de Melo {
1224c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1225c323cf04SArnaldo Carvalho de Melo }
1226