xref: /linux/tools/perf/ui/browsers/annotate.c (revision 00ea0eb21e9ba38636608e3eb0ac332fc022d5bb)
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;
43e1b60b5bSJiri Olsa 	struct annotation_line	  **offsets;
44dcaa3948SJin Yao 	struct arch		   *arch;
45c7e7b610SNamhyung Kim 	int			    nr_events;
46aca7a94dSNamhyung Kim 	u64			    start;
47aca7a94dSNamhyung Kim 	int			    nr_asm_entries;
48aca7a94dSNamhyung Kim 	int			    nr_entries;
492402e4a9SArnaldo Carvalho de Melo 	int			    max_jump_sources;
502402e4a9SArnaldo Carvalho de Melo 	int			    nr_jumps;
51aca7a94dSNamhyung Kim 	bool			    searching_backwards;
5230e863bbSAndi Kleen 	bool			    have_cycles;
5383b1f2aaSArnaldo Carvalho de Melo 	u8			    addr_width;
542402e4a9SArnaldo Carvalho de Melo 	u8			    jumps_width;
552402e4a9SArnaldo Carvalho de Melo 	u8			    target_width;
5683b1f2aaSArnaldo Carvalho de Melo 	u8			    min_addr_width;
5783b1f2aaSArnaldo Carvalho de Melo 	u8			    max_addr_width;
58aca7a94dSNamhyung Kim 	char			    search_bf[128];
59aca7a94dSNamhyung Kim };
60aca7a94dSNamhyung Kim 
61a5ef2702SJiri Olsa static inline struct browser_line *browser_line(struct annotation_line *al)
62aca7a94dSNamhyung Kim {
63a5ef2702SJiri Olsa 	void *ptr = al;
64a5ef2702SJiri Olsa 
65a5ef2702SJiri Olsa 	ptr = container_of(al, struct disasm_line, al);
66a5ef2702SJiri Olsa 	return ptr - sizeof(struct browser_line);
67aca7a94dSNamhyung Kim }
68aca7a94dSNamhyung Kim 
691d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
701d037ca1SIrina Tirdea 				void *entry)
71aca7a94dSNamhyung Kim {
72e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
73d5490b96SJiri Olsa 		struct annotation_line *al = list_entry(entry, struct annotation_line, node);
74d5490b96SJiri Olsa 
75d5490b96SJiri Olsa 		return al->offset == -1;
76aca7a94dSNamhyung Kim 	}
77aca7a94dSNamhyung Kim 
78aca7a94dSNamhyung Kim 	return false;
79aca7a94dSNamhyung Kim }
80aca7a94dSNamhyung Kim 
812402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
822402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
832402e4a9SArnaldo Carvalho de Melo {
842402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
852402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
862402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
872402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
882402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
892402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
902402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
912402e4a9SArnaldo Carvalho de Melo }
922402e4a9SArnaldo Carvalho de Melo 
932402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
942402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
952402e4a9SArnaldo Carvalho de Melo {
962402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
972402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
982402e4a9SArnaldo Carvalho de Melo }
992402e4a9SArnaldo Carvalho de Melo 
100f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
101f8f4aaeaSAndi Kleen {
1023861c4a4SArnaldo Carvalho de Melo 	return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events;
103bc1e5d60SArnaldo Carvalho de Melo }
104f8f4aaeaSAndi Kleen 
105bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab)
106bc1e5d60SArnaldo Carvalho de Melo {
107c426e584SArnaldo Carvalho de Melo 	return ab->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
108f8f4aaeaSAndi Kleen }
109f8f4aaeaSAndi Kleen 
110a5433b3eSJiri Olsa static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser,
111a5433b3eSJiri Olsa 			       char *bf, size_t size)
112aca7a94dSNamhyung Kim {
11375b49202SArnaldo Carvalho de Melo 	if (dl->ins.ops && dl->ins.ops->scnprintf) {
11475b49202SArnaldo Carvalho de Melo 		if (ins__is_jump(&dl->ins)) {
115d5490b96SJiri Olsa 			bool fwd = dl->ops.target.offset > dl->al.offset;
11651a0d455SArnaldo Carvalho de Melo 
11705e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
11851a0d455SArnaldo Carvalho de Melo 							    SLSMG_UARROW_CHAR);
11951a0d455SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
12075b49202SArnaldo Carvalho de Melo 		} else if (ins__is_call(&dl->ins)) {
12105e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
12288298f5aSArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
12375b49202SArnaldo Carvalho de Melo 		} else if (ins__is_ret(&dl->ins)) {
12405e8b080SArnaldo Carvalho de Melo 			ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
1254ea08b52SArnaldo Carvalho de Melo 			SLsmg_write_char(' ');
1266ef94929SNaveen N. Rao 		} else {
1276ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
1284ea08b52SArnaldo Carvalho de Melo 		}
1296ef94929SNaveen N. Rao 	} else {
1306ef94929SNaveen N. Rao 		ui_browser__write_nstring(browser, " ", 2);
1314ea08b52SArnaldo Carvalho de Melo 	}
1324ea08b52SArnaldo Carvalho de Melo 
133a5433b3eSJiri Olsa 	disasm_line__scnprintf(dl, bf, size, !annotate_browser__opts.use_offset);
134a5433b3eSJiri Olsa }
135a5433b3eSJiri Olsa 
136a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
137a5433b3eSJiri Olsa {
138a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
139a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
140a5433b3eSJiri Olsa 	struct browser_line *bl = browser_line(al);
141a5433b3eSJiri Olsa 	bool current_entry = ui_browser__is_current_entry(browser, row);
142a5433b3eSJiri Olsa 	bool change_color = (!annotate_browser__opts.hide_src_code &&
143a5433b3eSJiri Olsa 			     (!current_entry || (browser->use_navkeypressed &&
144a5433b3eSJiri Olsa 					         !browser->navkeypressed)));
145a5433b3eSJiri Olsa 	int width = browser->width, printed;
146a5433b3eSJiri Olsa 	int i, pcnt_width = annotate_browser__pcnt_width(ab),
147a5433b3eSJiri Olsa 	       cycles_width = annotate_browser__cycles_width(ab);
148a5433b3eSJiri Olsa 	double percent_max = 0.0;
149a5433b3eSJiri Olsa 	char bf[256];
150a5433b3eSJiri Olsa 	bool show_title = false;
151a5433b3eSJiri Olsa 
152a5433b3eSJiri Olsa 	for (i = 0; i < ab->nr_events; i++) {
153a5433b3eSJiri Olsa 		if (al->samples[i].percent > percent_max)
154a5433b3eSJiri Olsa 			percent_max = al->samples[i].percent;
155a5433b3eSJiri Olsa 	}
156a5433b3eSJiri Olsa 
157a5433b3eSJiri Olsa 	if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) {
158a5433b3eSJiri Olsa 		if (ab->have_cycles) {
159a5433b3eSJiri Olsa 			if (al->ipc == 0.0 && al->cycles == 0)
160a5433b3eSJiri Olsa 				show_title = true;
161a5433b3eSJiri Olsa 		} else
162a5433b3eSJiri Olsa 			show_title = true;
163a5433b3eSJiri Olsa 	}
164a5433b3eSJiri Olsa 
165a5433b3eSJiri Olsa 	if (al->offset != -1 && percent_max != 0.0) {
166a5433b3eSJiri Olsa 		for (i = 0; i < ab->nr_events; i++) {
167a5433b3eSJiri Olsa 			ui_browser__set_percent_color(browser,
168a5433b3eSJiri Olsa 						al->samples[i].percent,
169a5433b3eSJiri Olsa 						current_entry);
170a5433b3eSJiri Olsa 			if (annotate_browser__opts.show_total_period) {
171a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%11" PRIu64 " ",
172a5433b3eSJiri Olsa 						   al->samples[i].he.period);
173a5433b3eSJiri Olsa 			} else if (annotate_browser__opts.show_nr_samples) {
174a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6" PRIu64 " ",
175a5433b3eSJiri Olsa 						   al->samples[i].he.nr_samples);
176a5433b3eSJiri Olsa 			} else {
177a5433b3eSJiri Olsa 				ui_browser__printf(browser, "%6.2f ",
178a5433b3eSJiri Olsa 						   al->samples[i].percent);
179a5433b3eSJiri Olsa 			}
180a5433b3eSJiri Olsa 		}
181a5433b3eSJiri Olsa 	} else {
182a5433b3eSJiri Olsa 		ui_browser__set_percent_color(browser, 0, current_entry);
183a5433b3eSJiri Olsa 
184a5433b3eSJiri Olsa 		if (!show_title)
185a5433b3eSJiri Olsa 			ui_browser__write_nstring(browser, " ", pcnt_width);
186a5433b3eSJiri Olsa 		else {
187a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*s", pcnt_width,
188a5433b3eSJiri Olsa 					   annotate_browser__opts.show_total_period ? "Period" :
189a5433b3eSJiri Olsa 					   annotate_browser__opts.show_nr_samples ? "Samples" : "Percent");
190a5433b3eSJiri Olsa 		}
191a5433b3eSJiri Olsa 	}
192a5433b3eSJiri Olsa 	if (ab->have_cycles) {
193a5433b3eSJiri Olsa 		if (al->ipc)
194c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
195a5433b3eSJiri Olsa 		else if (!show_title)
196c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__IPC_WIDTH);
197a5433b3eSJiri Olsa 		else
198c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
199a5433b3eSJiri Olsa 
200a5433b3eSJiri Olsa 		if (al->cycles)
201a5433b3eSJiri Olsa 			ui_browser__printf(browser, "%*" PRIu64 " ",
202c426e584SArnaldo Carvalho de Melo 					   ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
203a5433b3eSJiri Olsa 		else if (!show_title)
204c426e584SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", ANNOTATION__CYCLES_WIDTH);
205a5433b3eSJiri Olsa 		else
206c426e584SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle");
207a5433b3eSJiri Olsa 	}
208a5433b3eSJiri Olsa 
209a5433b3eSJiri Olsa 	SLsmg_write_char(' ');
210a5433b3eSJiri Olsa 
211a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
212a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
213a5433b3eSJiri Olsa 		width += 1;
214a5433b3eSJiri Olsa 
215a5433b3eSJiri Olsa 	if (!*al->line)
216a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
217a5433b3eSJiri Olsa 	else if (al->offset == -1) {
218a5433b3eSJiri Olsa 		if (al->line_nr && annotate_browser__opts.show_linenr)
219a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
220a5433b3eSJiri Olsa 					ab->addr_width + 1, al->line_nr);
221a5433b3eSJiri Olsa 		else
222a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
223a5433b3eSJiri Olsa 				    ab->addr_width, " ");
224a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
225a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1);
226a5433b3eSJiri Olsa 	} else {
227a5433b3eSJiri Olsa 		u64 addr = al->offset;
228a5433b3eSJiri Olsa 		int color = -1;
229a5433b3eSJiri Olsa 
230a5433b3eSJiri Olsa 		if (!annotate_browser__opts.use_offset)
231a5433b3eSJiri Olsa 			addr += ab->start;
232a5433b3eSJiri Olsa 
233a5433b3eSJiri Olsa 		if (!annotate_browser__opts.use_offset) {
234a5433b3eSJiri Olsa 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
235a5433b3eSJiri Olsa 		} else {
236a5433b3eSJiri Olsa 			if (bl->jump_sources) {
237a5433b3eSJiri Olsa 				if (annotate_browser__opts.show_nr_jumps) {
238a5433b3eSJiri Olsa 					int prev;
239a5433b3eSJiri Olsa 					printed = scnprintf(bf, sizeof(bf), "%*d ",
240a5433b3eSJiri Olsa 							    ab->jumps_width,
241a5433b3eSJiri Olsa 							    bl->jump_sources);
242a5433b3eSJiri Olsa 					prev = annotate_browser__set_jumps_percent_color(ab, bl->jump_sources,
243a5433b3eSJiri Olsa 											 current_entry);
244a5433b3eSJiri Olsa 					ui_browser__write_nstring(browser, bf, printed);
245a5433b3eSJiri Olsa 					ui_browser__set_color(browser, prev);
246a5433b3eSJiri Olsa 				}
247a5433b3eSJiri Olsa 
248a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
249a5433b3eSJiri Olsa 						    ab->target_width, addr);
250a5433b3eSJiri Olsa 			} else {
251a5433b3eSJiri Olsa 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
252a5433b3eSJiri Olsa 						    ab->addr_width, " ");
253a5433b3eSJiri Olsa 			}
254a5433b3eSJiri Olsa 		}
255a5433b3eSJiri Olsa 
256a5433b3eSJiri Olsa 		if (change_color)
257a5433b3eSJiri Olsa 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
258a5433b3eSJiri Olsa 		ui_browser__write_nstring(browser, bf, printed);
259a5433b3eSJiri Olsa 		if (change_color)
260a5433b3eSJiri Olsa 			ui_browser__set_color(browser, color);
261a5433b3eSJiri Olsa 
262a5433b3eSJiri Olsa 		disasm_line__write(disasm_line(al), browser, bf, sizeof(bf));
263a5433b3eSJiri Olsa 
264bc1e5d60SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
265aca7a94dSNamhyung Kim 	}
266aca7a94dSNamhyung Kim 
267aca7a94dSNamhyung Kim 	if (current_entry)
268a5433b3eSJiri Olsa 		ab->selection = al;
269aca7a94dSNamhyung Kim }
270aca7a94dSNamhyung Kim 
271865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
272865c66c4SFrederik Deweerdt {
27375b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
274865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
275e216874cSRavi Bangoria 	    || dl->ops.target.offset < 0
276e216874cSRavi Bangoria 	    || dl->ops.target.offset >= (s64)symbol__size(sym))
277865c66c4SFrederik Deweerdt 		return false;
278865c66c4SFrederik Deweerdt 
279865c66c4SFrederik Deweerdt 	return true;
280865c66c4SFrederik Deweerdt }
281865c66c4SFrederik Deweerdt 
2827e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
2837e63a13aSJin Yao {
284a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
2857e63a13aSJin Yao 	const char *name;
2867e63a13aSJin Yao 
2877e63a13aSJin Yao 	if (!pos)
2887e63a13aSJin Yao 		return false;
2897e63a13aSJin Yao 
2907e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
2917e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
2927e63a13aSJin Yao 	else
2937e63a13aSJin Yao 		name = pos->ins.name;
2947e63a13aSJin Yao 
2957e63a13aSJin Yao 	if (!name || !cursor->ins.name)
2967e63a13aSJin Yao 		return false;
2977e63a13aSJin Yao 
2987e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
2997e63a13aSJin Yao }
3007e63a13aSJin Yao 
3019d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
302a3f895beSArnaldo Carvalho de Melo {
303a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
3047bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
305a5ef2702SJiri Olsa 	struct annotation_line *target;
3060d957970SJiri Olsa 	struct browser_line *btarget, *bcursor;
30783b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
30832ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
30932ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
310f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
311*00ea0eb2SArnaldo Carvalho de Melo 	int width;
31232ae1efdSNamhyung Kim 
31332ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
31432ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
31532ae1efdSNamhyung Kim 		return;
316a3f895beSArnaldo Carvalho de Melo 
317865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
318a3f895beSArnaldo Carvalho de Melo 		return;
319a3f895beSArnaldo Carvalho de Melo 
3209c04409dSArnaldo Carvalho de Melo 	/*
3219c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
3229c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
3239c04409dSArnaldo Carvalho de Melo 	 *
3249c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
3259c04409dSArnaldo Carvalho de Melo 	 *
3269c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
3279c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
3289c04409dSArnaldo Carvalho de Melo 	 *
3299c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
3309c04409dSArnaldo Carvalho de Melo 	 *
3319c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
3329c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
3339c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
3349c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
3359c04409dSArnaldo Carvalho de Melo 	 *
3369c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
3379c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
3389c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
3399c04409dSArnaldo Carvalho de Melo 	 */
340a5ef2702SJiri Olsa 	target = ab->offsets[cursor->ops.target.offset];
3419c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
3429c04409dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n",
3439c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
3449c04409dSArnaldo Carvalho de Melo 		return;
3459c04409dSArnaldo Carvalho de Melo 	}
3469d1ef56dSArnaldo Carvalho de Melo 
347a5ef2702SJiri Olsa 	bcursor = browser_line(&cursor->al);
348daf25d43SJiri Olsa 	btarget = browser_line(target);
3499d1ef56dSArnaldo Carvalho de Melo 
350e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
3519d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
352a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
353a3f895beSArnaldo Carvalho de Melo 	} else {
3549d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
355a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
356a3f895beSArnaldo Carvalho de Melo 	}
357a3f895beSArnaldo Carvalho de Melo 
358*00ea0eb2SArnaldo Carvalho de Melo 	width = annotate_browser__cycles_width(ab);
359b40982e8SJin Yao 
36078ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
361b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
362b40982e8SJin Yao 				 pcnt_width + 2 + ab->addr_width + width,
363c7e7b610SNamhyung Kim 				 from, to);
3647e63a13aSJin Yao 
3657e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
3667e63a13aSJin Yao 		ui_browser__mark_fused(browser,
367b40982e8SJin Yao 				       pcnt_width + 3 + ab->addr_width + width,
3687e63a13aSJin Yao 				       from - 1,
3697e63a13aSJin Yao 				       to > from ? true : false);
3707e63a13aSJin Yao 	}
371a3f895beSArnaldo Carvalho de Melo }
372a3f895beSArnaldo Carvalho de Melo 
373a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
374a3f895beSArnaldo Carvalho de Melo {
375c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
376a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
377f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
378a3f895beSArnaldo Carvalho de Melo 
379e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
3809d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
381a3f895beSArnaldo Carvalho de Melo 
38283b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
383c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
384a3f895beSArnaldo Carvalho de Melo 	return ret;
385a3f895beSArnaldo Carvalho de Melo }
386a3f895beSArnaldo Carvalho de Melo 
387b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
388c7e7b610SNamhyung Kim {
389c7e7b610SNamhyung Kim 	int i;
390c7e7b610SNamhyung Kim 
391b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
3920c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
393c7e7b610SNamhyung Kim 			continue;
3940c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
395c7e7b610SNamhyung Kim 	}
396c7e7b610SNamhyung Kim 	return 0;
397c7e7b610SNamhyung Kim }
398c7e7b610SNamhyung Kim 
399b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
400aca7a94dSNamhyung Kim {
40129ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
402aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
4033ab6db8dSJiri Olsa 	struct annotation_line *l;
404aca7a94dSNamhyung Kim 
405aca7a94dSNamhyung Kim 	while (*p != NULL) {
406aca7a94dSNamhyung Kim 		parent = *p;
4073ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
408c7e7b610SNamhyung Kim 
409b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
410aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
411aca7a94dSNamhyung Kim 		else
412aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
413aca7a94dSNamhyung Kim 	}
4143ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
4153ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
416aca7a94dSNamhyung Kim }
417aca7a94dSNamhyung Kim 
41805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
419ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
420aca7a94dSNamhyung Kim {
421aca7a94dSNamhyung Kim 	unsigned back;
422aca7a94dSNamhyung Kim 
42305e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
42405e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
42505e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
426aca7a94dSNamhyung Kim 
42705e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
428ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
429aca7a94dSNamhyung Kim 
430ec03a77dSJiri Olsa 		if (disasm_line__filter(&browser->b, &pos->node))
431aca7a94dSNamhyung Kim 			continue;
432aca7a94dSNamhyung Kim 
43305e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
434aca7a94dSNamhyung Kim 		--back;
435aca7a94dSNamhyung Kim 	}
436aca7a94dSNamhyung Kim 
437ec03a77dSJiri Olsa 	browser->b.top = pos;
43805e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
439aca7a94dSNamhyung Kim }
440aca7a94dSNamhyung Kim 
441aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
442aca7a94dSNamhyung Kim 					 struct rb_node *nd)
443aca7a94dSNamhyung Kim {
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;
452e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.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 {
501ec03a77dSJiri Olsa 	struct annotation_line *al;
502a5ef2702SJiri Olsa 	struct browser_line *bl;
503aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
504aca7a94dSNamhyung Kim 
505aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
506ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
507ec03a77dSJiri Olsa 	bl = browser_line(al);
508aca7a94dSNamhyung Kim 
509e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
510a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
511a5ef2702SJiri Olsa 			offset = bl->idx;
512aca7a94dSNamhyung Kim 
513aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
514e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
515aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
516a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx - offset;
517a5ef2702SJiri Olsa 		browser->b.index = bl->idx;
518aca7a94dSNamhyung Kim 	} else {
519a5ef2702SJiri Olsa 		if (bl->idx_asm < 0) {
520aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
521aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
522aca7a94dSNamhyung Kim 			return false;
523aca7a94dSNamhyung Kim 		}
524aca7a94dSNamhyung Kim 
525a5ef2702SJiri Olsa 		if (bl->idx_asm < offset)
526a5ef2702SJiri Olsa 			offset = bl->idx_asm;
527aca7a94dSNamhyung Kim 
528aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
529e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
530aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
531a5ef2702SJiri Olsa 		browser->b.top_idx = bl->idx_asm - offset;
532a5ef2702SJiri Olsa 		browser->b.index = bl->idx_asm;
533aca7a94dSNamhyung Kim 	}
534aca7a94dSNamhyung Kim 
535aca7a94dSNamhyung Kim 	return true;
536aca7a94dSNamhyung Kim }
537aca7a94dSNamhyung Kim 
538e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
539e9823b21SArnaldo Carvalho de Melo {
540e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
541e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
542e9823b21SArnaldo Carvalho de Melo }
543e9823b21SArnaldo Carvalho de Melo 
54434f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
54534f77abcSAdrian Hunter 
54634f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
54734f77abcSAdrian Hunter 		     size_t sz)
54834f77abcSAdrian Hunter {
54934f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
55034f77abcSAdrian Hunter }
55134f77abcSAdrian Hunter 
552db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
553db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
5549783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
555aca7a94dSNamhyung Kim {
556aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
5577bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
558aca7a94dSNamhyung Kim 	struct annotation *notes;
55934f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
560aca7a94dSNamhyung Kim 
56175b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
562aca7a94dSNamhyung Kim 		return false;
563aca7a94dSNamhyung Kim 
564696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
565aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
566aca7a94dSNamhyung Kim 		return true;
567aca7a94dSNamhyung Kim 	}
568aca7a94dSNamhyung Kim 
569696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
570aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
571aca7a94dSNamhyung Kim 
572696703afSArnaldo Carvalho de Melo 	if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) {
573aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
574aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
575696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
576aca7a94dSNamhyung Kim 		return true;
577aca7a94dSNamhyung Kim 	}
578aca7a94dSNamhyung Kim 
579aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
580696703afSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt);
5811179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
58234f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
583aca7a94dSNamhyung Kim 	return true;
584aca7a94dSNamhyung Kim }
585aca7a94dSNamhyung Kim 
58629ed6e76SArnaldo Carvalho de Melo static
58729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
588aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
589aca7a94dSNamhyung Kim {
590aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
591aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
592aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
59329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
594aca7a94dSNamhyung Kim 
595aca7a94dSNamhyung Kim 	*idx = 0;
596a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
597d5490b96SJiri Olsa 		if (pos->al.offset == offset)
598aca7a94dSNamhyung Kim 			return pos;
599a17c4ca0SJiri Olsa 		if (!disasm_line__filter(&browser->b, &pos->al.node))
600aca7a94dSNamhyung Kim 			++*idx;
601aca7a94dSNamhyung Kim 	}
602aca7a94dSNamhyung Kim 
603aca7a94dSNamhyung Kim 	return NULL;
604aca7a94dSNamhyung Kim }
605aca7a94dSNamhyung Kim 
606aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
607aca7a94dSNamhyung Kim {
6087bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
6095252b1aeSArnaldo Carvalho de Melo 	u64 offset;
6104f9d0325SArnaldo Carvalho de Melo 	s64 idx;
611aca7a94dSNamhyung Kim 
61275b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
613aca7a94dSNamhyung Kim 		return false;
614aca7a94dSNamhyung Kim 
6155252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
6165252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
61729ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
6185252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
619aca7a94dSNamhyung Kim 		return true;
620aca7a94dSNamhyung Kim 	}
621aca7a94dSNamhyung Kim 
622ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
623aca7a94dSNamhyung Kim 
624aca7a94dSNamhyung Kim 	return true;
625aca7a94dSNamhyung Kim }
626aca7a94dSNamhyung Kim 
62729ed6e76SArnaldo Carvalho de Melo static
6289213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
629aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
630aca7a94dSNamhyung Kim {
631aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
632aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
633aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
6349213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
635aca7a94dSNamhyung Kim 
636aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6379213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
6389213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
639aca7a94dSNamhyung Kim 			continue;
640aca7a94dSNamhyung Kim 
641aca7a94dSNamhyung Kim 		++*idx;
642aca7a94dSNamhyung Kim 
6439213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6449213afbdSJiri Olsa 			return al;
645aca7a94dSNamhyung Kim 	}
646aca7a94dSNamhyung Kim 
647aca7a94dSNamhyung Kim 	return NULL;
648aca7a94dSNamhyung Kim }
649aca7a94dSNamhyung Kim 
650aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
651aca7a94dSNamhyung Kim {
6529213afbdSJiri Olsa 	struct annotation_line *al;
653aca7a94dSNamhyung Kim 	s64 idx;
654aca7a94dSNamhyung Kim 
6559213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
6569213afbdSJiri Olsa 	if (al == NULL) {
657aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
658aca7a94dSNamhyung Kim 		return false;
659aca7a94dSNamhyung Kim 	}
660aca7a94dSNamhyung Kim 
661ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
662aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
663aca7a94dSNamhyung Kim 	return true;
664aca7a94dSNamhyung Kim }
665aca7a94dSNamhyung Kim 
66629ed6e76SArnaldo Carvalho de Melo static
6679213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
668aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
669aca7a94dSNamhyung Kim {
670aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
671aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
672aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
6739213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
674aca7a94dSNamhyung Kim 
675aca7a94dSNamhyung Kim 	*idx = browser->b.index;
6769213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
6779213afbdSJiri Olsa 		if (disasm_line__filter(&browser->b, &al->node))
678aca7a94dSNamhyung Kim 			continue;
679aca7a94dSNamhyung Kim 
680aca7a94dSNamhyung Kim 		--*idx;
681aca7a94dSNamhyung Kim 
6829213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
6839213afbdSJiri Olsa 			return al;
684aca7a94dSNamhyung Kim 	}
685aca7a94dSNamhyung Kim 
686aca7a94dSNamhyung Kim 	return NULL;
687aca7a94dSNamhyung Kim }
688aca7a94dSNamhyung Kim 
689aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
690aca7a94dSNamhyung Kim {
6919213afbdSJiri Olsa 	struct annotation_line *al;
692aca7a94dSNamhyung Kim 	s64 idx;
693aca7a94dSNamhyung Kim 
6949213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
6959213afbdSJiri Olsa 	if (al == NULL) {
696aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
697aca7a94dSNamhyung Kim 		return false;
698aca7a94dSNamhyung Kim 	}
699aca7a94dSNamhyung Kim 
700ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
701aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
702aca7a94dSNamhyung Kim 	return true;
703aca7a94dSNamhyung Kim }
704aca7a94dSNamhyung Kim 
705aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
706aca7a94dSNamhyung Kim 					    int delay_secs)
707aca7a94dSNamhyung Kim {
708aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
709aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
710aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
711aca7a94dSNamhyung Kim 	    !*browser->search_bf)
712aca7a94dSNamhyung Kim 		return false;
713aca7a94dSNamhyung Kim 
714aca7a94dSNamhyung Kim 	return true;
715aca7a94dSNamhyung Kim }
716aca7a94dSNamhyung Kim 
717aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
718aca7a94dSNamhyung Kim {
719aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
720aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
721aca7a94dSNamhyung Kim 
722aca7a94dSNamhyung Kim 	return false;
723aca7a94dSNamhyung Kim }
724aca7a94dSNamhyung Kim 
725aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
726aca7a94dSNamhyung Kim 					      int delay_secs)
727aca7a94dSNamhyung Kim {
728aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
729aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
730aca7a94dSNamhyung Kim 
731aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
732aca7a94dSNamhyung Kim }
733aca7a94dSNamhyung Kim 
734aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
735aca7a94dSNamhyung Kim 					   int delay_secs)
736aca7a94dSNamhyung Kim {
737aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
738aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
739aca7a94dSNamhyung Kim 
740aca7a94dSNamhyung Kim 	return false;
741aca7a94dSNamhyung Kim }
742aca7a94dSNamhyung Kim 
743aca7a94dSNamhyung Kim static
744aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
745aca7a94dSNamhyung Kim 					       int delay_secs)
746aca7a94dSNamhyung Kim {
747aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
748aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
749aca7a94dSNamhyung Kim 
750aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
751aca7a94dSNamhyung Kim }
752aca7a94dSNamhyung Kim 
753e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
754e9823b21SArnaldo Carvalho de Melo {
755e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
756e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
757e9823b21SArnaldo Carvalho de Melo 	else
758e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
759e9823b21SArnaldo Carvalho de Melo 
760e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
761e9823b21SArnaldo Carvalho de Melo 
762e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
763e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
764e9823b21SArnaldo Carvalho de Melo }
765e9823b21SArnaldo Carvalho de Melo 
766db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
767db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7689783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
769aca7a94dSNamhyung Kim {
770aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
77105e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
772aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
77354e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7749783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
775aca7a94dSNamhyung Kim 	int key;
77634f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
777aca7a94dSNamhyung Kim 
77834f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
77934f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
780aca7a94dSNamhyung Kim 		return -1;
781aca7a94dSNamhyung Kim 
782db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
783aca7a94dSNamhyung Kim 
78405e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
78505e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
78605e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
787aca7a94dSNamhyung Kim 	}
788aca7a94dSNamhyung Kim 
78905e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
790aca7a94dSNamhyung Kim 
791aca7a94dSNamhyung Kim 	while (1) {
79205e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
793aca7a94dSNamhyung Kim 
794aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
795db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
796aca7a94dSNamhyung Kim 			/*
797aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
798aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
799aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
800aca7a94dSNamhyung Kim 			 */
801aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
802aca7a94dSNamhyung Kim 				nd = NULL;
803aca7a94dSNamhyung Kim 		}
804aca7a94dSNamhyung Kim 
805aca7a94dSNamhyung Kim 		switch (key) {
806aca7a94dSNamhyung Kim 		case K_TIMER:
8079783adf7SNamhyung Kim 			if (hbt)
8089783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
809aca7a94dSNamhyung Kim 
810aca7a94dSNamhyung Kim 			if (delay_secs != 0)
811db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
812aca7a94dSNamhyung Kim 			continue;
813aca7a94dSNamhyung Kim 		case K_TAB:
814aca7a94dSNamhyung Kim 			if (nd != NULL) {
815aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
816aca7a94dSNamhyung Kim 				if (nd == NULL)
81705e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
818aca7a94dSNamhyung Kim 			} else
81905e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
820aca7a94dSNamhyung Kim 			break;
821aca7a94dSNamhyung Kim 		case K_UNTAB:
822d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
823aca7a94dSNamhyung Kim 				nd = rb_next(nd);
824aca7a94dSNamhyung Kim 				if (nd == NULL)
82505e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
826d4913cbdSMarkus Trippelsdorf 			} else
82705e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
828aca7a94dSNamhyung Kim 			break;
82954e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
830aca7a94dSNamhyung Kim 		case 'h':
83105e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
83254e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
83354e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
83454e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
8357727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
8367727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
837eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
838eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
83954e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
84054e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
84154e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
84254e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
84354e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
8443a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
84554e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
846e592488cSAndi Kleen 		"k             Toggle line numbers\n"
84779ee47faSFeng Tang 		"r             Run available scripts\n"
848fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
84954e7a4e8SArnaldo Carvalho de Melo 			continue;
85079ee47faSFeng Tang 		case 'r':
85179ee47faSFeng Tang 			{
85279ee47faSFeng Tang 				script_browse(NULL);
85379ee47faSFeng Tang 				continue;
85479ee47faSFeng Tang 			}
855e592488cSAndi Kleen 		case 'k':
856e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
857e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
858e592488cSAndi Kleen 			break;
85954e7a4e8SArnaldo Carvalho de Melo 		case 'H':
86005e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
861aca7a94dSNamhyung Kim 			break;
862aca7a94dSNamhyung Kim 		case 's':
86305e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
864aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
865aca7a94dSNamhyung Kim 			continue;
866aca7a94dSNamhyung Kim 		case 'o':
867e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
86805e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
869aca7a94dSNamhyung Kim 			continue;
8709d1ef56dSArnaldo Carvalho de Melo 		case 'j':
871e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8729d1ef56dSArnaldo Carvalho de Melo 			continue;
8732402e4a9SArnaldo Carvalho de Melo 		case 'J':
874e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
87505e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
876e9823b21SArnaldo Carvalho de Melo 			continue;
877aca7a94dSNamhyung Kim 		case '/':
87805e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
879aca7a94dSNamhyung Kim show_help:
880aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
881aca7a94dSNamhyung Kim 			}
882aca7a94dSNamhyung Kim 			continue;
883aca7a94dSNamhyung Kim 		case 'n':
88405e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
88505e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
88605e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
887aca7a94dSNamhyung Kim 				goto show_help;
888aca7a94dSNamhyung Kim 			continue;
889aca7a94dSNamhyung Kim 		case '?':
89005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
891aca7a94dSNamhyung Kim 				goto show_help;
892aca7a94dSNamhyung Kim 			continue;
893e9823b21SArnaldo Carvalho de Melo 		case 'D': {
894e9823b21SArnaldo Carvalho de Melo 			static int seq;
895e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
896e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
89705e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
89805e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
89905e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
90005e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
90105e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
902e9823b21SArnaldo Carvalho de Melo 		}
903e9823b21SArnaldo Carvalho de Melo 			continue;
904aca7a94dSNamhyung Kim 		case K_ENTER:
905aca7a94dSNamhyung Kim 		case K_RIGHT:
9067bcbcd58SJiri Olsa 		{
9077bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
9087bcbcd58SJiri Olsa 
90905e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
910aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
9117bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
912aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
9137bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
914c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
9157bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
916c4cceae3SArnaldo Carvalho de Melo 				goto out;
9176ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
918db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
919c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
9206ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
921c4cceae3SArnaldo Carvalho de Melo 			}
922aca7a94dSNamhyung Kim 			continue;
9237bcbcd58SJiri Olsa 		}
9240c4a5bceSMartin Liška 		case 't':
9253a555c77STaeung Song 			if (annotate_browser__opts.show_total_period) {
9263a555c77STaeung Song 				annotate_browser__opts.show_total_period = false;
9273a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = true;
9283a555c77STaeung Song 			} else if (annotate_browser__opts.show_nr_samples)
9293a555c77STaeung Song 				annotate_browser__opts.show_nr_samples = false;
9303a555c77STaeung Song 			else
9313a555c77STaeung Song 				annotate_browser__opts.show_total_period = true;
9320c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
9330c4a5bceSMartin Liška 			continue;
934aca7a94dSNamhyung Kim 		case K_LEFT:
935aca7a94dSNamhyung Kim 		case K_ESC:
936aca7a94dSNamhyung Kim 		case 'q':
937aca7a94dSNamhyung Kim 		case CTRL('c'):
938aca7a94dSNamhyung Kim 			goto out;
939aca7a94dSNamhyung Kim 		default:
940aca7a94dSNamhyung Kim 			continue;
941aca7a94dSNamhyung Kim 		}
942aca7a94dSNamhyung Kim 
943aca7a94dSNamhyung Kim 		if (nd != NULL)
94405e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
945aca7a94dSNamhyung Kim 	}
946aca7a94dSNamhyung Kim out:
94705e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
948aca7a94dSNamhyung Kim 	return key;
949aca7a94dSNamhyung Kim }
950aca7a94dSNamhyung Kim 
951d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
952d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
953d5dbc518SArnaldo Carvalho de Melo {
9549cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
9550c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
9560c4a5bceSMartin Liška 		symbol_conf.show_total_period;
9579cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
9589cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
9590c4a5bceSMartin Liška 
960d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
961d5dbc518SArnaldo Carvalho de Melo }
962d5dbc518SArnaldo Carvalho de Melo 
963db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9649783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
965aca7a94dSNamhyung Kim {
966ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
967ed426915SNamhyung Kim 	SLang_reset_tty();
968ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
969ed426915SNamhyung Kim 
970d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
971aca7a94dSNamhyung Kim }
972aca7a94dSNamhyung Kim 
97330e863bbSAndi Kleen 
97430e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
97530e863bbSAndi Kleen {
97630e863bbSAndi Kleen 	unsigned n_insn = 0;
97730e863bbSAndi Kleen 	u64 offset;
97830e863bbSAndi Kleen 
97930e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
98030e863bbSAndi Kleen 		if (browser->offsets[offset])
98130e863bbSAndi Kleen 			n_insn++;
98230e863bbSAndi Kleen 	}
98330e863bbSAndi Kleen 	return n_insn;
98430e863bbSAndi Kleen }
98530e863bbSAndi Kleen 
98630e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
98730e863bbSAndi Kleen 			   struct cyc_hist *ch)
98830e863bbSAndi Kleen {
98930e863bbSAndi Kleen 	unsigned n_insn;
99030e863bbSAndi Kleen 	u64 offset;
99130e863bbSAndi Kleen 
99230e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
99330e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
99430e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
99530e863bbSAndi Kleen 
99630e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
99730e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
99830e863bbSAndi Kleen 			return;
99930e863bbSAndi Kleen 
100030e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
1001e1b60b5bSJiri Olsa 			struct annotation_line *al = browser->offsets[offset];
100230e863bbSAndi Kleen 
1003e1b60b5bSJiri Olsa 			if (al)
1004e1b60b5bSJiri Olsa 				al->ipc = ipc;
100530e863bbSAndi Kleen 		}
100630e863bbSAndi Kleen 	}
100730e863bbSAndi Kleen }
100830e863bbSAndi Kleen 
100930e863bbSAndi Kleen /*
101030e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
101130e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
101230e863bbSAndi Kleen  * which are only here.
101330e863bbSAndi Kleen  */
101430e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
101530e863bbSAndi Kleen 			   struct symbol *sym)
101630e863bbSAndi Kleen {
101730e863bbSAndi Kleen 	u64 offset;
101830e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
101930e863bbSAndi Kleen 
102030e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
102130e863bbSAndi Kleen 		return;
102230e863bbSAndi Kleen 
102330e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
102430e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
102530e863bbSAndi Kleen 		struct cyc_hist *ch;
102630e863bbSAndi Kleen 
102730e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
102830e863bbSAndi Kleen 		if (ch && ch->cycles) {
1029e1b60b5bSJiri Olsa 			struct annotation_line *al;
103030e863bbSAndi Kleen 
103130e863bbSAndi Kleen 			if (ch->have_start)
103230e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
1033e1b60b5bSJiri Olsa 			al = browser->offsets[offset];
1034e1b60b5bSJiri Olsa 			if (al && ch->num_aggr)
1035e1b60b5bSJiri Olsa 				al->cycles = ch->cycles_aggr / ch->num_aggr;
103630e863bbSAndi Kleen 			browser->have_cycles = true;
103730e863bbSAndi Kleen 		}
103830e863bbSAndi Kleen 	}
103930e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
104030e863bbSAndi Kleen }
104130e863bbSAndi Kleen 
1042b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
1043b793a401SArnaldo Carvalho de Melo 						size_t size)
1044b793a401SArnaldo Carvalho de Melo {
1045b793a401SArnaldo Carvalho de Melo 	u64 offset;
104632ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
104732ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
104832ae1efdSNamhyung Kim 
104932ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
105032ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
105132ae1efdSNamhyung Kim 		return;
1052b793a401SArnaldo Carvalho de Melo 
1053b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
1054e1b60b5bSJiri Olsa 		struct annotation_line *al = browser->offsets[offset];
1055a5ef2702SJiri Olsa 		struct disasm_line *dl;
1056a5ef2702SJiri Olsa 		struct browser_line *blt;
1057b793a401SArnaldo Carvalho de Melo 
1058e1b60b5bSJiri Olsa 		dl = disasm_line(al);
1059e1b60b5bSJiri Olsa 
1060865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
1061b793a401SArnaldo Carvalho de Melo 			continue;
1062b793a401SArnaldo Carvalho de Melo 
1063e1b60b5bSJiri Olsa 		al = browser->offsets[dl->ops.target.offset];
1064e1b60b5bSJiri Olsa 
10659481ede9SArnaldo Carvalho de Melo 		/*
10669481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
10679481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
10689481ede9SArnaldo Carvalho de Melo  		 */
1069a5ef2702SJiri Olsa 		if (al == NULL)
10709481ede9SArnaldo Carvalho de Melo 			continue;
10719481ede9SArnaldo Carvalho de Melo 
1072a5ef2702SJiri Olsa 		blt = browser_line(al);
1073a5ef2702SJiri Olsa 		if (++blt->jump_sources > browser->max_jump_sources)
1074a5ef2702SJiri Olsa 			browser->max_jump_sources = blt->jump_sources;
10752402e4a9SArnaldo Carvalho de Melo 
10762402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
1077b793a401SArnaldo Carvalho de Melo 	}
1078b793a401SArnaldo Carvalho de Melo }
1079b793a401SArnaldo Carvalho de Melo 
10802402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10812402e4a9SArnaldo Carvalho de Melo {
10822402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10832402e4a9SArnaldo Carvalho de Melo 		return 5;
10842402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10852402e4a9SArnaldo Carvalho de Melo 		return 2;
10862402e4a9SArnaldo Carvalho de Melo 	return 1;
10872402e4a9SArnaldo Carvalho de Melo }
10882402e4a9SArnaldo Carvalho de Melo 
1089db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1090db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10919783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1092aca7a94dSNamhyung Kim {
1093e1b60b5bSJiri Olsa 	struct annotation_line *al;
1094aca7a94dSNamhyung Kim 	struct annotation *notes;
1095c0a58fb2SSamuel Liao 	size_t size;
1096aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1097aca7a94dSNamhyung Kim 		.map = map,
1098aca7a94dSNamhyung Kim 		.sym = sym,
1099aca7a94dSNamhyung Kim 	};
1100aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1101aca7a94dSNamhyung Kim 		.b = {
1102a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1103aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1104aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
110529ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1106aca7a94dSNamhyung Kim 			.priv	 = &ms,
1107aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1108aca7a94dSNamhyung Kim 		},
1109aca7a94dSNamhyung Kim 	};
1110ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1111c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1112aca7a94dSNamhyung Kim 
1113aca7a94dSNamhyung Kim 	if (sym == NULL)
1114aca7a94dSNamhyung Kim 		return -1;
1115aca7a94dSNamhyung Kim 
1116c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1117c0a58fb2SSamuel Liao 
1118aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1119aca7a94dSNamhyung Kim 		return -1;
1120aca7a94dSNamhyung Kim 
1121e1b60b5bSJiri Olsa 	browser.offsets = zalloc(size * sizeof(struct annotation_line *));
1122b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1123b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1124b793a401SArnaldo Carvalho de Melo 		return -1;
1125b793a401SArnaldo Carvalho de Melo 	}
1126b793a401SArnaldo Carvalho de Melo 
11273ab6db8dSJiri Olsa 	if (perf_evsel__is_group_event(evsel))
1128c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
1129c7e7b610SNamhyung Kim 
11305449f13cSArnaldo Carvalho de Melo 	err = symbol__annotate(sym, map, evsel, sizeof(struct browser_line), &browser.arch);
1131ee51d851SArnaldo Carvalho de Melo 	if (err) {
1132ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1133ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1134ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1135b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1136aca7a94dSNamhyung Kim 	}
1137aca7a94dSNamhyung Kim 
113805d3f1a1SJiri Olsa 	symbol__calc_percent(sym, evsel);
113905d3f1a1SJiri Olsa 
11407727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1141aca7a94dSNamhyung Kim 
1142aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1143aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1144aca7a94dSNamhyung Kim 
1145e1b60b5bSJiri Olsa 	list_for_each_entry(al, &notes->src->source, node) {
11460d957970SJiri Olsa 		struct browser_line *bpos;
1147e1b60b5bSJiri Olsa 		size_t line_len = strlen(al->line);
1148aca7a94dSNamhyung Kim 
1149aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1150aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1151a5ef2702SJiri Olsa 		bpos = browser_line(al);
1152887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1153e1b60b5bSJiri Olsa 		if (al->offset != -1) {
1154887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
115597148a97SArnaldo Carvalho de Melo 			/*
115697148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
115797148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
115897148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
115997148a97SArnaldo Carvalho de Melo 			 *
116097148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
116197148a97SArnaldo Carvalho de Melo  			 */
1162e1b60b5bSJiri Olsa 			if (al->offset < (s64)size)
1163e1b60b5bSJiri Olsa 				browser.offsets[al->offset] = al;
1164b793a401SArnaldo Carvalho de Melo 		} else
1165887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1166aca7a94dSNamhyung Kim 	}
1167aca7a94dSNamhyung Kim 
1168b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
116930e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1170b793a401SArnaldo Carvalho de Melo 
11712402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
117283b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
11732402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1174c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1175aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1176aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1177aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1178e9823b21SArnaldo Carvalho de Melo 
1179e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1180e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1181e9823b21SArnaldo Carvalho de Melo 
1182e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1183e9823b21SArnaldo Carvalho de Melo 
1184db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1185f8eb37bdSJiri Olsa 
1186f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
1187b793a401SArnaldo Carvalho de Melo 
1188b793a401SArnaldo Carvalho de Melo out_free_offsets:
1189b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1190aca7a94dSNamhyung Kim 	return ret;
1191aca7a94dSNamhyung Kim }
1192c323cf04SArnaldo Carvalho de Melo 
1193c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1194c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1195c323cf04SArnaldo Carvalho de Melo 
1196c323cf04SArnaldo Carvalho de Melo /*
1197c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1198c323cf04SArnaldo Carvalho de Melo  */
11997c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1200c323cf04SArnaldo Carvalho de Melo 	const char *name;
1201c323cf04SArnaldo Carvalho de Melo 	bool *value;
1202c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1203c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1204c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1205e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1206c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
12079cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
12080c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
120939ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1210c323cf04SArnaldo Carvalho de Melo };
1211c323cf04SArnaldo Carvalho de Melo 
1212c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1213c323cf04SArnaldo Carvalho de Melo 
1214c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1215c323cf04SArnaldo Carvalho de Melo {
12167c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1217c323cf04SArnaldo Carvalho de Melo 
1218c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1219c323cf04SArnaldo Carvalho de Melo }
1220c323cf04SArnaldo Carvalho de Melo 
12211d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
12221d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1223c323cf04SArnaldo Carvalho de Melo {
12247c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1225c323cf04SArnaldo Carvalho de Melo 	const char *name;
1226c323cf04SArnaldo Carvalho de Melo 
12278e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
1228c323cf04SArnaldo Carvalho de Melo 		return 0;
1229c323cf04SArnaldo Carvalho de Melo 
1230c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1231c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
12327c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1233c323cf04SArnaldo Carvalho de Melo 
1234c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1235f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1236f06cff7cSArnaldo Carvalho de Melo 	else
1237c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1238c323cf04SArnaldo Carvalho de Melo 	return 0;
1239c323cf04SArnaldo Carvalho de Melo }
1240c323cf04SArnaldo Carvalho de Melo 
1241c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1242c323cf04SArnaldo Carvalho de Melo {
1243c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1244c323cf04SArnaldo Carvalho de Melo }
1245