xref: /linux/tools/perf/ui/browsers/annotate.c (revision 9b80d1f946ee40923f7bf51c69cb3a6ac6097e4a)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2aca7a94dSNamhyung Kim #include "../../util/util.h"
3aca7a94dSNamhyung Kim #include "../browser.h"
4aca7a94dSNamhyung Kim #include "../helpline.h"
5aca7a94dSNamhyung Kim #include "../ui.h"
6aca7a94dSNamhyung Kim #include "../util.h"
7aca7a94dSNamhyung Kim #include "../../util/annotate.h"
8aca7a94dSNamhyung Kim #include "../../util/hist.h"
9aca7a94dSNamhyung Kim #include "../../util/sort.h"
10aca7a94dSNamhyung Kim #include "../../util/symbol.h"
11db8fd07aSNamhyung Kim #include "../../util/evsel.h"
1241840d21STaeung Song #include "../../util/config.h"
1369fb09f6SJin Yao #include "../../util/evlist.h"
14fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
15aca7a94dSNamhyung Kim #include <pthread.h>
16877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
178e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h>
18b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h>
19aca7a94dSNamhyung Kim 
200c4a5bceSMartin Liška struct disasm_line_samples {
210c4a5bceSMartin Liška 	double		      percent;
22bb79a232SArnaldo Carvalho de Melo 	struct sym_hist_entry he;
230c4a5bceSMartin Liška };
240c4a5bceSMartin Liška 
2598bc80b0SArnaldo Carvalho de Melo static struct annotation_options annotate_browser__opts = {
26e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
27e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
28e9823b21SArnaldo Carvalho de Melo };
29e9823b21SArnaldo Carvalho de Melo 
30dcaa3948SJin Yao struct arch;
31dcaa3948SJin Yao 
32aca7a94dSNamhyung Kim struct annotate_browser {
33aca7a94dSNamhyung Kim 	struct ui_browser	    b;
34aca7a94dSNamhyung Kim 	struct rb_root		    entries;
35aca7a94dSNamhyung Kim 	struct rb_node		   *curr_hot;
367bcbcd58SJiri Olsa 	struct annotation_line	   *selection;
37dcaa3948SJin Yao 	struct arch		   *arch;
38aca7a94dSNamhyung Kim 	bool			    searching_backwards;
39aca7a94dSNamhyung Kim 	char			    search_bf[128];
40aca7a94dSNamhyung Kim };
41aca7a94dSNamhyung Kim 
4295aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser)
4395aa89d9SArnaldo Carvalho de Melo {
4495aa89d9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
4595aa89d9SArnaldo Carvalho de Melo 	return symbol__annotation(ms->sym);
4695aa89d9SArnaldo Carvalho de Melo }
4795aa89d9SArnaldo Carvalho de Melo 
4816932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
49aca7a94dSNamhyung Kim {
5095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
51d5490b96SJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
52*9b80d1f9SArnaldo Carvalho de Melo 	return annotation_line__filter(al, notes);
53aca7a94dSNamhyung Kim }
54aca7a94dSNamhyung Kim 
5527feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
562402e4a9SArnaldo Carvalho de Melo {
5727feb761SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
58bc1c0f3dSArnaldo Carvalho de Melo 
5927feb761SArnaldo Carvalho de Melo 	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
602402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
61bc1c0f3dSArnaldo Carvalho de Melo 	if (nr == notes->max_jump_sources)
622402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
632402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
642402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
652402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
662402e4a9SArnaldo Carvalho de Melo }
672402e4a9SArnaldo Carvalho de Melo 
68a1e9b74cSArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
692402e4a9SArnaldo Carvalho de Melo {
7027feb761SArnaldo Carvalho de Melo 	 int color = ui_browser__jumps_percent_color(browser, nr, current);
7127feb761SArnaldo Carvalho de Melo 	 return ui_browser__set_color(browser, color);
722402e4a9SArnaldo Carvalho de Melo }
732402e4a9SArnaldo Carvalho de Melo 
74a1e9b74cSArnaldo Carvalho de Melo static int annotate_browser__set_color(void *browser, int color)
75aca7a94dSNamhyung Kim {
76a1e9b74cSArnaldo Carvalho de Melo 	return ui_browser__set_color(browser, color);
774ea08b52SArnaldo Carvalho de Melo }
784ea08b52SArnaldo Carvalho de Melo 
79a1e9b74cSArnaldo Carvalho de Melo static void annotate_browser__write_graph(void *browser, int graph)
80a1e9b74cSArnaldo Carvalho de Melo {
81a1e9b74cSArnaldo Carvalho de Melo 	ui_browser__write_graph(browser, graph);
82a5433b3eSJiri Olsa }
83a5433b3eSJiri Olsa 
842ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
852ba5eca1SArnaldo Carvalho de Melo {
862ba5eca1SArnaldo Carvalho de Melo 	ui_browser__set_percent_color(browser, percent, current);
872ba5eca1SArnaldo Carvalho de Melo }
882ba5eca1SArnaldo Carvalho de Melo 
892ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__printf(void *browser, const char *fmt, ...)
902ba5eca1SArnaldo Carvalho de Melo {
912ba5eca1SArnaldo Carvalho de Melo 	va_list args;
922ba5eca1SArnaldo Carvalho de Melo 
932ba5eca1SArnaldo Carvalho de Melo 	va_start(args, fmt);
942ba5eca1SArnaldo Carvalho de Melo 	ui_browser__vprintf(browser, fmt, args);
952ba5eca1SArnaldo Carvalho de Melo 	va_end(args);
962ba5eca1SArnaldo Carvalho de Melo }
972ba5eca1SArnaldo Carvalho de Melo 
98a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
99a5433b3eSJiri Olsa {
100a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
10195aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
102a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
103c298304bSArnaldo Carvalho de Melo 	struct annotation_write_ops ops = {
104c298304bSArnaldo Carvalho de Melo 		.first_line		 = row == 0,
105c298304bSArnaldo Carvalho de Melo 		.current_entry		 = ui_browser__is_current_entry(browser, row),
106c298304bSArnaldo Carvalho de Melo 		.change_color		 = (!notes->options->hide_src_code &&
107c298304bSArnaldo Carvalho de Melo 					    (!ops.current_entry ||
108c298304bSArnaldo Carvalho de Melo 					     (browser->use_navkeypressed &&
109c298304bSArnaldo Carvalho de Melo 					      !browser->navkeypressed))),
110c298304bSArnaldo Carvalho de Melo 		.width			 = browser->width,
111c298304bSArnaldo Carvalho de Melo 		.obj			 = browser,
112c298304bSArnaldo Carvalho de Melo 		.set_color		 = annotate_browser__set_color,
113c298304bSArnaldo Carvalho de Melo 		.set_percent_color	 = annotate_browser__set_percent_color,
114c298304bSArnaldo Carvalho de Melo 		.set_jumps_percent_color = ui_browser__set_jumps_percent_color,
115c298304bSArnaldo Carvalho de Melo 		.printf			 = annotate_browser__printf,
116c298304bSArnaldo Carvalho de Melo 		.write_graph		 = annotate_browser__write_graph,
117c298304bSArnaldo Carvalho de Melo 	};
118a5433b3eSJiri Olsa 
119a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
120a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
121c298304bSArnaldo Carvalho de Melo 		ops.width += 1;
122a5433b3eSJiri Olsa 
123c298304bSArnaldo Carvalho de Melo 	annotation_line__write(al, notes, &ops);
124aca7a94dSNamhyung Kim 
125c298304bSArnaldo Carvalho de Melo 	if (ops.current_entry)
126a5433b3eSJiri Olsa 		ab->selection = al;
127aca7a94dSNamhyung Kim }
128aca7a94dSNamhyung Kim 
1297e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
1307e63a13aSJin Yao {
131a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
1327e63a13aSJin Yao 	const char *name;
1337e63a13aSJin Yao 
1347e63a13aSJin Yao 	if (!pos)
1357e63a13aSJin Yao 		return false;
1367e63a13aSJin Yao 
1377e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
1387e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
1397e63a13aSJin Yao 	else
1407e63a13aSJin Yao 		name = pos->ins.name;
1417e63a13aSJin Yao 
1427e63a13aSJin Yao 	if (!name || !cursor->ins.name)
1437e63a13aSJin Yao 		return false;
1447e63a13aSJin Yao 
1457e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
1467e63a13aSJin Yao }
1477e63a13aSJin Yao 
1489d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
149a3f895beSArnaldo Carvalho de Melo {
150a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1517bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
152a5ef2702SJiri Olsa 	struct annotation_line *target;
15383b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
15432ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
15532ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
1560e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1576af612d2SArnaldo Carvalho de Melo 	u8 pcnt_width = annotation__pcnt_width(notes);
15800ea0eb2SArnaldo Carvalho de Melo 	int width;
15932ae1efdSNamhyung Kim 
16032ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
16132ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
16232ae1efdSNamhyung Kim 		return;
163a3f895beSArnaldo Carvalho de Melo 
164865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
165a3f895beSArnaldo Carvalho de Melo 		return;
166a3f895beSArnaldo Carvalho de Melo 
1679c04409dSArnaldo Carvalho de Melo 	/*
1689c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
1699c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
1709c04409dSArnaldo Carvalho de Melo 	 *
1719c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
1729c04409dSArnaldo Carvalho de Melo 	 *
1739c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
1749c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
1759c04409dSArnaldo Carvalho de Melo 	 *
1769c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
1779c04409dSArnaldo Carvalho de Melo 	 *
1789c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
1799c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
1809c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
1819c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
1829c04409dSArnaldo Carvalho de Melo 	 *
1839c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
1849c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
1859c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
1869c04409dSArnaldo Carvalho de Melo 	 */
1879d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
1889c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
1899d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
1909c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
1919c04409dSArnaldo Carvalho de Melo 		return;
1929c04409dSArnaldo Carvalho de Melo 	}
1939d1ef56dSArnaldo Carvalho de Melo 
19416932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
1954850c92eSArnaldo Carvalho de Melo 		from = cursor->al.idx_asm;
1964850c92eSArnaldo Carvalho de Melo 		to = target->idx_asm;
197a3f895beSArnaldo Carvalho de Melo 	} else {
1984850c92eSArnaldo Carvalho de Melo 		from = (u64)cursor->al.idx;
1994850c92eSArnaldo Carvalho de Melo 		to = (u64)target->idx;
200a3f895beSArnaldo Carvalho de Melo 	}
201a3f895beSArnaldo Carvalho de Melo 
2020e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
203b40982e8SJin Yao 
20478ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
205b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
2069761e86eSArnaldo Carvalho de Melo 				 pcnt_width + 2 + notes->widths.addr + width,
207c7e7b610SNamhyung Kim 				 from, to);
2087e63a13aSJin Yao 
2097e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
2107e63a13aSJin Yao 		ui_browser__mark_fused(browser,
2119761e86eSArnaldo Carvalho de Melo 				       pcnt_width + 3 + notes->widths.addr + width,
2127e63a13aSJin Yao 				       from - 1,
2137e63a13aSJin Yao 				       to > from ? true : false);
2147e63a13aSJin Yao 	}
215a3f895beSArnaldo Carvalho de Melo }
216a3f895beSArnaldo Carvalho de Melo 
217a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
218a3f895beSArnaldo Carvalho de Melo {
21995aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
220a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
2216af612d2SArnaldo Carvalho de Melo 	int pcnt_width = annotation__pcnt_width(notes);
222a3f895beSArnaldo Carvalho de Melo 
22316932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
2249d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
225a3f895beSArnaldo Carvalho de Melo 
22683b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
227c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
228a3f895beSArnaldo Carvalho de Melo 	return ret;
229a3f895beSArnaldo Carvalho de Melo }
230a3f895beSArnaldo Carvalho de Melo 
231b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
232c7e7b610SNamhyung Kim {
233c7e7b610SNamhyung Kim 	int i;
234c7e7b610SNamhyung Kim 
235b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
2360c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
237c7e7b610SNamhyung Kim 			continue;
2380c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
239c7e7b610SNamhyung Kim 	}
240c7e7b610SNamhyung Kim 	return 0;
241c7e7b610SNamhyung Kim }
242c7e7b610SNamhyung Kim 
243b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
244aca7a94dSNamhyung Kim {
24529ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
246aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
2473ab6db8dSJiri Olsa 	struct annotation_line *l;
248aca7a94dSNamhyung Kim 
249aca7a94dSNamhyung Kim 	while (*p != NULL) {
250aca7a94dSNamhyung Kim 		parent = *p;
2513ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
252c7e7b610SNamhyung Kim 
253b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
254aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
255aca7a94dSNamhyung Kim 		else
256aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
257aca7a94dSNamhyung Kim 	}
2583ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
2593ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
260aca7a94dSNamhyung Kim }
261aca7a94dSNamhyung Kim 
26205e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
263ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
264aca7a94dSNamhyung Kim {
265*9b80d1f9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
266aca7a94dSNamhyung Kim 	unsigned back;
267aca7a94dSNamhyung Kim 
26805e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
26905e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
27005e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
271aca7a94dSNamhyung Kim 
27205e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
273ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
274aca7a94dSNamhyung Kim 
275*9b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(pos, notes))
276aca7a94dSNamhyung Kim 			continue;
277aca7a94dSNamhyung Kim 
27805e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
279aca7a94dSNamhyung Kim 		--back;
280aca7a94dSNamhyung Kim 	}
281aca7a94dSNamhyung Kim 
282ec03a77dSJiri Olsa 	browser->b.top = pos;
28305e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
284aca7a94dSNamhyung Kim }
285aca7a94dSNamhyung Kim 
286aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
287aca7a94dSNamhyung Kim 					 struct rb_node *nd)
288aca7a94dSNamhyung Kim {
28995aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
2904850c92eSArnaldo Carvalho de Melo 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
2914850c92eSArnaldo Carvalho de Melo 	u32 idx = pos->idx;
292aca7a94dSNamhyung Kim 
29316932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
2944850c92eSArnaldo Carvalho de Melo 		idx = pos->idx_asm;
295a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
296aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
297aca7a94dSNamhyung Kim }
298aca7a94dSNamhyung Kim 
299aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
300db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
301aca7a94dSNamhyung Kim {
302aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
303aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
304aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
305c4c72436SJiri Olsa 	struct disasm_line *pos;
306aca7a94dSNamhyung Kim 
307aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
308aca7a94dSNamhyung Kim 
309aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
310aca7a94dSNamhyung Kim 
311e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
312e425da6cSJiri Olsa 
313a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
314c7e7b610SNamhyung Kim 		double max_percent = 0.0;
315c7e7b610SNamhyung Kim 		int i;
316e64aa75bSNamhyung Kim 
317d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
3185b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
319e64aa75bSNamhyung Kim 			continue;
320e64aa75bSNamhyung Kim 		}
321e64aa75bSNamhyung Kim 
322b15636c6SJiri Olsa 		for (i = 0; i < pos->al.samples_nr; i++) {
323e425da6cSJiri Olsa 			struct annotation_data *sample = &pos->al.samples[i];
3240c4a5bceSMartin Liška 
3253ab6db8dSJiri Olsa 			if (max_percent < sample->percent)
3263ab6db8dSJiri Olsa 				max_percent = sample->percent;
327c7e7b610SNamhyung Kim 		}
328c7e7b610SNamhyung Kim 
32937236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
3305b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
331aca7a94dSNamhyung Kim 			continue;
332aca7a94dSNamhyung Kim 		}
333b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
334aca7a94dSNamhyung Kim 	}
335aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
336aca7a94dSNamhyung Kim 
337aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
338aca7a94dSNamhyung Kim }
339aca7a94dSNamhyung Kim 
340aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
341aca7a94dSNamhyung Kim {
34295aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
343ec03a77dSJiri Olsa 	struct annotation_line *al;
344aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
345aca7a94dSNamhyung Kim 
346aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
347ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
348aca7a94dSNamhyung Kim 
34916932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3504850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3514850c92eSArnaldo Carvalho de Melo 			offset = al->idx;
352aca7a94dSNamhyung Kim 
3531cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_entries;
35416932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
355aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3564850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx - offset;
3574850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx;
358aca7a94dSNamhyung Kim 	} else {
3594850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < 0) {
360aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
361aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
362aca7a94dSNamhyung Kim 			return false;
363aca7a94dSNamhyung Kim 		}
364aca7a94dSNamhyung Kim 
3654850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3664850c92eSArnaldo Carvalho de Melo 			offset = al->idx_asm;
367aca7a94dSNamhyung Kim 
3681cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_asm_entries;
36916932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
370aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3714850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx_asm - offset;
3724850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx_asm;
373aca7a94dSNamhyung Kim 	}
374aca7a94dSNamhyung Kim 
375aca7a94dSNamhyung Kim 	return true;
376aca7a94dSNamhyung Kim }
377aca7a94dSNamhyung Kim 
3781cf5f98aSArnaldo Carvalho de Melo static void ui_browser__init_asm_mode(struct ui_browser *browser)
379e9823b21SArnaldo Carvalho de Melo {
3801cf5f98aSArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
3811cf5f98aSArnaldo Carvalho de Melo 	ui_browser__reset_index(browser);
3821cf5f98aSArnaldo Carvalho de Melo 	browser->nr_entries = notes->nr_asm_entries;
383e9823b21SArnaldo Carvalho de Melo }
384e9823b21SArnaldo Carvalho de Melo 
38534f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
38634f77abcSAdrian Hunter 
38734f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
38834f77abcSAdrian Hunter 		     size_t sz)
38934f77abcSAdrian Hunter {
39034f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
39134f77abcSAdrian Hunter }
39234f77abcSAdrian Hunter 
393db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
394db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
3959783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
396aca7a94dSNamhyung Kim {
397aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
3987bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
399aca7a94dSNamhyung Kim 	struct annotation *notes;
40034f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
401aca7a94dSNamhyung Kim 
40275b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
403aca7a94dSNamhyung Kim 		return false;
404aca7a94dSNamhyung Kim 
405696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
406aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
407aca7a94dSNamhyung Kim 		return true;
408aca7a94dSNamhyung Kim 	}
409aca7a94dSNamhyung Kim 
410696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
411aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
412aca7a94dSNamhyung Kim 
413696703afSArnaldo Carvalho de Melo 	if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) {
414aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
415aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
416696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
417aca7a94dSNamhyung Kim 		return true;
418aca7a94dSNamhyung Kim 	}
419aca7a94dSNamhyung Kim 
420aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
421696703afSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt);
4221179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
42334f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
424aca7a94dSNamhyung Kim 	return true;
425aca7a94dSNamhyung Kim }
426aca7a94dSNamhyung Kim 
42729ed6e76SArnaldo Carvalho de Melo static
42829ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
429aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
430aca7a94dSNamhyung Kim {
43195aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
43229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
433aca7a94dSNamhyung Kim 
434aca7a94dSNamhyung Kim 	*idx = 0;
435a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
436d5490b96SJiri Olsa 		if (pos->al.offset == offset)
437aca7a94dSNamhyung Kim 			return pos;
438*9b80d1f9SArnaldo Carvalho de Melo 		if (!annotation_line__filter(&pos->al, notes))
439aca7a94dSNamhyung Kim 			++*idx;
440aca7a94dSNamhyung Kim 	}
441aca7a94dSNamhyung Kim 
442aca7a94dSNamhyung Kim 	return NULL;
443aca7a94dSNamhyung Kim }
444aca7a94dSNamhyung Kim 
445aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
446aca7a94dSNamhyung Kim {
4477bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
4485252b1aeSArnaldo Carvalho de Melo 	u64 offset;
4494f9d0325SArnaldo Carvalho de Melo 	s64 idx;
450aca7a94dSNamhyung Kim 
45175b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
452aca7a94dSNamhyung Kim 		return false;
453aca7a94dSNamhyung Kim 
4545252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
4555252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
45629ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
4575252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
458aca7a94dSNamhyung Kim 		return true;
459aca7a94dSNamhyung Kim 	}
460aca7a94dSNamhyung Kim 
461ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
462aca7a94dSNamhyung Kim 
463aca7a94dSNamhyung Kim 	return true;
464aca7a94dSNamhyung Kim }
465aca7a94dSNamhyung Kim 
46629ed6e76SArnaldo Carvalho de Melo static
4679213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
468aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
469aca7a94dSNamhyung Kim {
47095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
4719213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
472aca7a94dSNamhyung Kim 
473aca7a94dSNamhyung Kim 	*idx = browser->b.index;
4749213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
475*9b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
476aca7a94dSNamhyung Kim 			continue;
477aca7a94dSNamhyung Kim 
478aca7a94dSNamhyung Kim 		++*idx;
479aca7a94dSNamhyung Kim 
4809213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
4819213afbdSJiri Olsa 			return al;
482aca7a94dSNamhyung Kim 	}
483aca7a94dSNamhyung Kim 
484aca7a94dSNamhyung Kim 	return NULL;
485aca7a94dSNamhyung Kim }
486aca7a94dSNamhyung Kim 
487aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
488aca7a94dSNamhyung Kim {
4899213afbdSJiri Olsa 	struct annotation_line *al;
490aca7a94dSNamhyung Kim 	s64 idx;
491aca7a94dSNamhyung Kim 
4929213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
4939213afbdSJiri Olsa 	if (al == NULL) {
494aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
495aca7a94dSNamhyung Kim 		return false;
496aca7a94dSNamhyung Kim 	}
497aca7a94dSNamhyung Kim 
498ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
499aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
500aca7a94dSNamhyung Kim 	return true;
501aca7a94dSNamhyung Kim }
502aca7a94dSNamhyung Kim 
50329ed6e76SArnaldo Carvalho de Melo static
5049213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
505aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
506aca7a94dSNamhyung Kim {
50795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
5089213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
509aca7a94dSNamhyung Kim 
510aca7a94dSNamhyung Kim 	*idx = browser->b.index;
5119213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
512*9b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
513aca7a94dSNamhyung Kim 			continue;
514aca7a94dSNamhyung Kim 
515aca7a94dSNamhyung Kim 		--*idx;
516aca7a94dSNamhyung Kim 
5179213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
5189213afbdSJiri Olsa 			return al;
519aca7a94dSNamhyung Kim 	}
520aca7a94dSNamhyung Kim 
521aca7a94dSNamhyung Kim 	return NULL;
522aca7a94dSNamhyung Kim }
523aca7a94dSNamhyung Kim 
524aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
525aca7a94dSNamhyung Kim {
5269213afbdSJiri Olsa 	struct annotation_line *al;
527aca7a94dSNamhyung Kim 	s64 idx;
528aca7a94dSNamhyung Kim 
5299213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
5309213afbdSJiri Olsa 	if (al == NULL) {
531aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
532aca7a94dSNamhyung Kim 		return false;
533aca7a94dSNamhyung Kim 	}
534aca7a94dSNamhyung Kim 
535ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
536aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
537aca7a94dSNamhyung Kim 	return true;
538aca7a94dSNamhyung Kim }
539aca7a94dSNamhyung Kim 
540aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
541aca7a94dSNamhyung Kim 					    int delay_secs)
542aca7a94dSNamhyung Kim {
543aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
544aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
545aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
546aca7a94dSNamhyung Kim 	    !*browser->search_bf)
547aca7a94dSNamhyung Kim 		return false;
548aca7a94dSNamhyung Kim 
549aca7a94dSNamhyung Kim 	return true;
550aca7a94dSNamhyung Kim }
551aca7a94dSNamhyung Kim 
552aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
553aca7a94dSNamhyung Kim {
554aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
555aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
556aca7a94dSNamhyung Kim 
557aca7a94dSNamhyung Kim 	return false;
558aca7a94dSNamhyung Kim }
559aca7a94dSNamhyung Kim 
560aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
561aca7a94dSNamhyung Kim 					      int delay_secs)
562aca7a94dSNamhyung Kim {
563aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
564aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
565aca7a94dSNamhyung Kim 
566aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
567aca7a94dSNamhyung Kim }
568aca7a94dSNamhyung Kim 
569aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
570aca7a94dSNamhyung Kim 					   int delay_secs)
571aca7a94dSNamhyung Kim {
572aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
573aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
574aca7a94dSNamhyung Kim 
575aca7a94dSNamhyung Kim 	return false;
576aca7a94dSNamhyung Kim }
577aca7a94dSNamhyung Kim 
578aca7a94dSNamhyung Kim static
579aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
580aca7a94dSNamhyung Kim 					       int delay_secs)
581aca7a94dSNamhyung Kim {
582aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
583aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
584aca7a94dSNamhyung Kim 
585aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
586aca7a94dSNamhyung Kim }
587aca7a94dSNamhyung Kim 
588db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
589db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
5909783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
591aca7a94dSNamhyung Kim {
592aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
59305e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
594aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
59516932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
59654e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
5979783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
598aca7a94dSNamhyung Kim 	int key;
59934f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
600aca7a94dSNamhyung Kim 
60134f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
60234f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
603aca7a94dSNamhyung Kim 		return -1;
604aca7a94dSNamhyung Kim 
605db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
606aca7a94dSNamhyung Kim 
60705e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
60805e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
60905e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
610aca7a94dSNamhyung Kim 	}
611aca7a94dSNamhyung Kim 
61205e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
613aca7a94dSNamhyung Kim 
614aca7a94dSNamhyung Kim 	while (1) {
61505e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
616aca7a94dSNamhyung Kim 
617aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
618db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
619aca7a94dSNamhyung Kim 			/*
620aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
621aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
622aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
623aca7a94dSNamhyung Kim 			 */
624aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
625aca7a94dSNamhyung Kim 				nd = NULL;
626aca7a94dSNamhyung Kim 		}
627aca7a94dSNamhyung Kim 
628aca7a94dSNamhyung Kim 		switch (key) {
629aca7a94dSNamhyung Kim 		case K_TIMER:
6309783adf7SNamhyung Kim 			if (hbt)
6319783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
632aca7a94dSNamhyung Kim 
633aca7a94dSNamhyung Kim 			if (delay_secs != 0)
634db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
635aca7a94dSNamhyung Kim 			continue;
636aca7a94dSNamhyung Kim 		case K_TAB:
637aca7a94dSNamhyung Kim 			if (nd != NULL) {
638aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
639aca7a94dSNamhyung Kim 				if (nd == NULL)
64005e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
641aca7a94dSNamhyung Kim 			} else
64205e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
643aca7a94dSNamhyung Kim 			break;
644aca7a94dSNamhyung Kim 		case K_UNTAB:
645d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
646aca7a94dSNamhyung Kim 				nd = rb_next(nd);
647aca7a94dSNamhyung Kim 				if (nd == NULL)
64805e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
649d4913cbdSMarkus Trippelsdorf 			} else
65005e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
651aca7a94dSNamhyung Kim 			break;
65254e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
653aca7a94dSNamhyung Kim 		case 'h':
65405e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
65554e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
65654e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
65754e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
6587727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
6597727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
660eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
661eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
66254e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
66354e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
66454e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
66554e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
66654e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
6673a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
66854e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
669e592488cSAndi Kleen 		"k             Toggle line numbers\n"
67079ee47faSFeng Tang 		"r             Run available scripts\n"
671fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
67254e7a4e8SArnaldo Carvalho de Melo 			continue;
67379ee47faSFeng Tang 		case 'r':
67479ee47faSFeng Tang 			{
67579ee47faSFeng Tang 				script_browse(NULL);
67679ee47faSFeng Tang 				continue;
67779ee47faSFeng Tang 			}
678e592488cSAndi Kleen 		case 'k':
67916932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
680e592488cSAndi Kleen 			break;
68154e7a4e8SArnaldo Carvalho de Melo 		case 'H':
68205e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
683aca7a94dSNamhyung Kim 			break;
684aca7a94dSNamhyung Kim 		case 's':
68505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
686aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
687aca7a94dSNamhyung Kim 			continue;
688aca7a94dSNamhyung Kim 		case 'o':
68916932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
6909761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
691aca7a94dSNamhyung Kim 			continue;
6929d1ef56dSArnaldo Carvalho de Melo 		case 'j':
69316932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
6949d1ef56dSArnaldo Carvalho de Melo 			continue;
6952402e4a9SArnaldo Carvalho de Melo 		case 'J':
69616932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
6979761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
698e9823b21SArnaldo Carvalho de Melo 			continue;
699aca7a94dSNamhyung Kim 		case '/':
70005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
701aca7a94dSNamhyung Kim show_help:
702aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
703aca7a94dSNamhyung Kim 			}
704aca7a94dSNamhyung Kim 			continue;
705aca7a94dSNamhyung Kim 		case 'n':
70605e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
70705e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
70805e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
709aca7a94dSNamhyung Kim 				goto show_help;
710aca7a94dSNamhyung Kim 			continue;
711aca7a94dSNamhyung Kim 		case '?':
71205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
713aca7a94dSNamhyung Kim 				goto show_help;
714aca7a94dSNamhyung Kim 			continue;
715e9823b21SArnaldo Carvalho de Melo 		case 'D': {
716e9823b21SArnaldo Carvalho de Melo 			static int seq;
717e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
718e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
71905e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
72005e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
72105e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
72205e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
7231cf5f98aSArnaldo Carvalho de Melo 					   notes->nr_asm_entries);
724e9823b21SArnaldo Carvalho de Melo 		}
725e9823b21SArnaldo Carvalho de Melo 			continue;
726aca7a94dSNamhyung Kim 		case K_ENTER:
727aca7a94dSNamhyung Kim 		case K_RIGHT:
7287bcbcd58SJiri Olsa 		{
7297bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
7307bcbcd58SJiri Olsa 
73105e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
732aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
7337bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
734aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
7357bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
736c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
7377bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
738c4cceae3SArnaldo Carvalho de Melo 				goto out;
7396ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
740db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
741c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
7426ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
743c4cceae3SArnaldo Carvalho de Melo 			}
744aca7a94dSNamhyung Kim 			continue;
7457bcbcd58SJiri Olsa 		}
7460c4a5bceSMartin Liška 		case 't':
74716932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
74816932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
74916932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
75016932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
75116932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
7523a555c77STaeung Song 			else
75316932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
7549761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
7550c4a5bceSMartin Liška 			continue;
756aca7a94dSNamhyung Kim 		case K_LEFT:
757aca7a94dSNamhyung Kim 		case K_ESC:
758aca7a94dSNamhyung Kim 		case 'q':
759aca7a94dSNamhyung Kim 		case CTRL('c'):
760aca7a94dSNamhyung Kim 			goto out;
761aca7a94dSNamhyung Kim 		default:
762aca7a94dSNamhyung Kim 			continue;
763aca7a94dSNamhyung Kim 		}
764aca7a94dSNamhyung Kim 
765aca7a94dSNamhyung Kim 		if (nd != NULL)
76605e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
767aca7a94dSNamhyung Kim 	}
768aca7a94dSNamhyung Kim out:
76905e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
770aca7a94dSNamhyung Kim 	return key;
771aca7a94dSNamhyung Kim }
772aca7a94dSNamhyung Kim 
773d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
774d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
775d5dbc518SArnaldo Carvalho de Melo {
7769cef4b0bSTaeung Song 	/* Set default value for show_total_period and show_nr_samples  */
7770c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
7780c4a5bceSMartin Liška 		symbol_conf.show_total_period;
7799cef4b0bSTaeung Song 	annotate_browser__opts.show_nr_samples =
7809cef4b0bSTaeung Song 		symbol_conf.show_nr_samples;
7810c4a5bceSMartin Liška 
782d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
783d5dbc518SArnaldo Carvalho de Melo }
784d5dbc518SArnaldo Carvalho de Melo 
785db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
7869783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
787aca7a94dSNamhyung Kim {
788ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
789ed426915SNamhyung Kim 	SLang_reset_tty();
790ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
791ed426915SNamhyung Kim 
792d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
793aca7a94dSNamhyung Kim }
794aca7a94dSNamhyung Kim 
795db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
796db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
7979783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
798aca7a94dSNamhyung Kim {
7999d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
800aca7a94dSNamhyung Kim 	struct map_symbol ms = {
801aca7a94dSNamhyung Kim 		.map = map,
802aca7a94dSNamhyung Kim 		.sym = sym,
803aca7a94dSNamhyung Kim 	};
804aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
805aca7a94dSNamhyung Kim 		.b = {
806a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
807aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
808aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
80929ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
810aca7a94dSNamhyung Kim 			.priv	 = &ms,
811aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
812aca7a94dSNamhyung Kim 		},
813aca7a94dSNamhyung Kim 	};
814ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
815aca7a94dSNamhyung Kim 
816aca7a94dSNamhyung Kim 	if (sym == NULL)
817aca7a94dSNamhyung Kim 		return -1;
818aca7a94dSNamhyung Kim 
819aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
820aca7a94dSNamhyung Kim 		return -1;
821aca7a94dSNamhyung Kim 
822ecda45bdSArnaldo Carvalho de Melo 	err = symbol__annotate2(sym, map, evsel, &annotate_browser__opts, &browser.arch);
823ee51d851SArnaldo Carvalho de Melo 	if (err) {
824ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
825ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
826ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
827b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
828aca7a94dSNamhyung Kim 	}
829aca7a94dSNamhyung Kim 
8307727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
831aca7a94dSNamhyung Kim 
8325bc49f61SArnaldo Carvalho de Melo 	browser.b.width = notes->max_line_len;
8331cf5f98aSArnaldo Carvalho de Melo 	browser.b.nr_entries = notes->nr_entries;
834aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
835aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
836e9823b21SArnaldo Carvalho de Melo 
83716932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
8381cf5f98aSArnaldo Carvalho de Melo 		ui_browser__init_asm_mode(&browser.b);
839e9823b21SArnaldo Carvalho de Melo 
840db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
841f8eb37bdSJiri Olsa 
842f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
843b793a401SArnaldo Carvalho de Melo 
844b793a401SArnaldo Carvalho de Melo out_free_offsets:
8459d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
846aca7a94dSNamhyung Kim 	return ret;
847aca7a94dSNamhyung Kim }
848c323cf04SArnaldo Carvalho de Melo 
849c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
850c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
851c323cf04SArnaldo Carvalho de Melo 
852c323cf04SArnaldo Carvalho de Melo /*
853c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
854c323cf04SArnaldo Carvalho de Melo  */
8557c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
856c323cf04SArnaldo Carvalho de Melo 	const char *name;
857c323cf04SArnaldo Carvalho de Melo 	bool *value;
858c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
859c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
860c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
861e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
862c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
8639cef4b0bSTaeung Song 	ANNOTATE_CFG(show_nr_samples),
8640c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
86539ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
866c323cf04SArnaldo Carvalho de Melo };
867c323cf04SArnaldo Carvalho de Melo 
868c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
869c323cf04SArnaldo Carvalho de Melo 
870c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
871c323cf04SArnaldo Carvalho de Melo {
8727c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
873c323cf04SArnaldo Carvalho de Melo 
874c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
875c323cf04SArnaldo Carvalho de Melo }
876c323cf04SArnaldo Carvalho de Melo 
8771d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
8781d037ca1SIrina Tirdea 			    void *data __maybe_unused)
879c323cf04SArnaldo Carvalho de Melo {
8807c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
881c323cf04SArnaldo Carvalho de Melo 	const char *name;
882c323cf04SArnaldo Carvalho de Melo 
8838e99b6d4SArnaldo Carvalho de Melo 	if (!strstarts(var, "annotate."))
884c323cf04SArnaldo Carvalho de Melo 		return 0;
885c323cf04SArnaldo Carvalho de Melo 
886c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
887c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
8887c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
889c323cf04SArnaldo Carvalho de Melo 
890c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
891f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
892f06cff7cSArnaldo Carvalho de Melo 	else
893c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
894c323cf04SArnaldo Carvalho de Melo 	return 0;
895c323cf04SArnaldo Carvalho de Melo }
896c323cf04SArnaldo Carvalho de Melo 
897c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
898c323cf04SArnaldo Carvalho de Melo {
899c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
900c323cf04SArnaldo Carvalho de Melo }
901