xref: /linux/tools/perf/ui/browsers/annotate.c (revision 4c650ddc2e9e8f1d8dc46f13b30b1b9a6017fb02)
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"
1269fb09f6SJin Yao #include "../../util/evlist.h"
13fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
14aca7a94dSNamhyung Kim #include <pthread.h>
15877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
168e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h>
17b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h>
18aca7a94dSNamhyung Kim 
190c4a5bceSMartin Liška struct disasm_line_samples {
200c4a5bceSMartin Liška 	double		      percent;
21bb79a232SArnaldo Carvalho de Melo 	struct sym_hist_entry he;
220c4a5bceSMartin Liška };
230c4a5bceSMartin Liška 
24dcaa3948SJin Yao struct arch;
25dcaa3948SJin Yao 
26aca7a94dSNamhyung Kim struct annotate_browser {
27aca7a94dSNamhyung Kim 	struct ui_browser	    b;
28aca7a94dSNamhyung Kim 	struct rb_root		    entries;
29aca7a94dSNamhyung Kim 	struct rb_node		   *curr_hot;
307bcbcd58SJiri Olsa 	struct annotation_line	   *selection;
31dcaa3948SJin Yao 	struct arch		   *arch;
32cd0cccbaSArnaldo Carvalho de Melo 	struct annotation_options  *opts;
33aca7a94dSNamhyung Kim 	bool			    searching_backwards;
34aca7a94dSNamhyung Kim 	char			    search_bf[128];
35aca7a94dSNamhyung Kim };
36aca7a94dSNamhyung Kim 
3795aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser)
3895aa89d9SArnaldo Carvalho de Melo {
3995aa89d9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
4095aa89d9SArnaldo Carvalho de Melo 	return symbol__annotation(ms->sym);
4195aa89d9SArnaldo Carvalho de Melo }
4295aa89d9SArnaldo Carvalho de Melo 
4316932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
44aca7a94dSNamhyung Kim {
4595aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
46d5490b96SJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
479b80d1f9SArnaldo Carvalho de Melo 	return annotation_line__filter(al, notes);
48aca7a94dSNamhyung Kim }
49aca7a94dSNamhyung Kim 
5027feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
512402e4a9SArnaldo Carvalho de Melo {
5227feb761SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
53bc1c0f3dSArnaldo Carvalho de Melo 
5427feb761SArnaldo Carvalho de Melo 	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
552402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
56bc1c0f3dSArnaldo Carvalho de Melo 	if (nr == notes->max_jump_sources)
572402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
582402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
592402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
602402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
612402e4a9SArnaldo Carvalho de Melo }
622402e4a9SArnaldo Carvalho de Melo 
63a1e9b74cSArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
642402e4a9SArnaldo Carvalho de Melo {
6527feb761SArnaldo Carvalho de Melo 	 int color = ui_browser__jumps_percent_color(browser, nr, current);
6627feb761SArnaldo Carvalho de Melo 	 return ui_browser__set_color(browser, color);
672402e4a9SArnaldo Carvalho de Melo }
682402e4a9SArnaldo Carvalho de Melo 
69a1e9b74cSArnaldo Carvalho de Melo static int annotate_browser__set_color(void *browser, int color)
70aca7a94dSNamhyung Kim {
71a1e9b74cSArnaldo Carvalho de Melo 	return ui_browser__set_color(browser, color);
724ea08b52SArnaldo Carvalho de Melo }
734ea08b52SArnaldo Carvalho de Melo 
74a1e9b74cSArnaldo Carvalho de Melo static void annotate_browser__write_graph(void *browser, int graph)
75a1e9b74cSArnaldo Carvalho de Melo {
76a1e9b74cSArnaldo Carvalho de Melo 	ui_browser__write_graph(browser, graph);
77a5433b3eSJiri Olsa }
78a5433b3eSJiri Olsa 
792ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
802ba5eca1SArnaldo Carvalho de Melo {
812ba5eca1SArnaldo Carvalho de Melo 	ui_browser__set_percent_color(browser, percent, current);
822ba5eca1SArnaldo Carvalho de Melo }
832ba5eca1SArnaldo Carvalho de Melo 
842ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__printf(void *browser, const char *fmt, ...)
852ba5eca1SArnaldo Carvalho de Melo {
862ba5eca1SArnaldo Carvalho de Melo 	va_list args;
872ba5eca1SArnaldo Carvalho de Melo 
882ba5eca1SArnaldo Carvalho de Melo 	va_start(args, fmt);
892ba5eca1SArnaldo Carvalho de Melo 	ui_browser__vprintf(browser, fmt, args);
902ba5eca1SArnaldo Carvalho de Melo 	va_end(args);
912ba5eca1SArnaldo Carvalho de Melo }
922ba5eca1SArnaldo Carvalho de Melo 
93a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
94a5433b3eSJiri Olsa {
95a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9695aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
97a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
98c298304bSArnaldo Carvalho de Melo 	struct annotation_write_ops ops = {
99c298304bSArnaldo Carvalho de Melo 		.first_line		 = row == 0,
100c298304bSArnaldo Carvalho de Melo 		.current_entry		 = ui_browser__is_current_entry(browser, row),
101c298304bSArnaldo Carvalho de Melo 		.change_color		 = (!notes->options->hide_src_code &&
102c298304bSArnaldo Carvalho de Melo 					    (!ops.current_entry ||
103c298304bSArnaldo Carvalho de Melo 					     (browser->use_navkeypressed &&
104c298304bSArnaldo Carvalho de Melo 					      !browser->navkeypressed))),
105c298304bSArnaldo Carvalho de Melo 		.width			 = browser->width,
106c298304bSArnaldo Carvalho de Melo 		.obj			 = browser,
107c298304bSArnaldo Carvalho de Melo 		.set_color		 = annotate_browser__set_color,
108c298304bSArnaldo Carvalho de Melo 		.set_percent_color	 = annotate_browser__set_percent_color,
109c298304bSArnaldo Carvalho de Melo 		.set_jumps_percent_color = ui_browser__set_jumps_percent_color,
110c298304bSArnaldo Carvalho de Melo 		.printf			 = annotate_browser__printf,
111c298304bSArnaldo Carvalho de Melo 		.write_graph		 = annotate_browser__write_graph,
112c298304bSArnaldo Carvalho de Melo 	};
113a5433b3eSJiri Olsa 
114a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
115a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
116c298304bSArnaldo Carvalho de Melo 		ops.width += 1;
117a5433b3eSJiri Olsa 
118*4c650ddcSJiri Olsa 	annotation_line__write(al, notes, &ops, ab->opts);
119aca7a94dSNamhyung Kim 
120c298304bSArnaldo Carvalho de Melo 	if (ops.current_entry)
121a5433b3eSJiri Olsa 		ab->selection = al;
122aca7a94dSNamhyung Kim }
123aca7a94dSNamhyung Kim 
1247e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
1257e63a13aSJin Yao {
126a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
1277e63a13aSJin Yao 	const char *name;
1287e63a13aSJin Yao 
1297e63a13aSJin Yao 	if (!pos)
1307e63a13aSJin Yao 		return false;
1317e63a13aSJin Yao 
1327e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
1337e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
1347e63a13aSJin Yao 	else
1357e63a13aSJin Yao 		name = pos->ins.name;
1367e63a13aSJin Yao 
1377e63a13aSJin Yao 	if (!name || !cursor->ins.name)
1387e63a13aSJin Yao 		return false;
1397e63a13aSJin Yao 
1407e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
1417e63a13aSJin Yao }
1427e63a13aSJin Yao 
1439d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
144a3f895beSArnaldo Carvalho de Melo {
145a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1467bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
147a5ef2702SJiri Olsa 	struct annotation_line *target;
14883b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
14932ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
15032ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
1510e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1526af612d2SArnaldo Carvalho de Melo 	u8 pcnt_width = annotation__pcnt_width(notes);
15300ea0eb2SArnaldo Carvalho de Melo 	int width;
15432ae1efdSNamhyung Kim 
15532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
15632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
15732ae1efdSNamhyung Kim 		return;
158a3f895beSArnaldo Carvalho de Melo 
1592eff0611SArnaldo Carvalho de Melo 	if (!disasm_line__is_valid_local_jump(cursor, sym))
160a3f895beSArnaldo Carvalho de Melo 		return;
161a3f895beSArnaldo Carvalho de Melo 
1629c04409dSArnaldo Carvalho de Melo 	/*
1639c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
1649c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
1659c04409dSArnaldo Carvalho de Melo 	 *
1669c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
1679c04409dSArnaldo Carvalho de Melo 	 *
1689c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
1699c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
1709c04409dSArnaldo Carvalho de Melo 	 *
1719c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
1729c04409dSArnaldo Carvalho de Melo 	 *
1739c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
1749c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
1759c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
1769c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
1779c04409dSArnaldo Carvalho de Melo 	 *
1789c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
1799c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
1809c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
1819c04409dSArnaldo Carvalho de Melo 	 */
1829d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
1839c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
1849d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
1859c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
1869c04409dSArnaldo Carvalho de Melo 		return;
1879c04409dSArnaldo Carvalho de Melo 	}
1889d1ef56dSArnaldo Carvalho de Melo 
18916932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
1904850c92eSArnaldo Carvalho de Melo 		from = cursor->al.idx_asm;
1914850c92eSArnaldo Carvalho de Melo 		to = target->idx_asm;
192a3f895beSArnaldo Carvalho de Melo 	} else {
1934850c92eSArnaldo Carvalho de Melo 		from = (u64)cursor->al.idx;
1944850c92eSArnaldo Carvalho de Melo 		to = (u64)target->idx;
195a3f895beSArnaldo Carvalho de Melo 	}
196a3f895beSArnaldo Carvalho de Melo 
1970e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
198b40982e8SJin Yao 
19978ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
200b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
2019761e86eSArnaldo Carvalho de Melo 				 pcnt_width + 2 + notes->widths.addr + width,
202c7e7b610SNamhyung Kim 				 from, to);
2037e63a13aSJin Yao 
2047e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
2057e63a13aSJin Yao 		ui_browser__mark_fused(browser,
2069761e86eSArnaldo Carvalho de Melo 				       pcnt_width + 3 + notes->widths.addr + width,
2077e63a13aSJin Yao 				       from - 1,
2087e63a13aSJin Yao 				       to > from ? true : false);
2097e63a13aSJin Yao 	}
210a3f895beSArnaldo Carvalho de Melo }
211a3f895beSArnaldo Carvalho de Melo 
212a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
213a3f895beSArnaldo Carvalho de Melo {
21495aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
215a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
2166af612d2SArnaldo Carvalho de Melo 	int pcnt_width = annotation__pcnt_width(notes);
217a3f895beSArnaldo Carvalho de Melo 
21816932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
2199d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
220a3f895beSArnaldo Carvalho de Melo 
22183b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
222e726c851SArnaldo Carvalho de Melo 	__ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
223a3f895beSArnaldo Carvalho de Melo 	return ret;
224a3f895beSArnaldo Carvalho de Melo }
225a3f895beSArnaldo Carvalho de Melo 
226b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
227c7e7b610SNamhyung Kim {
228c7e7b610SNamhyung Kim 	int i;
229c7e7b610SNamhyung Kim 
230c2f938baSJiri Olsa 	for (i = 0; i < a->data_nr; i++) {
231c2f938baSJiri Olsa 		if (a->data[i].percent == b->data[i].percent)
232c7e7b610SNamhyung Kim 			continue;
233c2f938baSJiri Olsa 		return a->data[i].percent < b->data[i].percent;
234c7e7b610SNamhyung Kim 	}
235c7e7b610SNamhyung Kim 	return 0;
236c7e7b610SNamhyung Kim }
237c7e7b610SNamhyung Kim 
238b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
239aca7a94dSNamhyung Kim {
24029ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
241aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
2423ab6db8dSJiri Olsa 	struct annotation_line *l;
243aca7a94dSNamhyung Kim 
244aca7a94dSNamhyung Kim 	while (*p != NULL) {
245aca7a94dSNamhyung Kim 		parent = *p;
2463ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
247c7e7b610SNamhyung Kim 
248b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
249aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
250aca7a94dSNamhyung Kim 		else
251aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
252aca7a94dSNamhyung Kim 	}
2533ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
2543ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
255aca7a94dSNamhyung Kim }
256aca7a94dSNamhyung Kim 
25705e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
258ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
259aca7a94dSNamhyung Kim {
2609b80d1f9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
261aca7a94dSNamhyung Kim 	unsigned back;
262aca7a94dSNamhyung Kim 
26305e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
26405e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
26505e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
266aca7a94dSNamhyung Kim 
26705e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
268ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
269aca7a94dSNamhyung Kim 
2709b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(pos, notes))
271aca7a94dSNamhyung Kim 			continue;
272aca7a94dSNamhyung Kim 
27305e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
274aca7a94dSNamhyung Kim 		--back;
275aca7a94dSNamhyung Kim 	}
276aca7a94dSNamhyung Kim 
277ec03a77dSJiri Olsa 	browser->b.top = pos;
27805e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
279aca7a94dSNamhyung Kim }
280aca7a94dSNamhyung Kim 
281aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
282aca7a94dSNamhyung Kim 					 struct rb_node *nd)
283aca7a94dSNamhyung Kim {
28495aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
2854850c92eSArnaldo Carvalho de Melo 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
2864850c92eSArnaldo Carvalho de Melo 	u32 idx = pos->idx;
287aca7a94dSNamhyung Kim 
28816932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
2894850c92eSArnaldo Carvalho de Melo 		idx = pos->idx_asm;
290a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
291aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
292aca7a94dSNamhyung Kim }
293aca7a94dSNamhyung Kim 
294aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
295db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
296aca7a94dSNamhyung Kim {
297aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
298aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
299aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
300c4c72436SJiri Olsa 	struct disasm_line *pos;
301aca7a94dSNamhyung Kim 
302aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
303aca7a94dSNamhyung Kim 
304aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
305aca7a94dSNamhyung Kim 
306e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
307e425da6cSJiri Olsa 
308a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
309c7e7b610SNamhyung Kim 		double max_percent = 0.0;
310c7e7b610SNamhyung Kim 		int i;
311e64aa75bSNamhyung Kim 
312d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
3135b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
314e64aa75bSNamhyung Kim 			continue;
315e64aa75bSNamhyung Kim 		}
316e64aa75bSNamhyung Kim 
317c2f938baSJiri Olsa 		for (i = 0; i < pos->al.data_nr; i++) {
3186d9f0c2dSJiri Olsa 			double percent;
3190c4a5bceSMartin Liška 
3206d9f0c2dSJiri Olsa 			percent = annotation_data__percent(&pos->al.data[i],
3216d9f0c2dSJiri Olsa 							   PERCENT_HITS_LOCAL);
3226d9f0c2dSJiri Olsa 
3236d9f0c2dSJiri Olsa 			if (max_percent < percent)
3246d9f0c2dSJiri Olsa 				max_percent = percent;
325c7e7b610SNamhyung Kim 		}
326c7e7b610SNamhyung Kim 
32737236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
3285b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
329aca7a94dSNamhyung Kim 			continue;
330aca7a94dSNamhyung Kim 		}
331b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
332aca7a94dSNamhyung Kim 	}
333aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
334aca7a94dSNamhyung Kim 
335aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
336aca7a94dSNamhyung Kim }
337aca7a94dSNamhyung Kim 
338aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
339aca7a94dSNamhyung Kim {
34095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
341ec03a77dSJiri Olsa 	struct annotation_line *al;
342aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
343aca7a94dSNamhyung Kim 
344aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
345ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
346aca7a94dSNamhyung Kim 
34716932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3484850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3494850c92eSArnaldo Carvalho de Melo 			offset = al->idx;
350aca7a94dSNamhyung Kim 
3511cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_entries;
35216932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
353aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3544850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx - offset;
3554850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx;
356aca7a94dSNamhyung Kim 	} else {
3574850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < 0) {
358aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
359aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
360aca7a94dSNamhyung Kim 			return false;
361aca7a94dSNamhyung Kim 		}
362aca7a94dSNamhyung Kim 
3634850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3644850c92eSArnaldo Carvalho de Melo 			offset = al->idx_asm;
365aca7a94dSNamhyung Kim 
3661cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_asm_entries;
36716932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
368aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3694850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx_asm - offset;
3704850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx_asm;
371aca7a94dSNamhyung Kim 	}
372aca7a94dSNamhyung Kim 
373aca7a94dSNamhyung Kim 	return true;
374aca7a94dSNamhyung Kim }
375aca7a94dSNamhyung Kim 
3761cf5f98aSArnaldo Carvalho de Melo static void ui_browser__init_asm_mode(struct ui_browser *browser)
377e9823b21SArnaldo Carvalho de Melo {
3781cf5f98aSArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
3791cf5f98aSArnaldo Carvalho de Melo 	ui_browser__reset_index(browser);
3801cf5f98aSArnaldo Carvalho de Melo 	browser->nr_entries = notes->nr_asm_entries;
381e9823b21SArnaldo Carvalho de Melo }
382e9823b21SArnaldo Carvalho de Melo 
38334f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
38434f77abcSAdrian Hunter 
38534f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
38634f77abcSAdrian Hunter 		     size_t sz)
38734f77abcSAdrian Hunter {
38834f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
38934f77abcSAdrian Hunter }
39034f77abcSAdrian Hunter 
391e4cc91b8SArnaldo Carvalho de Melo /*
392e4cc91b8SArnaldo Carvalho de Melo  * This can be called from external jumps, i.e. jumps from one functon
393e4cc91b8SArnaldo Carvalho de Melo  * to another, like from the kernel's entry_SYSCALL_64 function to the
394e4cc91b8SArnaldo Carvalho de Melo  * swapgs_restore_regs_and_return_to_usermode() function.
395e4cc91b8SArnaldo Carvalho de Melo  *
396e4cc91b8SArnaldo Carvalho de Melo  * So all we check here is that dl->ops.target.sym is set, if it is, just
397e4cc91b8SArnaldo Carvalho de Melo  * go to that function and when exiting from its disassembly, come back
398e4cc91b8SArnaldo Carvalho de Melo  * to the calling function.
399e4cc91b8SArnaldo Carvalho de Melo  */
400db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
401db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
4029783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
403aca7a94dSNamhyung Kim {
404aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
4057bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
406aca7a94dSNamhyung Kim 	struct annotation *notes;
40734f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
408aca7a94dSNamhyung Kim 
409696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
410aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
411aca7a94dSNamhyung Kim 		return true;
412aca7a94dSNamhyung Kim 	}
413aca7a94dSNamhyung Kim 
414696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
415aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
416aca7a94dSNamhyung Kim 
41714c8dde1SArnaldo Carvalho de Melo 	if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) {
418aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
419aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
420696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
421aca7a94dSNamhyung Kim 		return true;
422aca7a94dSNamhyung Kim 	}
423aca7a94dSNamhyung Kim 
424aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
425cd0cccbaSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
4261179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
42734f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
428aca7a94dSNamhyung Kim 	return true;
429aca7a94dSNamhyung Kim }
430aca7a94dSNamhyung Kim 
43129ed6e76SArnaldo Carvalho de Melo static
43229ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
433aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
434aca7a94dSNamhyung Kim {
43595aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
43629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
437aca7a94dSNamhyung Kim 
438aca7a94dSNamhyung Kim 	*idx = 0;
439a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
440d5490b96SJiri Olsa 		if (pos->al.offset == offset)
441aca7a94dSNamhyung Kim 			return pos;
4429b80d1f9SArnaldo Carvalho de Melo 		if (!annotation_line__filter(&pos->al, notes))
443aca7a94dSNamhyung Kim 			++*idx;
444aca7a94dSNamhyung Kim 	}
445aca7a94dSNamhyung Kim 
446aca7a94dSNamhyung Kim 	return NULL;
447aca7a94dSNamhyung Kim }
448aca7a94dSNamhyung Kim 
449e4cc91b8SArnaldo Carvalho de Melo static bool annotate_browser__jump(struct annotate_browser *browser,
450e4cc91b8SArnaldo Carvalho de Melo 				   struct perf_evsel *evsel,
451e4cc91b8SArnaldo Carvalho de Melo 				   struct hist_browser_timer *hbt)
452aca7a94dSNamhyung Kim {
4537bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
4545252b1aeSArnaldo Carvalho de Melo 	u64 offset;
4554f9d0325SArnaldo Carvalho de Melo 	s64 idx;
456aca7a94dSNamhyung Kim 
45775b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
458aca7a94dSNamhyung Kim 		return false;
459aca7a94dSNamhyung Kim 
460e4cc91b8SArnaldo Carvalho de Melo 	if (dl->ops.target.outside) {
461e4cc91b8SArnaldo Carvalho de Melo 		annotate_browser__callq(browser, evsel, hbt);
462e4cc91b8SArnaldo Carvalho de Melo 		return true;
463e4cc91b8SArnaldo Carvalho de Melo 	}
464e4cc91b8SArnaldo Carvalho de Melo 
4655252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
4665252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
46729ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
4685252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
469aca7a94dSNamhyung Kim 		return true;
470aca7a94dSNamhyung Kim 	}
471aca7a94dSNamhyung Kim 
472ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
473aca7a94dSNamhyung Kim 
474aca7a94dSNamhyung Kim 	return true;
475aca7a94dSNamhyung Kim }
476aca7a94dSNamhyung Kim 
47729ed6e76SArnaldo Carvalho de Melo static
4789213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
479aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
480aca7a94dSNamhyung Kim {
48195aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
4829213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
483aca7a94dSNamhyung Kim 
484aca7a94dSNamhyung Kim 	*idx = browser->b.index;
4859213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
4869b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
487aca7a94dSNamhyung Kim 			continue;
488aca7a94dSNamhyung Kim 
489aca7a94dSNamhyung Kim 		++*idx;
490aca7a94dSNamhyung Kim 
4919213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
4929213afbdSJiri Olsa 			return al;
493aca7a94dSNamhyung Kim 	}
494aca7a94dSNamhyung Kim 
495aca7a94dSNamhyung Kim 	return NULL;
496aca7a94dSNamhyung Kim }
497aca7a94dSNamhyung Kim 
498aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
499aca7a94dSNamhyung Kim {
5009213afbdSJiri Olsa 	struct annotation_line *al;
501aca7a94dSNamhyung Kim 	s64 idx;
502aca7a94dSNamhyung Kim 
5039213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
5049213afbdSJiri Olsa 	if (al == NULL) {
505aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
506aca7a94dSNamhyung Kim 		return false;
507aca7a94dSNamhyung Kim 	}
508aca7a94dSNamhyung Kim 
509ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
510aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
511aca7a94dSNamhyung Kim 	return true;
512aca7a94dSNamhyung Kim }
513aca7a94dSNamhyung Kim 
51429ed6e76SArnaldo Carvalho de Melo static
5159213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
516aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
517aca7a94dSNamhyung Kim {
51895aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
5199213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
520aca7a94dSNamhyung Kim 
521aca7a94dSNamhyung Kim 	*idx = browser->b.index;
5229213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
5239b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
524aca7a94dSNamhyung Kim 			continue;
525aca7a94dSNamhyung Kim 
526aca7a94dSNamhyung Kim 		--*idx;
527aca7a94dSNamhyung Kim 
5289213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
5299213afbdSJiri Olsa 			return al;
530aca7a94dSNamhyung Kim 	}
531aca7a94dSNamhyung Kim 
532aca7a94dSNamhyung Kim 	return NULL;
533aca7a94dSNamhyung Kim }
534aca7a94dSNamhyung Kim 
535aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
536aca7a94dSNamhyung Kim {
5379213afbdSJiri Olsa 	struct annotation_line *al;
538aca7a94dSNamhyung Kim 	s64 idx;
539aca7a94dSNamhyung Kim 
5409213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
5419213afbdSJiri Olsa 	if (al == NULL) {
542aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
543aca7a94dSNamhyung Kim 		return false;
544aca7a94dSNamhyung Kim 	}
545aca7a94dSNamhyung Kim 
546ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
547aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
548aca7a94dSNamhyung Kim 	return true;
549aca7a94dSNamhyung Kim }
550aca7a94dSNamhyung Kim 
551aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
552aca7a94dSNamhyung Kim 					    int delay_secs)
553aca7a94dSNamhyung Kim {
554aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
555aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
556aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
557aca7a94dSNamhyung Kim 	    !*browser->search_bf)
558aca7a94dSNamhyung Kim 		return false;
559aca7a94dSNamhyung Kim 
560aca7a94dSNamhyung Kim 	return true;
561aca7a94dSNamhyung Kim }
562aca7a94dSNamhyung Kim 
563aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
564aca7a94dSNamhyung Kim {
565aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
566aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
567aca7a94dSNamhyung Kim 
568aca7a94dSNamhyung Kim 	return false;
569aca7a94dSNamhyung Kim }
570aca7a94dSNamhyung Kim 
571aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
572aca7a94dSNamhyung Kim 					      int delay_secs)
573aca7a94dSNamhyung Kim {
574aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
575aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
576aca7a94dSNamhyung Kim 
577aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
578aca7a94dSNamhyung Kim }
579aca7a94dSNamhyung Kim 
580aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
581aca7a94dSNamhyung Kim 					   int delay_secs)
582aca7a94dSNamhyung Kim {
583aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
584aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
585aca7a94dSNamhyung Kim 
586aca7a94dSNamhyung Kim 	return false;
587aca7a94dSNamhyung Kim }
588aca7a94dSNamhyung Kim 
589aca7a94dSNamhyung Kim static
590aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
591aca7a94dSNamhyung Kim 					       int delay_secs)
592aca7a94dSNamhyung Kim {
593aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
594aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
595aca7a94dSNamhyung Kim 
596aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
597aca7a94dSNamhyung Kim }
598aca7a94dSNamhyung Kim 
5996920e285SArnaldo Carvalho de Melo static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
6006920e285SArnaldo Carvalho de Melo {
6016920e285SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
6026920e285SArnaldo Carvalho de Melo 	struct symbol *sym = ms->sym;
6036920e285SArnaldo Carvalho de Melo 	char symbol_dso[SYM_TITLE_MAX_SIZE];
6046920e285SArnaldo Carvalho de Melo 
6056920e285SArnaldo Carvalho de Melo 	if (ui_browser__show(browser, title, help) < 0)
6066920e285SArnaldo Carvalho de Melo 		return -1;
6076920e285SArnaldo Carvalho de Melo 
6086920e285SArnaldo Carvalho de Melo 	sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso));
6096920e285SArnaldo Carvalho de Melo 
6106920e285SArnaldo Carvalho de Melo 	ui_browser__gotorc_title(browser, 0, 0);
6116920e285SArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_ROOT);
6126920e285SArnaldo Carvalho de Melo 	ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
6136920e285SArnaldo Carvalho de Melo 	return 0;
6146920e285SArnaldo Carvalho de Melo }
6156920e285SArnaldo Carvalho de Melo 
616db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
617db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
6189783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
619aca7a94dSNamhyung Kim {
620aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
6216920e285SArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
62205e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
623aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
62416932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
62554e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
6269783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
6276920e285SArnaldo Carvalho de Melo 	char title[256];
628aca7a94dSNamhyung Kim 	int key;
629aca7a94dSNamhyung Kim 
6300683d13cSJiri Olsa 	hists__scnprintf_title(hists, title, sizeof(title));
6316920e285SArnaldo Carvalho de Melo 	if (annotate_browser__show(&browser->b, title, help) < 0)
632aca7a94dSNamhyung Kim 		return -1;
633aca7a94dSNamhyung Kim 
634db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
635aca7a94dSNamhyung Kim 
63605e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
63705e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
63805e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
639aca7a94dSNamhyung Kim 	}
640aca7a94dSNamhyung Kim 
64105e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
642aca7a94dSNamhyung Kim 
643aca7a94dSNamhyung Kim 	while (1) {
64405e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
645aca7a94dSNamhyung Kim 
646aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
647db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
648aca7a94dSNamhyung Kim 			/*
649aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
650aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
651aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
652aca7a94dSNamhyung Kim 			 */
653aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
654aca7a94dSNamhyung Kim 				nd = NULL;
655aca7a94dSNamhyung Kim 		}
656aca7a94dSNamhyung Kim 
657aca7a94dSNamhyung Kim 		switch (key) {
658aca7a94dSNamhyung Kim 		case K_TIMER:
6599783adf7SNamhyung Kim 			if (hbt)
6609783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
661aca7a94dSNamhyung Kim 
6626920e285SArnaldo Carvalho de Melo 			if (delay_secs != 0) {
663db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
6646920e285SArnaldo Carvalho de Melo 				hists__scnprintf_title(hists, title, sizeof(title));
6656920e285SArnaldo Carvalho de Melo 				annotate_browser__show(&browser->b, title, help);
6666920e285SArnaldo Carvalho de Melo 			}
667aca7a94dSNamhyung Kim 			continue;
668aca7a94dSNamhyung Kim 		case K_TAB:
669aca7a94dSNamhyung Kim 			if (nd != NULL) {
670aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
671aca7a94dSNamhyung Kim 				if (nd == NULL)
67205e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
673aca7a94dSNamhyung Kim 			} else
67405e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
675aca7a94dSNamhyung Kim 			break;
676aca7a94dSNamhyung Kim 		case K_UNTAB:
677d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
678aca7a94dSNamhyung Kim 				nd = rb_next(nd);
679aca7a94dSNamhyung Kim 				if (nd == NULL)
68005e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
681d4913cbdSMarkus Trippelsdorf 			} else
68205e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
683aca7a94dSNamhyung Kim 			break;
68454e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
685aca7a94dSNamhyung Kim 		case 'h':
68605e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
68754e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
68854e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
68954e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
6907727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
6917727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
692eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
693eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
69454e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
69554e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
69654e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
69754e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
69851f39603SArnaldo Carvalho de Melo 		"O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
69954e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
7003a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
7013e71fc03SJin Yao 		"c             Show min/max cycle\n"
70254e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
703e592488cSAndi Kleen 		"k             Toggle line numbers\n"
704d9bd7665SArnaldo Carvalho de Melo 		"P             Print to [symbol_name].annotation file.\n"
70579ee47faSFeng Tang 		"r             Run available scripts\n"
706fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
70754e7a4e8SArnaldo Carvalho de Melo 			continue;
70879ee47faSFeng Tang 		case 'r':
70979ee47faSFeng Tang 			{
71079ee47faSFeng Tang 				script_browse(NULL);
71179ee47faSFeng Tang 				continue;
71279ee47faSFeng Tang 			}
713e592488cSAndi Kleen 		case 'k':
71416932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
715e592488cSAndi Kleen 			break;
71654e7a4e8SArnaldo Carvalho de Melo 		case 'H':
71705e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
718aca7a94dSNamhyung Kim 			break;
719aca7a94dSNamhyung Kim 		case 's':
72005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
721aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
722aca7a94dSNamhyung Kim 			continue;
723aca7a94dSNamhyung Kim 		case 'o':
72416932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
7259761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
726aca7a94dSNamhyung Kim 			continue;
72751f39603SArnaldo Carvalho de Melo 		case 'O':
72851f39603SArnaldo Carvalho de Melo 			if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
72951f39603SArnaldo Carvalho de Melo 				notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
73051f39603SArnaldo Carvalho de Melo 			continue;
7319d1ef56dSArnaldo Carvalho de Melo 		case 'j':
73216932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
7339d1ef56dSArnaldo Carvalho de Melo 			continue;
7342402e4a9SArnaldo Carvalho de Melo 		case 'J':
73516932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
7369761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
737e9823b21SArnaldo Carvalho de Melo 			continue;
738aca7a94dSNamhyung Kim 		case '/':
73905e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
740aca7a94dSNamhyung Kim show_help:
741aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
742aca7a94dSNamhyung Kim 			}
743aca7a94dSNamhyung Kim 			continue;
744aca7a94dSNamhyung Kim 		case 'n':
74505e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
74605e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
74705e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
748aca7a94dSNamhyung Kim 				goto show_help;
749aca7a94dSNamhyung Kim 			continue;
750aca7a94dSNamhyung Kim 		case '?':
75105e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
752aca7a94dSNamhyung Kim 				goto show_help;
753aca7a94dSNamhyung Kim 			continue;
754e9823b21SArnaldo Carvalho de Melo 		case 'D': {
755e9823b21SArnaldo Carvalho de Melo 			static int seq;
756e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
757e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
75805e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
75905e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
76005e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
76105e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
7621cf5f98aSArnaldo Carvalho de Melo 					   notes->nr_asm_entries);
763e9823b21SArnaldo Carvalho de Melo 		}
764e9823b21SArnaldo Carvalho de Melo 			continue;
765aca7a94dSNamhyung Kim 		case K_ENTER:
766aca7a94dSNamhyung Kim 		case K_RIGHT:
7677bcbcd58SJiri Olsa 		{
7687bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
7697bcbcd58SJiri Olsa 
77005e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
771aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
7727bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
773aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
7747bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
775c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
7767bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
777c4cceae3SArnaldo Carvalho de Melo 				goto out;
778e4cc91b8SArnaldo Carvalho de Melo 			else if (!(annotate_browser__jump(browser, evsel, hbt) ||
779db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
780c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
7816ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
782c4cceae3SArnaldo Carvalho de Melo 			}
783aca7a94dSNamhyung Kim 			continue;
7847bcbcd58SJiri Olsa 		}
785d9bd7665SArnaldo Carvalho de Melo 		case 'P':
786*4c650ddcSJiri Olsa 			map_symbol__annotation_dump(ms, evsel, browser->opts);
787d9bd7665SArnaldo Carvalho de Melo 			continue;
7880c4a5bceSMartin Liška 		case 't':
78916932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
79016932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
79116932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
79216932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
79316932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
7943a555c77STaeung Song 			else
79516932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
7969761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
7970c4a5bceSMartin Liška 			continue;
7983e71fc03SJin Yao 		case 'c':
7993e71fc03SJin Yao 			if (notes->options->show_minmax_cycle)
8003e71fc03SJin Yao 				notes->options->show_minmax_cycle = false;
8013e71fc03SJin Yao 			else
8023e71fc03SJin Yao 				notes->options->show_minmax_cycle = true;
8033e71fc03SJin Yao 			annotation__update_column_widths(notes);
8043e71fc03SJin Yao 			continue;
805aca7a94dSNamhyung Kim 		case K_LEFT:
806aca7a94dSNamhyung Kim 		case K_ESC:
807aca7a94dSNamhyung Kim 		case 'q':
808aca7a94dSNamhyung Kim 		case CTRL('c'):
809aca7a94dSNamhyung Kim 			goto out;
810aca7a94dSNamhyung Kim 		default:
811aca7a94dSNamhyung Kim 			continue;
812aca7a94dSNamhyung Kim 		}
813aca7a94dSNamhyung Kim 
814aca7a94dSNamhyung Kim 		if (nd != NULL)
81505e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
816aca7a94dSNamhyung Kim 	}
817aca7a94dSNamhyung Kim out:
81805e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
819aca7a94dSNamhyung Kim 	return key;
820aca7a94dSNamhyung Kim }
821aca7a94dSNamhyung Kim 
822d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
823cd0cccbaSArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt,
824cd0cccbaSArnaldo Carvalho de Melo 			     struct annotation_options *opts)
825d5dbc518SArnaldo Carvalho de Melo {
826cd0cccbaSArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts);
827d5dbc518SArnaldo Carvalho de Melo }
828d5dbc518SArnaldo Carvalho de Melo 
829db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
830cd0cccbaSArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt,
831cd0cccbaSArnaldo Carvalho de Melo 			     struct annotation_options *opts)
832aca7a94dSNamhyung Kim {
833ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
834ed426915SNamhyung Kim 	SLang_reset_tty();
835ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
836ed426915SNamhyung Kim 
837cd0cccbaSArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
838aca7a94dSNamhyung Kim }
839aca7a94dSNamhyung Kim 
840db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
841db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
842cd0cccbaSArnaldo Carvalho de Melo 			 struct hist_browser_timer *hbt,
843cd0cccbaSArnaldo Carvalho de Melo 			 struct annotation_options *opts)
844aca7a94dSNamhyung Kim {
8459d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
846aca7a94dSNamhyung Kim 	struct map_symbol ms = {
847aca7a94dSNamhyung Kim 		.map = map,
848aca7a94dSNamhyung Kim 		.sym = sym,
849aca7a94dSNamhyung Kim 	};
850aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
851aca7a94dSNamhyung Kim 		.b = {
852a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
853aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
854aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
85529ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
8566920e285SArnaldo Carvalho de Melo 			.extra_title_lines = 1, /* for hists__scnprintf_title() */
857aca7a94dSNamhyung Kim 			.priv	 = &ms,
858aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
859aca7a94dSNamhyung Kim 		},
860cd0cccbaSArnaldo Carvalho de Melo 		.opts = opts,
861aca7a94dSNamhyung Kim 	};
862ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
863aca7a94dSNamhyung Kim 
864aca7a94dSNamhyung Kim 	if (sym == NULL)
865aca7a94dSNamhyung Kim 		return -1;
866aca7a94dSNamhyung Kim 
867aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
868aca7a94dSNamhyung Kim 		return -1;
869aca7a94dSNamhyung Kim 
870cd0cccbaSArnaldo Carvalho de Melo 	err = symbol__annotate2(sym, map, evsel, opts, &browser.arch);
871ee51d851SArnaldo Carvalho de Melo 	if (err) {
872ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
873ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
874ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
875b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
876aca7a94dSNamhyung Kim 	}
877aca7a94dSNamhyung Kim 
8787727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
879aca7a94dSNamhyung Kim 
8805bc49f61SArnaldo Carvalho de Melo 	browser.b.width = notes->max_line_len;
8811cf5f98aSArnaldo Carvalho de Melo 	browser.b.nr_entries = notes->nr_entries;
882aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
883aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
884e9823b21SArnaldo Carvalho de Melo 
88516932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
8861cf5f98aSArnaldo Carvalho de Melo 		ui_browser__init_asm_mode(&browser.b);
887e9823b21SArnaldo Carvalho de Melo 
888db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
889f8eb37bdSJiri Olsa 
890f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
891b793a401SArnaldo Carvalho de Melo 
892b793a401SArnaldo Carvalho de Melo out_free_offsets:
8939d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
894aca7a94dSNamhyung Kim 	return ret;
895aca7a94dSNamhyung Kim }
896