xref: /linux/tools/perf/ui/browsers/annotate.c (revision bc1c0f3dfa77619ad90f6fed290636cf54629d30)
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			    nr_jumps;
48aca7a94dSNamhyung Kim 	bool			    searching_backwards;
4983b1f2aaSArnaldo Carvalho de Melo 	u8			    addr_width;
502402e4a9SArnaldo Carvalho de Melo 	u8			    jumps_width;
512402e4a9SArnaldo Carvalho de Melo 	u8			    target_width;
5283b1f2aaSArnaldo Carvalho de Melo 	u8			    min_addr_width;
5383b1f2aaSArnaldo Carvalho de Melo 	u8			    max_addr_width;
54aca7a94dSNamhyung Kim 	char			    search_bf[128];
55aca7a94dSNamhyung Kim };
56aca7a94dSNamhyung Kim 
5795aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser)
5895aa89d9SArnaldo Carvalho de Melo {
5995aa89d9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
6095aa89d9SArnaldo Carvalho de Melo 	return symbol__annotation(ms->sym);
6195aa89d9SArnaldo Carvalho de Melo }
6295aa89d9SArnaldo Carvalho de Melo 
63a5ef2702SJiri Olsa static inline struct browser_line *browser_line(struct annotation_line *al)
64aca7a94dSNamhyung Kim {
65a5ef2702SJiri Olsa 	void *ptr = al;
66a5ef2702SJiri Olsa 
67a5ef2702SJiri Olsa 	ptr = container_of(al, struct disasm_line, al);
68a5ef2702SJiri Olsa 	return ptr - sizeof(struct browser_line);
69aca7a94dSNamhyung Kim }
70aca7a94dSNamhyung Kim 
7116932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
72aca7a94dSNamhyung Kim {
7395aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
7416932d77SArnaldo Carvalho de Melo 
7516932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
76d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
77d5490b96SJiri Olsa 
78d5490b96SJiri Olsa 		return al->offset == -1;
79aca7a94dSNamhyung Kim 	}
80aca7a94dSNamhyung Kim 
81aca7a94dSNamhyung Kim 	return false;
82aca7a94dSNamhyung Kim }
83aca7a94dSNamhyung Kim 
842402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
852402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
862402e4a9SArnaldo Carvalho de Melo {
87*bc1c0f3dSArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
88*bc1c0f3dSArnaldo Carvalho de Melo 
892402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
902402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
91*bc1c0f3dSArnaldo Carvalho de Melo 	if (nr == notes->max_jump_sources)
922402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
932402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
942402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
952402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
962402e4a9SArnaldo Carvalho de Melo }
972402e4a9SArnaldo Carvalho de Melo 
982402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
992402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
1002402e4a9SArnaldo Carvalho de Melo {
1012402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1022402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1032402e4a9SArnaldo Carvalho de Melo }
1042402e4a9SArnaldo Carvalho de Melo 
105a5433b3eSJiri Olsa static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser,
106a5433b3eSJiri Olsa 			       char *bf, size_t size)
107aca7a94dSNamhyung Kim {
10895aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
10916932d77SArnaldo Carvalho de Melo 
11075b49202SArnaldo Carvalho de Melo 	if (dl->ins.ops && dl->ins.ops->scnprintf) {
11175b49202SArnaldo Carvalho de Melo 		if (ins__is_jump(&dl->ins)) {
112d5490b96SJiri Olsa 			bool fwd = dl->ops.target.offset > dl->al.offset;
11351a0d455SArnaldo Carvalho de Melo 
11405e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
11551a0d455SArnaldo Carvalho de Melo 							    SLSMG_UARROW_CHAR);
11651a0d455SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
11775b49202SArnaldo Carvalho de Melo 		} else if (ins__is_call(&dl->ins)) {
11805e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
11988298f5aSArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
12075b49202SArnaldo Carvalho de Melo 		} else if (ins__is_ret(&dl->ins)) {
12105e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
1224ea08b52SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
1236ef94929SNaveen N. Rao 		} else {
1246ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
1254ea08b52SArnaldo Carvalho de Melo 		}
1266ef94929SNaveen N. Rao 	} else {
1276ef94929SNaveen N. Rao 		ui_browser__write_nstring(browser, " ", 2);
1284ea08b52SArnaldo Carvalho de Melo 	}
1294ea08b52SArnaldo Carvalho de Melo 
13016932d77SArnaldo Carvalho de Melo 	disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset);
131a5433b3eSJiri Olsa }
132a5433b3eSJiri Olsa 
133a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
134a5433b3eSJiri Olsa {
135a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
13695aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
137a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
138a5433b3eSJiri Olsa 	struct browser_line *bl = browser_line(al);
139a5433b3eSJiri Olsa 	bool current_entry = ui_browser__is_current_entry(browser, row);
14016932d77SArnaldo Carvalho de Melo 	bool change_color = (!notes->options->hide_src_code &&
141a5433b3eSJiri Olsa 			     (!current_entry || (browser->use_navkeypressed &&
142a5433b3eSJiri Olsa 					         !browser->navkeypressed)));
143a5433b3eSJiri Olsa 	int width = browser->width, printed;
1446af612d2SArnaldo Carvalho de Melo 	int i, pcnt_width = annotation__pcnt_width(notes),
1450e83a7e9SArnaldo Carvalho de Melo 	       cycles_width = annotation__cycles_width(notes);
146a5433b3eSJiri Olsa 	double percent_max = 0.0;
147a5433b3eSJiri Olsa 	char bf[256];
148a5433b3eSJiri Olsa 	bool show_title = false;
149a5433b3eSJiri Olsa 
1500553e83dSArnaldo Carvalho de Melo 	for (i = 0; i < notes->nr_events; i++) {
151a5433b3eSJiri Olsa 		if (al->samples[i].percent > percent_max)
152a5433b3eSJiri Olsa 			percent_max = al->samples[i].percent;
153a5433b3eSJiri Olsa 	}
154a5433b3eSJiri Olsa 
155a5433b3eSJiri Olsa 	if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) {
1560e83a7e9SArnaldo Carvalho de Melo 		if (notes->have_cycles) {
157a5433b3eSJiri Olsa 			if (al->ipc == 0.0 && al->cycles == 0)
158a5433b3eSJiri Olsa 				show_title = true;
159a5433b3eSJiri Olsa 		} else
160a5433b3eSJiri Olsa 			show_title = true;
161a5433b3eSJiri Olsa 	}
162a5433b3eSJiri Olsa 
163a5433b3eSJiri Olsa 	if (al->offset != -1 && percent_max != 0.0) {
1640553e83dSArnaldo Carvalho de Melo 		for (i = 0; i < notes->nr_events; i++) {
165a5433b3eSJiri Olsa 			ui_browser__set_percent_color(browser,
166a5433b3eSJiri Olsa 						al->samples[i].percent,
167a5433b3eSJiri Olsa 						current_entry);
16816932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
169a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%11" PRIu64 " ",
170a5433b3eSJiri Olsa 						   al->samples[i].he.period);
17116932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples) {
172a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6" PRIu64 " ",
173a5433b3eSJiri Olsa 						   al->samples[i].he.nr_samples);
174a5433b3eSJiri Olsa 			} else {
175a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6.2f ",
176a5433b3eSJiri Olsa 						   al->samples[i].percent);
177a5433b3eSJiri Olsa 			}
178a5433b3eSJiri Olsa 		}
179a5433b3eSJiri Olsa 	} else {
180a5433b3eSJiri Olsa 		ui_browser__set_percent_color(browser, 0, current_entry);
181a5433b3eSJiri Olsa 
182a5433b3eSJiri Olsa 		if (!show_title)
183a5433b3eSJiri Olsa 			ui_browser__write_nstring(browser, " ", pcnt_width);
184a5433b3eSJiri Olsa 		else {
185a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*s", pcnt_width,
18616932d77SArnaldo Carvalho de Melo 					   notes->options->show_total_period ? "Period" :
18716932d77SArnaldo Carvalho de Melo 					   notes->options->show_nr_samples ? "Samples" : "Percent");
188a5433b3eSJiri Olsa 		}
189a5433b3eSJiri Olsa 	}
1900e83a7e9SArnaldo Carvalho de Melo 	if (notes->have_cycles) {
191a5433b3eSJiri Olsa 		if (al->ipc)
192c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
193a5433b3eSJiri Olsa 		else if (!show_title)
194c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__IPC_WIDTH);
195a5433b3eSJiri Olsa 		else
196c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
197a5433b3eSJiri Olsa 
198a5433b3eSJiri Olsa 		if (al->cycles)
199a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*" PRIu64 " ",
200c426e584SArnaldo Carvalho de Melo 					   ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
201a5433b3eSJiri Olsa 		else if (!show_title)
202c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__CYCLES_WIDTH);
203a5433b3eSJiri Olsa 		else
204c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle");
205a5433b3eSJiri Olsa 	}
206a5433b3eSJiri Olsa 
207a5433b3eSJiri Olsa 	SLsmg_write_char(' ');
208a5433b3eSJiri Olsa 
209a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
210a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
211a5433b3eSJiri Olsa 		width += 1;
212a5433b3eSJiri Olsa 
213a5433b3eSJiri Olsa 	if (!*al->line)
214a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
215a5433b3eSJiri Olsa 	else if (al->offset == -1) {
21616932d77SArnaldo Carvalho de Melo 		if (al->line_nr && notes->options->show_linenr)
217a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
218a5433b3eSJiri Olsa 					ab->addr_width + 1, al->line_nr);
219a5433b3eSJiri Olsa 		else
220a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
221a5433b3eSJiri Olsa 				    ab->addr_width, " ");
222a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
223a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1);
224a5433b3eSJiri Olsa 	} else {
225a5433b3eSJiri Olsa 		u64 addr = al->offset;
226a5433b3eSJiri Olsa 		int color = -1;
227a5433b3eSJiri Olsa 
22816932d77SArnaldo Carvalho de Melo 		if (!notes->options->use_offset)
229a5433b3eSJiri Olsa 			addr += ab->start;
230a5433b3eSJiri Olsa 
23116932d77SArnaldo Carvalho de Melo 		if (!notes->options->use_offset) {
232a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
233a5433b3eSJiri Olsa 		} else {
234a5433b3eSJiri Olsa 			if (bl->jump_sources) {
23516932d77SArnaldo Carvalho de Melo 				if (notes->options->show_nr_jumps) {
236a5433b3eSJiri Olsa 					int prev;
237a5433b3eSJiri Olsa 					printed = scnprintf(bf, sizeof(bf), "%*d ",
238a5433b3eSJiri Olsa 							    ab->jumps_width,
239a5433b3eSJiri Olsa 							    bl->jump_sources);
240a5433b3eSJiri Olsa 					prev = annotate_browser__set_jumps_percent_color(ab, bl->jump_sources,
241a5433b3eSJiri Olsa 											 current_entry);
242a5433b3eSJiri Olsa 					ui_browser__write_nstring(browser, bf, printed);
243a5433b3eSJiri Olsa 					ui_browser__set_color(browser, prev);
244a5433b3eSJiri Olsa 				}
245a5433b3eSJiri Olsa 
246a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
247a5433b3eSJiri Olsa 						    ab->target_width, addr);
248a5433b3eSJiri Olsa 			} else {
249a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
250a5433b3eSJiri Olsa 						    ab->addr_width, " ");
251a5433b3eSJiri Olsa 			}
252a5433b3eSJiri Olsa 		}
253a5433b3eSJiri Olsa 
254a5433b3eSJiri Olsa 		if (change_color)
255a5433b3eSJiri Olsa 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
256a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
257a5433b3eSJiri Olsa 		if (change_color)
258a5433b3eSJiri Olsa 			ui_browser__set_color(browser, color);
259a5433b3eSJiri Olsa 
260a5433b3eSJiri Olsa 		disasm_line__write(disasm_line(al), browser, bf, sizeof(bf));
261a5433b3eSJiri Olsa 
262bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
263aca7a94dSNamhyung Kim 	}
264aca7a94dSNamhyung Kim 
265aca7a94dSNamhyung Kim 	if (current_entry)
266a5433b3eSJiri Olsa 		ab->selection = al;
267aca7a94dSNamhyung Kim }
268aca7a94dSNamhyung Kim 
269865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
270865c66c4SFrederik Deweerdt {
27175b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
272865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
273e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
274e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
275865c66c4SFrederik Deweerdt 		return false;
276865c66c4SFrederik Deweerdt 
277865c66c4SFrederik Deweerdt 	return true;
278865c66c4SFrederik Deweerdt }
279865c66c4SFrederik Deweerdt 
2807e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2817e63a13aSJin Yao {
282a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2837e63a13aSJin Yao 	const char *name;
2847e63a13aSJin Yao 
2857e63a13aSJin Yao 	if (!pos)
2867e63a13aSJin Yao 		return false;
2877e63a13aSJin Yao 
2887e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2897e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2907e63a13aSJin Yao 	else
2917e63a13aSJin Yao 		name = pos->ins.name;
2927e63a13aSJin Yao 
2937e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2947e63a13aSJin Yao 		return false;
2957e63a13aSJin Yao 
2967e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
2977e63a13aSJin Yao }
2987e63a13aSJin Yao 
2999d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
300a3f895beSArnaldo Carvalho de Melo {
301a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3027bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
303a5ef2702SJiri Olsa 	struct annotation_line *target;
3040d957970SJiri Olsa 	struct browser_line *btarget, *bcursor;
30583b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
30632ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
30732ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
3080e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
3096af612d2SArnaldo Carvalho de Melo 	u8 pcnt_width = annotation__pcnt_width(notes);
31000ea0eb2SArnaldo Carvalho de Melo 	int width;
31132ae1efdSNamhyung Kim 
31232ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31332ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31432ae1efdSNamhyung Kim 		return;
315a3f895beSArnaldo Carvalho de Melo 
316865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
317a3f895beSArnaldo Carvalho de Melo 		return;
318a3f895beSArnaldo Carvalho de Melo 
3199c04409dSArnaldo Carvalho de Melo 	/*
3209c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
3219c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
3229c04409dSArnaldo Carvalho de Melo 	 *
3239c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
3249c04409dSArnaldo Carvalho de Melo 	 *
3259c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
3269c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
3279c04409dSArnaldo Carvalho de Melo 	 *
3289c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
3299c04409dSArnaldo Carvalho de Melo 	 *
3309c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
3319c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
3329c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
3339c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
3349c04409dSArnaldo Carvalho de Melo 	 *
3359c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
3369c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
3379c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
3389c04409dSArnaldo Carvalho de Melo 	 */
3399d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
3409c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
3419d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
3429c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
3439c04409dSArnaldo Carvalho de Melo 		return;
3449c04409dSArnaldo Carvalho de Melo 	}
3459d1ef56dSArnaldo Carvalho de Melo 
346a5ef2702SJiri Olsa 	bcursor = browser_line(&cursor->al);
347daf25d43SJiri Olsa 	btarget = browser_line(target);
3489d1ef56dSArnaldo Carvalho de Melo 
34916932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3509d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
351a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
352a3f895beSArnaldo Carvalho de Melo 	} else {
3539d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
354a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
355a3f895beSArnaldo Carvalho de Melo 	}
356a3f895beSArnaldo Carvalho de Melo 
3570e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
358b40982e8SJin Yao 
35978ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
360b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
361b40982e8SJin Yao 				 pcnt_width + 2 + ab->addr_width + width,
362c7e7b610SNamhyung Kim 				 from, to);
3637e63a13aSJin Yao 
3647e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3657e63a13aSJin Yao 		ui_browser__mark_fused(browser,
366b40982e8SJin Yao 				       pcnt_width + 3 + ab->addr_width + width,
3677e63a13aSJin Yao 				       from - 1,
3687e63a13aSJin Yao 				       to > from ? true : false);
3697e63a13aSJin Yao 	}
370a3f895beSArnaldo Carvalho de Melo }
371a3f895beSArnaldo Carvalho de Melo 
372a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
373a3f895beSArnaldo Carvalho de Melo {
37495aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
375a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
3766af612d2SArnaldo Carvalho de Melo 	int pcnt_width = annotation__pcnt_width(notes);
377a3f895beSArnaldo Carvalho de Melo 
37816932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
3799d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
380a3f895beSArnaldo Carvalho de Melo 
38183b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
382c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
383a3f895beSArnaldo Carvalho de Melo 	return ret;
384a3f895beSArnaldo Carvalho de Melo }
385a3f895beSArnaldo Carvalho de Melo 
386b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
387c7e7b610SNamhyung Kim {
388c7e7b610SNamhyung Kim 	int i;
389c7e7b610SNamhyung Kim 
390b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
3910c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
392c7e7b610SNamhyung Kim 			continue;
3930c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
394c7e7b610SNamhyung Kim 	}
395c7e7b610SNamhyung Kim 	return 0;
396c7e7b610SNamhyung Kim }
397c7e7b610SNamhyung Kim 
398b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
399aca7a94dSNamhyung Kim {
40029ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
401aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
4023ab6db8dSJiri Olsa 	struct annotation_line *l;
403aca7a94dSNamhyung Kim 
404aca7a94dSNamhyung Kim 	while (*p != NULL) {
405aca7a94dSNamhyung Kim 		parent = *p;
4063ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
407c7e7b610SNamhyung Kim 
408b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
409aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
410aca7a94dSNamhyung Kim 		else
411aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
412aca7a94dSNamhyung Kim 	}
4133ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
4143ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
415aca7a94dSNamhyung Kim }
416aca7a94dSNamhyung Kim 
41705e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
418ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
419aca7a94dSNamhyung Kim {
420aca7a94dSNamhyung Kim 	unsigned back;
421aca7a94dSNamhyung Kim 
42205e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
42305e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
42405e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
425aca7a94dSNamhyung Kim 
42605e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
427ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
428aca7a94dSNamhyung Kim 
429ec03a77dSJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->node))
430aca7a94dSNamhyung Kim 			continue;
431aca7a94dSNamhyung Kim 
43205e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
433aca7a94dSNamhyung Kim 		--back;
434aca7a94dSNamhyung Kim 	}
435aca7a94dSNamhyung Kim 
436ec03a77dSJiri Olsa 	browser->b.top = pos;
43705e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
438aca7a94dSNamhyung Kim }
439aca7a94dSNamhyung Kim 
440aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
441aca7a94dSNamhyung Kim 					 struct rb_node *nd)
442aca7a94dSNamhyung Kim {
44395aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
4440d957970SJiri Olsa 	struct browser_line *bpos;
445ec03a77dSJiri Olsa 	struct annotation_line *pos;
446a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
447aca7a94dSNamhyung Kim 
448ec03a77dSJiri Olsa 	pos = rb_entry(nd, struct annotation_line, rb_node);
449ec03a77dSJiri Olsa 	bpos = browser_line(pos);
4505b12adc8SJiri Olsa 
451a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
45216932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
453a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
454a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
455aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
456aca7a94dSNamhyung Kim }
457aca7a94dSNamhyung Kim 
458aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
459db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
460aca7a94dSNamhyung Kim {
461aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
462aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
463aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
464c4c72436SJiri Olsa 	struct disasm_line *pos;
465aca7a94dSNamhyung Kim 
466aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
467aca7a94dSNamhyung Kim 
468aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
469aca7a94dSNamhyung Kim 
470e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
471e425da6cSJiri Olsa 
472a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
473c7e7b610SNamhyung Kim 		double max_percent = 0.0;
474c7e7b610SNamhyung Kim 		int i;
475e64aa75bSNamhyung Kim 
476d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
4775b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
478e64aa75bSNamhyung Kim 			continue;
479e64aa75bSNamhyung Kim 		}
480e64aa75bSNamhyung Kim 
481b15636c6SJiri Olsa 		for (i = 0; i < pos->al.samples_nr; i++) {
482e425da6cSJiri Olsa 			struct annotation_data *sample = &pos->al.samples[i];
4830c4a5bceSMartin Liška 
4843ab6db8dSJiri Olsa 			if (max_percent < sample->percent)
4853ab6db8dSJiri Olsa 				max_percent = sample->percent;
486c7e7b610SNamhyung Kim 		}
487c7e7b610SNamhyung Kim 
48837236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
4895b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
490aca7a94dSNamhyung Kim 			continue;
491aca7a94dSNamhyung Kim 		}
492b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
493aca7a94dSNamhyung Kim 	}
494aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
495aca7a94dSNamhyung Kim 
496aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
497aca7a94dSNamhyung Kim }
498aca7a94dSNamhyung Kim 
499aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
500aca7a94dSNamhyung Kim {
50195aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
502ec03a77dSJiri Olsa 	struct annotation_line *al;
503a5ef2702SJiri Olsa 	struct browser_line *bl;
504aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
505aca7a94dSNamhyung Kim 
506aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
507ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
508ec03a77dSJiri Olsa 	bl = browser_line(al);
509aca7a94dSNamhyung Kim 
51016932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
511a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
512a5ef2702SJiri Olsa 			offset = bl->idx;
513aca7a94dSNamhyung Kim 
514aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
51516932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
516aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
517a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx - offset;
518a5ef2702SJiri Olsa 		browser->b.index = bl->idx;
519aca7a94dSNamhyung Kim 	} else {
520a5ef2702SJiri Olsa 		if (bl->idx_asm < 0) {
521aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
522aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
523aca7a94dSNamhyung Kim 			return false;
524aca7a94dSNamhyung Kim 		}
525aca7a94dSNamhyung Kim 
526a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
527a5ef2702SJiri Olsa 			offset = bl->idx_asm;
528aca7a94dSNamhyung Kim 
529aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
53016932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
531aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
532a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx_asm - offset;
533a5ef2702SJiri Olsa 		browser->b.index = bl->idx_asm;
534aca7a94dSNamhyung Kim 	}
535aca7a94dSNamhyung Kim 
536aca7a94dSNamhyung Kim 	return true;
537aca7a94dSNamhyung Kim }
538aca7a94dSNamhyung Kim 
539e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
540e9823b21SArnaldo Carvalho de Melo {
541e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
542e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
543e9823b21SArnaldo Carvalho de Melo }
544e9823b21SArnaldo Carvalho de Melo 
54534f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
54634f77abcSAdrian Hunter 
54734f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
54834f77abcSAdrian Hunter 		     size_t sz)
54934f77abcSAdrian Hunter {
55034f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
55134f77abcSAdrian Hunter }
55234f77abcSAdrian Hunter 
553db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
554db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5559783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
556aca7a94dSNamhyung Kim {
557aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
5587bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
559aca7a94dSNamhyung Kim 	struct annotation *notes;
56034f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
561aca7a94dSNamhyung Kim 
56275b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
563aca7a94dSNamhyung Kim 		return false;
564aca7a94dSNamhyung Kim 
565696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
566aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
567aca7a94dSNamhyung Kim 		return true;
568aca7a94dSNamhyung Kim 	}
569aca7a94dSNamhyung Kim 
570696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
571aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
572aca7a94dSNamhyung Kim 
573696703afSArnaldo Carvalho de Melo 	if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) {
574aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
575aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
576696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
577aca7a94dSNamhyung Kim 		return true;
578aca7a94dSNamhyung Kim 	}
579aca7a94dSNamhyung Kim 
580aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
581696703afSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt);
5821179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
58334f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
584aca7a94dSNamhyung Kim 	return true;
585aca7a94dSNamhyung Kim }
586aca7a94dSNamhyung Kim 
58729ed6e76SArnaldo Carvalho de Melo static
58829ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
589aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
590aca7a94dSNamhyung Kim {
59195aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
59229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
593aca7a94dSNamhyung Kim 
594aca7a94dSNamhyung Kim 	*idx = 0;
595a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
596d5490b96SJiri Olsa 		if (pos->al.offset == offset)
597aca7a94dSNamhyung Kim 			return pos;
598a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
599aca7a94dSNamhyung Kim 			++*idx;
600aca7a94dSNamhyung Kim 	}
601aca7a94dSNamhyung Kim 
602aca7a94dSNamhyung Kim 	return NULL;
603aca7a94dSNamhyung Kim }
604aca7a94dSNamhyung Kim 
605aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
606aca7a94dSNamhyung Kim {
6077bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
6085252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6094f9d0325SArnaldo Carvalho de Melo 	s64 idx;
610aca7a94dSNamhyung Kim 
61175b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
612aca7a94dSNamhyung Kim 		return false;
613aca7a94dSNamhyung Kim 
6145252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6155252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
61629ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6175252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
618aca7a94dSNamhyung Kim 		return true;
619aca7a94dSNamhyung Kim 	}
620aca7a94dSNamhyung Kim 
621ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
622aca7a94dSNamhyung Kim 
623aca7a94dSNamhyung Kim 	return true;
624aca7a94dSNamhyung Kim }
625aca7a94dSNamhyung Kim 
62629ed6e76SArnaldo Carvalho de Melo static
6279213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
628aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
629aca7a94dSNamhyung Kim {
63095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
6319213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
632aca7a94dSNamhyung Kim 
633aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6349213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
6359213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
636aca7a94dSNamhyung Kim 			continue;
637aca7a94dSNamhyung Kim 
638aca7a94dSNamhyung Kim 		++*idx;
639aca7a94dSNamhyung Kim 
6409213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6419213afbdSJiri Olsa 			return al;
642aca7a94dSNamhyung Kim 	}
643aca7a94dSNamhyung Kim 
644aca7a94dSNamhyung Kim 	return NULL;
645aca7a94dSNamhyung Kim }
646aca7a94dSNamhyung Kim 
647aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
648aca7a94dSNamhyung Kim {
6499213afbdSJiri Olsa 	struct annotation_line *al;
650aca7a94dSNamhyung Kim 	s64 idx;
651aca7a94dSNamhyung Kim 
6529213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
6539213afbdSJiri Olsa 	if (al == NULL) {
654aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
655aca7a94dSNamhyung Kim 		return false;
656aca7a94dSNamhyung Kim 	}
657aca7a94dSNamhyung Kim 
658ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
659aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
660aca7a94dSNamhyung Kim 	return true;
661aca7a94dSNamhyung Kim }
662aca7a94dSNamhyung Kim 
66329ed6e76SArnaldo Carvalho de Melo static
6649213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
665aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
666aca7a94dSNamhyung Kim {
66795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
6689213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
669aca7a94dSNamhyung Kim 
670aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6719213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
6729213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
673aca7a94dSNamhyung Kim 			continue;
674aca7a94dSNamhyung Kim 
675aca7a94dSNamhyung Kim 		--*idx;
676aca7a94dSNamhyung Kim 
6779213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6789213afbdSJiri Olsa 			return al;
679aca7a94dSNamhyung Kim 	}
680aca7a94dSNamhyung Kim 
681aca7a94dSNamhyung Kim 	return NULL;
682aca7a94dSNamhyung Kim }
683aca7a94dSNamhyung Kim 
684aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
685aca7a94dSNamhyung Kim {
6869213afbdSJiri Olsa 	struct annotation_line *al;
687aca7a94dSNamhyung Kim 	s64 idx;
688aca7a94dSNamhyung Kim 
6899213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
6909213afbdSJiri Olsa 	if (al == NULL) {
691aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
692aca7a94dSNamhyung Kim 		return false;
693aca7a94dSNamhyung Kim 	}
694aca7a94dSNamhyung Kim 
695ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
696aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
697aca7a94dSNamhyung Kim 	return true;
698aca7a94dSNamhyung Kim }
699aca7a94dSNamhyung Kim 
700aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
701aca7a94dSNamhyung Kim 					    int delay_secs)
702aca7a94dSNamhyung Kim {
703aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
704aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
705aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
706aca7a94dSNamhyung Kim 	    !*browser->search_bf)
707aca7a94dSNamhyung Kim 		return false;
708aca7a94dSNamhyung Kim 
709aca7a94dSNamhyung Kim 	return true;
710aca7a94dSNamhyung Kim }
711aca7a94dSNamhyung Kim 
712aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
713aca7a94dSNamhyung Kim {
714aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
715aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
716aca7a94dSNamhyung Kim 
717aca7a94dSNamhyung Kim 	return false;
718aca7a94dSNamhyung Kim }
719aca7a94dSNamhyung Kim 
720aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
721aca7a94dSNamhyung Kim 					      int delay_secs)
722aca7a94dSNamhyung Kim {
723aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
724aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
725aca7a94dSNamhyung Kim 
726aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
727aca7a94dSNamhyung Kim }
728aca7a94dSNamhyung Kim 
729aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
730aca7a94dSNamhyung Kim 					   int delay_secs)
731aca7a94dSNamhyung Kim {
732aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
733aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
734aca7a94dSNamhyung Kim 
735aca7a94dSNamhyung Kim 	return false;
736aca7a94dSNamhyung Kim }
737aca7a94dSNamhyung Kim 
738aca7a94dSNamhyung Kim static
739aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
740aca7a94dSNamhyung Kim 					       int delay_secs)
741aca7a94dSNamhyung Kim {
742aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
743aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
744aca7a94dSNamhyung Kim 
745aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
746aca7a94dSNamhyung Kim }
747aca7a94dSNamhyung Kim 
748e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
749e9823b21SArnaldo Carvalho de Melo {
75095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
75116932d77SArnaldo Carvalho de Melo 
75216932d77SArnaldo Carvalho de Melo 	if (notes->options->use_offset)
753e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
754e9823b21SArnaldo Carvalho de Melo 	else
755e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
756e9823b21SArnaldo Carvalho de Melo 
757e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
758e9823b21SArnaldo Carvalho de Melo 
75916932d77SArnaldo Carvalho de Melo 	if (notes->options->show_nr_jumps)
760e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
761e9823b21SArnaldo Carvalho de Melo }
762e9823b21SArnaldo Carvalho de Melo 
763db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
764db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7659783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
766aca7a94dSNamhyung Kim {
767aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
76805e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
769aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
77016932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
77154e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7729783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
773aca7a94dSNamhyung Kim 	int key;
77434f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
775aca7a94dSNamhyung Kim 
77634f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
77734f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
778aca7a94dSNamhyung Kim 		return -1;
779aca7a94dSNamhyung Kim 
780db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
781aca7a94dSNamhyung Kim 
78205e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
78305e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
78405e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
785aca7a94dSNamhyung Kim 	}
786aca7a94dSNamhyung Kim 
78705e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
788aca7a94dSNamhyung Kim 
789aca7a94dSNamhyung Kim 	while (1) {
79005e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
791aca7a94dSNamhyung Kim 
792aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
793db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
794aca7a94dSNamhyung Kim 			/*
795aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
796aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
797aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
798aca7a94dSNamhyung Kim 			 */
799aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
800aca7a94dSNamhyung Kim 				nd = NULL;
801aca7a94dSNamhyung Kim 		}
802aca7a94dSNamhyung Kim 
803aca7a94dSNamhyung Kim 		switch (key) {
804aca7a94dSNamhyung Kim 		case K_TIMER:
8059783adf7SNamhyung Kim 			if (hbt)
8069783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
807aca7a94dSNamhyung Kim 
808aca7a94dSNamhyung Kim 			if (delay_secs != 0)
809db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
810aca7a94dSNamhyung Kim 			continue;
811aca7a94dSNamhyung Kim 		case K_TAB:
812aca7a94dSNamhyung Kim 			if (nd != NULL) {
813aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
814aca7a94dSNamhyung Kim 				if (nd == NULL)
81505e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
816aca7a94dSNamhyung Kim 			} else
81705e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
818aca7a94dSNamhyung Kim 			break;
819aca7a94dSNamhyung Kim 		case K_UNTAB:
820d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
821aca7a94dSNamhyung Kim 				nd = rb_next(nd);
822aca7a94dSNamhyung Kim 				if (nd == NULL)
82305e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
824d4913cbdSMarkus Trippelsdorf 			} else
82505e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
826aca7a94dSNamhyung Kim 			break;
82754e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
828aca7a94dSNamhyung Kim 		case 'h':
82905e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
83054e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
83154e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
83254e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8337727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8347727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
835eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
836eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
83754e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
83854e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
83954e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
84054e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
84154e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8423a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
84354e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
844e592488cSAndi Kleen 		"k             Toggle line numbers\n"
84579ee47faSFeng Tang 		"r             Run available scripts\n"
846fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
84754e7a4e8SArnaldo Carvalho de Melo 			continue;
84879ee47faSFeng Tang 		case 'r':
84979ee47faSFeng Tang 			{
85079ee47faSFeng Tang 				script_browse(NULL);
85179ee47faSFeng Tang 				continue;
85279ee47faSFeng Tang 			}
853e592488cSAndi Kleen 		case 'k':
85416932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
855e592488cSAndi Kleen 			break;
85654e7a4e8SArnaldo Carvalho de Melo 		case 'H':
85705e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
858aca7a94dSNamhyung Kim 			break;
859aca7a94dSNamhyung Kim 		case 's':
86005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
861aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
862aca7a94dSNamhyung Kim 			continue;
863aca7a94dSNamhyung Kim 		case 'o':
86416932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
86505e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
866aca7a94dSNamhyung Kim 			continue;
8679d1ef56dSArnaldo Carvalho de Melo 		case 'j':
86816932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
8699d1ef56dSArnaldo Carvalho de Melo 			continue;
8702402e4a9SArnaldo Carvalho de Melo 		case 'J':
87116932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
87205e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
873e9823b21SArnaldo Carvalho de Melo 			continue;
874aca7a94dSNamhyung Kim 		case '/':
87505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
876aca7a94dSNamhyung Kim show_help:
877aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
878aca7a94dSNamhyung Kim 			}
879aca7a94dSNamhyung Kim 			continue;
880aca7a94dSNamhyung Kim 		case 'n':
88105e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
88205e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
88305e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
884aca7a94dSNamhyung Kim 				goto show_help;
885aca7a94dSNamhyung Kim 			continue;
886aca7a94dSNamhyung Kim 		case '?':
88705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
888aca7a94dSNamhyung Kim 				goto show_help;
889aca7a94dSNamhyung Kim 			continue;
890e9823b21SArnaldo Carvalho de Melo 		case 'D': {
891e9823b21SArnaldo Carvalho de Melo 			static int seq;
892e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
893e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
89405e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
89505e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
89605e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
89705e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
89805e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
899e9823b21SArnaldo Carvalho de Melo 		}
900e9823b21SArnaldo Carvalho de Melo 			continue;
901aca7a94dSNamhyung Kim 		case K_ENTER:
902aca7a94dSNamhyung Kim 		case K_RIGHT:
9037bcbcd58SJiri Olsa 		{
9047bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
9057bcbcd58SJiri Olsa 
90605e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
907aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
9087bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
909aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
9107bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
911c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
9127bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
913c4cceae3SArnaldo Carvalho de Melo 				goto out;
9146ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
915db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
916c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9176ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
918c4cceae3SArnaldo Carvalho de Melo 			}
919aca7a94dSNamhyung Kim 			continue;
9207bcbcd58SJiri Olsa 		}
9210c4a5bceSMartin Liška 		case 't':
92216932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
92316932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
92416932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
92516932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
92616932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
9273a555c77STaeung Song 			else
92816932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
9290c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9300c4a5bceSMartin Liška 			continue;
931aca7a94dSNamhyung Kim 		case K_LEFT:
932aca7a94dSNamhyung Kim 		case K_ESC:
933aca7a94dSNamhyung Kim 		case 'q':
934aca7a94dSNamhyung Kim 		case CTRL('c'):
935aca7a94dSNamhyung Kim 			goto out;
936aca7a94dSNamhyung Kim 		default:
937aca7a94dSNamhyung Kim 			continue;
938aca7a94dSNamhyung Kim 		}
939aca7a94dSNamhyung Kim 
940aca7a94dSNamhyung Kim 		if (nd != NULL)
94105e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
942aca7a94dSNamhyung Kim 	}
943aca7a94dSNamhyung Kim out:
94405e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
945aca7a94dSNamhyung Kim 	return key;
946aca7a94dSNamhyung Kim }
947aca7a94dSNamhyung Kim 
948d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
949d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
950d5dbc518SArnaldo Carvalho de Melo {
9519cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9520c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9530c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9549cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9559cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9560c4a5bceSMartin Liška 
957d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
958d5dbc518SArnaldo Carvalho de Melo }
959d5dbc518SArnaldo Carvalho de Melo 
960db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9619783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
962aca7a94dSNamhyung Kim {
963ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
964ed426915SNamhyung Kim 	SLang_reset_tty();
965ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
966ed426915SNamhyung Kim 
967d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
968aca7a94dSNamhyung Kim }
969aca7a94dSNamhyung Kim 
970b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
971b793a401SArnaldo Carvalho de Melo 						size_t size)
972b793a401SArnaldo Carvalho de Melo {
973b793a401SArnaldo Carvalho de Melo 	u64 offset;
97432ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
97532ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
9769d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
97732ae1efdSNamhyung Kim 
97832ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
97932ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
98032ae1efdSNamhyung Kim 		return;
981b793a401SArnaldo Carvalho de Melo 
982b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
9839d6bb41dSArnaldo Carvalho de Melo 		struct annotation_line *al = notes->offsets[offset];
984a5ef2702SJiri Olsa 		struct disasm_line *dl;
985a5ef2702SJiri Olsa 		struct browser_line *blt;
986b793a401SArnaldo Carvalho de Melo 
987e1b60b5bSJiri Olsa 		dl = disasm_line(al);
988e1b60b5bSJiri Olsa 
989865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
990b793a401SArnaldo Carvalho de Melo 			continue;
991b793a401SArnaldo Carvalho de Melo 
9929d6bb41dSArnaldo Carvalho de Melo 		al = notes->offsets[dl->ops.target.offset];
993e1b60b5bSJiri Olsa 
9949481ede9SArnaldo Carvalho de Melo 		/*
9959481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
9969481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
9979481ede9SArnaldo Carvalho de Melo  		 */
998a5ef2702SJiri Olsa 		if (al == NULL)
9999481ede9SArnaldo Carvalho de Melo 			continue;
10009481ede9SArnaldo Carvalho de Melo 
1001a5ef2702SJiri Olsa 		blt = browser_line(al);
1002*bc1c0f3dSArnaldo Carvalho de Melo 		if (++blt->jump_sources > notes->max_jump_sources)
1003*bc1c0f3dSArnaldo Carvalho de Melo 			notes->max_jump_sources = blt->jump_sources;
10042402e4a9SArnaldo Carvalho de Melo 
10052402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1006b793a401SArnaldo Carvalho de Melo 	}
1007b793a401SArnaldo Carvalho de Melo }
1008b793a401SArnaldo Carvalho de Melo 
10092402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10102402e4a9SArnaldo Carvalho de Melo {
10112402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10122402e4a9SArnaldo Carvalho de Melo 		return 5;
10132402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10142402e4a9SArnaldo Carvalho de Melo 		return 2;
10152402e4a9SArnaldo Carvalho de Melo 	return 1;
10162402e4a9SArnaldo Carvalho de Melo }
10172402e4a9SArnaldo Carvalho de Melo 
1018db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1019db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10209783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1021aca7a94dSNamhyung Kim {
1022e1b60b5bSJiri Olsa 	struct annotation_line *al;
10239d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1024c0a58fb2SSamuel Liao 	size_t size;
1025aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1026aca7a94dSNamhyung Kim 		.map = map,
1027aca7a94dSNamhyung Kim 		.sym = sym,
1028aca7a94dSNamhyung Kim 	};
1029aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1030aca7a94dSNamhyung Kim 		.b = {
1031a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1032aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1033aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
103429ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1035aca7a94dSNamhyung Kim 			.priv	 = &ms,
1036aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1037aca7a94dSNamhyung Kim 		},
1038aca7a94dSNamhyung Kim 	};
1039ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1040c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1041aca7a94dSNamhyung Kim 
1042aca7a94dSNamhyung Kim 	if (sym == NULL)
1043aca7a94dSNamhyung Kim 		return -1;
1044aca7a94dSNamhyung Kim 
1045c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1046c0a58fb2SSamuel Liao 
1047aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1048aca7a94dSNamhyung Kim 		return -1;
1049aca7a94dSNamhyung Kim 
105016932d77SArnaldo Carvalho de Melo 	notes->options = &annotate_browser__opts;
105116932d77SArnaldo Carvalho de Melo 
10529d6bb41dSArnaldo Carvalho de Melo 	notes->offsets = zalloc(size * sizeof(struct annotation_line *));
10539d6bb41dSArnaldo Carvalho de Melo 	if (notes->offsets == NULL) {
1054b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1055b793a401SArnaldo Carvalho de Melo 		return -1;
1056b793a401SArnaldo Carvalho de Melo 	}
1057b793a401SArnaldo Carvalho de Melo 
10583ab6db8dSJiri Olsa 	if (perf_evsel__is_group_event(evsel))
1059c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
1060c7e7b610SNamhyung Kim 
10615449f13cSArnaldo Carvalho de Melo 	err = symbol__annotate(sym, map, evsel, sizeof(struct browser_line), &browser.arch);
1062ee51d851SArnaldo Carvalho de Melo 	if (err) {
1063ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1064ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1065ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1066b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1067aca7a94dSNamhyung Kim 	}
1068aca7a94dSNamhyung Kim 
106905d3f1a1SJiri Olsa 	symbol__calc_percent(sym, evsel);
107005d3f1a1SJiri Olsa 
10717727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1072aca7a94dSNamhyung Kim 
1073aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1074aca7a94dSNamhyung Kim 
1075e1b60b5bSJiri Olsa 	list_for_each_entry(al, &notes->src->source, node) {
10760d957970SJiri Olsa 		struct browser_line *bpos;
1077e1b60b5bSJiri Olsa 		size_t line_len = strlen(al->line);
1078aca7a94dSNamhyung Kim 
1079aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1080aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1081a5ef2702SJiri Olsa 		bpos = browser_line(al);
1082887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1083e1b60b5bSJiri Olsa 		if (al->offset != -1) {
1084887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
108597148a97SArnaldo Carvalho de Melo 			/*
108697148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
108797148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
108897148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
108997148a97SArnaldo Carvalho de Melo 			 *
109097148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
109197148a97SArnaldo Carvalho de Melo  			 */
1092e1b60b5bSJiri Olsa 			if (al->offset < (s64)size)
10939d6bb41dSArnaldo Carvalho de Melo 				notes->offsets[al->offset] = al;
1094b793a401SArnaldo Carvalho de Melo 		} else
1095887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1096aca7a94dSNamhyung Kim 	}
1097aca7a94dSNamhyung Kim 
1098b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
1099f56c083bSArnaldo Carvalho de Melo 	annotation__compute_ipc(notes, size);
1100b793a401SArnaldo Carvalho de Melo 
11012402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
110283b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
1103*bc1c0f3dSArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(notes->max_jump_sources);
11040553e83dSArnaldo Carvalho de Melo 	notes->nr_events = nr_pcnt;
1105aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1106aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1107aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1108e9823b21SArnaldo Carvalho de Melo 
110916932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
1110e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1111e9823b21SArnaldo Carvalho de Melo 
1112e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1113e9823b21SArnaldo Carvalho de Melo 
1114db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1115f8eb37bdSJiri Olsa 
1116f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
1117b793a401SArnaldo Carvalho de Melo 
1118b793a401SArnaldo Carvalho de Melo out_free_offsets:
11199d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
1120aca7a94dSNamhyung Kim 	return ret;
1121aca7a94dSNamhyung Kim }
1122c323cf04SArnaldo Carvalho de Melo 
1123c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1124c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1125c323cf04SArnaldo Carvalho de Melo 
1126c323cf04SArnaldo Carvalho de Melo /*
1127c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1128c323cf04SArnaldo Carvalho de Melo  */
11297c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1130c323cf04SArnaldo Carvalho de Melo 	const char *name;
1131c323cf04SArnaldo Carvalho de Melo 	bool *value;
1132c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1133c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1134c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1135e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1136c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11379cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
11380c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
113939ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1140c323cf04SArnaldo Carvalho de Melo };
1141c323cf04SArnaldo Carvalho de Melo 
1142c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1143c323cf04SArnaldo Carvalho de Melo 
1144c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1145c323cf04SArnaldo Carvalho de Melo {
11467c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1147c323cf04SArnaldo Carvalho de Melo 
1148c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1149c323cf04SArnaldo Carvalho de Melo }
1150c323cf04SArnaldo Carvalho de Melo 
11511d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11521d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1153c323cf04SArnaldo Carvalho de Melo {
11547c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1155c323cf04SArnaldo Carvalho de Melo 	const char *name;
1156c323cf04SArnaldo Carvalho de Melo 
11578e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1158c323cf04SArnaldo Carvalho de Melo 		return 0;
1159c323cf04SArnaldo Carvalho de Melo 
1160c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1161c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
11627c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1163c323cf04SArnaldo Carvalho de Melo 
1164c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1165f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1166f06cff7cSArnaldo Carvalho de Melo 	else
1167c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1168c323cf04SArnaldo Carvalho de Melo 	return 0;
1169c323cf04SArnaldo Carvalho de Melo }
1170c323cf04SArnaldo Carvalho de Melo 
1171c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1172c323cf04SArnaldo Carvalho de Melo {
1173c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1174c323cf04SArnaldo Carvalho de Melo }
1175