xref: /linux/tools/perf/ui/browsers/annotate.c (revision 3e71fc0319775723adc08991ba7fbaeff1150347)
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;
32aca7a94dSNamhyung Kim 	bool			    searching_backwards;
33aca7a94dSNamhyung Kim 	char			    search_bf[128];
34aca7a94dSNamhyung Kim };
35aca7a94dSNamhyung Kim 
3695aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser)
3795aa89d9SArnaldo Carvalho de Melo {
3895aa89d9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
3995aa89d9SArnaldo Carvalho de Melo 	return symbol__annotation(ms->sym);
4095aa89d9SArnaldo Carvalho de Melo }
4195aa89d9SArnaldo Carvalho de Melo 
4216932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
43aca7a94dSNamhyung Kim {
4495aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
45d5490b96SJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
469b80d1f9SArnaldo Carvalho de Melo 	return annotation_line__filter(al, notes);
47aca7a94dSNamhyung Kim }
48aca7a94dSNamhyung Kim 
4927feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
502402e4a9SArnaldo Carvalho de Melo {
5127feb761SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
52bc1c0f3dSArnaldo Carvalho de Melo 
5327feb761SArnaldo Carvalho de Melo 	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
542402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
55bc1c0f3dSArnaldo Carvalho de Melo 	if (nr == notes->max_jump_sources)
562402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
572402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
582402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
592402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
602402e4a9SArnaldo Carvalho de Melo }
612402e4a9SArnaldo Carvalho de Melo 
62a1e9b74cSArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
632402e4a9SArnaldo Carvalho de Melo {
6427feb761SArnaldo Carvalho de Melo 	 int color = ui_browser__jumps_percent_color(browser, nr, current);
6527feb761SArnaldo Carvalho de Melo 	 return ui_browser__set_color(browser, color);
662402e4a9SArnaldo Carvalho de Melo }
672402e4a9SArnaldo Carvalho de Melo 
68a1e9b74cSArnaldo Carvalho de Melo static int annotate_browser__set_color(void *browser, int color)
69aca7a94dSNamhyung Kim {
70a1e9b74cSArnaldo Carvalho de Melo 	return ui_browser__set_color(browser, color);
714ea08b52SArnaldo Carvalho de Melo }
724ea08b52SArnaldo Carvalho de Melo 
73a1e9b74cSArnaldo Carvalho de Melo static void annotate_browser__write_graph(void *browser, int graph)
74a1e9b74cSArnaldo Carvalho de Melo {
75a1e9b74cSArnaldo Carvalho de Melo 	ui_browser__write_graph(browser, graph);
76a5433b3eSJiri Olsa }
77a5433b3eSJiri Olsa 
782ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
792ba5eca1SArnaldo Carvalho de Melo {
802ba5eca1SArnaldo Carvalho de Melo 	ui_browser__set_percent_color(browser, percent, current);
812ba5eca1SArnaldo Carvalho de Melo }
822ba5eca1SArnaldo Carvalho de Melo 
832ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__printf(void *browser, const char *fmt, ...)
842ba5eca1SArnaldo Carvalho de Melo {
852ba5eca1SArnaldo Carvalho de Melo 	va_list args;
862ba5eca1SArnaldo Carvalho de Melo 
872ba5eca1SArnaldo Carvalho de Melo 	va_start(args, fmt);
882ba5eca1SArnaldo Carvalho de Melo 	ui_browser__vprintf(browser, fmt, args);
892ba5eca1SArnaldo Carvalho de Melo 	va_end(args);
902ba5eca1SArnaldo Carvalho de Melo }
912ba5eca1SArnaldo Carvalho de Melo 
92a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
93a5433b3eSJiri Olsa {
94a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9595aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
96a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
97c298304bSArnaldo Carvalho de Melo 	struct annotation_write_ops ops = {
98c298304bSArnaldo Carvalho de Melo 		.first_line		 = row == 0,
99c298304bSArnaldo Carvalho de Melo 		.current_entry		 = ui_browser__is_current_entry(browser, row),
100c298304bSArnaldo Carvalho de Melo 		.change_color		 = (!notes->options->hide_src_code &&
101c298304bSArnaldo Carvalho de Melo 					    (!ops.current_entry ||
102c298304bSArnaldo Carvalho de Melo 					     (browser->use_navkeypressed &&
103c298304bSArnaldo Carvalho de Melo 					      !browser->navkeypressed))),
104c298304bSArnaldo Carvalho de Melo 		.width			 = browser->width,
105c298304bSArnaldo Carvalho de Melo 		.obj			 = browser,
106c298304bSArnaldo Carvalho de Melo 		.set_color		 = annotate_browser__set_color,
107c298304bSArnaldo Carvalho de Melo 		.set_percent_color	 = annotate_browser__set_percent_color,
108c298304bSArnaldo Carvalho de Melo 		.set_jumps_percent_color = ui_browser__set_jumps_percent_color,
109c298304bSArnaldo Carvalho de Melo 		.printf			 = annotate_browser__printf,
110c298304bSArnaldo Carvalho de Melo 		.write_graph		 = annotate_browser__write_graph,
111c298304bSArnaldo Carvalho de Melo 	};
112a5433b3eSJiri Olsa 
113a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
114a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
115c298304bSArnaldo Carvalho de Melo 		ops.width += 1;
116a5433b3eSJiri Olsa 
117c298304bSArnaldo Carvalho de Melo 	annotation_line__write(al, notes, &ops);
118aca7a94dSNamhyung Kim 
119c298304bSArnaldo Carvalho de Melo 	if (ops.current_entry)
120a5433b3eSJiri Olsa 		ab->selection = al;
121aca7a94dSNamhyung Kim }
122aca7a94dSNamhyung Kim 
1237e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
1247e63a13aSJin Yao {
125a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
1267e63a13aSJin Yao 	const char *name;
1277e63a13aSJin Yao 
1287e63a13aSJin Yao 	if (!pos)
1297e63a13aSJin Yao 		return false;
1307e63a13aSJin Yao 
1317e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
1327e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
1337e63a13aSJin Yao 	else
1347e63a13aSJin Yao 		name = pos->ins.name;
1357e63a13aSJin Yao 
1367e63a13aSJin Yao 	if (!name || !cursor->ins.name)
1377e63a13aSJin Yao 		return false;
1387e63a13aSJin Yao 
1397e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
1407e63a13aSJin Yao }
1417e63a13aSJin Yao 
1429d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
143a3f895beSArnaldo Carvalho de Melo {
144a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1457bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
146a5ef2702SJiri Olsa 	struct annotation_line *target;
14783b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
14832ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
14932ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
1500e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1516af612d2SArnaldo Carvalho de Melo 	u8 pcnt_width = annotation__pcnt_width(notes);
15200ea0eb2SArnaldo Carvalho de Melo 	int width;
15332ae1efdSNamhyung Kim 
15432ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
15532ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
15632ae1efdSNamhyung Kim 		return;
157a3f895beSArnaldo Carvalho de Melo 
1582eff0611SArnaldo Carvalho de Melo 	if (!disasm_line__is_valid_local_jump(cursor, sym))
159a3f895beSArnaldo Carvalho de Melo 		return;
160a3f895beSArnaldo Carvalho de Melo 
1619c04409dSArnaldo Carvalho de Melo 	/*
1629c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
1639c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
1649c04409dSArnaldo Carvalho de Melo 	 *
1659c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
1669c04409dSArnaldo Carvalho de Melo 	 *
1679c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
1689c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
1699c04409dSArnaldo Carvalho de Melo 	 *
1709c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
1719c04409dSArnaldo Carvalho de Melo 	 *
1729c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
1739c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
1749c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
1759c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
1769c04409dSArnaldo Carvalho de Melo 	 *
1779c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
1789c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
1799c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
1809c04409dSArnaldo Carvalho de Melo 	 */
1819d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
1829c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
1839d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
1849c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
1859c04409dSArnaldo Carvalho de Melo 		return;
1869c04409dSArnaldo Carvalho de Melo 	}
1879d1ef56dSArnaldo Carvalho de Melo 
18816932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
1894850c92eSArnaldo Carvalho de Melo 		from = cursor->al.idx_asm;
1904850c92eSArnaldo Carvalho de Melo 		to = target->idx_asm;
191a3f895beSArnaldo Carvalho de Melo 	} else {
1924850c92eSArnaldo Carvalho de Melo 		from = (u64)cursor->al.idx;
1934850c92eSArnaldo Carvalho de Melo 		to = (u64)target->idx;
194a3f895beSArnaldo Carvalho de Melo 	}
195a3f895beSArnaldo Carvalho de Melo 
1960e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
197b40982e8SJin Yao 
19878ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
199b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
2009761e86eSArnaldo Carvalho de Melo 				 pcnt_width + 2 + notes->widths.addr + width,
201c7e7b610SNamhyung Kim 				 from, to);
2027e63a13aSJin Yao 
2037e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
2047e63a13aSJin Yao 		ui_browser__mark_fused(browser,
2059761e86eSArnaldo Carvalho de Melo 				       pcnt_width + 3 + notes->widths.addr + width,
2067e63a13aSJin Yao 				       from - 1,
2077e63a13aSJin Yao 				       to > from ? true : false);
2087e63a13aSJin Yao 	}
209a3f895beSArnaldo Carvalho de Melo }
210a3f895beSArnaldo Carvalho de Melo 
211a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
212a3f895beSArnaldo Carvalho de Melo {
21395aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
214a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
2156af612d2SArnaldo Carvalho de Melo 	int pcnt_width = annotation__pcnt_width(notes);
216a3f895beSArnaldo Carvalho de Melo 
21716932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
2189d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
219a3f895beSArnaldo Carvalho de Melo 
22083b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
221e726c851SArnaldo Carvalho de Melo 	__ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
222a3f895beSArnaldo Carvalho de Melo 	return ret;
223a3f895beSArnaldo Carvalho de Melo }
224a3f895beSArnaldo Carvalho de Melo 
225b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
226c7e7b610SNamhyung Kim {
227c7e7b610SNamhyung Kim 	int i;
228c7e7b610SNamhyung Kim 
229b15636c6SJiri Olsa 	for (i = 0; i < a->samples_nr; i++) {
2300c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
231c7e7b610SNamhyung Kim 			continue;
2320c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
233c7e7b610SNamhyung Kim 	}
234c7e7b610SNamhyung Kim 	return 0;
235c7e7b610SNamhyung Kim }
236c7e7b610SNamhyung Kim 
237b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
238aca7a94dSNamhyung Kim {
23929ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
240aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
2413ab6db8dSJiri Olsa 	struct annotation_line *l;
242aca7a94dSNamhyung Kim 
243aca7a94dSNamhyung Kim 	while (*p != NULL) {
244aca7a94dSNamhyung Kim 		parent = *p;
2453ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
246c7e7b610SNamhyung Kim 
247b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
248aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
249aca7a94dSNamhyung Kim 		else
250aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
251aca7a94dSNamhyung Kim 	}
2523ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
2533ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
254aca7a94dSNamhyung Kim }
255aca7a94dSNamhyung Kim 
25605e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
257ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
258aca7a94dSNamhyung Kim {
2599b80d1f9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
260aca7a94dSNamhyung Kim 	unsigned back;
261aca7a94dSNamhyung Kim 
26205e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
26305e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
26405e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
265aca7a94dSNamhyung Kim 
26605e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
267ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
268aca7a94dSNamhyung Kim 
2699b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(pos, notes))
270aca7a94dSNamhyung Kim 			continue;
271aca7a94dSNamhyung Kim 
27205e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
273aca7a94dSNamhyung Kim 		--back;
274aca7a94dSNamhyung Kim 	}
275aca7a94dSNamhyung Kim 
276ec03a77dSJiri Olsa 	browser->b.top = pos;
27705e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
278aca7a94dSNamhyung Kim }
279aca7a94dSNamhyung Kim 
280aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
281aca7a94dSNamhyung Kim 					 struct rb_node *nd)
282aca7a94dSNamhyung Kim {
28395aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
2844850c92eSArnaldo Carvalho de Melo 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
2854850c92eSArnaldo Carvalho de Melo 	u32 idx = pos->idx;
286aca7a94dSNamhyung Kim 
28716932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
2884850c92eSArnaldo Carvalho de Melo 		idx = pos->idx_asm;
289a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
290aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
291aca7a94dSNamhyung Kim }
292aca7a94dSNamhyung Kim 
293aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
294db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
295aca7a94dSNamhyung Kim {
296aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
297aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
298aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
299c4c72436SJiri Olsa 	struct disasm_line *pos;
300aca7a94dSNamhyung Kim 
301aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
302aca7a94dSNamhyung Kim 
303aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
304aca7a94dSNamhyung Kim 
305e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
306e425da6cSJiri Olsa 
307a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
308c7e7b610SNamhyung Kim 		double max_percent = 0.0;
309c7e7b610SNamhyung Kim 		int i;
310e64aa75bSNamhyung Kim 
311d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
3125b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
313e64aa75bSNamhyung Kim 			continue;
314e64aa75bSNamhyung Kim 		}
315e64aa75bSNamhyung Kim 
316b15636c6SJiri Olsa 		for (i = 0; i < pos->al.samples_nr; i++) {
317e425da6cSJiri Olsa 			struct annotation_data *sample = &pos->al.samples[i];
3180c4a5bceSMartin Liška 
3193ab6db8dSJiri Olsa 			if (max_percent < sample->percent)
3203ab6db8dSJiri Olsa 				max_percent = sample->percent;
321c7e7b610SNamhyung Kim 		}
322c7e7b610SNamhyung Kim 
32337236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
3245b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
325aca7a94dSNamhyung Kim 			continue;
326aca7a94dSNamhyung Kim 		}
327b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
328aca7a94dSNamhyung Kim 	}
329aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
330aca7a94dSNamhyung Kim 
331aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
332aca7a94dSNamhyung Kim }
333aca7a94dSNamhyung Kim 
334aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
335aca7a94dSNamhyung Kim {
33695aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
337ec03a77dSJiri Olsa 	struct annotation_line *al;
338aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
339aca7a94dSNamhyung Kim 
340aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
341ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
342aca7a94dSNamhyung Kim 
34316932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3444850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3454850c92eSArnaldo Carvalho de Melo 			offset = al->idx;
346aca7a94dSNamhyung Kim 
3471cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_entries;
34816932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
349aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3504850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx - offset;
3514850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx;
352aca7a94dSNamhyung Kim 	} else {
3534850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < 0) {
354aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
355aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
356aca7a94dSNamhyung Kim 			return false;
357aca7a94dSNamhyung Kim 		}
358aca7a94dSNamhyung Kim 
3594850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3604850c92eSArnaldo Carvalho de Melo 			offset = al->idx_asm;
361aca7a94dSNamhyung Kim 
3621cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_asm_entries;
36316932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
364aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3654850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx_asm - offset;
3664850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx_asm;
367aca7a94dSNamhyung Kim 	}
368aca7a94dSNamhyung Kim 
369aca7a94dSNamhyung Kim 	return true;
370aca7a94dSNamhyung Kim }
371aca7a94dSNamhyung Kim 
3721cf5f98aSArnaldo Carvalho de Melo static void ui_browser__init_asm_mode(struct ui_browser *browser)
373e9823b21SArnaldo Carvalho de Melo {
3741cf5f98aSArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
3751cf5f98aSArnaldo Carvalho de Melo 	ui_browser__reset_index(browser);
3761cf5f98aSArnaldo Carvalho de Melo 	browser->nr_entries = notes->nr_asm_entries;
377e9823b21SArnaldo Carvalho de Melo }
378e9823b21SArnaldo Carvalho de Melo 
37934f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
38034f77abcSAdrian Hunter 
38134f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
38234f77abcSAdrian Hunter 		     size_t sz)
38334f77abcSAdrian Hunter {
38434f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
38534f77abcSAdrian Hunter }
38634f77abcSAdrian Hunter 
387e4cc91b8SArnaldo Carvalho de Melo /*
388e4cc91b8SArnaldo Carvalho de Melo  * This can be called from external jumps, i.e. jumps from one functon
389e4cc91b8SArnaldo Carvalho de Melo  * to another, like from the kernel's entry_SYSCALL_64 function to the
390e4cc91b8SArnaldo Carvalho de Melo  * swapgs_restore_regs_and_return_to_usermode() function.
391e4cc91b8SArnaldo Carvalho de Melo  *
392e4cc91b8SArnaldo Carvalho de Melo  * So all we check here is that dl->ops.target.sym is set, if it is, just
393e4cc91b8SArnaldo Carvalho de Melo  * go to that function and when exiting from its disassembly, come back
394e4cc91b8SArnaldo Carvalho de Melo  * to the calling function.
395e4cc91b8SArnaldo Carvalho de Melo  */
396db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
397db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
3989783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
399aca7a94dSNamhyung Kim {
400aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
4017bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
402aca7a94dSNamhyung Kim 	struct annotation *notes;
40334f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
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;
4389b80d1f9SArnaldo 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 
445e4cc91b8SArnaldo Carvalho de Melo static bool annotate_browser__jump(struct annotate_browser *browser,
446e4cc91b8SArnaldo Carvalho de Melo 				   struct perf_evsel *evsel,
447e4cc91b8SArnaldo Carvalho de Melo 				   struct hist_browser_timer *hbt)
448aca7a94dSNamhyung Kim {
4497bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
4505252b1aeSArnaldo Carvalho de Melo 	u64 offset;
4514f9d0325SArnaldo Carvalho de Melo 	s64 idx;
452aca7a94dSNamhyung Kim 
45375b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
454aca7a94dSNamhyung Kim 		return false;
455aca7a94dSNamhyung Kim 
456e4cc91b8SArnaldo Carvalho de Melo 	if (dl->ops.target.outside) {
457e4cc91b8SArnaldo Carvalho de Melo 		annotate_browser__callq(browser, evsel, hbt);
458e4cc91b8SArnaldo Carvalho de Melo 		return true;
459e4cc91b8SArnaldo Carvalho de Melo 	}
460e4cc91b8SArnaldo Carvalho de Melo 
4615252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
4625252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
46329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
4645252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
465aca7a94dSNamhyung Kim 		return true;
466aca7a94dSNamhyung Kim 	}
467aca7a94dSNamhyung Kim 
468ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
469aca7a94dSNamhyung Kim 
470aca7a94dSNamhyung Kim 	return true;
471aca7a94dSNamhyung Kim }
472aca7a94dSNamhyung Kim 
47329ed6e76SArnaldo Carvalho de Melo static
4749213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
475aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
476aca7a94dSNamhyung Kim {
47795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
4789213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
479aca7a94dSNamhyung Kim 
480aca7a94dSNamhyung Kim 	*idx = browser->b.index;
4819213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
4829b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
483aca7a94dSNamhyung Kim 			continue;
484aca7a94dSNamhyung Kim 
485aca7a94dSNamhyung Kim 		++*idx;
486aca7a94dSNamhyung Kim 
4879213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
4889213afbdSJiri Olsa 			return al;
489aca7a94dSNamhyung Kim 	}
490aca7a94dSNamhyung Kim 
491aca7a94dSNamhyung Kim 	return NULL;
492aca7a94dSNamhyung Kim }
493aca7a94dSNamhyung Kim 
494aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
495aca7a94dSNamhyung Kim {
4969213afbdSJiri Olsa 	struct annotation_line *al;
497aca7a94dSNamhyung Kim 	s64 idx;
498aca7a94dSNamhyung Kim 
4999213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
5009213afbdSJiri Olsa 	if (al == NULL) {
501aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
502aca7a94dSNamhyung Kim 		return false;
503aca7a94dSNamhyung Kim 	}
504aca7a94dSNamhyung Kim 
505ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
506aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
507aca7a94dSNamhyung Kim 	return true;
508aca7a94dSNamhyung Kim }
509aca7a94dSNamhyung Kim 
51029ed6e76SArnaldo Carvalho de Melo static
5119213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
512aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
513aca7a94dSNamhyung Kim {
51495aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
5159213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
516aca7a94dSNamhyung Kim 
517aca7a94dSNamhyung Kim 	*idx = browser->b.index;
5189213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
5199b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
520aca7a94dSNamhyung Kim 			continue;
521aca7a94dSNamhyung Kim 
522aca7a94dSNamhyung Kim 		--*idx;
523aca7a94dSNamhyung Kim 
5249213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
5259213afbdSJiri Olsa 			return al;
526aca7a94dSNamhyung Kim 	}
527aca7a94dSNamhyung Kim 
528aca7a94dSNamhyung Kim 	return NULL;
529aca7a94dSNamhyung Kim }
530aca7a94dSNamhyung Kim 
531aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
532aca7a94dSNamhyung Kim {
5339213afbdSJiri Olsa 	struct annotation_line *al;
534aca7a94dSNamhyung Kim 	s64 idx;
535aca7a94dSNamhyung Kim 
5369213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
5379213afbdSJiri Olsa 	if (al == NULL) {
538aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
539aca7a94dSNamhyung Kim 		return false;
540aca7a94dSNamhyung Kim 	}
541aca7a94dSNamhyung Kim 
542ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
543aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
544aca7a94dSNamhyung Kim 	return true;
545aca7a94dSNamhyung Kim }
546aca7a94dSNamhyung Kim 
547aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
548aca7a94dSNamhyung Kim 					    int delay_secs)
549aca7a94dSNamhyung Kim {
550aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
551aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
552aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
553aca7a94dSNamhyung Kim 	    !*browser->search_bf)
554aca7a94dSNamhyung Kim 		return false;
555aca7a94dSNamhyung Kim 
556aca7a94dSNamhyung Kim 	return true;
557aca7a94dSNamhyung Kim }
558aca7a94dSNamhyung Kim 
559aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
560aca7a94dSNamhyung Kim {
561aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
562aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
563aca7a94dSNamhyung Kim 
564aca7a94dSNamhyung Kim 	return false;
565aca7a94dSNamhyung Kim }
566aca7a94dSNamhyung Kim 
567aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
568aca7a94dSNamhyung Kim 					      int delay_secs)
569aca7a94dSNamhyung Kim {
570aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
571aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
572aca7a94dSNamhyung Kim 
573aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
574aca7a94dSNamhyung Kim }
575aca7a94dSNamhyung Kim 
576aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
577aca7a94dSNamhyung Kim 					   int delay_secs)
578aca7a94dSNamhyung Kim {
579aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
580aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
581aca7a94dSNamhyung Kim 
582aca7a94dSNamhyung Kim 	return false;
583aca7a94dSNamhyung Kim }
584aca7a94dSNamhyung Kim 
585aca7a94dSNamhyung Kim static
586aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
587aca7a94dSNamhyung Kim 					       int delay_secs)
588aca7a94dSNamhyung Kim {
589aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
590aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
591aca7a94dSNamhyung Kim 
592aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
593aca7a94dSNamhyung Kim }
594aca7a94dSNamhyung Kim 
5956920e285SArnaldo Carvalho de Melo static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
5966920e285SArnaldo Carvalho de Melo {
5976920e285SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
5986920e285SArnaldo Carvalho de Melo 	struct symbol *sym = ms->sym;
5996920e285SArnaldo Carvalho de Melo 	char symbol_dso[SYM_TITLE_MAX_SIZE];
6006920e285SArnaldo Carvalho de Melo 
6016920e285SArnaldo Carvalho de Melo 	if (ui_browser__show(browser, title, help) < 0)
6026920e285SArnaldo Carvalho de Melo 		return -1;
6036920e285SArnaldo Carvalho de Melo 
6046920e285SArnaldo Carvalho de Melo 	sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso));
6056920e285SArnaldo Carvalho de Melo 
6066920e285SArnaldo Carvalho de Melo 	ui_browser__gotorc_title(browser, 0, 0);
6076920e285SArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_ROOT);
6086920e285SArnaldo Carvalho de Melo 	ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
6096920e285SArnaldo Carvalho de Melo 	return 0;
6106920e285SArnaldo Carvalho de Melo }
6116920e285SArnaldo Carvalho de Melo 
612db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
613db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
6149783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
615aca7a94dSNamhyung Kim {
616aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
6176920e285SArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
61805e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
619aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
62016932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
62154e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
6229783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
6236920e285SArnaldo Carvalho de Melo 	char title[256];
624aca7a94dSNamhyung Kim 	int key;
625aca7a94dSNamhyung Kim 
6266920e285SArnaldo Carvalho de Melo 	annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel);
6276920e285SArnaldo Carvalho de Melo 
6286920e285SArnaldo Carvalho de Melo 	if (annotate_browser__show(&browser->b, title, help) < 0)
629aca7a94dSNamhyung Kim 		return -1;
630aca7a94dSNamhyung Kim 
631db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
632aca7a94dSNamhyung Kim 
63305e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
63405e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
63505e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
636aca7a94dSNamhyung Kim 	}
637aca7a94dSNamhyung Kim 
63805e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
639aca7a94dSNamhyung Kim 
640aca7a94dSNamhyung Kim 	while (1) {
64105e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
642aca7a94dSNamhyung Kim 
643aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
644db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
645aca7a94dSNamhyung Kim 			/*
646aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
647aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
648aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
649aca7a94dSNamhyung Kim 			 */
650aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
651aca7a94dSNamhyung Kim 				nd = NULL;
652aca7a94dSNamhyung Kim 		}
653aca7a94dSNamhyung Kim 
654aca7a94dSNamhyung Kim 		switch (key) {
655aca7a94dSNamhyung Kim 		case K_TIMER:
6569783adf7SNamhyung Kim 			if (hbt)
6579783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
658aca7a94dSNamhyung Kim 
6596920e285SArnaldo Carvalho de Melo 			if (delay_secs != 0) {
660db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
6616920e285SArnaldo Carvalho de Melo 				hists__scnprintf_title(hists, title, sizeof(title));
6626920e285SArnaldo Carvalho de Melo 				annotate_browser__show(&browser->b, title, help);
6636920e285SArnaldo Carvalho de Melo 			}
664aca7a94dSNamhyung Kim 			continue;
665aca7a94dSNamhyung Kim 		case K_TAB:
666aca7a94dSNamhyung Kim 			if (nd != NULL) {
667aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
668aca7a94dSNamhyung Kim 				if (nd == NULL)
66905e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
670aca7a94dSNamhyung Kim 			} else
67105e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
672aca7a94dSNamhyung Kim 			break;
673aca7a94dSNamhyung Kim 		case K_UNTAB:
674d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
675aca7a94dSNamhyung Kim 				nd = rb_next(nd);
676aca7a94dSNamhyung Kim 				if (nd == NULL)
67705e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
678d4913cbdSMarkus Trippelsdorf 			} else
67905e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
680aca7a94dSNamhyung Kim 			break;
68154e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
682aca7a94dSNamhyung Kim 		case 'h':
68305e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
68454e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
68554e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
68654e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
6877727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
6887727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
689eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
690eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
69154e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
69254e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
69354e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
69454e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
69551f39603SArnaldo Carvalho de Melo 		"O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
69654e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
6973a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
698*3e71fc03SJin Yao 		"c             Show min/max cycle\n"
69954e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
700e592488cSAndi Kleen 		"k             Toggle line numbers\n"
701d9bd7665SArnaldo Carvalho de Melo 		"P             Print to [symbol_name].annotation file.\n"
70279ee47faSFeng Tang 		"r             Run available scripts\n"
703fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
70454e7a4e8SArnaldo Carvalho de Melo 			continue;
70579ee47faSFeng Tang 		case 'r':
70679ee47faSFeng Tang 			{
70779ee47faSFeng Tang 				script_browse(NULL);
70879ee47faSFeng Tang 				continue;
70979ee47faSFeng Tang 			}
710e592488cSAndi Kleen 		case 'k':
71116932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
712e592488cSAndi Kleen 			break;
71354e7a4e8SArnaldo Carvalho de Melo 		case 'H':
71405e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
715aca7a94dSNamhyung Kim 			break;
716aca7a94dSNamhyung Kim 		case 's':
71705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
718aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
719aca7a94dSNamhyung Kim 			continue;
720aca7a94dSNamhyung Kim 		case 'o':
72116932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
7229761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
723aca7a94dSNamhyung Kim 			continue;
72451f39603SArnaldo Carvalho de Melo 		case 'O':
72551f39603SArnaldo Carvalho de Melo 			if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
72651f39603SArnaldo Carvalho de Melo 				notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
72751f39603SArnaldo Carvalho de Melo 			continue;
7289d1ef56dSArnaldo Carvalho de Melo 		case 'j':
72916932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
7309d1ef56dSArnaldo Carvalho de Melo 			continue;
7312402e4a9SArnaldo Carvalho de Melo 		case 'J':
73216932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
7339761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
734e9823b21SArnaldo Carvalho de Melo 			continue;
735aca7a94dSNamhyung Kim 		case '/':
73605e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
737aca7a94dSNamhyung Kim show_help:
738aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
739aca7a94dSNamhyung Kim 			}
740aca7a94dSNamhyung Kim 			continue;
741aca7a94dSNamhyung Kim 		case 'n':
74205e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
74305e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
74405e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
745aca7a94dSNamhyung Kim 				goto show_help;
746aca7a94dSNamhyung Kim 			continue;
747aca7a94dSNamhyung Kim 		case '?':
74805e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
749aca7a94dSNamhyung Kim 				goto show_help;
750aca7a94dSNamhyung Kim 			continue;
751e9823b21SArnaldo Carvalho de Melo 		case 'D': {
752e9823b21SArnaldo Carvalho de Melo 			static int seq;
753e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
754e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
75505e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
75605e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
75705e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
75805e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
7591cf5f98aSArnaldo Carvalho de Melo 					   notes->nr_asm_entries);
760e9823b21SArnaldo Carvalho de Melo 		}
761e9823b21SArnaldo Carvalho de Melo 			continue;
762aca7a94dSNamhyung Kim 		case K_ENTER:
763aca7a94dSNamhyung Kim 		case K_RIGHT:
7647bcbcd58SJiri Olsa 		{
7657bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
7667bcbcd58SJiri Olsa 
76705e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
768aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
7697bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
770aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
7717bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
772c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
7737bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
774c4cceae3SArnaldo Carvalho de Melo 				goto out;
775e4cc91b8SArnaldo Carvalho de Melo 			else if (!(annotate_browser__jump(browser, evsel, hbt) ||
776db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
777c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
7786ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
779c4cceae3SArnaldo Carvalho de Melo 			}
780aca7a94dSNamhyung Kim 			continue;
7817bcbcd58SJiri Olsa 		}
782d9bd7665SArnaldo Carvalho de Melo 		case 'P':
783d9bd7665SArnaldo Carvalho de Melo 			map_symbol__annotation_dump(ms, evsel);
784d9bd7665SArnaldo Carvalho de Melo 			continue;
7850c4a5bceSMartin Liška 		case 't':
78616932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
78716932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
78816932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
78916932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
79016932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
7913a555c77STaeung Song 			else
79216932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
7939761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
7940c4a5bceSMartin Liška 			continue;
795*3e71fc03SJin Yao 		case 'c':
796*3e71fc03SJin Yao 			if (notes->options->show_minmax_cycle)
797*3e71fc03SJin Yao 				notes->options->show_minmax_cycle = false;
798*3e71fc03SJin Yao 			else
799*3e71fc03SJin Yao 				notes->options->show_minmax_cycle = true;
800*3e71fc03SJin Yao 			annotation__update_column_widths(notes);
801*3e71fc03SJin Yao 			continue;
802aca7a94dSNamhyung Kim 		case K_LEFT:
803aca7a94dSNamhyung Kim 		case K_ESC:
804aca7a94dSNamhyung Kim 		case 'q':
805aca7a94dSNamhyung Kim 		case CTRL('c'):
806aca7a94dSNamhyung Kim 			goto out;
807aca7a94dSNamhyung Kim 		default:
808aca7a94dSNamhyung Kim 			continue;
809aca7a94dSNamhyung Kim 		}
810aca7a94dSNamhyung Kim 
811aca7a94dSNamhyung Kim 		if (nd != NULL)
81205e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
813aca7a94dSNamhyung Kim 	}
814aca7a94dSNamhyung Kim out:
81505e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
816aca7a94dSNamhyung Kim 	return key;
817aca7a94dSNamhyung Kim }
818aca7a94dSNamhyung Kim 
819d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
820d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
821d5dbc518SArnaldo Carvalho de Melo {
822d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
823d5dbc518SArnaldo Carvalho de Melo }
824d5dbc518SArnaldo Carvalho de Melo 
825db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
8269783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
827aca7a94dSNamhyung Kim {
828ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
829ed426915SNamhyung Kim 	SLang_reset_tty();
830ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
831ed426915SNamhyung Kim 
832d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
833aca7a94dSNamhyung Kim }
834aca7a94dSNamhyung Kim 
835db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
836db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
8379783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
838aca7a94dSNamhyung Kim {
8399d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
840aca7a94dSNamhyung Kim 	struct map_symbol ms = {
841aca7a94dSNamhyung Kim 		.map = map,
842aca7a94dSNamhyung Kim 		.sym = sym,
843aca7a94dSNamhyung Kim 	};
844aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
845aca7a94dSNamhyung Kim 		.b = {
846a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
847aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
848aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
84929ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
8506920e285SArnaldo Carvalho de Melo 			.extra_title_lines = 1, /* for hists__scnprintf_title() */
851aca7a94dSNamhyung Kim 			.priv	 = &ms,
852aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
853aca7a94dSNamhyung Kim 		},
854aca7a94dSNamhyung Kim 	};
855ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
856aca7a94dSNamhyung Kim 
857aca7a94dSNamhyung Kim 	if (sym == NULL)
858aca7a94dSNamhyung Kim 		return -1;
859aca7a94dSNamhyung Kim 
860aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
861aca7a94dSNamhyung Kim 		return -1;
862aca7a94dSNamhyung Kim 
8637f0b6fdeSArnaldo Carvalho de Melo 	err = symbol__annotate2(sym, map, evsel, &annotation__default_options, &browser.arch);
864ee51d851SArnaldo Carvalho de Melo 	if (err) {
865ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
866ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
867ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
868b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
869aca7a94dSNamhyung Kim 	}
870aca7a94dSNamhyung Kim 
8717727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
872aca7a94dSNamhyung Kim 
8735bc49f61SArnaldo Carvalho de Melo 	browser.b.width = notes->max_line_len;
8741cf5f98aSArnaldo Carvalho de Melo 	browser.b.nr_entries = notes->nr_entries;
875aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
876aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
877e9823b21SArnaldo Carvalho de Melo 
87816932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
8791cf5f98aSArnaldo Carvalho de Melo 		ui_browser__init_asm_mode(&browser.b);
880e9823b21SArnaldo Carvalho de Melo 
881db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
882f8eb37bdSJiri Olsa 
883f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
884b793a401SArnaldo Carvalho de Melo 
885b793a401SArnaldo Carvalho de Melo out_free_offsets:
8869d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
887aca7a94dSNamhyung Kim 	return ret;
888aca7a94dSNamhyung Kim }
889