xref: /linux/tools/perf/ui/browsers/annotate.c (revision 16932d77050fb3d76bc265c21c53eeec14639d5e)
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 
250d957970SJiri Olsa struct browser_line {
26b793a401SArnaldo Carvalho de Melo 	u32	idx;
27b793a401SArnaldo Carvalho de Melo 	int	idx_asm;
287d5b12f5SArnaldo Carvalho de Melo 	int	jump_sources;
29b793a401SArnaldo Carvalho de Melo };
30b793a401SArnaldo Carvalho de Melo 
3198bc80b0SArnaldo Carvalho de Melo static struct annotation_options annotate_browser__opts = {
32e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
33e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
34e9823b21SArnaldo Carvalho de Melo };
35e9823b21SArnaldo Carvalho de Melo 
36dcaa3948SJin Yao struct arch;
37dcaa3948SJin Yao 
38aca7a94dSNamhyung Kim struct annotate_browser {
39aca7a94dSNamhyung Kim 	struct ui_browser	    b;
40aca7a94dSNamhyung Kim 	struct rb_root		    entries;
41aca7a94dSNamhyung Kim 	struct rb_node		   *curr_hot;
427bcbcd58SJiri Olsa 	struct annotation_line	   *selection;
43dcaa3948SJin Yao 	struct arch		   *arch;
44aca7a94dSNamhyung Kim 	u64			    start;
45aca7a94dSNamhyung Kim 	int			    nr_asm_entries;
46aca7a94dSNamhyung Kim 	int			    nr_entries;
472402e4a9SArnaldo Carvalho de Melo 	int			    max_jump_sources;
482402e4a9SArnaldo Carvalho de Melo 	int			    nr_jumps;
49aca7a94dSNamhyung Kim 	bool			    searching_backwards;
5083b1f2aaSArnaldo Carvalho de Melo 	u8			    addr_width;
512402e4a9SArnaldo Carvalho de Melo 	u8			    jumps_width;
522402e4a9SArnaldo Carvalho de Melo 	u8			    target_width;
5383b1f2aaSArnaldo Carvalho de Melo 	u8			    min_addr_width;
5483b1f2aaSArnaldo Carvalho de Melo 	u8			    max_addr_width;
55aca7a94dSNamhyung Kim 	char			    search_bf[128];
56aca7a94dSNamhyung Kim };
57aca7a94dSNamhyung Kim 
58a5ef2702SJiri Olsa static inline struct browser_line *browser_line(struct annotation_line *al)
59aca7a94dSNamhyung Kim {
60a5ef2702SJiri Olsa 	void *ptr = al;
61a5ef2702SJiri Olsa 
62a5ef2702SJiri Olsa 	ptr = container_of(al, struct disasm_line, al);
63a5ef2702SJiri Olsa 	return ptr - sizeof(struct browser_line);
64aca7a94dSNamhyung Kim }
65aca7a94dSNamhyung Kim 
66*16932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
67aca7a94dSNamhyung Kim {
68*16932d77SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
69*16932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
70*16932d77SArnaldo Carvalho de Melo 
71*16932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
72d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
73d5490b96SJiri Olsa 
74d5490b96SJiri Olsa 		return al->offset == -1;
75aca7a94dSNamhyung Kim 	}
76aca7a94dSNamhyung Kim 
77aca7a94dSNamhyung Kim 	return false;
78aca7a94dSNamhyung Kim }
79aca7a94dSNamhyung Kim 
802402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
812402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
822402e4a9SArnaldo Carvalho de Melo {
832402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
842402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
852402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
862402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
872402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
882402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
892402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
902402e4a9SArnaldo Carvalho de Melo }
912402e4a9SArnaldo Carvalho de Melo 
922402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
932402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
942402e4a9SArnaldo Carvalho de Melo {
952402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
962402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
972402e4a9SArnaldo Carvalho de Melo }
982402e4a9SArnaldo Carvalho de Melo 
99f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
100f8f4aaeaSAndi Kleen {
1010553e83dSArnaldo Carvalho de Melo 	struct map_symbol *ms = ab->b.priv;
1020553e83dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
103*16932d77SArnaldo Carvalho de Melo 	return (notes->options->show_total_period ? 12 : 7) * notes->nr_events;
104bc1e5d60SArnaldo Carvalho de Melo }
105f8f4aaeaSAndi Kleen 
106a5433b3eSJiri Olsa static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser,
107a5433b3eSJiri Olsa 			       char *bf, size_t size)
108aca7a94dSNamhyung Kim {
109*16932d77SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
110*16932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
111*16932d77SArnaldo Carvalho de Melo 
11275b49202SArnaldo Carvalho de Melo 	if (dl->ins.ops && dl->ins.ops->scnprintf) {
11375b49202SArnaldo Carvalho de Melo 		if (ins__is_jump(&dl->ins)) {
114d5490b96SJiri Olsa 			bool fwd = dl->ops.target.offset > dl->al.offset;
11551a0d455SArnaldo Carvalho de Melo 
11605e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
11751a0d455SArnaldo Carvalho de Melo 							    SLSMG_UARROW_CHAR);
11851a0d455SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
11975b49202SArnaldo Carvalho de Melo 		} else if (ins__is_call(&dl->ins)) {
12005e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
12188298f5aSArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
12275b49202SArnaldo Carvalho de Melo 		} else if (ins__is_ret(&dl->ins)) {
12305e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
1244ea08b52SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
1256ef94929SNaveen N. Rao 		} else {
1266ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
1274ea08b52SArnaldo Carvalho de Melo 		}
1286ef94929SNaveen N. Rao 	} else {
1296ef94929SNaveen N. Rao 		ui_browser__write_nstring(browser, " ", 2);
1304ea08b52SArnaldo Carvalho de Melo 	}
1314ea08b52SArnaldo Carvalho de Melo 
132*16932d77SArnaldo Carvalho de Melo 	disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset);
133a5433b3eSJiri Olsa }
134a5433b3eSJiri Olsa 
135a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
136a5433b3eSJiri Olsa {
137a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1380e83a7e9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
1390e83a7e9SArnaldo Carvalho de Melo 	struct symbol *sym = ms->sym;
1400e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
141a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
142a5433b3eSJiri Olsa 	struct browser_line *bl = browser_line(al);
143a5433b3eSJiri Olsa 	bool current_entry = ui_browser__is_current_entry(browser, row);
144*16932d77SArnaldo Carvalho de Melo 	bool change_color = (!notes->options->hide_src_code &&
145a5433b3eSJiri Olsa 			     (!current_entry || (browser->use_navkeypressed &&
146a5433b3eSJiri Olsa 					         !browser->navkeypressed)));
147a5433b3eSJiri Olsa 	int width = browser->width, printed;
148a5433b3eSJiri Olsa 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
1490e83a7e9SArnaldo Carvalho de Melo 	       cycles_width = annotation__cycles_width(notes);
150a5433b3eSJiri Olsa 	double percent_max = 0.0;
151a5433b3eSJiri Olsa 	char bf[256];
152a5433b3eSJiri Olsa 	bool show_title = false;
153a5433b3eSJiri Olsa 
1540553e83dSArnaldo Carvalho de Melo 	for (i = 0; i < notes->nr_events; i++) {
155a5433b3eSJiri Olsa 		if (al->samples[i].percent > percent_max)
156a5433b3eSJiri Olsa 			percent_max = al->samples[i].percent;
157a5433b3eSJiri Olsa 	}
158a5433b3eSJiri Olsa 
159a5433b3eSJiri Olsa 	if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) {
1600e83a7e9SArnaldo Carvalho de Melo 		if (notes->have_cycles) {
161a5433b3eSJiri Olsa 			if (al->ipc == 0.0 && al->cycles == 0)
162a5433b3eSJiri Olsa 				show_title = true;
163a5433b3eSJiri Olsa 		} else
164a5433b3eSJiri Olsa 			show_title = true;
165a5433b3eSJiri Olsa 	}
166a5433b3eSJiri Olsa 
167a5433b3eSJiri Olsa 	if (al->offset != -1 && percent_max != 0.0) {
1680553e83dSArnaldo Carvalho de Melo 		for (i = 0; i < notes->nr_events; i++) {
169a5433b3eSJiri Olsa 			ui_browser__set_percent_color(browser,
170a5433b3eSJiri Olsa 						al->samples[i].percent,
171a5433b3eSJiri Olsa 						current_entry);
172*16932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
173a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%11" PRIu64 " ",
174a5433b3eSJiri Olsa 						   al->samples[i].he.period);
175*16932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples) {
176a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6" PRIu64 " ",
177a5433b3eSJiri Olsa 						   al->samples[i].he.nr_samples);
178a5433b3eSJiri Olsa 			} else {
179a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6.2f ",
180a5433b3eSJiri Olsa 						   al->samples[i].percent);
181a5433b3eSJiri Olsa 			}
182a5433b3eSJiri Olsa 		}
183a5433b3eSJiri Olsa 	} else {
184a5433b3eSJiri Olsa 		ui_browser__set_percent_color(browser, 0, current_entry);
185a5433b3eSJiri Olsa 
186a5433b3eSJiri Olsa 		if (!show_title)
187a5433b3eSJiri Olsa 			ui_browser__write_nstring(browser, " ", pcnt_width);
188a5433b3eSJiri Olsa 		else {
189a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*s", pcnt_width,
190*16932d77SArnaldo Carvalho de Melo 					   notes->options->show_total_period ? "Period" :
191*16932d77SArnaldo Carvalho de Melo 					   notes->options->show_nr_samples ? "Samples" : "Percent");
192a5433b3eSJiri Olsa 		}
193a5433b3eSJiri Olsa 	}
1940e83a7e9SArnaldo Carvalho de Melo 	if (notes->have_cycles) {
195a5433b3eSJiri Olsa 		if (al->ipc)
196c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
197a5433b3eSJiri Olsa 		else if (!show_title)
198c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__IPC_WIDTH);
199a5433b3eSJiri Olsa 		else
200c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
201a5433b3eSJiri Olsa 
202a5433b3eSJiri Olsa 		if (al->cycles)
203a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*" PRIu64 " ",
204c426e584SArnaldo Carvalho de Melo 					   ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
205a5433b3eSJiri Olsa 		else if (!show_title)
206c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__CYCLES_WIDTH);
207a5433b3eSJiri Olsa 		else
208c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle");
209a5433b3eSJiri Olsa 	}
210a5433b3eSJiri Olsa 
211a5433b3eSJiri Olsa 	SLsmg_write_char(' ');
212a5433b3eSJiri Olsa 
213a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
214a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
215a5433b3eSJiri Olsa 		width += 1;
216a5433b3eSJiri Olsa 
217a5433b3eSJiri Olsa 	if (!*al->line)
218a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
219a5433b3eSJiri Olsa 	else if (al->offset == -1) {
220*16932d77SArnaldo Carvalho de Melo 		if (al->line_nr && notes->options->show_linenr)
221a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
222a5433b3eSJiri Olsa 					ab->addr_width + 1, al->line_nr);
223a5433b3eSJiri Olsa 		else
224a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
225a5433b3eSJiri Olsa 				    ab->addr_width, " ");
226a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
227a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1);
228a5433b3eSJiri Olsa 	} else {
229a5433b3eSJiri Olsa 		u64 addr = al->offset;
230a5433b3eSJiri Olsa 		int color = -1;
231a5433b3eSJiri Olsa 
232*16932d77SArnaldo Carvalho de Melo 		if (!notes->options->use_offset)
233a5433b3eSJiri Olsa 			addr += ab->start;
234a5433b3eSJiri Olsa 
235*16932d77SArnaldo Carvalho de Melo 		if (!notes->options->use_offset) {
236a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
237a5433b3eSJiri Olsa 		} else {
238a5433b3eSJiri Olsa 			if (bl->jump_sources) {
239*16932d77SArnaldo Carvalho de Melo 				if (notes->options->show_nr_jumps) {
240a5433b3eSJiri Olsa 					int prev;
241a5433b3eSJiri Olsa 					printed = scnprintf(bf, sizeof(bf), "%*d ",
242a5433b3eSJiri Olsa 							    ab->jumps_width,
243a5433b3eSJiri Olsa 							    bl->jump_sources);
244a5433b3eSJiri Olsa 					prev = annotate_browser__set_jumps_percent_color(ab, bl->jump_sources,
245a5433b3eSJiri Olsa 											 current_entry);
246a5433b3eSJiri Olsa 					ui_browser__write_nstring(browser, bf, printed);
247a5433b3eSJiri Olsa 					ui_browser__set_color(browser, prev);
248a5433b3eSJiri Olsa 				}
249a5433b3eSJiri Olsa 
250a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
251a5433b3eSJiri Olsa 						    ab->target_width, addr);
252a5433b3eSJiri Olsa 			} else {
253a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
254a5433b3eSJiri Olsa 						    ab->addr_width, " ");
255a5433b3eSJiri Olsa 			}
256a5433b3eSJiri Olsa 		}
257a5433b3eSJiri Olsa 
258a5433b3eSJiri Olsa 		if (change_color)
259a5433b3eSJiri Olsa 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
260a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
261a5433b3eSJiri Olsa 		if (change_color)
262a5433b3eSJiri Olsa 			ui_browser__set_color(browser, color);
263a5433b3eSJiri Olsa 
264a5433b3eSJiri Olsa 		disasm_line__write(disasm_line(al), browser, bf, sizeof(bf));
265a5433b3eSJiri Olsa 
266bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
267aca7a94dSNamhyung Kim 	}
268aca7a94dSNamhyung Kim 
269aca7a94dSNamhyung Kim 	if (current_entry)
270a5433b3eSJiri Olsa 		ab->selection = al;
271aca7a94dSNamhyung Kim }
272aca7a94dSNamhyung Kim 
273865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
274865c66c4SFrederik Deweerdt {
27575b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
276865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
277e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
278e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
279865c66c4SFrederik Deweerdt 		return false;
280865c66c4SFrederik Deweerdt 
281865c66c4SFrederik Deweerdt 	return true;
282865c66c4SFrederik Deweerdt }
283865c66c4SFrederik Deweerdt 
2847e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2857e63a13aSJin Yao {
286a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2877e63a13aSJin Yao 	const char *name;
2887e63a13aSJin Yao 
2897e63a13aSJin Yao 	if (!pos)
2907e63a13aSJin Yao 		return false;
2917e63a13aSJin Yao 
2927e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2937e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2947e63a13aSJin Yao 	else
2957e63a13aSJin Yao 		name = pos->ins.name;
2967e63a13aSJin Yao 
2977e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2987e63a13aSJin Yao 		return false;
2997e63a13aSJin Yao 
3007e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
3017e63a13aSJin Yao }
3027e63a13aSJin Yao 
3039d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
304a3f895beSArnaldo Carvalho de Melo {
305a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3067bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
307a5ef2702SJiri Olsa 	struct annotation_line *target;
3080d957970SJiri Olsa 	struct browser_line *btarget, *bcursor;
30983b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
31032ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
31132ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
3120e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
313f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
31400ea0eb2SArnaldo Carvalho de Melo 	int width;
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 
3239c04409dSArnaldo Carvalho de Melo 	/*
3249c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
3259c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
3269c04409dSArnaldo Carvalho de Melo 	 *
3279c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
3289c04409dSArnaldo Carvalho de Melo 	 *
3299c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
3309c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
3319c04409dSArnaldo Carvalho de Melo 	 *
3329c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
3339c04409dSArnaldo Carvalho de Melo 	 *
3349c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
3359c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
3369c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
3379c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
3389c04409dSArnaldo Carvalho de Melo 	 *
3399c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
3409c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
3419c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
3429c04409dSArnaldo Carvalho de Melo 	 */
3439d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
3449c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
3459d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
3469c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
3479c04409dSArnaldo Carvalho de Melo 		return;
3489c04409dSArnaldo Carvalho de Melo 	}
3499d1ef56dSArnaldo Carvalho de Melo 
350a5ef2702SJiri Olsa 	bcursor = browser_line(&cursor->al);
351daf25d43SJiri Olsa 	btarget = browser_line(target);
3529d1ef56dSArnaldo Carvalho de Melo 
353*16932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3549d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
355a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
356a3f895beSArnaldo Carvalho de Melo 	} else {
3579d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
358a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
359a3f895beSArnaldo Carvalho de Melo 	}
360a3f895beSArnaldo Carvalho de Melo 
3610e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
362b40982e8SJin Yao 
36378ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
364b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
365b40982e8SJin Yao 				 pcnt_width + 2 + ab->addr_width + width,
366c7e7b610SNamhyung Kim 				 from, to);
3677e63a13aSJin Yao 
3687e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3697e63a13aSJin Yao 		ui_browser__mark_fused(browser,
370b40982e8SJin Yao 				       pcnt_width + 3 + ab->addr_width + width,
3717e63a13aSJin Yao 				       from - 1,
3727e63a13aSJin Yao 				       to > from ? true : false);
3737e63a13aSJin Yao 	}
374a3f895beSArnaldo Carvalho de Melo }
375a3f895beSArnaldo Carvalho de Melo 
376a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
377a3f895beSArnaldo Carvalho de Melo {
378c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
379*16932d77SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
380*16932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
381a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
382f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
383a3f895beSArnaldo Carvalho de Melo 
384*16932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
3859d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
386a3f895beSArnaldo Carvalho de Melo 
38783b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
388c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
389a3f895beSArnaldo Carvalho de Melo 	return ret;
390a3f895beSArnaldo Carvalho de Melo }
391a3f895beSArnaldo Carvalho de Melo 
392b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
393c7e7b610SNamhyung Kim {
394c7e7b610SNamhyung Kim 	int i;
395c7e7b610SNamhyung Kim 
396b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
3970c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
398c7e7b610SNamhyung Kim 			continue;
3990c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
400c7e7b610SNamhyung Kim 	}
401c7e7b610SNamhyung Kim 	return 0;
402c7e7b610SNamhyung Kim }
403c7e7b610SNamhyung Kim 
404b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
405aca7a94dSNamhyung Kim {
40629ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
407aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
4083ab6db8dSJiri Olsa 	struct annotation_line *l;
409aca7a94dSNamhyung Kim 
410aca7a94dSNamhyung Kim 	while (*p != NULL) {
411aca7a94dSNamhyung Kim 		parent = *p;
4123ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
413c7e7b610SNamhyung Kim 
414b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
415aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
416aca7a94dSNamhyung Kim 		else
417aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
418aca7a94dSNamhyung Kim 	}
4193ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
4203ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
421aca7a94dSNamhyung Kim }
422aca7a94dSNamhyung Kim 
42305e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
424ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
425aca7a94dSNamhyung Kim {
426aca7a94dSNamhyung Kim 	unsigned back;
427aca7a94dSNamhyung Kim 
42805e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
42905e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
43005e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
431aca7a94dSNamhyung Kim 
43205e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
433ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
434aca7a94dSNamhyung Kim 
435ec03a77dSJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->node))
436aca7a94dSNamhyung Kim 			continue;
437aca7a94dSNamhyung Kim 
43805e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
439aca7a94dSNamhyung Kim 		--back;
440aca7a94dSNamhyung Kim 	}
441aca7a94dSNamhyung Kim 
442ec03a77dSJiri Olsa 	browser->b.top = pos;
44305e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
444aca7a94dSNamhyung Kim }
445aca7a94dSNamhyung Kim 
446aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
447aca7a94dSNamhyung Kim 					 struct rb_node *nd)
448aca7a94dSNamhyung Kim {
449*16932d77SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
450*16932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
4510d957970SJiri Olsa 	struct browser_line *bpos;
452ec03a77dSJiri Olsa 	struct annotation_line *pos;
453a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
454aca7a94dSNamhyung Kim 
455ec03a77dSJiri Olsa 	pos = rb_entry(nd, struct annotation_line, rb_node);
456ec03a77dSJiri Olsa 	bpos = browser_line(pos);
4575b12adc8SJiri Olsa 
458a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
459*16932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
460a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
461a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
462aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
463aca7a94dSNamhyung Kim }
464aca7a94dSNamhyung Kim 
465aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
466db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
467aca7a94dSNamhyung Kim {
468aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
469aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
470aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
471c4c72436SJiri Olsa 	struct disasm_line *pos;
472aca7a94dSNamhyung Kim 
473aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
474aca7a94dSNamhyung Kim 
475aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
476aca7a94dSNamhyung Kim 
477e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
478e425da6cSJiri Olsa 
479a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
480c7e7b610SNamhyung Kim 		double max_percent = 0.0;
481c7e7b610SNamhyung Kim 		int i;
482e64aa75bSNamhyung Kim 
483d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
4845b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
485e64aa75bSNamhyung Kim 			continue;
486e64aa75bSNamhyung Kim 		}
487e64aa75bSNamhyung Kim 
488b15636c6SJiri Olsa 		for (i = 0; i < pos->al.samples_nr; i++) {
489e425da6cSJiri Olsa 			struct annotation_data *sample = &pos->al.samples[i];
4900c4a5bceSMartin Liška 
4913ab6db8dSJiri Olsa 			if (max_percent < sample->percent)
4923ab6db8dSJiri Olsa 				max_percent = sample->percent;
493c7e7b610SNamhyung Kim 		}
494c7e7b610SNamhyung Kim 
49537236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
4965b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
497aca7a94dSNamhyung Kim 			continue;
498aca7a94dSNamhyung Kim 		}
499b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
500aca7a94dSNamhyung Kim 	}
501aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
502aca7a94dSNamhyung Kim 
503aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
504aca7a94dSNamhyung Kim }
505aca7a94dSNamhyung Kim 
506aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
507aca7a94dSNamhyung Kim {
508*16932d77SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
509*16932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
510ec03a77dSJiri Olsa 	struct annotation_line *al;
511a5ef2702SJiri Olsa 	struct browser_line *bl;
512aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
513aca7a94dSNamhyung Kim 
514aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
515ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
516ec03a77dSJiri Olsa 	bl = browser_line(al);
517aca7a94dSNamhyung Kim 
518*16932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
519a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
520a5ef2702SJiri Olsa 			offset = bl->idx;
521aca7a94dSNamhyung Kim 
522aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
523*16932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
524aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
525a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx - offset;
526a5ef2702SJiri Olsa 		browser->b.index = bl->idx;
527aca7a94dSNamhyung Kim 	} else {
528a5ef2702SJiri Olsa 		if (bl->idx_asm < 0) {
529aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
530aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
531aca7a94dSNamhyung Kim 			return false;
532aca7a94dSNamhyung Kim 		}
533aca7a94dSNamhyung Kim 
534a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
535a5ef2702SJiri Olsa 			offset = bl->idx_asm;
536aca7a94dSNamhyung Kim 
537aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
538*16932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
539aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
540a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx_asm - offset;
541a5ef2702SJiri Olsa 		browser->b.index = bl->idx_asm;
542aca7a94dSNamhyung Kim 	}
543aca7a94dSNamhyung Kim 
544aca7a94dSNamhyung Kim 	return true;
545aca7a94dSNamhyung Kim }
546aca7a94dSNamhyung Kim 
547e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
548e9823b21SArnaldo Carvalho de Melo {
549e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
550e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
551e9823b21SArnaldo Carvalho de Melo }
552e9823b21SArnaldo Carvalho de Melo 
55334f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
55434f77abcSAdrian Hunter 
55534f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
55634f77abcSAdrian Hunter 		     size_t sz)
55734f77abcSAdrian Hunter {
55834f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
55934f77abcSAdrian Hunter }
56034f77abcSAdrian Hunter 
561db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
562db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5639783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
564aca7a94dSNamhyung Kim {
565aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
5667bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
567aca7a94dSNamhyung Kim 	struct annotation *notes;
56834f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
569aca7a94dSNamhyung Kim 
57075b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
571aca7a94dSNamhyung Kim 		return false;
572aca7a94dSNamhyung Kim 
573696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
574aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
575aca7a94dSNamhyung Kim 		return true;
576aca7a94dSNamhyung Kim 	}
577aca7a94dSNamhyung Kim 
578696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
579aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
580aca7a94dSNamhyung Kim 
581696703afSArnaldo Carvalho de Melo 	if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) {
582aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
583aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
584696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
585aca7a94dSNamhyung Kim 		return true;
586aca7a94dSNamhyung Kim 	}
587aca7a94dSNamhyung Kim 
588aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
589696703afSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt);
5901179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
59134f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
592aca7a94dSNamhyung Kim 	return true;
593aca7a94dSNamhyung Kim }
594aca7a94dSNamhyung Kim 
59529ed6e76SArnaldo Carvalho de Melo static
59629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
597aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
598aca7a94dSNamhyung Kim {
599aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
600aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
601aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
60229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
603aca7a94dSNamhyung Kim 
604aca7a94dSNamhyung Kim 	*idx = 0;
605a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
606d5490b96SJiri Olsa 		if (pos->al.offset == offset)
607aca7a94dSNamhyung Kim 			return pos;
608a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
609aca7a94dSNamhyung Kim 			++*idx;
610aca7a94dSNamhyung Kim 	}
611aca7a94dSNamhyung Kim 
612aca7a94dSNamhyung Kim 	return NULL;
613aca7a94dSNamhyung Kim }
614aca7a94dSNamhyung Kim 
615aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
616aca7a94dSNamhyung Kim {
6177bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
6185252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6194f9d0325SArnaldo Carvalho de Melo 	s64 idx;
620aca7a94dSNamhyung Kim 
62175b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
622aca7a94dSNamhyung Kim 		return false;
623aca7a94dSNamhyung Kim 
6245252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6255252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
62629ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6275252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
628aca7a94dSNamhyung Kim 		return true;
629aca7a94dSNamhyung Kim 	}
630aca7a94dSNamhyung Kim 
631ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
632aca7a94dSNamhyung Kim 
633aca7a94dSNamhyung Kim 	return true;
634aca7a94dSNamhyung Kim }
635aca7a94dSNamhyung Kim 
63629ed6e76SArnaldo Carvalho de Melo static
6379213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
638aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
639aca7a94dSNamhyung Kim {
640aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
641aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
642aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
6439213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
644aca7a94dSNamhyung Kim 
645aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6469213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
6479213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
648aca7a94dSNamhyung Kim 			continue;
649aca7a94dSNamhyung Kim 
650aca7a94dSNamhyung Kim 		++*idx;
651aca7a94dSNamhyung Kim 
6529213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6539213afbdSJiri Olsa 			return al;
654aca7a94dSNamhyung Kim 	}
655aca7a94dSNamhyung Kim 
656aca7a94dSNamhyung Kim 	return NULL;
657aca7a94dSNamhyung Kim }
658aca7a94dSNamhyung Kim 
659aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
660aca7a94dSNamhyung Kim {
6619213afbdSJiri Olsa 	struct annotation_line *al;
662aca7a94dSNamhyung Kim 	s64 idx;
663aca7a94dSNamhyung Kim 
6649213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
6659213afbdSJiri Olsa 	if (al == NULL) {
666aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
667aca7a94dSNamhyung Kim 		return false;
668aca7a94dSNamhyung Kim 	}
669aca7a94dSNamhyung Kim 
670ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
671aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
672aca7a94dSNamhyung Kim 	return true;
673aca7a94dSNamhyung Kim }
674aca7a94dSNamhyung Kim 
67529ed6e76SArnaldo Carvalho de Melo static
6769213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
677aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
678aca7a94dSNamhyung Kim {
679aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
680aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
681aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
6829213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
683aca7a94dSNamhyung Kim 
684aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6859213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
6869213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
687aca7a94dSNamhyung Kim 			continue;
688aca7a94dSNamhyung Kim 
689aca7a94dSNamhyung Kim 		--*idx;
690aca7a94dSNamhyung Kim 
6919213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6929213afbdSJiri Olsa 			return al;
693aca7a94dSNamhyung Kim 	}
694aca7a94dSNamhyung Kim 
695aca7a94dSNamhyung Kim 	return NULL;
696aca7a94dSNamhyung Kim }
697aca7a94dSNamhyung Kim 
698aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
699aca7a94dSNamhyung Kim {
7009213afbdSJiri Olsa 	struct annotation_line *al;
701aca7a94dSNamhyung Kim 	s64 idx;
702aca7a94dSNamhyung Kim 
7039213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
7049213afbdSJiri Olsa 	if (al == NULL) {
705aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
706aca7a94dSNamhyung Kim 		return false;
707aca7a94dSNamhyung Kim 	}
708aca7a94dSNamhyung Kim 
709ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
710aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
711aca7a94dSNamhyung Kim 	return true;
712aca7a94dSNamhyung Kim }
713aca7a94dSNamhyung Kim 
714aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
715aca7a94dSNamhyung Kim 					    int delay_secs)
716aca7a94dSNamhyung Kim {
717aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
718aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
719aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
720aca7a94dSNamhyung Kim 	    !*browser->search_bf)
721aca7a94dSNamhyung Kim 		return false;
722aca7a94dSNamhyung Kim 
723aca7a94dSNamhyung Kim 	return true;
724aca7a94dSNamhyung Kim }
725aca7a94dSNamhyung Kim 
726aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
727aca7a94dSNamhyung Kim {
728aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
729aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
730aca7a94dSNamhyung Kim 
731aca7a94dSNamhyung Kim 	return false;
732aca7a94dSNamhyung Kim }
733aca7a94dSNamhyung Kim 
734aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
735aca7a94dSNamhyung Kim 					      int delay_secs)
736aca7a94dSNamhyung Kim {
737aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
738aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
739aca7a94dSNamhyung Kim 
740aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
741aca7a94dSNamhyung Kim }
742aca7a94dSNamhyung Kim 
743aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
744aca7a94dSNamhyung Kim 					   int delay_secs)
745aca7a94dSNamhyung Kim {
746aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
747aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
748aca7a94dSNamhyung Kim 
749aca7a94dSNamhyung Kim 	return false;
750aca7a94dSNamhyung Kim }
751aca7a94dSNamhyung Kim 
752aca7a94dSNamhyung Kim static
753aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
754aca7a94dSNamhyung Kim 					       int delay_secs)
755aca7a94dSNamhyung Kim {
756aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
757aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
758aca7a94dSNamhyung Kim 
759aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
760aca7a94dSNamhyung Kim }
761aca7a94dSNamhyung Kim 
762e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
763e9823b21SArnaldo Carvalho de Melo {
764*16932d77SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
765*16932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
766*16932d77SArnaldo Carvalho de Melo 
767*16932d77SArnaldo Carvalho de Melo 	if (notes->options->use_offset)
768e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
769e9823b21SArnaldo Carvalho de Melo 	else
770e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
771e9823b21SArnaldo Carvalho de Melo 
772e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
773e9823b21SArnaldo Carvalho de Melo 
774*16932d77SArnaldo Carvalho de Melo 	if (notes->options->show_nr_jumps)
775e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
776e9823b21SArnaldo Carvalho de Melo }
777e9823b21SArnaldo Carvalho de Melo 
778db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
779db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7809783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
781aca7a94dSNamhyung Kim {
782aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
78305e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
784aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
785*16932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
78654e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7879783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
788aca7a94dSNamhyung Kim 	int key;
78934f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
790aca7a94dSNamhyung Kim 
79134f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
79234f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
793aca7a94dSNamhyung Kim 		return -1;
794aca7a94dSNamhyung Kim 
795db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
796aca7a94dSNamhyung Kim 
79705e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
79805e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
79905e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
800aca7a94dSNamhyung Kim 	}
801aca7a94dSNamhyung Kim 
80205e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
803aca7a94dSNamhyung Kim 
804aca7a94dSNamhyung Kim 	while (1) {
80505e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
806aca7a94dSNamhyung Kim 
807aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
808db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
809aca7a94dSNamhyung Kim 			/*
810aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
811aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
812aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
813aca7a94dSNamhyung Kim 			 */
814aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
815aca7a94dSNamhyung Kim 				nd = NULL;
816aca7a94dSNamhyung Kim 		}
817aca7a94dSNamhyung Kim 
818aca7a94dSNamhyung Kim 		switch (key) {
819aca7a94dSNamhyung Kim 		case K_TIMER:
8209783adf7SNamhyung Kim 			if (hbt)
8219783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
822aca7a94dSNamhyung Kim 
823aca7a94dSNamhyung Kim 			if (delay_secs != 0)
824db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
825aca7a94dSNamhyung Kim 			continue;
826aca7a94dSNamhyung Kim 		case K_TAB:
827aca7a94dSNamhyung Kim 			if (nd != NULL) {
828aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
829aca7a94dSNamhyung Kim 				if (nd == NULL)
83005e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
831aca7a94dSNamhyung Kim 			} else
83205e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
833aca7a94dSNamhyung Kim 			break;
834aca7a94dSNamhyung Kim 		case K_UNTAB:
835d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
836aca7a94dSNamhyung Kim 				nd = rb_next(nd);
837aca7a94dSNamhyung Kim 				if (nd == NULL)
83805e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
839d4913cbdSMarkus Trippelsdorf 			} else
84005e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
841aca7a94dSNamhyung Kim 			break;
84254e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
843aca7a94dSNamhyung Kim 		case 'h':
84405e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
84554e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
84654e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
84754e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8487727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8497727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
850eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
851eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
85254e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
85354e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
85454e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
85554e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
85654e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8573a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
85854e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
859e592488cSAndi Kleen 		"k             Toggle line numbers\n"
86079ee47faSFeng Tang 		"r             Run available scripts\n"
861fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
86254e7a4e8SArnaldo Carvalho de Melo 			continue;
86379ee47faSFeng Tang 		case 'r':
86479ee47faSFeng Tang 			{
86579ee47faSFeng Tang 				script_browse(NULL);
86679ee47faSFeng Tang 				continue;
86779ee47faSFeng Tang 			}
868e592488cSAndi Kleen 		case 'k':
869*16932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
870e592488cSAndi Kleen 			break;
87154e7a4e8SArnaldo Carvalho de Melo 		case 'H':
87205e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
873aca7a94dSNamhyung Kim 			break;
874aca7a94dSNamhyung Kim 		case 's':
87505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
876aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
877aca7a94dSNamhyung Kim 			continue;
878aca7a94dSNamhyung Kim 		case 'o':
879*16932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
88005e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
881aca7a94dSNamhyung Kim 			continue;
8829d1ef56dSArnaldo Carvalho de Melo 		case 'j':
883*16932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
8849d1ef56dSArnaldo Carvalho de Melo 			continue;
8852402e4a9SArnaldo Carvalho de Melo 		case 'J':
886*16932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
88705e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
888e9823b21SArnaldo Carvalho de Melo 			continue;
889aca7a94dSNamhyung Kim 		case '/':
89005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
891aca7a94dSNamhyung Kim show_help:
892aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
893aca7a94dSNamhyung Kim 			}
894aca7a94dSNamhyung Kim 			continue;
895aca7a94dSNamhyung Kim 		case 'n':
89605e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
89705e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
89805e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
899aca7a94dSNamhyung Kim 				goto show_help;
900aca7a94dSNamhyung Kim 			continue;
901aca7a94dSNamhyung Kim 		case '?':
90205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
903aca7a94dSNamhyung Kim 				goto show_help;
904aca7a94dSNamhyung Kim 			continue;
905e9823b21SArnaldo Carvalho de Melo 		case 'D': {
906e9823b21SArnaldo Carvalho de Melo 			static int seq;
907e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
908e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
90905e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
91005e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
91105e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
91205e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
91305e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
914e9823b21SArnaldo Carvalho de Melo 		}
915e9823b21SArnaldo Carvalho de Melo 			continue;
916aca7a94dSNamhyung Kim 		case K_ENTER:
917aca7a94dSNamhyung Kim 		case K_RIGHT:
9187bcbcd58SJiri Olsa 		{
9197bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
9207bcbcd58SJiri Olsa 
92105e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
922aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
9237bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
924aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
9257bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
926c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
9277bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
928c4cceae3SArnaldo Carvalho de Melo 				goto out;
9296ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
930db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
931c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9326ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
933c4cceae3SArnaldo Carvalho de Melo 			}
934aca7a94dSNamhyung Kim 			continue;
9357bcbcd58SJiri Olsa 		}
9360c4a5bceSMartin Liška 		case 't':
937*16932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
938*16932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
939*16932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
940*16932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
941*16932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
9423a555c77STaeung Song 			else
943*16932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
9440c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9450c4a5bceSMartin Liška 			continue;
946aca7a94dSNamhyung Kim 		case K_LEFT:
947aca7a94dSNamhyung Kim 		case K_ESC:
948aca7a94dSNamhyung Kim 		case 'q':
949aca7a94dSNamhyung Kim 		case CTRL('c'):
950aca7a94dSNamhyung Kim 			goto out;
951aca7a94dSNamhyung Kim 		default:
952aca7a94dSNamhyung Kim 			continue;
953aca7a94dSNamhyung Kim 		}
954aca7a94dSNamhyung Kim 
955aca7a94dSNamhyung Kim 		if (nd != NULL)
95605e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
957aca7a94dSNamhyung Kim 	}
958aca7a94dSNamhyung Kim out:
95905e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
960aca7a94dSNamhyung Kim 	return key;
961aca7a94dSNamhyung Kim }
962aca7a94dSNamhyung Kim 
963d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
964d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
965d5dbc518SArnaldo Carvalho de Melo {
9669cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9670c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9680c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9699cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9709cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9710c4a5bceSMartin Liška 
972d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
973d5dbc518SArnaldo Carvalho de Melo }
974d5dbc518SArnaldo Carvalho de Melo 
975db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9769783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
977aca7a94dSNamhyung Kim {
978ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
979ed426915SNamhyung Kim 	SLang_reset_tty();
980ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
981ed426915SNamhyung Kim 
982d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
983aca7a94dSNamhyung Kim }
984aca7a94dSNamhyung Kim 
985b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
986b793a401SArnaldo Carvalho de Melo 						size_t size)
987b793a401SArnaldo Carvalho de Melo {
988b793a401SArnaldo Carvalho de Melo 	u64 offset;
98932ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
99032ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
9919d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
99232ae1efdSNamhyung Kim 
99332ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
99432ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
99532ae1efdSNamhyung Kim 		return;
996b793a401SArnaldo Carvalho de Melo 
997b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
9989d6bb41dSArnaldo Carvalho de Melo 		struct annotation_line *al = notes->offsets[offset];
999a5ef2702SJiri Olsa 		struct disasm_line *dl;
1000a5ef2702SJiri Olsa 		struct browser_line *blt;
1001b793a401SArnaldo Carvalho de Melo 
1002e1b60b5bSJiri Olsa 		dl = disasm_line(al);
1003e1b60b5bSJiri Olsa 
1004865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1005b793a401SArnaldo Carvalho de Melo 			continue;
1006b793a401SArnaldo Carvalho de Melo 
10079d6bb41dSArnaldo Carvalho de Melo 		al = notes->offsets[dl->ops.target.offset];
1008e1b60b5bSJiri Olsa 
10099481ede9SArnaldo Carvalho de Melo 		/*
10109481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10119481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10129481ede9SArnaldo Carvalho de Melo  		 */
1013a5ef2702SJiri Olsa 		if (al == NULL)
10149481ede9SArnaldo Carvalho de Melo 			continue;
10159481ede9SArnaldo Carvalho de Melo 
1016a5ef2702SJiri Olsa 		blt = browser_line(al);
1017a5ef2702SJiri Olsa 		if (++blt->jump_sources > browser->max_jump_sources)
1018a5ef2702SJiri Olsa 			browser->max_jump_sources = blt->jump_sources;
10192402e4a9SArnaldo Carvalho de Melo 
10202402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1021b793a401SArnaldo Carvalho de Melo 	}
1022b793a401SArnaldo Carvalho de Melo }
1023b793a401SArnaldo Carvalho de Melo 
10242402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10252402e4a9SArnaldo Carvalho de Melo {
10262402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10272402e4a9SArnaldo Carvalho de Melo 		return 5;
10282402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10292402e4a9SArnaldo Carvalho de Melo 		return 2;
10302402e4a9SArnaldo Carvalho de Melo 	return 1;
10312402e4a9SArnaldo Carvalho de Melo }
10322402e4a9SArnaldo Carvalho de Melo 
1033db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1034db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10359783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1036aca7a94dSNamhyung Kim {
1037e1b60b5bSJiri Olsa 	struct annotation_line *al;
10389d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1039c0a58fb2SSamuel Liao 	size_t size;
1040aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1041aca7a94dSNamhyung Kim 		.map = map,
1042aca7a94dSNamhyung Kim 		.sym = sym,
1043aca7a94dSNamhyung Kim 	};
1044aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1045aca7a94dSNamhyung Kim 		.b = {
1046a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1047aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1048aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
104929ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1050aca7a94dSNamhyung Kim 			.priv	 = &ms,
1051aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1052aca7a94dSNamhyung Kim 		},
1053aca7a94dSNamhyung Kim 	};
1054ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1055c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1056aca7a94dSNamhyung Kim 
1057aca7a94dSNamhyung Kim 	if (sym == NULL)
1058aca7a94dSNamhyung Kim 		return -1;
1059aca7a94dSNamhyung Kim 
1060c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1061c0a58fb2SSamuel Liao 
1062aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1063aca7a94dSNamhyung Kim 		return -1;
1064aca7a94dSNamhyung Kim 
1065*16932d77SArnaldo Carvalho de Melo 	notes->options = &annotate_browser__opts;
1066*16932d77SArnaldo Carvalho de Melo 
10679d6bb41dSArnaldo Carvalho de Melo 	notes->offsets = zalloc(size * sizeof(struct annotation_line *));
10689d6bb41dSArnaldo Carvalho de Melo 	if (notes->offsets == NULL) {
1069b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1070b793a401SArnaldo Carvalho de Melo 		return -1;
1071b793a401SArnaldo Carvalho de Melo 	}
1072b793a401SArnaldo Carvalho de Melo 
10733ab6db8dSJiri Olsa 	if (perf_evsel__is_group_event(evsel))
1074c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
1075c7e7b610SNamhyung Kim 
10765449f13cSArnaldo Carvalho de Melo 	err = symbol__annotate(sym, map, evsel, sizeof(struct browser_line), &browser.arch);
1077ee51d851SArnaldo Carvalho de Melo 	if (err) {
1078ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1079ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1080ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1081b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1082aca7a94dSNamhyung Kim 	}
1083aca7a94dSNamhyung Kim 
108405d3f1a1SJiri Olsa 	symbol__calc_percent(sym, evsel);
108505d3f1a1SJiri Olsa 
10867727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1087aca7a94dSNamhyung Kim 
1088aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1089aca7a94dSNamhyung Kim 
1090e1b60b5bSJiri Olsa 	list_for_each_entry(al, &notes->src->source, node) {
10910d957970SJiri Olsa 		struct browser_line *bpos;
1092e1b60b5bSJiri Olsa 		size_t line_len = strlen(al->line);
1093aca7a94dSNamhyung Kim 
1094aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1095aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1096a5ef2702SJiri Olsa 		bpos = browser_line(al);
1097887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1098e1b60b5bSJiri Olsa 		if (al->offset != -1) {
1099887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
110097148a97SArnaldo Carvalho de Melo 			/*
110197148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
110297148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
110397148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
110497148a97SArnaldo Carvalho de Melo 			 *
110597148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
110697148a97SArnaldo Carvalho de Melo  			 */
1107e1b60b5bSJiri Olsa 			if (al->offset < (s64)size)
11089d6bb41dSArnaldo Carvalho de Melo 				notes->offsets[al->offset] = al;
1109b793a401SArnaldo Carvalho de Melo 		} else
1110887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1111aca7a94dSNamhyung Kim 	}
1112aca7a94dSNamhyung Kim 
1113b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
1114f56c083bSArnaldo Carvalho de Melo 	annotation__compute_ipc(notes, size);
1115b793a401SArnaldo Carvalho de Melo 
11162402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
111783b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11182402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
11190553e83dSArnaldo Carvalho de Melo 	notes->nr_events = nr_pcnt;
1120aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1121aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1122aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1123e9823b21SArnaldo Carvalho de Melo 
1124*16932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
1125e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1126e9823b21SArnaldo Carvalho de Melo 
1127e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1128e9823b21SArnaldo Carvalho de Melo 
1129db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1130f8eb37bdSJiri Olsa 
1131f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
1132b793a401SArnaldo Carvalho de Melo 
1133b793a401SArnaldo Carvalho de Melo out_free_offsets:
11349d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
1135aca7a94dSNamhyung Kim 	return ret;
1136aca7a94dSNamhyung Kim }
1137c323cf04SArnaldo Carvalho de Melo 
1138c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1139c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1140c323cf04SArnaldo Carvalho de Melo 
1141c323cf04SArnaldo Carvalho de Melo /*
1142c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1143c323cf04SArnaldo Carvalho de Melo  */
11447c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1145c323cf04SArnaldo Carvalho de Melo 	const char *name;
1146c323cf04SArnaldo Carvalho de Melo 	bool *value;
1147c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1148c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1149c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1150e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1151c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11529cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
11530c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
115439ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1155c323cf04SArnaldo Carvalho de Melo };
1156c323cf04SArnaldo Carvalho de Melo 
1157c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1158c323cf04SArnaldo Carvalho de Melo 
1159c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1160c323cf04SArnaldo Carvalho de Melo {
11617c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1162c323cf04SArnaldo Carvalho de Melo 
1163c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1164c323cf04SArnaldo Carvalho de Melo }
1165c323cf04SArnaldo Carvalho de Melo 
11661d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11671d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1168c323cf04SArnaldo Carvalho de Melo {
11697c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1170c323cf04SArnaldo Carvalho de Melo 	const char *name;
1171c323cf04SArnaldo Carvalho de Melo 
11728e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1173c323cf04SArnaldo Carvalho de Melo 		return 0;
1174c323cf04SArnaldo Carvalho de Melo 
1175c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1176c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
11777c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1178c323cf04SArnaldo Carvalho de Melo 
1179c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1180f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1181f06cff7cSArnaldo Carvalho de Melo 	else
1182c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1183c323cf04SArnaldo Carvalho de Melo 	return 0;
1184c323cf04SArnaldo Carvalho de Melo }
1185c323cf04SArnaldo Carvalho de Melo 
1186c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1187c323cf04SArnaldo Carvalho de Melo {
1188c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1189c323cf04SArnaldo Carvalho de Melo }
1190