xref: /linux/tools/perf/ui/browsers/annotate.c (revision 1101f69af5335a863765100d1df1999fd1e8c5bf)
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"
10*1101f69aSArnaldo Carvalho de Melo #include "../../util/map.h"
11aca7a94dSNamhyung Kim #include "../../util/symbol.h"
12db8fd07aSNamhyung Kim #include "../../util/evsel.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>
193e0d7953SJiri Olsa #include <asm/bug.h>
20aca7a94dSNamhyung Kim 
210c4a5bceSMartin Liška struct disasm_line_samples {
220c4a5bceSMartin Liška 	double		      percent;
23bb79a232SArnaldo Carvalho de Melo 	struct sym_hist_entry he;
240c4a5bceSMartin Liška };
250c4a5bceSMartin Liška 
26dcaa3948SJin Yao struct arch;
27dcaa3948SJin Yao 
28aca7a94dSNamhyung Kim struct annotate_browser {
29aca7a94dSNamhyung Kim 	struct ui_browser	    b;
30aca7a94dSNamhyung Kim 	struct rb_root		    entries;
31aca7a94dSNamhyung Kim 	struct rb_node		   *curr_hot;
327bcbcd58SJiri Olsa 	struct annotation_line	   *selection;
33dcaa3948SJin Yao 	struct arch		   *arch;
34cd0cccbaSArnaldo Carvalho de Melo 	struct annotation_options  *opts;
35aca7a94dSNamhyung Kim 	bool			    searching_backwards;
36aca7a94dSNamhyung Kim 	char			    search_bf[128];
37aca7a94dSNamhyung Kim };
38aca7a94dSNamhyung Kim 
3995aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser)
4095aa89d9SArnaldo Carvalho de Melo {
4195aa89d9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
4295aa89d9SArnaldo Carvalho de Melo 	return symbol__annotation(ms->sym);
4395aa89d9SArnaldo Carvalho de Melo }
4495aa89d9SArnaldo Carvalho de Melo 
4516932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
46aca7a94dSNamhyung Kim {
4795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
48d5490b96SJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
499b80d1f9SArnaldo Carvalho de Melo 	return annotation_line__filter(al, notes);
50aca7a94dSNamhyung Kim }
51aca7a94dSNamhyung Kim 
5227feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
532402e4a9SArnaldo Carvalho de Melo {
5427feb761SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
55bc1c0f3dSArnaldo Carvalho de Melo 
5627feb761SArnaldo Carvalho de Melo 	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
572402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
58bc1c0f3dSArnaldo Carvalho de Melo 	if (nr == notes->max_jump_sources)
592402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
602402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
612402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
622402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
632402e4a9SArnaldo Carvalho de Melo }
642402e4a9SArnaldo Carvalho de Melo 
65a1e9b74cSArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
662402e4a9SArnaldo Carvalho de Melo {
6727feb761SArnaldo Carvalho de Melo 	 int color = ui_browser__jumps_percent_color(browser, nr, current);
6827feb761SArnaldo Carvalho de Melo 	 return ui_browser__set_color(browser, color);
692402e4a9SArnaldo Carvalho de Melo }
702402e4a9SArnaldo Carvalho de Melo 
71a1e9b74cSArnaldo Carvalho de Melo static int annotate_browser__set_color(void *browser, int color)
72aca7a94dSNamhyung Kim {
73a1e9b74cSArnaldo Carvalho de Melo 	return ui_browser__set_color(browser, color);
744ea08b52SArnaldo Carvalho de Melo }
754ea08b52SArnaldo Carvalho de Melo 
76a1e9b74cSArnaldo Carvalho de Melo static void annotate_browser__write_graph(void *browser, int graph)
77a1e9b74cSArnaldo Carvalho de Melo {
78a1e9b74cSArnaldo Carvalho de Melo 	ui_browser__write_graph(browser, graph);
79a5433b3eSJiri Olsa }
80a5433b3eSJiri Olsa 
812ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
822ba5eca1SArnaldo Carvalho de Melo {
832ba5eca1SArnaldo Carvalho de Melo 	ui_browser__set_percent_color(browser, percent, current);
842ba5eca1SArnaldo Carvalho de Melo }
852ba5eca1SArnaldo Carvalho de Melo 
862ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__printf(void *browser, const char *fmt, ...)
872ba5eca1SArnaldo Carvalho de Melo {
882ba5eca1SArnaldo Carvalho de Melo 	va_list args;
892ba5eca1SArnaldo Carvalho de Melo 
902ba5eca1SArnaldo Carvalho de Melo 	va_start(args, fmt);
912ba5eca1SArnaldo Carvalho de Melo 	ui_browser__vprintf(browser, fmt, args);
922ba5eca1SArnaldo Carvalho de Melo 	va_end(args);
932ba5eca1SArnaldo Carvalho de Melo }
942ba5eca1SArnaldo Carvalho de Melo 
95a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
96a5433b3eSJiri Olsa {
97a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9895aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
99a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
100c298304bSArnaldo Carvalho de Melo 	struct annotation_write_ops ops = {
101c298304bSArnaldo Carvalho de Melo 		.first_line		 = row == 0,
102c298304bSArnaldo Carvalho de Melo 		.current_entry		 = ui_browser__is_current_entry(browser, row),
103c298304bSArnaldo Carvalho de Melo 		.change_color		 = (!notes->options->hide_src_code &&
104c298304bSArnaldo Carvalho de Melo 					    (!ops.current_entry ||
105c298304bSArnaldo Carvalho de Melo 					     (browser->use_navkeypressed &&
106c298304bSArnaldo Carvalho de Melo 					      !browser->navkeypressed))),
107c298304bSArnaldo Carvalho de Melo 		.width			 = browser->width,
108c298304bSArnaldo Carvalho de Melo 		.obj			 = browser,
109c298304bSArnaldo Carvalho de Melo 		.set_color		 = annotate_browser__set_color,
110c298304bSArnaldo Carvalho de Melo 		.set_percent_color	 = annotate_browser__set_percent_color,
111c298304bSArnaldo Carvalho de Melo 		.set_jumps_percent_color = ui_browser__set_jumps_percent_color,
112c298304bSArnaldo Carvalho de Melo 		.printf			 = annotate_browser__printf,
113c298304bSArnaldo Carvalho de Melo 		.write_graph		 = annotate_browser__write_graph,
114c298304bSArnaldo Carvalho de Melo 	};
115a5433b3eSJiri Olsa 
116a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
117a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
118c298304bSArnaldo Carvalho de Melo 		ops.width += 1;
119a5433b3eSJiri Olsa 
1204c650ddcSJiri Olsa 	annotation_line__write(al, notes, &ops, ab->opts);
121aca7a94dSNamhyung Kim 
122c298304bSArnaldo Carvalho de Melo 	if (ops.current_entry)
123a5433b3eSJiri Olsa 		ab->selection = al;
124aca7a94dSNamhyung Kim }
125aca7a94dSNamhyung Kim 
1267e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
1277e63a13aSJin Yao {
128a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
1297e63a13aSJin Yao 	const char *name;
1307e63a13aSJin Yao 
1317e63a13aSJin Yao 	if (!pos)
1327e63a13aSJin Yao 		return false;
1337e63a13aSJin Yao 
1347e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
1357e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
1367e63a13aSJin Yao 	else
1377e63a13aSJin Yao 		name = pos->ins.name;
1387e63a13aSJin Yao 
1397e63a13aSJin Yao 	if (!name || !cursor->ins.name)
1407e63a13aSJin Yao 		return false;
1417e63a13aSJin Yao 
1427e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
1437e63a13aSJin Yao }
1447e63a13aSJin Yao 
1459d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
146a3f895beSArnaldo Carvalho de Melo {
147a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1487bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
149a5ef2702SJiri Olsa 	struct annotation_line *target;
15083b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
15132ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
15232ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
1530e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1546af612d2SArnaldo Carvalho de Melo 	u8 pcnt_width = annotation__pcnt_width(notes);
15500ea0eb2SArnaldo Carvalho de Melo 	int width;
15632ae1efdSNamhyung Kim 
15732ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
15832ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
15932ae1efdSNamhyung Kim 		return;
160a3f895beSArnaldo Carvalho de Melo 
1612eff0611SArnaldo Carvalho de Melo 	if (!disasm_line__is_valid_local_jump(cursor, sym))
162a3f895beSArnaldo Carvalho de Melo 		return;
163a3f895beSArnaldo Carvalho de Melo 
1649c04409dSArnaldo Carvalho de Melo 	/*
1659c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
1669c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
1679c04409dSArnaldo Carvalho de Melo 	 *
1689c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
1699c04409dSArnaldo Carvalho de Melo 	 *
1709c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
1719c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
1729c04409dSArnaldo Carvalho de Melo 	 *
1739c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
1749c04409dSArnaldo Carvalho de Melo 	 *
1759c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
1769c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
1779c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
1789c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
1799c04409dSArnaldo Carvalho de Melo 	 *
1809c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
1819c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
1829c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
1839c04409dSArnaldo Carvalho de Melo 	 */
1849d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
1859c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
1869d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
1879c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
1889c04409dSArnaldo Carvalho de Melo 		return;
1899c04409dSArnaldo Carvalho de Melo 	}
1909d1ef56dSArnaldo Carvalho de Melo 
19116932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
1924850c92eSArnaldo Carvalho de Melo 		from = cursor->al.idx_asm;
1934850c92eSArnaldo Carvalho de Melo 		to = target->idx_asm;
194a3f895beSArnaldo Carvalho de Melo 	} else {
1954850c92eSArnaldo Carvalho de Melo 		from = (u64)cursor->al.idx;
1964850c92eSArnaldo Carvalho de Melo 		to = (u64)target->idx;
197a3f895beSArnaldo Carvalho de Melo 	}
198a3f895beSArnaldo Carvalho de Melo 
1990e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
200b40982e8SJin Yao 
20178ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
202b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
2039761e86eSArnaldo Carvalho de Melo 				 pcnt_width + 2 + notes->widths.addr + width,
204c7e7b610SNamhyung Kim 				 from, to);
2057e63a13aSJin Yao 
2067e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
2077e63a13aSJin Yao 		ui_browser__mark_fused(browser,
2089761e86eSArnaldo Carvalho de Melo 				       pcnt_width + 3 + notes->widths.addr + width,
2097e63a13aSJin Yao 				       from - 1,
2107e63a13aSJin Yao 				       to > from ? true : false);
2117e63a13aSJin Yao 	}
212a3f895beSArnaldo Carvalho de Melo }
213a3f895beSArnaldo Carvalho de Melo 
214a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
215a3f895beSArnaldo Carvalho de Melo {
21695aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
217a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
2186af612d2SArnaldo Carvalho de Melo 	int pcnt_width = annotation__pcnt_width(notes);
219a3f895beSArnaldo Carvalho de Melo 
22016932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
2219d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
222a3f895beSArnaldo Carvalho de Melo 
22383b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
224e726c851SArnaldo Carvalho de Melo 	__ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
225a3f895beSArnaldo Carvalho de Melo 	return ret;
226a3f895beSArnaldo Carvalho de Melo }
227a3f895beSArnaldo Carvalho de Melo 
228da06d568SHe Kuang static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
229da06d568SHe Kuang 						  int percent_type)
230c7e7b610SNamhyung Kim {
231c7e7b610SNamhyung Kim 	int i;
232c7e7b610SNamhyung Kim 
233c2f938baSJiri Olsa 	for (i = 0; i < a->data_nr; i++) {
234da06d568SHe Kuang 		if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
235c7e7b610SNamhyung Kim 			continue;
236da06d568SHe Kuang 		return a->data[i].percent[percent_type] -
237da06d568SHe Kuang 			   b->data[i].percent[percent_type];
238c7e7b610SNamhyung Kim 	}
239c7e7b610SNamhyung Kim 	return 0;
240c7e7b610SNamhyung Kim }
241c7e7b610SNamhyung Kim 
242da06d568SHe Kuang static void disasm_rb_tree__insert(struct annotate_browser *browser,
243da06d568SHe Kuang 				struct annotation_line *al)
244aca7a94dSNamhyung Kim {
245da06d568SHe Kuang 	struct rb_root *root = &browser->entries;
24629ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
247aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
2483ab6db8dSJiri Olsa 	struct annotation_line *l;
249aca7a94dSNamhyung Kim 
250aca7a94dSNamhyung Kim 	while (*p != NULL) {
251aca7a94dSNamhyung Kim 		parent = *p;
2523ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
253c7e7b610SNamhyung Kim 
254da06d568SHe Kuang 		if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
255aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
256aca7a94dSNamhyung Kim 		else
257aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
258aca7a94dSNamhyung Kim 	}
2593ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
2603ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
261aca7a94dSNamhyung Kim }
262aca7a94dSNamhyung Kim 
26305e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
264ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
265aca7a94dSNamhyung Kim {
2669b80d1f9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
267aca7a94dSNamhyung Kim 	unsigned back;
268aca7a94dSNamhyung Kim 
26905e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
27005e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
27105e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
272aca7a94dSNamhyung Kim 
27305e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
274ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
275aca7a94dSNamhyung Kim 
2769b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(pos, notes))
277aca7a94dSNamhyung Kim 			continue;
278aca7a94dSNamhyung Kim 
27905e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
280aca7a94dSNamhyung Kim 		--back;
281aca7a94dSNamhyung Kim 	}
282aca7a94dSNamhyung Kim 
283ec03a77dSJiri Olsa 	browser->b.top = pos;
28405e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
285aca7a94dSNamhyung Kim }
286aca7a94dSNamhyung Kim 
287aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
288aca7a94dSNamhyung Kim 					 struct rb_node *nd)
289aca7a94dSNamhyung Kim {
29095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
2914850c92eSArnaldo Carvalho de Melo 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
2924850c92eSArnaldo Carvalho de Melo 	u32 idx = pos->idx;
293aca7a94dSNamhyung Kim 
29416932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
2954850c92eSArnaldo Carvalho de Melo 		idx = pos->idx_asm;
296a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
297aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
298aca7a94dSNamhyung Kim }
299aca7a94dSNamhyung Kim 
300aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
301db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
302aca7a94dSNamhyung Kim {
303aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
304aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
305aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
306c4c72436SJiri Olsa 	struct disasm_line *pos;
307aca7a94dSNamhyung Kim 
308aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
309aca7a94dSNamhyung Kim 
310aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
311aca7a94dSNamhyung Kim 
312e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
313e425da6cSJiri Olsa 
314a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
315c7e7b610SNamhyung Kim 		double max_percent = 0.0;
316c7e7b610SNamhyung Kim 		int i;
317e64aa75bSNamhyung Kim 
318d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
3195b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
320e64aa75bSNamhyung Kim 			continue;
321e64aa75bSNamhyung Kim 		}
322e64aa75bSNamhyung Kim 
323c2f938baSJiri Olsa 		for (i = 0; i < pos->al.data_nr; i++) {
3246d9f0c2dSJiri Olsa 			double percent;
3250c4a5bceSMartin Liška 
3266d9f0c2dSJiri Olsa 			percent = annotation_data__percent(&pos->al.data[i],
327d4265b1aSJiri Olsa 							   browser->opts->percent_type);
3286d9f0c2dSJiri Olsa 
3296d9f0c2dSJiri Olsa 			if (max_percent < percent)
3306d9f0c2dSJiri Olsa 				max_percent = percent;
331c7e7b610SNamhyung Kim 		}
332c7e7b610SNamhyung Kim 
33337236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
3345b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
335aca7a94dSNamhyung Kim 			continue;
336aca7a94dSNamhyung Kim 		}
337da06d568SHe Kuang 		disasm_rb_tree__insert(browser, &pos->al);
338aca7a94dSNamhyung Kim 	}
339aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
340aca7a94dSNamhyung Kim 
341aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
342aca7a94dSNamhyung Kim }
343aca7a94dSNamhyung Kim 
344aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
345aca7a94dSNamhyung Kim {
34695aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
347ec03a77dSJiri Olsa 	struct annotation_line *al;
348aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
349aca7a94dSNamhyung Kim 
350aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
351ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
352aca7a94dSNamhyung Kim 
35316932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3544850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3554850c92eSArnaldo Carvalho de Melo 			offset = al->idx;
356aca7a94dSNamhyung Kim 
3571cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_entries;
35816932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
359aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3604850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx - offset;
3614850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx;
362aca7a94dSNamhyung Kim 	} else {
3634850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < 0) {
364aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
365aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
366aca7a94dSNamhyung Kim 			return false;
367aca7a94dSNamhyung Kim 		}
368aca7a94dSNamhyung Kim 
3694850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3704850c92eSArnaldo Carvalho de Melo 			offset = al->idx_asm;
371aca7a94dSNamhyung Kim 
3721cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_asm_entries;
37316932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
374aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3754850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx_asm - offset;
3764850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx_asm;
377aca7a94dSNamhyung Kim 	}
378aca7a94dSNamhyung Kim 
379aca7a94dSNamhyung Kim 	return true;
380aca7a94dSNamhyung Kim }
381aca7a94dSNamhyung Kim 
3821cf5f98aSArnaldo Carvalho de Melo static void ui_browser__init_asm_mode(struct ui_browser *browser)
383e9823b21SArnaldo Carvalho de Melo {
3841cf5f98aSArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
3851cf5f98aSArnaldo Carvalho de Melo 	ui_browser__reset_index(browser);
3861cf5f98aSArnaldo Carvalho de Melo 	browser->nr_entries = notes->nr_asm_entries;
387e9823b21SArnaldo Carvalho de Melo }
388e9823b21SArnaldo Carvalho de Melo 
38934f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
39034f77abcSAdrian Hunter 
39134f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
3923e0d7953SJiri Olsa 		     size_t sz, int percent_type)
39334f77abcSAdrian Hunter {
3943e0d7953SJiri Olsa 	return snprintf(title, sz, "%s  %s [Percent: %s]", sym->name, map->dso->long_name,
3953e0d7953SJiri Olsa 			percent_type_str(percent_type));
39634f77abcSAdrian Hunter }
39734f77abcSAdrian Hunter 
398e4cc91b8SArnaldo Carvalho de Melo /*
399e4cc91b8SArnaldo Carvalho de Melo  * This can be called from external jumps, i.e. jumps from one functon
400e4cc91b8SArnaldo Carvalho de Melo  * to another, like from the kernel's entry_SYSCALL_64 function to the
401e4cc91b8SArnaldo Carvalho de Melo  * swapgs_restore_regs_and_return_to_usermode() function.
402e4cc91b8SArnaldo Carvalho de Melo  *
403e4cc91b8SArnaldo Carvalho de Melo  * So all we check here is that dl->ops.target.sym is set, if it is, just
404e4cc91b8SArnaldo Carvalho de Melo  * go to that function and when exiting from its disassembly, come back
405e4cc91b8SArnaldo Carvalho de Melo  * to the calling function.
406e4cc91b8SArnaldo Carvalho de Melo  */
407db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
408db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
4099783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
410aca7a94dSNamhyung Kim {
411aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
4127bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
413aca7a94dSNamhyung Kim 	struct annotation *notes;
41434f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
415aca7a94dSNamhyung Kim 
416696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
417aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
418aca7a94dSNamhyung Kim 		return true;
419aca7a94dSNamhyung Kim 	}
420aca7a94dSNamhyung Kim 
421696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
422aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
423aca7a94dSNamhyung Kim 
42414c8dde1SArnaldo Carvalho de Melo 	if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) {
425aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
426aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
427696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
428aca7a94dSNamhyung Kim 		return true;
429aca7a94dSNamhyung Kim 	}
430aca7a94dSNamhyung Kim 
431aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
432cd0cccbaSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
4333e0d7953SJiri Olsa 	sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
43434f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
435aca7a94dSNamhyung Kim 	return true;
436aca7a94dSNamhyung Kim }
437aca7a94dSNamhyung Kim 
43829ed6e76SArnaldo Carvalho de Melo static
43929ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
440aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
441aca7a94dSNamhyung Kim {
44295aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
44329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
444aca7a94dSNamhyung Kim 
445aca7a94dSNamhyung Kim 	*idx = 0;
446a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
447d5490b96SJiri Olsa 		if (pos->al.offset == offset)
448aca7a94dSNamhyung Kim 			return pos;
4499b80d1f9SArnaldo Carvalho de Melo 		if (!annotation_line__filter(&pos->al, notes))
450aca7a94dSNamhyung Kim 			++*idx;
451aca7a94dSNamhyung Kim 	}
452aca7a94dSNamhyung Kim 
453aca7a94dSNamhyung Kim 	return NULL;
454aca7a94dSNamhyung Kim }
455aca7a94dSNamhyung Kim 
456e4cc91b8SArnaldo Carvalho de Melo static bool annotate_browser__jump(struct annotate_browser *browser,
457e4cc91b8SArnaldo Carvalho de Melo 				   struct perf_evsel *evsel,
458e4cc91b8SArnaldo Carvalho de Melo 				   struct hist_browser_timer *hbt)
459aca7a94dSNamhyung Kim {
4607bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
4615252b1aeSArnaldo Carvalho de Melo 	u64 offset;
4624f9d0325SArnaldo Carvalho de Melo 	s64 idx;
463aca7a94dSNamhyung Kim 
46475b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
465aca7a94dSNamhyung Kim 		return false;
466aca7a94dSNamhyung Kim 
467e4cc91b8SArnaldo Carvalho de Melo 	if (dl->ops.target.outside) {
468e4cc91b8SArnaldo Carvalho de Melo 		annotate_browser__callq(browser, evsel, hbt);
469e4cc91b8SArnaldo Carvalho de Melo 		return true;
470e4cc91b8SArnaldo Carvalho de Melo 	}
471e4cc91b8SArnaldo Carvalho de Melo 
4725252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
4735252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
47429ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
4755252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
476aca7a94dSNamhyung Kim 		return true;
477aca7a94dSNamhyung Kim 	}
478aca7a94dSNamhyung Kim 
479ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
480aca7a94dSNamhyung Kim 
481aca7a94dSNamhyung Kim 	return true;
482aca7a94dSNamhyung Kim }
483aca7a94dSNamhyung Kim 
48429ed6e76SArnaldo Carvalho de Melo static
4859213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
486aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
487aca7a94dSNamhyung Kim {
48895aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
4899213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
490aca7a94dSNamhyung Kim 
491aca7a94dSNamhyung Kim 	*idx = browser->b.index;
4929213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
4939b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
494aca7a94dSNamhyung Kim 			continue;
495aca7a94dSNamhyung Kim 
496aca7a94dSNamhyung Kim 		++*idx;
497aca7a94dSNamhyung Kim 
4989213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
4999213afbdSJiri Olsa 			return al;
500aca7a94dSNamhyung Kim 	}
501aca7a94dSNamhyung Kim 
502aca7a94dSNamhyung Kim 	return NULL;
503aca7a94dSNamhyung Kim }
504aca7a94dSNamhyung Kim 
505aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
506aca7a94dSNamhyung Kim {
5079213afbdSJiri Olsa 	struct annotation_line *al;
508aca7a94dSNamhyung Kim 	s64 idx;
509aca7a94dSNamhyung Kim 
5109213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
5119213afbdSJiri Olsa 	if (al == NULL) {
512aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
513aca7a94dSNamhyung Kim 		return false;
514aca7a94dSNamhyung Kim 	}
515aca7a94dSNamhyung Kim 
516ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
517aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
518aca7a94dSNamhyung Kim 	return true;
519aca7a94dSNamhyung Kim }
520aca7a94dSNamhyung Kim 
52129ed6e76SArnaldo Carvalho de Melo static
5229213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
523aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
524aca7a94dSNamhyung Kim {
52595aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
5269213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
527aca7a94dSNamhyung Kim 
528aca7a94dSNamhyung Kim 	*idx = browser->b.index;
5299213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
5309b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
531aca7a94dSNamhyung Kim 			continue;
532aca7a94dSNamhyung Kim 
533aca7a94dSNamhyung Kim 		--*idx;
534aca7a94dSNamhyung Kim 
5359213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
5369213afbdSJiri Olsa 			return al;
537aca7a94dSNamhyung Kim 	}
538aca7a94dSNamhyung Kim 
539aca7a94dSNamhyung Kim 	return NULL;
540aca7a94dSNamhyung Kim }
541aca7a94dSNamhyung Kim 
542aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
543aca7a94dSNamhyung Kim {
5449213afbdSJiri Olsa 	struct annotation_line *al;
545aca7a94dSNamhyung Kim 	s64 idx;
546aca7a94dSNamhyung Kim 
5479213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
5489213afbdSJiri Olsa 	if (al == NULL) {
549aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
550aca7a94dSNamhyung Kim 		return false;
551aca7a94dSNamhyung Kim 	}
552aca7a94dSNamhyung Kim 
553ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
554aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
555aca7a94dSNamhyung Kim 	return true;
556aca7a94dSNamhyung Kim }
557aca7a94dSNamhyung Kim 
558aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
559aca7a94dSNamhyung Kim 					    int delay_secs)
560aca7a94dSNamhyung Kim {
561aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
562aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
563aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
564aca7a94dSNamhyung Kim 	    !*browser->search_bf)
565aca7a94dSNamhyung Kim 		return false;
566aca7a94dSNamhyung Kim 
567aca7a94dSNamhyung Kim 	return true;
568aca7a94dSNamhyung Kim }
569aca7a94dSNamhyung Kim 
570aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
571aca7a94dSNamhyung Kim {
572aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
573aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
574aca7a94dSNamhyung Kim 
575aca7a94dSNamhyung Kim 	return false;
576aca7a94dSNamhyung Kim }
577aca7a94dSNamhyung Kim 
578aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
579aca7a94dSNamhyung Kim 					      int delay_secs)
580aca7a94dSNamhyung Kim {
581aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
582aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
583aca7a94dSNamhyung Kim 
584aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
585aca7a94dSNamhyung Kim }
586aca7a94dSNamhyung Kim 
587aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
588aca7a94dSNamhyung Kim 					   int delay_secs)
589aca7a94dSNamhyung Kim {
590aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
591aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
592aca7a94dSNamhyung Kim 
593aca7a94dSNamhyung Kim 	return false;
594aca7a94dSNamhyung Kim }
595aca7a94dSNamhyung Kim 
596aca7a94dSNamhyung Kim static
597aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
598aca7a94dSNamhyung Kim 					       int delay_secs)
599aca7a94dSNamhyung Kim {
600aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
601aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
602aca7a94dSNamhyung Kim 
603aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
604aca7a94dSNamhyung Kim }
605aca7a94dSNamhyung Kim 
6066920e285SArnaldo Carvalho de Melo static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
6076920e285SArnaldo Carvalho de Melo {
6083e0d7953SJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
6096920e285SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
6106920e285SArnaldo Carvalho de Melo 	struct symbol *sym = ms->sym;
6116920e285SArnaldo Carvalho de Melo 	char symbol_dso[SYM_TITLE_MAX_SIZE];
6126920e285SArnaldo Carvalho de Melo 
6136920e285SArnaldo Carvalho de Melo 	if (ui_browser__show(browser, title, help) < 0)
6146920e285SArnaldo Carvalho de Melo 		return -1;
6156920e285SArnaldo Carvalho de Melo 
6163e0d7953SJiri Olsa 	sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
6176920e285SArnaldo Carvalho de Melo 
6186920e285SArnaldo Carvalho de Melo 	ui_browser__gotorc_title(browser, 0, 0);
6196920e285SArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_ROOT);
6206920e285SArnaldo Carvalho de Melo 	ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
6216920e285SArnaldo Carvalho de Melo 	return 0;
6226920e285SArnaldo Carvalho de Melo }
6236920e285SArnaldo Carvalho de Melo 
6243e0d7953SJiri Olsa static void
6253e0d7953SJiri Olsa switch_percent_type(struct annotation_options *opts, bool base)
6263e0d7953SJiri Olsa {
6273e0d7953SJiri Olsa 	switch (opts->percent_type) {
6283e0d7953SJiri Olsa 	case PERCENT_HITS_LOCAL:
6293e0d7953SJiri Olsa 		if (base)
6303e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_LOCAL;
6313e0d7953SJiri Olsa 		else
6323e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_GLOBAL;
6333e0d7953SJiri Olsa 		break;
6343e0d7953SJiri Olsa 	case PERCENT_HITS_GLOBAL:
6353e0d7953SJiri Olsa 		if (base)
6363e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_GLOBAL;
6373e0d7953SJiri Olsa 		else
6383e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_LOCAL;
6393e0d7953SJiri Olsa 		break;
6403e0d7953SJiri Olsa 	case PERCENT_PERIOD_LOCAL:
6413e0d7953SJiri Olsa 		if (base)
6423e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_LOCAL;
6433e0d7953SJiri Olsa 		else
6443e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_GLOBAL;
6453e0d7953SJiri Olsa 		break;
6463e0d7953SJiri Olsa 	case PERCENT_PERIOD_GLOBAL:
6473e0d7953SJiri Olsa 		if (base)
6483e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_GLOBAL;
6493e0d7953SJiri Olsa 		else
6503e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_LOCAL;
6513e0d7953SJiri Olsa 		break;
6523e0d7953SJiri Olsa 	default:
6533e0d7953SJiri Olsa 		WARN_ON(1);
6543e0d7953SJiri Olsa 	}
6553e0d7953SJiri Olsa }
6563e0d7953SJiri Olsa 
657db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
658db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
6599783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
660aca7a94dSNamhyung Kim {
661aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
6626920e285SArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
66305e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
664aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
66516932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
66654e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
6679783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
6686920e285SArnaldo Carvalho de Melo 	char title[256];
669aca7a94dSNamhyung Kim 	int key;
670aca7a94dSNamhyung Kim 
6710683d13cSJiri Olsa 	hists__scnprintf_title(hists, title, sizeof(title));
6726920e285SArnaldo Carvalho de Melo 	if (annotate_browser__show(&browser->b, title, help) < 0)
673aca7a94dSNamhyung Kim 		return -1;
674aca7a94dSNamhyung Kim 
675db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
676aca7a94dSNamhyung Kim 
67705e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
67805e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
67905e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
680aca7a94dSNamhyung Kim 	}
681aca7a94dSNamhyung Kim 
68205e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
683aca7a94dSNamhyung Kim 
684aca7a94dSNamhyung Kim 	while (1) {
68505e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
686aca7a94dSNamhyung Kim 
687aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
688db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
689aca7a94dSNamhyung Kim 			/*
690aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
691aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
692aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
693aca7a94dSNamhyung Kim 			 */
694aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
695aca7a94dSNamhyung Kim 				nd = NULL;
696aca7a94dSNamhyung Kim 		}
697aca7a94dSNamhyung Kim 
698aca7a94dSNamhyung Kim 		switch (key) {
699aca7a94dSNamhyung Kim 		case K_TIMER:
7009783adf7SNamhyung Kim 			if (hbt)
7019783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
702aca7a94dSNamhyung Kim 
7036920e285SArnaldo Carvalho de Melo 			if (delay_secs != 0) {
704db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
7056920e285SArnaldo Carvalho de Melo 				hists__scnprintf_title(hists, title, sizeof(title));
7066920e285SArnaldo Carvalho de Melo 				annotate_browser__show(&browser->b, title, help);
7076920e285SArnaldo Carvalho de Melo 			}
708aca7a94dSNamhyung Kim 			continue;
709aca7a94dSNamhyung Kim 		case K_TAB:
710aca7a94dSNamhyung Kim 			if (nd != NULL) {
711aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
712aca7a94dSNamhyung Kim 				if (nd == NULL)
71305e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
714aca7a94dSNamhyung Kim 			} else
71505e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
716aca7a94dSNamhyung Kim 			break;
717aca7a94dSNamhyung Kim 		case K_UNTAB:
718d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
719aca7a94dSNamhyung Kim 				nd = rb_next(nd);
720aca7a94dSNamhyung Kim 				if (nd == NULL)
72105e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
722d4913cbdSMarkus Trippelsdorf 			} else
72305e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
724aca7a94dSNamhyung Kim 			break;
72554e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
726aca7a94dSNamhyung Kim 		case 'h':
72705e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
72854e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
72954e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
73054e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
7317727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
7327727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
733eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
734eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
73554e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
73654e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
73754e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
73854e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
73951f39603SArnaldo Carvalho de Melo 		"O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
74054e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
7413a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
7423e71fc03SJin Yao 		"c             Show min/max cycle\n"
74354e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
744e592488cSAndi Kleen 		"k             Toggle line numbers\n"
745d9bd7665SArnaldo Carvalho de Melo 		"P             Print to [symbol_name].annotation file.\n"
74679ee47faSFeng Tang 		"r             Run available scripts\n"
7473e0d7953SJiri Olsa 		"p             Toggle percent type [local/global]\n"
7483e0d7953SJiri Olsa 		"b             Toggle percent base [period/hits]\n"
749fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
75054e7a4e8SArnaldo Carvalho de Melo 			continue;
75179ee47faSFeng Tang 		case 'r':
75279ee47faSFeng Tang 			{
75379ee47faSFeng Tang 				script_browse(NULL);
75479ee47faSFeng Tang 				continue;
75579ee47faSFeng Tang 			}
756e592488cSAndi Kleen 		case 'k':
75716932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
758e592488cSAndi Kleen 			break;
75954e7a4e8SArnaldo Carvalho de Melo 		case 'H':
76005e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
761aca7a94dSNamhyung Kim 			break;
762aca7a94dSNamhyung Kim 		case 's':
76305e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
764aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
765aca7a94dSNamhyung Kim 			continue;
766aca7a94dSNamhyung Kim 		case 'o':
76716932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
7689761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
769aca7a94dSNamhyung Kim 			continue;
77051f39603SArnaldo Carvalho de Melo 		case 'O':
77151f39603SArnaldo Carvalho de Melo 			if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
77251f39603SArnaldo Carvalho de Melo 				notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
77351f39603SArnaldo Carvalho de Melo 			continue;
7749d1ef56dSArnaldo Carvalho de Melo 		case 'j':
77516932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
7769d1ef56dSArnaldo Carvalho de Melo 			continue;
7772402e4a9SArnaldo Carvalho de Melo 		case 'J':
77816932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
7799761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
780e9823b21SArnaldo Carvalho de Melo 			continue;
781aca7a94dSNamhyung Kim 		case '/':
78205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
783aca7a94dSNamhyung Kim show_help:
784aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
785aca7a94dSNamhyung Kim 			}
786aca7a94dSNamhyung Kim 			continue;
787aca7a94dSNamhyung Kim 		case 'n':
78805e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
78905e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
79005e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
791aca7a94dSNamhyung Kim 				goto show_help;
792aca7a94dSNamhyung Kim 			continue;
793aca7a94dSNamhyung Kim 		case '?':
79405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
795aca7a94dSNamhyung Kim 				goto show_help;
796aca7a94dSNamhyung Kim 			continue;
797e9823b21SArnaldo Carvalho de Melo 		case 'D': {
798e9823b21SArnaldo Carvalho de Melo 			static int seq;
799e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
800e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
80105e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
80205e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
80305e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
80405e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
8051cf5f98aSArnaldo Carvalho de Melo 					   notes->nr_asm_entries);
806e9823b21SArnaldo Carvalho de Melo 		}
807e9823b21SArnaldo Carvalho de Melo 			continue;
808aca7a94dSNamhyung Kim 		case K_ENTER:
809aca7a94dSNamhyung Kim 		case K_RIGHT:
8107bcbcd58SJiri Olsa 		{
8117bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
8127bcbcd58SJiri Olsa 
81305e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
814aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
8157bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
816aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
8177bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
818c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
8197bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
820c4cceae3SArnaldo Carvalho de Melo 				goto out;
821e4cc91b8SArnaldo Carvalho de Melo 			else if (!(annotate_browser__jump(browser, evsel, hbt) ||
822db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
823c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
8246ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
825c4cceae3SArnaldo Carvalho de Melo 			}
826aca7a94dSNamhyung Kim 			continue;
8277bcbcd58SJiri Olsa 		}
828d9bd7665SArnaldo Carvalho de Melo 		case 'P':
8294c650ddcSJiri Olsa 			map_symbol__annotation_dump(ms, evsel, browser->opts);
830d9bd7665SArnaldo Carvalho de Melo 			continue;
8310c4a5bceSMartin Liška 		case 't':
83216932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
83316932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
83416932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
83516932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
83616932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
8373a555c77STaeung Song 			else
83816932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
8399761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
8400c4a5bceSMartin Liška 			continue;
8413e71fc03SJin Yao 		case 'c':
8423e71fc03SJin Yao 			if (notes->options->show_minmax_cycle)
8433e71fc03SJin Yao 				notes->options->show_minmax_cycle = false;
8443e71fc03SJin Yao 			else
8453e71fc03SJin Yao 				notes->options->show_minmax_cycle = true;
8463e71fc03SJin Yao 			annotation__update_column_widths(notes);
8473e71fc03SJin Yao 			continue;
8483e0d7953SJiri Olsa 		case 'p':
8493e0d7953SJiri Olsa 		case 'b':
8503e0d7953SJiri Olsa 			switch_percent_type(browser->opts, key == 'b');
8513e0d7953SJiri Olsa 			hists__scnprintf_title(hists, title, sizeof(title));
8523e0d7953SJiri Olsa 			annotate_browser__show(&browser->b, title, help);
8533e0d7953SJiri Olsa 			continue;
854aca7a94dSNamhyung Kim 		case K_LEFT:
855aca7a94dSNamhyung Kim 		case K_ESC:
856aca7a94dSNamhyung Kim 		case 'q':
857aca7a94dSNamhyung Kim 		case CTRL('c'):
858aca7a94dSNamhyung Kim 			goto out;
859aca7a94dSNamhyung Kim 		default:
860aca7a94dSNamhyung Kim 			continue;
861aca7a94dSNamhyung Kim 		}
862aca7a94dSNamhyung Kim 
863aca7a94dSNamhyung Kim 		if (nd != NULL)
86405e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
865aca7a94dSNamhyung Kim 	}
866aca7a94dSNamhyung Kim out:
86705e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
868aca7a94dSNamhyung Kim 	return key;
869aca7a94dSNamhyung Kim }
870aca7a94dSNamhyung Kim 
871d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
872cd0cccbaSArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt,
873cd0cccbaSArnaldo Carvalho de Melo 			     struct annotation_options *opts)
874d5dbc518SArnaldo Carvalho de Melo {
875cd0cccbaSArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts);
876d5dbc518SArnaldo Carvalho de Melo }
877d5dbc518SArnaldo Carvalho de Melo 
878db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
879cd0cccbaSArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt,
880cd0cccbaSArnaldo Carvalho de Melo 			     struct annotation_options *opts)
881aca7a94dSNamhyung Kim {
882ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
883ed426915SNamhyung Kim 	SLang_reset_tty();
884ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
885ed426915SNamhyung Kim 
886cd0cccbaSArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
887aca7a94dSNamhyung Kim }
888aca7a94dSNamhyung Kim 
889db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
890db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
891cd0cccbaSArnaldo Carvalho de Melo 			 struct hist_browser_timer *hbt,
892cd0cccbaSArnaldo Carvalho de Melo 			 struct annotation_options *opts)
893aca7a94dSNamhyung Kim {
8949d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
895aca7a94dSNamhyung Kim 	struct map_symbol ms = {
896aca7a94dSNamhyung Kim 		.map = map,
897aca7a94dSNamhyung Kim 		.sym = sym,
898aca7a94dSNamhyung Kim 	};
899aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
900aca7a94dSNamhyung Kim 		.b = {
901a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
902aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
903aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
90429ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
9056920e285SArnaldo Carvalho de Melo 			.extra_title_lines = 1, /* for hists__scnprintf_title() */
906aca7a94dSNamhyung Kim 			.priv	 = &ms,
907aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
908aca7a94dSNamhyung Kim 		},
909cd0cccbaSArnaldo Carvalho de Melo 		.opts = opts,
910aca7a94dSNamhyung Kim 	};
911ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
912aca7a94dSNamhyung Kim 
913aca7a94dSNamhyung Kim 	if (sym == NULL)
914aca7a94dSNamhyung Kim 		return -1;
915aca7a94dSNamhyung Kim 
916aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
917aca7a94dSNamhyung Kim 		return -1;
918aca7a94dSNamhyung Kim 
919cd0cccbaSArnaldo Carvalho de Melo 	err = symbol__annotate2(sym, map, evsel, opts, &browser.arch);
920ee51d851SArnaldo Carvalho de Melo 	if (err) {
921ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
922ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
923ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
924b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
925aca7a94dSNamhyung Kim 	}
926aca7a94dSNamhyung Kim 
9277727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
928aca7a94dSNamhyung Kim 
9295bc49f61SArnaldo Carvalho de Melo 	browser.b.width = notes->max_line_len;
9301cf5f98aSArnaldo Carvalho de Melo 	browser.b.nr_entries = notes->nr_entries;
931aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
932aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
933e9823b21SArnaldo Carvalho de Melo 
93416932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
9351cf5f98aSArnaldo Carvalho de Melo 		ui_browser__init_asm_mode(&browser.b);
936e9823b21SArnaldo Carvalho de Melo 
937db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
938f8eb37bdSJiri Olsa 
939f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
940b793a401SArnaldo Carvalho de Melo 
941b793a401SArnaldo Carvalho de Melo out_free_offsets:
9429d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
943aca7a94dSNamhyung Kim 	return ret;
944aca7a94dSNamhyung Kim }
945