xref: /linux/tools/perf/ui/browsers/annotate.c (revision 6dcd57e8ae2080bca776d55e6e2b3d529677cae5)
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;
47aca7a94dSNamhyung Kim 	bool			    searching_backwards;
4883b1f2aaSArnaldo Carvalho de Melo 	u8			    addr_width;
492402e4a9SArnaldo Carvalho de Melo 	u8			    jumps_width;
502402e4a9SArnaldo Carvalho de Melo 	u8			    target_width;
5183b1f2aaSArnaldo Carvalho de Melo 	u8			    min_addr_width;
5283b1f2aaSArnaldo Carvalho de Melo 	u8			    max_addr_width;
53aca7a94dSNamhyung Kim 	char			    search_bf[128];
54aca7a94dSNamhyung Kim };
55aca7a94dSNamhyung Kim 
5695aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser)
5795aa89d9SArnaldo Carvalho de Melo {
5895aa89d9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
5995aa89d9SArnaldo Carvalho de Melo 	return symbol__annotation(ms->sym);
6095aa89d9SArnaldo Carvalho de Melo }
6195aa89d9SArnaldo Carvalho de Melo 
62a5ef2702SJiri Olsa static inline struct browser_line *browser_line(struct annotation_line *al)
63aca7a94dSNamhyung Kim {
64a5ef2702SJiri Olsa 	void *ptr = al;
65a5ef2702SJiri Olsa 
66a5ef2702SJiri Olsa 	ptr = container_of(al, struct disasm_line, al);
67a5ef2702SJiri Olsa 	return ptr - sizeof(struct browser_line);
68aca7a94dSNamhyung Kim }
69aca7a94dSNamhyung Kim 
7016932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
71aca7a94dSNamhyung Kim {
7295aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
7316932d77SArnaldo Carvalho de Melo 
7416932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
75d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
76d5490b96SJiri Olsa 
77d5490b96SJiri Olsa 		return al->offset == -1;
78aca7a94dSNamhyung Kim 	}
79aca7a94dSNamhyung Kim 
80aca7a94dSNamhyung Kim 	return false;
81aca7a94dSNamhyung Kim }
82aca7a94dSNamhyung Kim 
8327feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
842402e4a9SArnaldo Carvalho de Melo {
8527feb761SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
86bc1c0f3dSArnaldo Carvalho de Melo 
8727feb761SArnaldo Carvalho de Melo 	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
882402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
89bc1c0f3dSArnaldo Carvalho de Melo 	if (nr == notes->max_jump_sources)
902402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
912402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
922402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
932402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
942402e4a9SArnaldo Carvalho de Melo }
952402e4a9SArnaldo Carvalho de Melo 
9627feb761SArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(struct ui_browser *browser, int nr, bool current)
972402e4a9SArnaldo Carvalho de Melo {
9827feb761SArnaldo Carvalho de Melo 	 int color = ui_browser__jumps_percent_color(browser, nr, current);
9927feb761SArnaldo Carvalho de Melo 	 return ui_browser__set_color(browser, color);
1002402e4a9SArnaldo Carvalho de Melo }
1012402e4a9SArnaldo Carvalho de Melo 
102a5433b3eSJiri Olsa static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser,
103a5433b3eSJiri Olsa 			       char *bf, size_t size)
104aca7a94dSNamhyung Kim {
10595aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
10616932d77SArnaldo Carvalho de Melo 
10775b49202SArnaldo Carvalho de Melo 	if (dl->ins.ops && dl->ins.ops->scnprintf) {
10875b49202SArnaldo Carvalho de Melo 		if (ins__is_jump(&dl->ins)) {
109d5490b96SJiri Olsa 			bool fwd = dl->ops.target.offset > dl->al.offset;
11051a0d455SArnaldo Carvalho de Melo 
11105e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
11251a0d455SArnaldo Carvalho de Melo 							    SLSMG_UARROW_CHAR);
11351a0d455SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
11475b49202SArnaldo Carvalho de Melo 		} else if (ins__is_call(&dl->ins)) {
11505e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
11688298f5aSArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
11775b49202SArnaldo Carvalho de Melo 		} else if (ins__is_ret(&dl->ins)) {
11805e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
1194ea08b52SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
1206ef94929SNaveen N. Rao 		} else {
1216ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
1224ea08b52SArnaldo Carvalho de Melo 		}
1236ef94929SNaveen N. Rao 	} else {
1246ef94929SNaveen N. Rao 		ui_browser__write_nstring(browser, " ", 2);
1254ea08b52SArnaldo Carvalho de Melo 	}
1264ea08b52SArnaldo Carvalho de Melo 
12716932d77SArnaldo Carvalho de Melo 	disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset);
128a5433b3eSJiri Olsa }
129a5433b3eSJiri Olsa 
130a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
131a5433b3eSJiri Olsa {
132a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
13395aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
134a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
135a5433b3eSJiri Olsa 	struct browser_line *bl = browser_line(al);
136a5433b3eSJiri Olsa 	bool current_entry = ui_browser__is_current_entry(browser, row);
13716932d77SArnaldo Carvalho de Melo 	bool change_color = (!notes->options->hide_src_code &&
138a5433b3eSJiri Olsa 			     (!current_entry || (browser->use_navkeypressed &&
139a5433b3eSJiri Olsa 					         !browser->navkeypressed)));
140a5433b3eSJiri Olsa 	int width = browser->width, printed;
1416af612d2SArnaldo Carvalho de Melo 	int i, pcnt_width = annotation__pcnt_width(notes),
1420e83a7e9SArnaldo Carvalho de Melo 	       cycles_width = annotation__cycles_width(notes);
143a5433b3eSJiri Olsa 	double percent_max = 0.0;
144a5433b3eSJiri Olsa 	char bf[256];
145a5433b3eSJiri Olsa 	bool show_title = false;
146a5433b3eSJiri Olsa 
1470553e83dSArnaldo Carvalho de Melo 	for (i = 0; i < notes->nr_events; i++) {
148a5433b3eSJiri Olsa 		if (al->samples[i].percent > percent_max)
149a5433b3eSJiri Olsa 			percent_max = al->samples[i].percent;
150a5433b3eSJiri Olsa 	}
151a5433b3eSJiri Olsa 
152a5433b3eSJiri Olsa 	if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) {
1530e83a7e9SArnaldo Carvalho de Melo 		if (notes->have_cycles) {
154a5433b3eSJiri Olsa 			if (al->ipc == 0.0 && al->cycles == 0)
155a5433b3eSJiri Olsa 				show_title = true;
156a5433b3eSJiri Olsa 		} else
157a5433b3eSJiri Olsa 			show_title = true;
158a5433b3eSJiri Olsa 	}
159a5433b3eSJiri Olsa 
160a5433b3eSJiri Olsa 	if (al->offset != -1 && percent_max != 0.0) {
1610553e83dSArnaldo Carvalho de Melo 		for (i = 0; i < notes->nr_events; i++) {
162a5433b3eSJiri Olsa 			ui_browser__set_percent_color(browser,
163a5433b3eSJiri Olsa 						al->samples[i].percent,
164a5433b3eSJiri Olsa 						current_entry);
16516932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
166a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%11" PRIu64 " ",
167a5433b3eSJiri Olsa 						   al->samples[i].he.period);
16816932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples) {
169a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6" PRIu64 " ",
170a5433b3eSJiri Olsa 						   al->samples[i].he.nr_samples);
171a5433b3eSJiri Olsa 			} else {
172a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6.2f ",
173a5433b3eSJiri Olsa 						   al->samples[i].percent);
174a5433b3eSJiri Olsa 			}
175a5433b3eSJiri Olsa 		}
176a5433b3eSJiri Olsa 	} else {
177a5433b3eSJiri Olsa 		ui_browser__set_percent_color(browser, 0, current_entry);
178a5433b3eSJiri Olsa 
179a5433b3eSJiri Olsa 		if (!show_title)
180a5433b3eSJiri Olsa 			ui_browser__write_nstring(browser, " ", pcnt_width);
181a5433b3eSJiri Olsa 		else {
182a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*s", pcnt_width,
18316932d77SArnaldo Carvalho de Melo 					   notes->options->show_total_period ? "Period" :
18416932d77SArnaldo Carvalho de Melo 					   notes->options->show_nr_samples ? "Samples" : "Percent");
185a5433b3eSJiri Olsa 		}
186a5433b3eSJiri Olsa 	}
1870e83a7e9SArnaldo Carvalho de Melo 	if (notes->have_cycles) {
188a5433b3eSJiri Olsa 		if (al->ipc)
189c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
190a5433b3eSJiri Olsa 		else if (!show_title)
191c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__IPC_WIDTH);
192a5433b3eSJiri Olsa 		else
193c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
194a5433b3eSJiri Olsa 
195a5433b3eSJiri Olsa 		if (al->cycles)
196a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*" PRIu64 " ",
197c426e584SArnaldo Carvalho de Melo 					   ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
198a5433b3eSJiri Olsa 		else if (!show_title)
199c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__CYCLES_WIDTH);
200a5433b3eSJiri Olsa 		else
201c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle");
202a5433b3eSJiri Olsa 	}
203a5433b3eSJiri Olsa 
204a5433b3eSJiri Olsa 	SLsmg_write_char(' ');
205a5433b3eSJiri Olsa 
206a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
207a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
208a5433b3eSJiri Olsa 		width += 1;
209a5433b3eSJiri Olsa 
210a5433b3eSJiri Olsa 	if (!*al->line)
211a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
212a5433b3eSJiri Olsa 	else if (al->offset == -1) {
21316932d77SArnaldo Carvalho de Melo 		if (al->line_nr && notes->options->show_linenr)
214a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
215a5433b3eSJiri Olsa 					ab->addr_width + 1, al->line_nr);
216a5433b3eSJiri Olsa 		else
217a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
218a5433b3eSJiri Olsa 				    ab->addr_width, " ");
219a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
220a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1);
221a5433b3eSJiri Olsa 	} else {
222a5433b3eSJiri Olsa 		u64 addr = al->offset;
223a5433b3eSJiri Olsa 		int color = -1;
224a5433b3eSJiri Olsa 
22516932d77SArnaldo Carvalho de Melo 		if (!notes->options->use_offset)
226a5433b3eSJiri Olsa 			addr += ab->start;
227a5433b3eSJiri Olsa 
22816932d77SArnaldo Carvalho de Melo 		if (!notes->options->use_offset) {
229a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
230a5433b3eSJiri Olsa 		} else {
231a5433b3eSJiri Olsa 			if (bl->jump_sources) {
23216932d77SArnaldo Carvalho de Melo 				if (notes->options->show_nr_jumps) {
233a5433b3eSJiri Olsa 					int prev;
234a5433b3eSJiri Olsa 					printed = scnprintf(bf, sizeof(bf), "%*d ",
235a5433b3eSJiri Olsa 							    ab->jumps_width,
236a5433b3eSJiri Olsa 							    bl->jump_sources);
23727feb761SArnaldo Carvalho de Melo 					prev = ui_browser__set_jumps_percent_color(browser, bl->jump_sources,
238a5433b3eSJiri Olsa 										   current_entry);
239a5433b3eSJiri Olsa 					ui_browser__write_nstring(browser, bf, printed);
240a5433b3eSJiri Olsa 					ui_browser__set_color(browser, prev);
241a5433b3eSJiri Olsa 				}
242a5433b3eSJiri Olsa 
243a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
244a5433b3eSJiri Olsa 						    ab->target_width, addr);
245a5433b3eSJiri Olsa 			} else {
246a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
247a5433b3eSJiri Olsa 						    ab->addr_width, " ");
248a5433b3eSJiri Olsa 			}
249a5433b3eSJiri Olsa 		}
250a5433b3eSJiri Olsa 
251a5433b3eSJiri Olsa 		if (change_color)
252a5433b3eSJiri Olsa 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
253a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
254a5433b3eSJiri Olsa 		if (change_color)
255a5433b3eSJiri Olsa 			ui_browser__set_color(browser, color);
256a5433b3eSJiri Olsa 
257a5433b3eSJiri Olsa 		disasm_line__write(disasm_line(al), browser, bf, sizeof(bf));
258a5433b3eSJiri Olsa 
259bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
260aca7a94dSNamhyung Kim 	}
261aca7a94dSNamhyung Kim 
262aca7a94dSNamhyung Kim 	if (current_entry)
263a5433b3eSJiri Olsa 		ab->selection = al;
264aca7a94dSNamhyung Kim }
265aca7a94dSNamhyung Kim 
266865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
267865c66c4SFrederik Deweerdt {
26875b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
269865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
270e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
271e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
272865c66c4SFrederik Deweerdt 		return false;
273865c66c4SFrederik Deweerdt 
274865c66c4SFrederik Deweerdt 	return true;
275865c66c4SFrederik Deweerdt }
276865c66c4SFrederik Deweerdt 
2777e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2787e63a13aSJin Yao {
279a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2807e63a13aSJin Yao 	const char *name;
2817e63a13aSJin Yao 
2827e63a13aSJin Yao 	if (!pos)
2837e63a13aSJin Yao 		return false;
2847e63a13aSJin Yao 
2857e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2867e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2877e63a13aSJin Yao 	else
2887e63a13aSJin Yao 		name = pos->ins.name;
2897e63a13aSJin Yao 
2907e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2917e63a13aSJin Yao 		return false;
2927e63a13aSJin Yao 
2937e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
2947e63a13aSJin Yao }
2957e63a13aSJin Yao 
2969d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
297a3f895beSArnaldo Carvalho de Melo {
298a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
2997bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
300a5ef2702SJiri Olsa 	struct annotation_line *target;
3010d957970SJiri Olsa 	struct browser_line *btarget, *bcursor;
30283b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
30332ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
30432ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
3050e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
3066af612d2SArnaldo Carvalho de Melo 	u8 pcnt_width = annotation__pcnt_width(notes);
30700ea0eb2SArnaldo Carvalho de Melo 	int width;
30832ae1efdSNamhyung Kim 
30932ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31032ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31132ae1efdSNamhyung Kim 		return;
312a3f895beSArnaldo Carvalho de Melo 
313865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
314a3f895beSArnaldo Carvalho de Melo 		return;
315a3f895beSArnaldo Carvalho de Melo 
3169c04409dSArnaldo Carvalho de Melo 	/*
3179c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
3189c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
3199c04409dSArnaldo Carvalho de Melo 	 *
3209c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
3219c04409dSArnaldo Carvalho de Melo 	 *
3229c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
3239c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
3249c04409dSArnaldo Carvalho de Melo 	 *
3259c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
3269c04409dSArnaldo Carvalho de Melo 	 *
3279c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
3289c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
3299c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
3309c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
3319c04409dSArnaldo Carvalho de Melo 	 *
3329c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
3339c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
3349c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
3359c04409dSArnaldo Carvalho de Melo 	 */
3369d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
3379c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
3389d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
3399c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
3409c04409dSArnaldo Carvalho de Melo 		return;
3419c04409dSArnaldo Carvalho de Melo 	}
3429d1ef56dSArnaldo Carvalho de Melo 
343a5ef2702SJiri Olsa 	bcursor = browser_line(&cursor->al);
344daf25d43SJiri Olsa 	btarget = browser_line(target);
3459d1ef56dSArnaldo Carvalho de Melo 
34616932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3479d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
348a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
349a3f895beSArnaldo Carvalho de Melo 	} else {
3509d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
351a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
352a3f895beSArnaldo Carvalho de Melo 	}
353a3f895beSArnaldo Carvalho de Melo 
3540e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
355b40982e8SJin Yao 
35678ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
357b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
358b40982e8SJin Yao 				 pcnt_width + 2 + ab->addr_width + width,
359c7e7b610SNamhyung Kim 				 from, to);
3607e63a13aSJin Yao 
3617e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3627e63a13aSJin Yao 		ui_browser__mark_fused(browser,
363b40982e8SJin Yao 				       pcnt_width + 3 + ab->addr_width + width,
3647e63a13aSJin Yao 				       from - 1,
3657e63a13aSJin Yao 				       to > from ? true : false);
3667e63a13aSJin Yao 	}
367a3f895beSArnaldo Carvalho de Melo }
368a3f895beSArnaldo Carvalho de Melo 
369a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
370a3f895beSArnaldo Carvalho de Melo {
37195aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
372a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
3736af612d2SArnaldo Carvalho de Melo 	int pcnt_width = annotation__pcnt_width(notes);
374a3f895beSArnaldo Carvalho de Melo 
37516932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
3769d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
377a3f895beSArnaldo Carvalho de Melo 
37883b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
379c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
380a3f895beSArnaldo Carvalho de Melo 	return ret;
381a3f895beSArnaldo Carvalho de Melo }
382a3f895beSArnaldo Carvalho de Melo 
383b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
384c7e7b610SNamhyung Kim {
385c7e7b610SNamhyung Kim 	int i;
386c7e7b610SNamhyung Kim 
387b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
3880c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
389c7e7b610SNamhyung Kim 			continue;
3900c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
391c7e7b610SNamhyung Kim 	}
392c7e7b610SNamhyung Kim 	return 0;
393c7e7b610SNamhyung Kim }
394c7e7b610SNamhyung Kim 
395b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
396aca7a94dSNamhyung Kim {
39729ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
398aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
3993ab6db8dSJiri Olsa 	struct annotation_line *l;
400aca7a94dSNamhyung Kim 
401aca7a94dSNamhyung Kim 	while (*p != NULL) {
402aca7a94dSNamhyung Kim 		parent = *p;
4033ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
404c7e7b610SNamhyung Kim 
405b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
406aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
407aca7a94dSNamhyung Kim 		else
408aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
409aca7a94dSNamhyung Kim 	}
4103ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
4113ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
412aca7a94dSNamhyung Kim }
413aca7a94dSNamhyung Kim 
41405e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
415ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
416aca7a94dSNamhyung Kim {
417aca7a94dSNamhyung Kim 	unsigned back;
418aca7a94dSNamhyung Kim 
41905e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
42005e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
42105e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
422aca7a94dSNamhyung Kim 
42305e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
424ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
425aca7a94dSNamhyung Kim 
426ec03a77dSJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->node))
427aca7a94dSNamhyung Kim 			continue;
428aca7a94dSNamhyung Kim 
42905e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
430aca7a94dSNamhyung Kim 		--back;
431aca7a94dSNamhyung Kim 	}
432aca7a94dSNamhyung Kim 
433ec03a77dSJiri Olsa 	browser->b.top = pos;
43405e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
435aca7a94dSNamhyung Kim }
436aca7a94dSNamhyung Kim 
437aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
438aca7a94dSNamhyung Kim 					 struct rb_node *nd)
439aca7a94dSNamhyung Kim {
44095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
4410d957970SJiri Olsa 	struct browser_line *bpos;
442ec03a77dSJiri Olsa 	struct annotation_line *pos;
443a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
444aca7a94dSNamhyung Kim 
445ec03a77dSJiri Olsa 	pos = rb_entry(nd, struct annotation_line, rb_node);
446ec03a77dSJiri Olsa 	bpos = browser_line(pos);
4475b12adc8SJiri Olsa 
448a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
44916932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
450a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
451a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
452aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
453aca7a94dSNamhyung Kim }
454aca7a94dSNamhyung Kim 
455aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
456db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
457aca7a94dSNamhyung Kim {
458aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
459aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
460aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
461c4c72436SJiri Olsa 	struct disasm_line *pos;
462aca7a94dSNamhyung Kim 
463aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
464aca7a94dSNamhyung Kim 
465aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
466aca7a94dSNamhyung Kim 
467e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
468e425da6cSJiri Olsa 
469a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
470c7e7b610SNamhyung Kim 		double max_percent = 0.0;
471c7e7b610SNamhyung Kim 		int i;
472e64aa75bSNamhyung Kim 
473d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
4745b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
475e64aa75bSNamhyung Kim 			continue;
476e64aa75bSNamhyung Kim 		}
477e64aa75bSNamhyung Kim 
478b15636c6SJiri Olsa 		for (i = 0; i < pos->al.samples_nr; i++) {
479e425da6cSJiri Olsa 			struct annotation_data *sample = &pos->al.samples[i];
4800c4a5bceSMartin Liška 
4813ab6db8dSJiri Olsa 			if (max_percent < sample->percent)
4823ab6db8dSJiri Olsa 				max_percent = sample->percent;
483c7e7b610SNamhyung Kim 		}
484c7e7b610SNamhyung Kim 
48537236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
4865b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
487aca7a94dSNamhyung Kim 			continue;
488aca7a94dSNamhyung Kim 		}
489b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
490aca7a94dSNamhyung Kim 	}
491aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
492aca7a94dSNamhyung Kim 
493aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
494aca7a94dSNamhyung Kim }
495aca7a94dSNamhyung Kim 
496aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
497aca7a94dSNamhyung Kim {
49895aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
499ec03a77dSJiri Olsa 	struct annotation_line *al;
500a5ef2702SJiri Olsa 	struct browser_line *bl;
501aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
502aca7a94dSNamhyung Kim 
503aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
504ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
505ec03a77dSJiri Olsa 	bl = browser_line(al);
506aca7a94dSNamhyung Kim 
50716932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
508a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
509a5ef2702SJiri Olsa 			offset = bl->idx;
510aca7a94dSNamhyung Kim 
511aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
51216932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
513aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
514a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx - offset;
515a5ef2702SJiri Olsa 		browser->b.index = bl->idx;
516aca7a94dSNamhyung Kim 	} else {
517a5ef2702SJiri Olsa 		if (bl->idx_asm < 0) {
518aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
519aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
520aca7a94dSNamhyung Kim 			return false;
521aca7a94dSNamhyung Kim 		}
522aca7a94dSNamhyung Kim 
523a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
524a5ef2702SJiri Olsa 			offset = bl->idx_asm;
525aca7a94dSNamhyung Kim 
526aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
52716932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
528aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
529a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx_asm - offset;
530a5ef2702SJiri Olsa 		browser->b.index = bl->idx_asm;
531aca7a94dSNamhyung Kim 	}
532aca7a94dSNamhyung Kim 
533aca7a94dSNamhyung Kim 	return true;
534aca7a94dSNamhyung Kim }
535aca7a94dSNamhyung Kim 
536e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
537e9823b21SArnaldo Carvalho de Melo {
538e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
539e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
540e9823b21SArnaldo Carvalho de Melo }
541e9823b21SArnaldo Carvalho de Melo 
54234f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
54334f77abcSAdrian Hunter 
54434f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
54534f77abcSAdrian Hunter 		     size_t sz)
54634f77abcSAdrian Hunter {
54734f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
54834f77abcSAdrian Hunter }
54934f77abcSAdrian Hunter 
550db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
551db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5529783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
553aca7a94dSNamhyung Kim {
554aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
5557bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
556aca7a94dSNamhyung Kim 	struct annotation *notes;
55734f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
558aca7a94dSNamhyung Kim 
55975b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
560aca7a94dSNamhyung Kim 		return false;
561aca7a94dSNamhyung Kim 
562696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
563aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
564aca7a94dSNamhyung Kim 		return true;
565aca7a94dSNamhyung Kim 	}
566aca7a94dSNamhyung Kim 
567696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
568aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
569aca7a94dSNamhyung Kim 
570696703afSArnaldo Carvalho de Melo 	if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) {
571aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
572aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
573696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
574aca7a94dSNamhyung Kim 		return true;
575aca7a94dSNamhyung Kim 	}
576aca7a94dSNamhyung Kim 
577aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
578696703afSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt);
5791179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
58034f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
581aca7a94dSNamhyung Kim 	return true;
582aca7a94dSNamhyung Kim }
583aca7a94dSNamhyung Kim 
58429ed6e76SArnaldo Carvalho de Melo static
58529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
586aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
587aca7a94dSNamhyung Kim {
58895aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
58929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
590aca7a94dSNamhyung Kim 
591aca7a94dSNamhyung Kim 	*idx = 0;
592a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
593d5490b96SJiri Olsa 		if (pos->al.offset == offset)
594aca7a94dSNamhyung Kim 			return pos;
595a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
596aca7a94dSNamhyung Kim 			++*idx;
597aca7a94dSNamhyung Kim 	}
598aca7a94dSNamhyung Kim 
599aca7a94dSNamhyung Kim 	return NULL;
600aca7a94dSNamhyung Kim }
601aca7a94dSNamhyung Kim 
602aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
603aca7a94dSNamhyung Kim {
6047bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
6055252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6064f9d0325SArnaldo Carvalho de Melo 	s64 idx;
607aca7a94dSNamhyung Kim 
60875b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
609aca7a94dSNamhyung Kim 		return false;
610aca7a94dSNamhyung Kim 
6115252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6125252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
61329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6145252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
615aca7a94dSNamhyung Kim 		return true;
616aca7a94dSNamhyung Kim 	}
617aca7a94dSNamhyung Kim 
618ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
619aca7a94dSNamhyung Kim 
620aca7a94dSNamhyung Kim 	return true;
621aca7a94dSNamhyung Kim }
622aca7a94dSNamhyung Kim 
62329ed6e76SArnaldo Carvalho de Melo static
6249213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
625aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
626aca7a94dSNamhyung Kim {
62795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
6289213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
629aca7a94dSNamhyung Kim 
630aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6319213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
6329213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
633aca7a94dSNamhyung Kim 			continue;
634aca7a94dSNamhyung Kim 
635aca7a94dSNamhyung Kim 		++*idx;
636aca7a94dSNamhyung Kim 
6379213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6389213afbdSJiri Olsa 			return al;
639aca7a94dSNamhyung Kim 	}
640aca7a94dSNamhyung Kim 
641aca7a94dSNamhyung Kim 	return NULL;
642aca7a94dSNamhyung Kim }
643aca7a94dSNamhyung Kim 
644aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
645aca7a94dSNamhyung Kim {
6469213afbdSJiri Olsa 	struct annotation_line *al;
647aca7a94dSNamhyung Kim 	s64 idx;
648aca7a94dSNamhyung Kim 
6499213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
6509213afbdSJiri Olsa 	if (al == NULL) {
651aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
652aca7a94dSNamhyung Kim 		return false;
653aca7a94dSNamhyung Kim 	}
654aca7a94dSNamhyung Kim 
655ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
656aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
657aca7a94dSNamhyung Kim 	return true;
658aca7a94dSNamhyung Kim }
659aca7a94dSNamhyung Kim 
66029ed6e76SArnaldo Carvalho de Melo static
6619213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
662aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
663aca7a94dSNamhyung Kim {
66495aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
6659213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
666aca7a94dSNamhyung Kim 
667aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6689213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
6699213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
670aca7a94dSNamhyung Kim 			continue;
671aca7a94dSNamhyung Kim 
672aca7a94dSNamhyung Kim 		--*idx;
673aca7a94dSNamhyung Kim 
6749213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6759213afbdSJiri Olsa 			return al;
676aca7a94dSNamhyung Kim 	}
677aca7a94dSNamhyung Kim 
678aca7a94dSNamhyung Kim 	return NULL;
679aca7a94dSNamhyung Kim }
680aca7a94dSNamhyung Kim 
681aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
682aca7a94dSNamhyung Kim {
6839213afbdSJiri Olsa 	struct annotation_line *al;
684aca7a94dSNamhyung Kim 	s64 idx;
685aca7a94dSNamhyung Kim 
6869213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
6879213afbdSJiri Olsa 	if (al == NULL) {
688aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
689aca7a94dSNamhyung Kim 		return false;
690aca7a94dSNamhyung Kim 	}
691aca7a94dSNamhyung Kim 
692ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
693aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
694aca7a94dSNamhyung Kim 	return true;
695aca7a94dSNamhyung Kim }
696aca7a94dSNamhyung Kim 
697aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
698aca7a94dSNamhyung Kim 					    int delay_secs)
699aca7a94dSNamhyung Kim {
700aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
701aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
702aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
703aca7a94dSNamhyung Kim 	    !*browser->search_bf)
704aca7a94dSNamhyung Kim 		return false;
705aca7a94dSNamhyung Kim 
706aca7a94dSNamhyung Kim 	return true;
707aca7a94dSNamhyung Kim }
708aca7a94dSNamhyung Kim 
709aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
710aca7a94dSNamhyung Kim {
711aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
712aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
713aca7a94dSNamhyung Kim 
714aca7a94dSNamhyung Kim 	return false;
715aca7a94dSNamhyung Kim }
716aca7a94dSNamhyung Kim 
717aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
718aca7a94dSNamhyung Kim 					      int delay_secs)
719aca7a94dSNamhyung Kim {
720aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
721aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
722aca7a94dSNamhyung Kim 
723aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
724aca7a94dSNamhyung Kim }
725aca7a94dSNamhyung Kim 
726aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
727aca7a94dSNamhyung Kim 					   int delay_secs)
728aca7a94dSNamhyung Kim {
729aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
730aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
731aca7a94dSNamhyung Kim 
732aca7a94dSNamhyung Kim 	return false;
733aca7a94dSNamhyung Kim }
734aca7a94dSNamhyung Kim 
735aca7a94dSNamhyung Kim static
736aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
737aca7a94dSNamhyung Kim 					       int delay_secs)
738aca7a94dSNamhyung Kim {
739aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
740aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
741aca7a94dSNamhyung Kim 
742aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
743aca7a94dSNamhyung Kim }
744aca7a94dSNamhyung Kim 
745e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
746e9823b21SArnaldo Carvalho de Melo {
74795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
74816932d77SArnaldo Carvalho de Melo 
74916932d77SArnaldo Carvalho de Melo 	if (notes->options->use_offset)
750e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
751e9823b21SArnaldo Carvalho de Melo 	else
752e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
753e9823b21SArnaldo Carvalho de Melo 
754e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
755e9823b21SArnaldo Carvalho de Melo 
75616932d77SArnaldo Carvalho de Melo 	if (notes->options->show_nr_jumps)
757e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
758e9823b21SArnaldo Carvalho de Melo }
759e9823b21SArnaldo Carvalho de Melo 
760db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
761db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7629783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
763aca7a94dSNamhyung Kim {
764aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
76505e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
766aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
76716932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
76854e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7699783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
770aca7a94dSNamhyung Kim 	int key;
77134f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
772aca7a94dSNamhyung Kim 
77334f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
77434f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
775aca7a94dSNamhyung Kim 		return -1;
776aca7a94dSNamhyung Kim 
777db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
778aca7a94dSNamhyung Kim 
77905e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
78005e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
78105e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
782aca7a94dSNamhyung Kim 	}
783aca7a94dSNamhyung Kim 
78405e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
785aca7a94dSNamhyung Kim 
786aca7a94dSNamhyung Kim 	while (1) {
78705e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
788aca7a94dSNamhyung Kim 
789aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
790db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
791aca7a94dSNamhyung Kim 			/*
792aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
793aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
794aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
795aca7a94dSNamhyung Kim 			 */
796aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
797aca7a94dSNamhyung Kim 				nd = NULL;
798aca7a94dSNamhyung Kim 		}
799aca7a94dSNamhyung Kim 
800aca7a94dSNamhyung Kim 		switch (key) {
801aca7a94dSNamhyung Kim 		case K_TIMER:
8029783adf7SNamhyung Kim 			if (hbt)
8039783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
804aca7a94dSNamhyung Kim 
805aca7a94dSNamhyung Kim 			if (delay_secs != 0)
806db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
807aca7a94dSNamhyung Kim 			continue;
808aca7a94dSNamhyung Kim 		case K_TAB:
809aca7a94dSNamhyung Kim 			if (nd != NULL) {
810aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
811aca7a94dSNamhyung Kim 				if (nd == NULL)
81205e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
813aca7a94dSNamhyung Kim 			} else
81405e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
815aca7a94dSNamhyung Kim 			break;
816aca7a94dSNamhyung Kim 		case K_UNTAB:
817d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
818aca7a94dSNamhyung Kim 				nd = rb_next(nd);
819aca7a94dSNamhyung Kim 				if (nd == NULL)
82005e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
821d4913cbdSMarkus Trippelsdorf 			} else
82205e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
823aca7a94dSNamhyung Kim 			break;
82454e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
825aca7a94dSNamhyung Kim 		case 'h':
82605e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
82754e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
82854e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
82954e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8307727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8317727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
832eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
833eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
83454e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
83554e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
83654e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
83754e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
83854e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8393a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
84054e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
841e592488cSAndi Kleen 		"k             Toggle line numbers\n"
84279ee47faSFeng Tang 		"r             Run available scripts\n"
843fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
84454e7a4e8SArnaldo Carvalho de Melo 			continue;
84579ee47faSFeng Tang 		case 'r':
84679ee47faSFeng Tang 			{
84779ee47faSFeng Tang 				script_browse(NULL);
84879ee47faSFeng Tang 				continue;
84979ee47faSFeng Tang 			}
850e592488cSAndi Kleen 		case 'k':
85116932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
852e592488cSAndi Kleen 			break;
85354e7a4e8SArnaldo Carvalho de Melo 		case 'H':
85405e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
855aca7a94dSNamhyung Kim 			break;
856aca7a94dSNamhyung Kim 		case 's':
85705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
858aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
859aca7a94dSNamhyung Kim 			continue;
860aca7a94dSNamhyung Kim 		case 'o':
86116932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
86205e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
863aca7a94dSNamhyung Kim 			continue;
8649d1ef56dSArnaldo Carvalho de Melo 		case 'j':
86516932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
8669d1ef56dSArnaldo Carvalho de Melo 			continue;
8672402e4a9SArnaldo Carvalho de Melo 		case 'J':
86816932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
86905e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
870e9823b21SArnaldo Carvalho de Melo 			continue;
871aca7a94dSNamhyung Kim 		case '/':
87205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
873aca7a94dSNamhyung Kim show_help:
874aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
875aca7a94dSNamhyung Kim 			}
876aca7a94dSNamhyung Kim 			continue;
877aca7a94dSNamhyung Kim 		case 'n':
87805e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
87905e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
88005e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
881aca7a94dSNamhyung Kim 				goto show_help;
882aca7a94dSNamhyung Kim 			continue;
883aca7a94dSNamhyung Kim 		case '?':
88405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
885aca7a94dSNamhyung Kim 				goto show_help;
886aca7a94dSNamhyung Kim 			continue;
887e9823b21SArnaldo Carvalho de Melo 		case 'D': {
888e9823b21SArnaldo Carvalho de Melo 			static int seq;
889e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
890e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
89105e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
89205e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
89305e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
89405e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
89505e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
896e9823b21SArnaldo Carvalho de Melo 		}
897e9823b21SArnaldo Carvalho de Melo 			continue;
898aca7a94dSNamhyung Kim 		case K_ENTER:
899aca7a94dSNamhyung Kim 		case K_RIGHT:
9007bcbcd58SJiri Olsa 		{
9017bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
9027bcbcd58SJiri Olsa 
90305e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
904aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
9057bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
906aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
9077bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
908c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
9097bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
910c4cceae3SArnaldo Carvalho de Melo 				goto out;
9116ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
912db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
913c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9146ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
915c4cceae3SArnaldo Carvalho de Melo 			}
916aca7a94dSNamhyung Kim 			continue;
9177bcbcd58SJiri Olsa 		}
9180c4a5bceSMartin Liška 		case 't':
91916932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
92016932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
92116932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
92216932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
92316932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
9243a555c77STaeung Song 			else
92516932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
9260c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9270c4a5bceSMartin Liška 			continue;
928aca7a94dSNamhyung Kim 		case K_LEFT:
929aca7a94dSNamhyung Kim 		case K_ESC:
930aca7a94dSNamhyung Kim 		case 'q':
931aca7a94dSNamhyung Kim 		case CTRL('c'):
932aca7a94dSNamhyung Kim 			goto out;
933aca7a94dSNamhyung Kim 		default:
934aca7a94dSNamhyung Kim 			continue;
935aca7a94dSNamhyung Kim 		}
936aca7a94dSNamhyung Kim 
937aca7a94dSNamhyung Kim 		if (nd != NULL)
93805e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
939aca7a94dSNamhyung Kim 	}
940aca7a94dSNamhyung Kim out:
94105e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
942aca7a94dSNamhyung Kim 	return key;
943aca7a94dSNamhyung Kim }
944aca7a94dSNamhyung Kim 
945d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
946d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
947d5dbc518SArnaldo Carvalho de Melo {
9489cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9490c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9500c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9519cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9529cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9530c4a5bceSMartin Liška 
954d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
955d5dbc518SArnaldo Carvalho de Melo }
956d5dbc518SArnaldo Carvalho de Melo 
957db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9589783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
959aca7a94dSNamhyung Kim {
960ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
961ed426915SNamhyung Kim 	SLang_reset_tty();
962ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
963ed426915SNamhyung Kim 
964d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
965aca7a94dSNamhyung Kim }
966aca7a94dSNamhyung Kim 
967*6dcd57e8SArnaldo Carvalho de Melo static void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym)
968b793a401SArnaldo Carvalho de Melo {
969*6dcd57e8SArnaldo Carvalho de Melo 	u64 offset, size = symbol__size(sym);
97032ae1efdSNamhyung Kim 
97132ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
97232ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
97332ae1efdSNamhyung Kim 		return;
974b793a401SArnaldo Carvalho de Melo 
975b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
9769d6bb41dSArnaldo Carvalho de Melo 		struct annotation_line *al = notes->offsets[offset];
977a5ef2702SJiri Olsa 		struct disasm_line *dl;
978a5ef2702SJiri Olsa 		struct browser_line *blt;
979b793a401SArnaldo Carvalho de Melo 
980e1b60b5bSJiri Olsa 		dl = disasm_line(al);
981e1b60b5bSJiri Olsa 
982865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
983b793a401SArnaldo Carvalho de Melo 			continue;
984b793a401SArnaldo Carvalho de Melo 
9859d6bb41dSArnaldo Carvalho de Melo 		al = notes->offsets[dl->ops.target.offset];
986e1b60b5bSJiri Olsa 
9879481ede9SArnaldo Carvalho de Melo 		/*
9889481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
9899481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
9909481ede9SArnaldo Carvalho de Melo  		 */
991a5ef2702SJiri Olsa 		if (al == NULL)
9929481ede9SArnaldo Carvalho de Melo 			continue;
9939481ede9SArnaldo Carvalho de Melo 
994a5ef2702SJiri Olsa 		blt = browser_line(al);
995bc1c0f3dSArnaldo Carvalho de Melo 		if (++blt->jump_sources > notes->max_jump_sources)
996bc1c0f3dSArnaldo Carvalho de Melo 			notes->max_jump_sources = blt->jump_sources;
9972402e4a9SArnaldo Carvalho de Melo 
998*6dcd57e8SArnaldo Carvalho de Melo 		++notes->nr_jumps;
999b793a401SArnaldo Carvalho de Melo 	}
1000b793a401SArnaldo Carvalho de Melo }
1001b793a401SArnaldo Carvalho de Melo 
10022402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10032402e4a9SArnaldo Carvalho de Melo {
10042402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10052402e4a9SArnaldo Carvalho de Melo 		return 5;
10062402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10072402e4a9SArnaldo Carvalho de Melo 		return 2;
10082402e4a9SArnaldo Carvalho de Melo 	return 1;
10092402e4a9SArnaldo Carvalho de Melo }
10102402e4a9SArnaldo Carvalho de Melo 
1011db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1012db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10139783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1014aca7a94dSNamhyung Kim {
1015e1b60b5bSJiri Olsa 	struct annotation_line *al;
10169d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1017c0a58fb2SSamuel Liao 	size_t size;
1018aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1019aca7a94dSNamhyung Kim 		.map = map,
1020aca7a94dSNamhyung Kim 		.sym = sym,
1021aca7a94dSNamhyung Kim 	};
1022aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1023aca7a94dSNamhyung Kim 		.b = {
1024a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1025aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1026aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
102729ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1028aca7a94dSNamhyung Kim 			.priv	 = &ms,
1029aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1030aca7a94dSNamhyung Kim 		},
1031aca7a94dSNamhyung Kim 	};
1032ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1033c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1034aca7a94dSNamhyung Kim 
1035aca7a94dSNamhyung Kim 	if (sym == NULL)
1036aca7a94dSNamhyung Kim 		return -1;
1037aca7a94dSNamhyung Kim 
1038c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1039c0a58fb2SSamuel Liao 
1040aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1041aca7a94dSNamhyung Kim 		return -1;
1042aca7a94dSNamhyung Kim 
104316932d77SArnaldo Carvalho de Melo 	notes->options = &annotate_browser__opts;
104416932d77SArnaldo Carvalho de Melo 
10459d6bb41dSArnaldo Carvalho de Melo 	notes->offsets = zalloc(size * sizeof(struct annotation_line *));
10469d6bb41dSArnaldo Carvalho de Melo 	if (notes->offsets == NULL) {
1047b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1048b793a401SArnaldo Carvalho de Melo 		return -1;
1049b793a401SArnaldo Carvalho de Melo 	}
1050b793a401SArnaldo Carvalho de Melo 
10513ab6db8dSJiri Olsa 	if (perf_evsel__is_group_event(evsel))
1052c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
1053c7e7b610SNamhyung Kim 
10545449f13cSArnaldo Carvalho de Melo 	err = symbol__annotate(sym, map, evsel, sizeof(struct browser_line), &browser.arch);
1055ee51d851SArnaldo Carvalho de Melo 	if (err) {
1056ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1057ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1058ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1059b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1060aca7a94dSNamhyung Kim 	}
1061aca7a94dSNamhyung Kim 
106205d3f1a1SJiri Olsa 	symbol__calc_percent(sym, evsel);
106305d3f1a1SJiri Olsa 
10647727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1065aca7a94dSNamhyung Kim 
1066aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1067aca7a94dSNamhyung Kim 
1068e1b60b5bSJiri Olsa 	list_for_each_entry(al, &notes->src->source, node) {
10690d957970SJiri Olsa 		struct browser_line *bpos;
1070e1b60b5bSJiri Olsa 		size_t line_len = strlen(al->line);
1071aca7a94dSNamhyung Kim 
1072aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1073aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1074a5ef2702SJiri Olsa 		bpos = browser_line(al);
1075887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1076e1b60b5bSJiri Olsa 		if (al->offset != -1) {
1077887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
107897148a97SArnaldo Carvalho de Melo 			/*
107997148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
108097148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
108197148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
108297148a97SArnaldo Carvalho de Melo 			 *
108397148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
108497148a97SArnaldo Carvalho de Melo  			 */
1085e1b60b5bSJiri Olsa 			if (al->offset < (s64)size)
10869d6bb41dSArnaldo Carvalho de Melo 				notes->offsets[al->offset] = al;
1087b793a401SArnaldo Carvalho de Melo 		} else
1088887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1089aca7a94dSNamhyung Kim 	}
1090aca7a94dSNamhyung Kim 
1091*6dcd57e8SArnaldo Carvalho de Melo 	annotation__mark_jump_targets(notes, sym);
1092f56c083bSArnaldo Carvalho de Melo 	annotation__compute_ipc(notes, size);
1093b793a401SArnaldo Carvalho de Melo 
10942402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
109583b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
1096bc1c0f3dSArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(notes->max_jump_sources);
10970553e83dSArnaldo Carvalho de Melo 	notes->nr_events = nr_pcnt;
1098aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1099aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1100aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1101e9823b21SArnaldo Carvalho de Melo 
110216932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
1103e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1104e9823b21SArnaldo Carvalho de Melo 
1105e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1106e9823b21SArnaldo Carvalho de Melo 
1107db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1108f8eb37bdSJiri Olsa 
1109f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
1110b793a401SArnaldo Carvalho de Melo 
1111b793a401SArnaldo Carvalho de Melo out_free_offsets:
11129d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
1113aca7a94dSNamhyung Kim 	return ret;
1114aca7a94dSNamhyung Kim }
1115c323cf04SArnaldo Carvalho de Melo 
1116c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1117c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1118c323cf04SArnaldo Carvalho de Melo 
1119c323cf04SArnaldo Carvalho de Melo /*
1120c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1121c323cf04SArnaldo Carvalho de Melo  */
11227c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1123c323cf04SArnaldo Carvalho de Melo 	const char *name;
1124c323cf04SArnaldo Carvalho de Melo 	bool *value;
1125c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1126c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1127c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1128e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1129c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11309cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
11310c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
113239ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1133c323cf04SArnaldo Carvalho de Melo };
1134c323cf04SArnaldo Carvalho de Melo 
1135c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1136c323cf04SArnaldo Carvalho de Melo 
1137c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1138c323cf04SArnaldo Carvalho de Melo {
11397c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1140c323cf04SArnaldo Carvalho de Melo 
1141c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1142c323cf04SArnaldo Carvalho de Melo }
1143c323cf04SArnaldo Carvalho de Melo 
11441d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11451d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1146c323cf04SArnaldo Carvalho de Melo {
11477c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1148c323cf04SArnaldo Carvalho de Melo 	const char *name;
1149c323cf04SArnaldo Carvalho de Melo 
11508e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1151c323cf04SArnaldo Carvalho de Melo 		return 0;
1152c323cf04SArnaldo Carvalho de Melo 
1153c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1154c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
11557c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1156c323cf04SArnaldo Carvalho de Melo 
1157c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1158f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1159f06cff7cSArnaldo Carvalho de Melo 	else
1160c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1161c323cf04SArnaldo Carvalho de Melo 	return 0;
1162c323cf04SArnaldo Carvalho de Melo }
1163c323cf04SArnaldo Carvalho de Melo 
1164c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1165c323cf04SArnaldo Carvalho de Melo {
1166c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1167c323cf04SArnaldo Carvalho de Melo }
1168