xref: /linux/tools/perf/ui/browsers/annotate.c (revision 3e0d79531984c731951d9a8a5be406df3a78ac97)
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>
18*3e0d7953SJiri Olsa #include <asm/bug.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 
25dcaa3948SJin Yao struct arch;
26dcaa3948SJin Yao 
27aca7a94dSNamhyung Kim struct annotate_browser {
28aca7a94dSNamhyung Kim 	struct ui_browser	    b;
29aca7a94dSNamhyung Kim 	struct rb_root		    entries;
30aca7a94dSNamhyung Kim 	struct rb_node		   *curr_hot;
317bcbcd58SJiri Olsa 	struct annotation_line	   *selection;
32dcaa3948SJin Yao 	struct arch		   *arch;
33cd0cccbaSArnaldo Carvalho de Melo 	struct annotation_options  *opts;
34aca7a94dSNamhyung Kim 	bool			    searching_backwards;
35aca7a94dSNamhyung Kim 	char			    search_bf[128];
36aca7a94dSNamhyung Kim };
37aca7a94dSNamhyung Kim 
3895aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser)
3995aa89d9SArnaldo Carvalho de Melo {
4095aa89d9SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
4195aa89d9SArnaldo Carvalho de Melo 	return symbol__annotation(ms->sym);
4295aa89d9SArnaldo Carvalho de Melo }
4395aa89d9SArnaldo Carvalho de Melo 
4416932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
45aca7a94dSNamhyung Kim {
4695aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
47d5490b96SJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
489b80d1f9SArnaldo Carvalho de Melo 	return annotation_line__filter(al, notes);
49aca7a94dSNamhyung Kim }
50aca7a94dSNamhyung Kim 
5127feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
522402e4a9SArnaldo Carvalho de Melo {
5327feb761SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
54bc1c0f3dSArnaldo Carvalho de Melo 
5527feb761SArnaldo Carvalho de Melo 	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
562402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
57bc1c0f3dSArnaldo Carvalho de Melo 	if (nr == notes->max_jump_sources)
582402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
592402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
602402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
612402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
622402e4a9SArnaldo Carvalho de Melo }
632402e4a9SArnaldo Carvalho de Melo 
64a1e9b74cSArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
652402e4a9SArnaldo Carvalho de Melo {
6627feb761SArnaldo Carvalho de Melo 	 int color = ui_browser__jumps_percent_color(browser, nr, current);
6727feb761SArnaldo Carvalho de Melo 	 return ui_browser__set_color(browser, color);
682402e4a9SArnaldo Carvalho de Melo }
692402e4a9SArnaldo Carvalho de Melo 
70a1e9b74cSArnaldo Carvalho de Melo static int annotate_browser__set_color(void *browser, int color)
71aca7a94dSNamhyung Kim {
72a1e9b74cSArnaldo Carvalho de Melo 	return ui_browser__set_color(browser, color);
734ea08b52SArnaldo Carvalho de Melo }
744ea08b52SArnaldo Carvalho de Melo 
75a1e9b74cSArnaldo Carvalho de Melo static void annotate_browser__write_graph(void *browser, int graph)
76a1e9b74cSArnaldo Carvalho de Melo {
77a1e9b74cSArnaldo Carvalho de Melo 	ui_browser__write_graph(browser, graph);
78a5433b3eSJiri Olsa }
79a5433b3eSJiri Olsa 
802ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
812ba5eca1SArnaldo Carvalho de Melo {
822ba5eca1SArnaldo Carvalho de Melo 	ui_browser__set_percent_color(browser, percent, current);
832ba5eca1SArnaldo Carvalho de Melo }
842ba5eca1SArnaldo Carvalho de Melo 
852ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__printf(void *browser, const char *fmt, ...)
862ba5eca1SArnaldo Carvalho de Melo {
872ba5eca1SArnaldo Carvalho de Melo 	va_list args;
882ba5eca1SArnaldo Carvalho de Melo 
892ba5eca1SArnaldo Carvalho de Melo 	va_start(args, fmt);
902ba5eca1SArnaldo Carvalho de Melo 	ui_browser__vprintf(browser, fmt, args);
912ba5eca1SArnaldo Carvalho de Melo 	va_end(args);
922ba5eca1SArnaldo Carvalho de Melo }
932ba5eca1SArnaldo Carvalho de Melo 
94a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
95a5433b3eSJiri Olsa {
96a5433b3eSJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
98a5433b3eSJiri Olsa 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
99c298304bSArnaldo Carvalho de Melo 	struct annotation_write_ops ops = {
100c298304bSArnaldo Carvalho de Melo 		.first_line		 = row == 0,
101c298304bSArnaldo Carvalho de Melo 		.current_entry		 = ui_browser__is_current_entry(browser, row),
102c298304bSArnaldo Carvalho de Melo 		.change_color		 = (!notes->options->hide_src_code &&
103c298304bSArnaldo Carvalho de Melo 					    (!ops.current_entry ||
104c298304bSArnaldo Carvalho de Melo 					     (browser->use_navkeypressed &&
105c298304bSArnaldo Carvalho de Melo 					      !browser->navkeypressed))),
106c298304bSArnaldo Carvalho de Melo 		.width			 = browser->width,
107c298304bSArnaldo Carvalho de Melo 		.obj			 = browser,
108c298304bSArnaldo Carvalho de Melo 		.set_color		 = annotate_browser__set_color,
109c298304bSArnaldo Carvalho de Melo 		.set_percent_color	 = annotate_browser__set_percent_color,
110c298304bSArnaldo Carvalho de Melo 		.set_jumps_percent_color = ui_browser__set_jumps_percent_color,
111c298304bSArnaldo Carvalho de Melo 		.printf			 = annotate_browser__printf,
112c298304bSArnaldo Carvalho de Melo 		.write_graph		 = annotate_browser__write_graph,
113c298304bSArnaldo Carvalho de Melo 	};
114a5433b3eSJiri Olsa 
115a5433b3eSJiri Olsa 	/* The scroll bar isn't being used */
116a5433b3eSJiri Olsa 	if (!browser->navkeypressed)
117c298304bSArnaldo Carvalho de Melo 		ops.width += 1;
118a5433b3eSJiri Olsa 
1194c650ddcSJiri Olsa 	annotation_line__write(al, notes, &ops, ab->opts);
120aca7a94dSNamhyung Kim 
121c298304bSArnaldo Carvalho de Melo 	if (ops.current_entry)
122a5433b3eSJiri Olsa 		ab->selection = al;
123aca7a94dSNamhyung Kim }
124aca7a94dSNamhyung Kim 
1257e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
1267e63a13aSJin Yao {
127a17c4ca0SJiri Olsa 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
1287e63a13aSJin Yao 	const char *name;
1297e63a13aSJin Yao 
1307e63a13aSJin Yao 	if (!pos)
1317e63a13aSJin Yao 		return false;
1327e63a13aSJin Yao 
1337e63a13aSJin Yao 	if (ins__is_lock(&pos->ins))
1347e63a13aSJin Yao 		name = pos->ops.locked.ins.name;
1357e63a13aSJin Yao 	else
1367e63a13aSJin Yao 		name = pos->ins.name;
1377e63a13aSJin Yao 
1387e63a13aSJin Yao 	if (!name || !cursor->ins.name)
1397e63a13aSJin Yao 		return false;
1407e63a13aSJin Yao 
1417e63a13aSJin Yao 	return ins__is_fused(ab->arch, name, cursor->ins.name);
1427e63a13aSJin Yao }
1437e63a13aSJin Yao 
1449d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
145a3f895beSArnaldo Carvalho de Melo {
146a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1477bcbcd58SJiri Olsa 	struct disasm_line *cursor = disasm_line(ab->selection);
148a5ef2702SJiri Olsa 	struct annotation_line *target;
14983b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
15032ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
15132ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
1520e83a7e9SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
1536af612d2SArnaldo Carvalho de Melo 	u8 pcnt_width = annotation__pcnt_width(notes);
15400ea0eb2SArnaldo Carvalho de Melo 	int width;
15532ae1efdSNamhyung Kim 
15632ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
15732ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
15832ae1efdSNamhyung Kim 		return;
159a3f895beSArnaldo Carvalho de Melo 
1602eff0611SArnaldo Carvalho de Melo 	if (!disasm_line__is_valid_local_jump(cursor, sym))
161a3f895beSArnaldo Carvalho de Melo 		return;
162a3f895beSArnaldo Carvalho de Melo 
1639c04409dSArnaldo Carvalho de Melo 	/*
1649c04409dSArnaldo Carvalho de Melo 	 * This first was seen with a gcc function, _cpp_lex_token, that
1659c04409dSArnaldo Carvalho de Melo 	 * has the usual jumps:
1669c04409dSArnaldo Carvalho de Melo 	 *
1679c04409dSArnaldo Carvalho de Melo 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
1689c04409dSArnaldo Carvalho de Melo 	 *
1699c04409dSArnaldo Carvalho de Melo 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
1709c04409dSArnaldo Carvalho de Melo 	 * those works, but also this kind:
1719c04409dSArnaldo Carvalho de Melo 	 *
1729c04409dSArnaldo Carvalho de Melo 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
1739c04409dSArnaldo Carvalho de Melo 	 *
1749c04409dSArnaldo Carvalho de Melo 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
1759c04409dSArnaldo Carvalho de Melo 	 *  are not being correctly handled generating as a side effect references
1769c04409dSArnaldo Carvalho de Melo 	 *  to ab->offset[] entries that are set to NULL, so to make this code
1779c04409dSArnaldo Carvalho de Melo 	 *  more robust, check that here.
1789c04409dSArnaldo Carvalho de Melo 	 *
1799c04409dSArnaldo Carvalho de Melo 	 *  A proper fix for will be put in place, looking at the function
1809c04409dSArnaldo Carvalho de Melo 	 *  name right after the '<' token and probably treating this like a
1819c04409dSArnaldo Carvalho de Melo 	 *  'call' instruction.
1829c04409dSArnaldo Carvalho de Melo 	 */
1839d6bb41dSArnaldo Carvalho de Melo 	target = notes->offsets[cursor->ops.target.offset];
1849c04409dSArnaldo Carvalho de Melo 	if (target == NULL) {
1859d6bb41dSArnaldo Carvalho de Melo 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
1869c04409dSArnaldo Carvalho de Melo 				    cursor->ops.target.offset);
1879c04409dSArnaldo Carvalho de Melo 		return;
1889c04409dSArnaldo Carvalho de Melo 	}
1899d1ef56dSArnaldo Carvalho de Melo 
19016932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
1914850c92eSArnaldo Carvalho de Melo 		from = cursor->al.idx_asm;
1924850c92eSArnaldo Carvalho de Melo 		to = target->idx_asm;
193a3f895beSArnaldo Carvalho de Melo 	} else {
1944850c92eSArnaldo Carvalho de Melo 		from = (u64)cursor->al.idx;
1954850c92eSArnaldo Carvalho de Melo 		to = (u64)target->idx;
196a3f895beSArnaldo Carvalho de Melo 	}
197a3f895beSArnaldo Carvalho de Melo 
1980e83a7e9SArnaldo Carvalho de Melo 	width = annotation__cycles_width(notes);
199b40982e8SJin Yao 
20078ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
201b40982e8SJin Yao 	__ui_browser__line_arrow(browser,
2029761e86eSArnaldo Carvalho de Melo 				 pcnt_width + 2 + notes->widths.addr + width,
203c7e7b610SNamhyung Kim 				 from, to);
2047e63a13aSJin Yao 
2057e63a13aSJin Yao 	if (is_fused(ab, cursor)) {
2067e63a13aSJin Yao 		ui_browser__mark_fused(browser,
2079761e86eSArnaldo Carvalho de Melo 				       pcnt_width + 3 + notes->widths.addr + width,
2087e63a13aSJin Yao 				       from - 1,
2097e63a13aSJin Yao 				       to > from ? true : false);
2107e63a13aSJin Yao 	}
211a3f895beSArnaldo Carvalho de Melo }
212a3f895beSArnaldo Carvalho de Melo 
213a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
214a3f895beSArnaldo Carvalho de Melo {
21595aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
216a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
2176af612d2SArnaldo Carvalho de Melo 	int pcnt_width = annotation__pcnt_width(notes);
218a3f895beSArnaldo Carvalho de Melo 
21916932d77SArnaldo Carvalho de Melo 	if (notes->options->jump_arrows)
2209d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
221a3f895beSArnaldo Carvalho de Melo 
22283b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
223e726c851SArnaldo Carvalho de Melo 	__ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
224a3f895beSArnaldo Carvalho de Melo 	return ret;
225a3f895beSArnaldo Carvalho de Melo }
226a3f895beSArnaldo Carvalho de Melo 
227b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
228c7e7b610SNamhyung Kim {
229c7e7b610SNamhyung Kim 	int i;
230c7e7b610SNamhyung Kim 
231c2f938baSJiri Olsa 	for (i = 0; i < a->data_nr; i++) {
232c2f938baSJiri Olsa 		if (a->data[i].percent == b->data[i].percent)
233c7e7b610SNamhyung Kim 			continue;
234c2f938baSJiri Olsa 		return a->data[i].percent < b->data[i].percent;
235c7e7b610SNamhyung Kim 	}
236c7e7b610SNamhyung Kim 	return 0;
237c7e7b610SNamhyung Kim }
238c7e7b610SNamhyung Kim 
239b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
240aca7a94dSNamhyung Kim {
24129ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
242aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
2433ab6db8dSJiri Olsa 	struct annotation_line *l;
244aca7a94dSNamhyung Kim 
245aca7a94dSNamhyung Kim 	while (*p != NULL) {
246aca7a94dSNamhyung Kim 		parent = *p;
2473ab6db8dSJiri Olsa 		l = rb_entry(parent, struct annotation_line, rb_node);
248c7e7b610SNamhyung Kim 
249b15636c6SJiri Olsa 		if (disasm__cmp(al, l))
250aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
251aca7a94dSNamhyung Kim 		else
252aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
253aca7a94dSNamhyung Kim 	}
2543ab6db8dSJiri Olsa 	rb_link_node(&al->rb_node, parent, p);
2553ab6db8dSJiri Olsa 	rb_insert_color(&al->rb_node, root);
256aca7a94dSNamhyung Kim }
257aca7a94dSNamhyung Kim 
25805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
259ec03a77dSJiri Olsa 				      struct annotation_line *pos, u32 idx)
260aca7a94dSNamhyung Kim {
2619b80d1f9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
262aca7a94dSNamhyung Kim 	unsigned back;
263aca7a94dSNamhyung Kim 
26405e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
26505e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
26605e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
267aca7a94dSNamhyung Kim 
26805e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
269ec03a77dSJiri Olsa 		pos = list_entry(pos->node.prev, struct annotation_line, node);
270aca7a94dSNamhyung Kim 
2719b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(pos, notes))
272aca7a94dSNamhyung Kim 			continue;
273aca7a94dSNamhyung Kim 
27405e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
275aca7a94dSNamhyung Kim 		--back;
276aca7a94dSNamhyung Kim 	}
277aca7a94dSNamhyung Kim 
278ec03a77dSJiri Olsa 	browser->b.top = pos;
27905e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
280aca7a94dSNamhyung Kim }
281aca7a94dSNamhyung Kim 
282aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
283aca7a94dSNamhyung Kim 					 struct rb_node *nd)
284aca7a94dSNamhyung Kim {
28595aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
2864850c92eSArnaldo Carvalho de Melo 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
2874850c92eSArnaldo Carvalho de Melo 	u32 idx = pos->idx;
288aca7a94dSNamhyung Kim 
28916932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
2904850c92eSArnaldo Carvalho de Melo 		idx = pos->idx_asm;
291a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
292aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
293aca7a94dSNamhyung Kim }
294aca7a94dSNamhyung Kim 
295aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
296db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
297aca7a94dSNamhyung Kim {
298aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
299aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
300aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
301c4c72436SJiri Olsa 	struct disasm_line *pos;
302aca7a94dSNamhyung Kim 
303aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
304aca7a94dSNamhyung Kim 
305aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
306aca7a94dSNamhyung Kim 
307e425da6cSJiri Olsa 	symbol__calc_percent(sym, evsel);
308e425da6cSJiri Olsa 
309a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
310c7e7b610SNamhyung Kim 		double max_percent = 0.0;
311c7e7b610SNamhyung Kim 		int i;
312e64aa75bSNamhyung Kim 
313d5490b96SJiri Olsa 		if (pos->al.offset == -1) {
3145b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
315e64aa75bSNamhyung Kim 			continue;
316e64aa75bSNamhyung Kim 		}
317e64aa75bSNamhyung Kim 
318c2f938baSJiri Olsa 		for (i = 0; i < pos->al.data_nr; i++) {
3196d9f0c2dSJiri Olsa 			double percent;
3200c4a5bceSMartin Liška 
3216d9f0c2dSJiri Olsa 			percent = annotation_data__percent(&pos->al.data[i],
322d4265b1aSJiri Olsa 							   browser->opts->percent_type);
3236d9f0c2dSJiri Olsa 
3246d9f0c2dSJiri Olsa 			if (max_percent < percent)
3256d9f0c2dSJiri Olsa 				max_percent = percent;
326c7e7b610SNamhyung Kim 		}
327c7e7b610SNamhyung Kim 
32837236d5eSJiri Olsa 		if (max_percent < 0.01 && pos->al.ipc == 0) {
3295b12adc8SJiri Olsa 			RB_CLEAR_NODE(&pos->al.rb_node);
330aca7a94dSNamhyung Kim 			continue;
331aca7a94dSNamhyung Kim 		}
332b15636c6SJiri Olsa 		disasm_rb_tree__insert(&browser->entries, &pos->al);
333aca7a94dSNamhyung Kim 	}
334aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
335aca7a94dSNamhyung Kim 
336aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
337aca7a94dSNamhyung Kim }
338aca7a94dSNamhyung Kim 
339aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
340aca7a94dSNamhyung Kim {
34195aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
342ec03a77dSJiri Olsa 	struct annotation_line *al;
343aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
344aca7a94dSNamhyung Kim 
345aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
346ec03a77dSJiri Olsa 	al = list_entry(browser->b.top, struct annotation_line, node);
347aca7a94dSNamhyung Kim 
34816932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code) {
3494850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3504850c92eSArnaldo Carvalho de Melo 			offset = al->idx;
351aca7a94dSNamhyung Kim 
3521cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_entries;
35316932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = false;
354aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3554850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx - offset;
3564850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx;
357aca7a94dSNamhyung Kim 	} else {
3584850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < 0) {
359aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
360aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
361aca7a94dSNamhyung Kim 			return false;
362aca7a94dSNamhyung Kim 		}
363aca7a94dSNamhyung Kim 
3644850c92eSArnaldo Carvalho de Melo 		if (al->idx_asm < offset)
3654850c92eSArnaldo Carvalho de Melo 			offset = al->idx_asm;
366aca7a94dSNamhyung Kim 
3671cf5f98aSArnaldo Carvalho de Melo 		browser->b.nr_entries = notes->nr_asm_entries;
36816932d77SArnaldo Carvalho de Melo 		notes->options->hide_src_code = true;
369aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
3704850c92eSArnaldo Carvalho de Melo 		browser->b.top_idx = al->idx_asm - offset;
3714850c92eSArnaldo Carvalho de Melo 		browser->b.index = al->idx_asm;
372aca7a94dSNamhyung Kim 	}
373aca7a94dSNamhyung Kim 
374aca7a94dSNamhyung Kim 	return true;
375aca7a94dSNamhyung Kim }
376aca7a94dSNamhyung Kim 
3771cf5f98aSArnaldo Carvalho de Melo static void ui_browser__init_asm_mode(struct ui_browser *browser)
378e9823b21SArnaldo Carvalho de Melo {
3791cf5f98aSArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(browser);
3801cf5f98aSArnaldo Carvalho de Melo 	ui_browser__reset_index(browser);
3811cf5f98aSArnaldo Carvalho de Melo 	browser->nr_entries = notes->nr_asm_entries;
382e9823b21SArnaldo Carvalho de Melo }
383e9823b21SArnaldo Carvalho de Melo 
38434f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
38534f77abcSAdrian Hunter 
38634f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
387*3e0d7953SJiri Olsa 		     size_t sz, int percent_type)
38834f77abcSAdrian Hunter {
389*3e0d7953SJiri Olsa 	return snprintf(title, sz, "%s  %s [Percent: %s]", sym->name, map->dso->long_name,
390*3e0d7953SJiri Olsa 			percent_type_str(percent_type));
39134f77abcSAdrian Hunter }
39234f77abcSAdrian Hunter 
393e4cc91b8SArnaldo Carvalho de Melo /*
394e4cc91b8SArnaldo Carvalho de Melo  * This can be called from external jumps, i.e. jumps from one functon
395e4cc91b8SArnaldo Carvalho de Melo  * to another, like from the kernel's entry_SYSCALL_64 function to the
396e4cc91b8SArnaldo Carvalho de Melo  * swapgs_restore_regs_and_return_to_usermode() function.
397e4cc91b8SArnaldo Carvalho de Melo  *
398e4cc91b8SArnaldo Carvalho de Melo  * So all we check here is that dl->ops.target.sym is set, if it is, just
399e4cc91b8SArnaldo Carvalho de Melo  * go to that function and when exiting from its disassembly, come back
400e4cc91b8SArnaldo Carvalho de Melo  * to the calling function.
401e4cc91b8SArnaldo Carvalho de Melo  */
402db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
403db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
4049783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
405aca7a94dSNamhyung Kim {
406aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
4077bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
408aca7a94dSNamhyung Kim 	struct annotation *notes;
40934f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
410aca7a94dSNamhyung Kim 
411696703afSArnaldo Carvalho de Melo 	if (!dl->ops.target.sym) {
412aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
413aca7a94dSNamhyung Kim 		return true;
414aca7a94dSNamhyung Kim 	}
415aca7a94dSNamhyung Kim 
416696703afSArnaldo Carvalho de Melo 	notes = symbol__annotation(dl->ops.target.sym);
417aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
418aca7a94dSNamhyung Kim 
41914c8dde1SArnaldo Carvalho de Melo 	if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) {
420aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
421aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
422696703afSArnaldo Carvalho de Melo 			    dl->ops.target.sym->name);
423aca7a94dSNamhyung Kim 		return true;
424aca7a94dSNamhyung Kim 	}
425aca7a94dSNamhyung Kim 
426aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
427cd0cccbaSArnaldo Carvalho de Melo 	symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
428*3e0d7953SJiri Olsa 	sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
42934f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
430aca7a94dSNamhyung Kim 	return true;
431aca7a94dSNamhyung Kim }
432aca7a94dSNamhyung Kim 
43329ed6e76SArnaldo Carvalho de Melo static
43429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
435aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
436aca7a94dSNamhyung Kim {
43795aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
43829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
439aca7a94dSNamhyung Kim 
440aca7a94dSNamhyung Kim 	*idx = 0;
441a17c4ca0SJiri Olsa 	list_for_each_entry(pos, &notes->src->source, al.node) {
442d5490b96SJiri Olsa 		if (pos->al.offset == offset)
443aca7a94dSNamhyung Kim 			return pos;
4449b80d1f9SArnaldo Carvalho de Melo 		if (!annotation_line__filter(&pos->al, notes))
445aca7a94dSNamhyung Kim 			++*idx;
446aca7a94dSNamhyung Kim 	}
447aca7a94dSNamhyung Kim 
448aca7a94dSNamhyung Kim 	return NULL;
449aca7a94dSNamhyung Kim }
450aca7a94dSNamhyung Kim 
451e4cc91b8SArnaldo Carvalho de Melo static bool annotate_browser__jump(struct annotate_browser *browser,
452e4cc91b8SArnaldo Carvalho de Melo 				   struct perf_evsel *evsel,
453e4cc91b8SArnaldo Carvalho de Melo 				   struct hist_browser_timer *hbt)
454aca7a94dSNamhyung Kim {
4557bcbcd58SJiri Olsa 	struct disasm_line *dl = disasm_line(browser->selection);
4565252b1aeSArnaldo Carvalho de Melo 	u64 offset;
4574f9d0325SArnaldo Carvalho de Melo 	s64 idx;
458aca7a94dSNamhyung Kim 
45975b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
460aca7a94dSNamhyung Kim 		return false;
461aca7a94dSNamhyung Kim 
462e4cc91b8SArnaldo Carvalho de Melo 	if (dl->ops.target.outside) {
463e4cc91b8SArnaldo Carvalho de Melo 		annotate_browser__callq(browser, evsel, hbt);
464e4cc91b8SArnaldo Carvalho de Melo 		return true;
465e4cc91b8SArnaldo Carvalho de Melo 	}
466e4cc91b8SArnaldo Carvalho de Melo 
4675252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
4685252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
46929ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
4705252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
471aca7a94dSNamhyung Kim 		return true;
472aca7a94dSNamhyung Kim 	}
473aca7a94dSNamhyung Kim 
474ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, &dl->al, idx);
475aca7a94dSNamhyung Kim 
476aca7a94dSNamhyung Kim 	return true;
477aca7a94dSNamhyung Kim }
478aca7a94dSNamhyung Kim 
47929ed6e76SArnaldo Carvalho de Melo static
4809213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
481aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
482aca7a94dSNamhyung Kim {
48395aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
4849213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
485aca7a94dSNamhyung Kim 
486aca7a94dSNamhyung Kim 	*idx = browser->b.index;
4879213afbdSJiri Olsa 	list_for_each_entry_continue(al, &notes->src->source, node) {
4889b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
489aca7a94dSNamhyung Kim 			continue;
490aca7a94dSNamhyung Kim 
491aca7a94dSNamhyung Kim 		++*idx;
492aca7a94dSNamhyung Kim 
4939213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
4949213afbdSJiri Olsa 			return al;
495aca7a94dSNamhyung Kim 	}
496aca7a94dSNamhyung Kim 
497aca7a94dSNamhyung Kim 	return NULL;
498aca7a94dSNamhyung Kim }
499aca7a94dSNamhyung Kim 
500aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
501aca7a94dSNamhyung Kim {
5029213afbdSJiri Olsa 	struct annotation_line *al;
503aca7a94dSNamhyung Kim 	s64 idx;
504aca7a94dSNamhyung Kim 
5059213afbdSJiri Olsa 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
5069213afbdSJiri Olsa 	if (al == NULL) {
507aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
508aca7a94dSNamhyung Kim 		return false;
509aca7a94dSNamhyung Kim 	}
510aca7a94dSNamhyung Kim 
511ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
512aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
513aca7a94dSNamhyung Kim 	return true;
514aca7a94dSNamhyung Kim }
515aca7a94dSNamhyung Kim 
51629ed6e76SArnaldo Carvalho de Melo static
5179213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
518aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
519aca7a94dSNamhyung Kim {
52095aa89d9SArnaldo Carvalho de Melo 	struct annotation *notes = browser__annotation(&browser->b);
5219213afbdSJiri Olsa 	struct annotation_line *al = browser->selection;
522aca7a94dSNamhyung Kim 
523aca7a94dSNamhyung Kim 	*idx = browser->b.index;
5249213afbdSJiri Olsa 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
5259b80d1f9SArnaldo Carvalho de Melo 		if (annotation_line__filter(al, notes))
526aca7a94dSNamhyung Kim 			continue;
527aca7a94dSNamhyung Kim 
528aca7a94dSNamhyung Kim 		--*idx;
529aca7a94dSNamhyung Kim 
5309213afbdSJiri Olsa 		if (al->line && strstr(al->line, s) != NULL)
5319213afbdSJiri Olsa 			return al;
532aca7a94dSNamhyung Kim 	}
533aca7a94dSNamhyung Kim 
534aca7a94dSNamhyung Kim 	return NULL;
535aca7a94dSNamhyung Kim }
536aca7a94dSNamhyung Kim 
537aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
538aca7a94dSNamhyung Kim {
5399213afbdSJiri Olsa 	struct annotation_line *al;
540aca7a94dSNamhyung Kim 	s64 idx;
541aca7a94dSNamhyung Kim 
5429213afbdSJiri Olsa 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
5439213afbdSJiri Olsa 	if (al == NULL) {
544aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
545aca7a94dSNamhyung Kim 		return false;
546aca7a94dSNamhyung Kim 	}
547aca7a94dSNamhyung Kim 
548ec03a77dSJiri Olsa 	annotate_browser__set_top(browser, al, idx);
549aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
550aca7a94dSNamhyung Kim 	return true;
551aca7a94dSNamhyung Kim }
552aca7a94dSNamhyung Kim 
553aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
554aca7a94dSNamhyung Kim 					    int delay_secs)
555aca7a94dSNamhyung Kim {
556aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
557aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
558aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
559aca7a94dSNamhyung Kim 	    !*browser->search_bf)
560aca7a94dSNamhyung Kim 		return false;
561aca7a94dSNamhyung Kim 
562aca7a94dSNamhyung Kim 	return true;
563aca7a94dSNamhyung Kim }
564aca7a94dSNamhyung Kim 
565aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
566aca7a94dSNamhyung Kim {
567aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
568aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
569aca7a94dSNamhyung Kim 
570aca7a94dSNamhyung Kim 	return false;
571aca7a94dSNamhyung Kim }
572aca7a94dSNamhyung Kim 
573aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
574aca7a94dSNamhyung Kim 					      int delay_secs)
575aca7a94dSNamhyung Kim {
576aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
577aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
578aca7a94dSNamhyung Kim 
579aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
580aca7a94dSNamhyung Kim }
581aca7a94dSNamhyung Kim 
582aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
583aca7a94dSNamhyung Kim 					   int delay_secs)
584aca7a94dSNamhyung Kim {
585aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
586aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
587aca7a94dSNamhyung Kim 
588aca7a94dSNamhyung Kim 	return false;
589aca7a94dSNamhyung Kim }
590aca7a94dSNamhyung Kim 
591aca7a94dSNamhyung Kim static
592aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
593aca7a94dSNamhyung Kim 					       int delay_secs)
594aca7a94dSNamhyung Kim {
595aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
596aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
597aca7a94dSNamhyung Kim 
598aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
599aca7a94dSNamhyung Kim }
600aca7a94dSNamhyung Kim 
6016920e285SArnaldo Carvalho de Melo static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
6026920e285SArnaldo Carvalho de Melo {
603*3e0d7953SJiri Olsa 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
6046920e285SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->priv;
6056920e285SArnaldo Carvalho de Melo 	struct symbol *sym = ms->sym;
6066920e285SArnaldo Carvalho de Melo 	char symbol_dso[SYM_TITLE_MAX_SIZE];
6076920e285SArnaldo Carvalho de Melo 
6086920e285SArnaldo Carvalho de Melo 	if (ui_browser__show(browser, title, help) < 0)
6096920e285SArnaldo Carvalho de Melo 		return -1;
6106920e285SArnaldo Carvalho de Melo 
611*3e0d7953SJiri Olsa 	sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
6126920e285SArnaldo Carvalho de Melo 
6136920e285SArnaldo Carvalho de Melo 	ui_browser__gotorc_title(browser, 0, 0);
6146920e285SArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_ROOT);
6156920e285SArnaldo Carvalho de Melo 	ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
6166920e285SArnaldo Carvalho de Melo 	return 0;
6176920e285SArnaldo Carvalho de Melo }
6186920e285SArnaldo Carvalho de Melo 
619*3e0d7953SJiri Olsa static void
620*3e0d7953SJiri Olsa switch_percent_type(struct annotation_options *opts, bool base)
621*3e0d7953SJiri Olsa {
622*3e0d7953SJiri Olsa 	switch (opts->percent_type) {
623*3e0d7953SJiri Olsa 	case PERCENT_HITS_LOCAL:
624*3e0d7953SJiri Olsa 		if (base)
625*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_LOCAL;
626*3e0d7953SJiri Olsa 		else
627*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_GLOBAL;
628*3e0d7953SJiri Olsa 		break;
629*3e0d7953SJiri Olsa 	case PERCENT_HITS_GLOBAL:
630*3e0d7953SJiri Olsa 		if (base)
631*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_GLOBAL;
632*3e0d7953SJiri Olsa 		else
633*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_LOCAL;
634*3e0d7953SJiri Olsa 		break;
635*3e0d7953SJiri Olsa 	case PERCENT_PERIOD_LOCAL:
636*3e0d7953SJiri Olsa 		if (base)
637*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_LOCAL;
638*3e0d7953SJiri Olsa 		else
639*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_GLOBAL;
640*3e0d7953SJiri Olsa 		break;
641*3e0d7953SJiri Olsa 	case PERCENT_PERIOD_GLOBAL:
642*3e0d7953SJiri Olsa 		if (base)
643*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_HITS_GLOBAL;
644*3e0d7953SJiri Olsa 		else
645*3e0d7953SJiri Olsa 			opts->percent_type = PERCENT_PERIOD_LOCAL;
646*3e0d7953SJiri Olsa 		break;
647*3e0d7953SJiri Olsa 	default:
648*3e0d7953SJiri Olsa 		WARN_ON(1);
649*3e0d7953SJiri Olsa 	}
650*3e0d7953SJiri Olsa }
651*3e0d7953SJiri Olsa 
652db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
653db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
6549783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
655aca7a94dSNamhyung Kim {
656aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
6576920e285SArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
65805e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
659aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
66016932d77SArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(ms->sym);
66154e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
6629783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
6636920e285SArnaldo Carvalho de Melo 	char title[256];
664aca7a94dSNamhyung Kim 	int key;
665aca7a94dSNamhyung Kim 
6660683d13cSJiri Olsa 	hists__scnprintf_title(hists, title, sizeof(title));
6676920e285SArnaldo Carvalho de Melo 	if (annotate_browser__show(&browser->b, title, help) < 0)
668aca7a94dSNamhyung Kim 		return -1;
669aca7a94dSNamhyung Kim 
670db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
671aca7a94dSNamhyung Kim 
67205e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
67305e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
67405e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
675aca7a94dSNamhyung Kim 	}
676aca7a94dSNamhyung Kim 
67705e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
678aca7a94dSNamhyung Kim 
679aca7a94dSNamhyung Kim 	while (1) {
68005e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
681aca7a94dSNamhyung Kim 
682aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
683db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
684aca7a94dSNamhyung Kim 			/*
685aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
686aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
687aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
688aca7a94dSNamhyung Kim 			 */
689aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
690aca7a94dSNamhyung Kim 				nd = NULL;
691aca7a94dSNamhyung Kim 		}
692aca7a94dSNamhyung Kim 
693aca7a94dSNamhyung Kim 		switch (key) {
694aca7a94dSNamhyung Kim 		case K_TIMER:
6959783adf7SNamhyung Kim 			if (hbt)
6969783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
697aca7a94dSNamhyung Kim 
6986920e285SArnaldo Carvalho de Melo 			if (delay_secs != 0) {
699db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
7006920e285SArnaldo Carvalho de Melo 				hists__scnprintf_title(hists, title, sizeof(title));
7016920e285SArnaldo Carvalho de Melo 				annotate_browser__show(&browser->b, title, help);
7026920e285SArnaldo Carvalho de Melo 			}
703aca7a94dSNamhyung Kim 			continue;
704aca7a94dSNamhyung Kim 		case K_TAB:
705aca7a94dSNamhyung Kim 			if (nd != NULL) {
706aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
707aca7a94dSNamhyung Kim 				if (nd == NULL)
70805e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
709aca7a94dSNamhyung Kim 			} else
71005e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
711aca7a94dSNamhyung Kim 			break;
712aca7a94dSNamhyung Kim 		case K_UNTAB:
713d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
714aca7a94dSNamhyung Kim 				nd = rb_next(nd);
715aca7a94dSNamhyung Kim 				if (nd == NULL)
71605e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
717d4913cbdSMarkus Trippelsdorf 			} else
71805e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
719aca7a94dSNamhyung Kim 			break;
72054e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
721aca7a94dSNamhyung Kim 		case 'h':
72205e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
72354e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
72454e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
72554e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
7267727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
7277727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
728eba9fac0SArnaldo Carvalho de Melo 		"H             Go to hottest instruction\n"
729eba9fac0SArnaldo Carvalho de Melo 		"TAB/shift+TAB Cycle thru hottest instructions\n"
73054e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
73154e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
73254e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
73354e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
73451f39603SArnaldo Carvalho de Melo 		"O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
73554e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
7363a555c77STaeung Song 		"t             Circulate percent, total period, samples view\n"
7373e71fc03SJin Yao 		"c             Show min/max cycle\n"
73854e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
739e592488cSAndi Kleen 		"k             Toggle line numbers\n"
740d9bd7665SArnaldo Carvalho de Melo 		"P             Print to [symbol_name].annotation file.\n"
74179ee47faSFeng Tang 		"r             Run available scripts\n"
742*3e0d7953SJiri Olsa 		"p             Toggle percent type [local/global]\n"
743*3e0d7953SJiri Olsa 		"b             Toggle percent base [period/hits]\n"
744fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
74554e7a4e8SArnaldo Carvalho de Melo 			continue;
74679ee47faSFeng Tang 		case 'r':
74779ee47faSFeng Tang 			{
74879ee47faSFeng Tang 				script_browse(NULL);
74979ee47faSFeng Tang 				continue;
75079ee47faSFeng Tang 			}
751e592488cSAndi Kleen 		case 'k':
75216932d77SArnaldo Carvalho de Melo 			notes->options->show_linenr = !notes->options->show_linenr;
753e592488cSAndi Kleen 			break;
75454e7a4e8SArnaldo Carvalho de Melo 		case 'H':
75505e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
756aca7a94dSNamhyung Kim 			break;
757aca7a94dSNamhyung Kim 		case 's':
75805e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
759aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
760aca7a94dSNamhyung Kim 			continue;
761aca7a94dSNamhyung Kim 		case 'o':
76216932d77SArnaldo Carvalho de Melo 			notes->options->use_offset = !notes->options->use_offset;
7639761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
764aca7a94dSNamhyung Kim 			continue;
76551f39603SArnaldo Carvalho de Melo 		case 'O':
76651f39603SArnaldo Carvalho de Melo 			if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
76751f39603SArnaldo Carvalho de Melo 				notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
76851f39603SArnaldo Carvalho de Melo 			continue;
7699d1ef56dSArnaldo Carvalho de Melo 		case 'j':
77016932d77SArnaldo Carvalho de Melo 			notes->options->jump_arrows = !notes->options->jump_arrows;
7719d1ef56dSArnaldo Carvalho de Melo 			continue;
7722402e4a9SArnaldo Carvalho de Melo 		case 'J':
77316932d77SArnaldo Carvalho de Melo 			notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
7749761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
775e9823b21SArnaldo Carvalho de Melo 			continue;
776aca7a94dSNamhyung Kim 		case '/':
77705e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
778aca7a94dSNamhyung Kim show_help:
779aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
780aca7a94dSNamhyung Kim 			}
781aca7a94dSNamhyung Kim 			continue;
782aca7a94dSNamhyung Kim 		case 'n':
78305e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
78405e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
78505e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
786aca7a94dSNamhyung Kim 				goto show_help;
787aca7a94dSNamhyung Kim 			continue;
788aca7a94dSNamhyung Kim 		case '?':
78905e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
790aca7a94dSNamhyung Kim 				goto show_help;
791aca7a94dSNamhyung Kim 			continue;
792e9823b21SArnaldo Carvalho de Melo 		case 'D': {
793e9823b21SArnaldo Carvalho de Melo 			static int seq;
794e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
795e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
79605e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
79705e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
79805e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
79905e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
8001cf5f98aSArnaldo Carvalho de Melo 					   notes->nr_asm_entries);
801e9823b21SArnaldo Carvalho de Melo 		}
802e9823b21SArnaldo Carvalho de Melo 			continue;
803aca7a94dSNamhyung Kim 		case K_ENTER:
804aca7a94dSNamhyung Kim 		case K_RIGHT:
8057bcbcd58SJiri Olsa 		{
8067bcbcd58SJiri Olsa 			struct disasm_line *dl = disasm_line(browser->selection);
8077bcbcd58SJiri Olsa 
80805e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
809aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
8107bcbcd58SJiri Olsa 			else if (browser->selection->offset == -1)
811aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
8127bcbcd58SJiri Olsa 			else if (!dl->ins.ops)
813c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
8147bcbcd58SJiri Olsa 			else if (ins__is_ret(&dl->ins))
815c4cceae3SArnaldo Carvalho de Melo 				goto out;
816e4cc91b8SArnaldo Carvalho de Melo 			else if (!(annotate_browser__jump(browser, evsel, hbt) ||
817db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
818c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
8196ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
820c4cceae3SArnaldo Carvalho de Melo 			}
821aca7a94dSNamhyung Kim 			continue;
8227bcbcd58SJiri Olsa 		}
823d9bd7665SArnaldo Carvalho de Melo 		case 'P':
8244c650ddcSJiri Olsa 			map_symbol__annotation_dump(ms, evsel, browser->opts);
825d9bd7665SArnaldo Carvalho de Melo 			continue;
8260c4a5bceSMartin Liška 		case 't':
82716932d77SArnaldo Carvalho de Melo 			if (notes->options->show_total_period) {
82816932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = false;
82916932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = true;
83016932d77SArnaldo Carvalho de Melo 			} else if (notes->options->show_nr_samples)
83116932d77SArnaldo Carvalho de Melo 				notes->options->show_nr_samples = false;
8323a555c77STaeung Song 			else
83316932d77SArnaldo Carvalho de Melo 				notes->options->show_total_period = true;
8349761e86eSArnaldo Carvalho de Melo 			annotation__update_column_widths(notes);
8350c4a5bceSMartin Liška 			continue;
8363e71fc03SJin Yao 		case 'c':
8373e71fc03SJin Yao 			if (notes->options->show_minmax_cycle)
8383e71fc03SJin Yao 				notes->options->show_minmax_cycle = false;
8393e71fc03SJin Yao 			else
8403e71fc03SJin Yao 				notes->options->show_minmax_cycle = true;
8413e71fc03SJin Yao 			annotation__update_column_widths(notes);
8423e71fc03SJin Yao 			continue;
843*3e0d7953SJiri Olsa 		case 'p':
844*3e0d7953SJiri Olsa 		case 'b':
845*3e0d7953SJiri Olsa 			switch_percent_type(browser->opts, key == 'b');
846*3e0d7953SJiri Olsa 			hists__scnprintf_title(hists, title, sizeof(title));
847*3e0d7953SJiri Olsa 			annotate_browser__show(&browser->b, title, help);
848*3e0d7953SJiri Olsa 			continue;
849aca7a94dSNamhyung Kim 		case K_LEFT:
850aca7a94dSNamhyung Kim 		case K_ESC:
851aca7a94dSNamhyung Kim 		case 'q':
852aca7a94dSNamhyung Kim 		case CTRL('c'):
853aca7a94dSNamhyung Kim 			goto out;
854aca7a94dSNamhyung Kim 		default:
855aca7a94dSNamhyung Kim 			continue;
856aca7a94dSNamhyung Kim 		}
857aca7a94dSNamhyung Kim 
858aca7a94dSNamhyung Kim 		if (nd != NULL)
85905e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
860aca7a94dSNamhyung Kim 	}
861aca7a94dSNamhyung Kim out:
86205e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
863aca7a94dSNamhyung Kim 	return key;
864aca7a94dSNamhyung Kim }
865aca7a94dSNamhyung Kim 
866d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
867cd0cccbaSArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt,
868cd0cccbaSArnaldo Carvalho de Melo 			     struct annotation_options *opts)
869d5dbc518SArnaldo Carvalho de Melo {
870cd0cccbaSArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts);
871d5dbc518SArnaldo Carvalho de Melo }
872d5dbc518SArnaldo Carvalho de Melo 
873db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
874cd0cccbaSArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt,
875cd0cccbaSArnaldo Carvalho de Melo 			     struct annotation_options *opts)
876aca7a94dSNamhyung Kim {
877ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
878ed426915SNamhyung Kim 	SLang_reset_tty();
879ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
880ed426915SNamhyung Kim 
881cd0cccbaSArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
882aca7a94dSNamhyung Kim }
883aca7a94dSNamhyung Kim 
884db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
885db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
886cd0cccbaSArnaldo Carvalho de Melo 			 struct hist_browser_timer *hbt,
887cd0cccbaSArnaldo Carvalho de Melo 			 struct annotation_options *opts)
888aca7a94dSNamhyung Kim {
8899d6bb41dSArnaldo Carvalho de Melo 	struct annotation *notes = symbol__annotation(sym);
890aca7a94dSNamhyung Kim 	struct map_symbol ms = {
891aca7a94dSNamhyung Kim 		.map = map,
892aca7a94dSNamhyung Kim 		.sym = sym,
893aca7a94dSNamhyung Kim 	};
894aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
895aca7a94dSNamhyung Kim 		.b = {
896a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
897aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
898aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
89929ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
9006920e285SArnaldo Carvalho de Melo 			.extra_title_lines = 1, /* for hists__scnprintf_title() */
901aca7a94dSNamhyung Kim 			.priv	 = &ms,
902aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
903aca7a94dSNamhyung Kim 		},
904cd0cccbaSArnaldo Carvalho de Melo 		.opts = opts,
905aca7a94dSNamhyung Kim 	};
906ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
907aca7a94dSNamhyung Kim 
908aca7a94dSNamhyung Kim 	if (sym == NULL)
909aca7a94dSNamhyung Kim 		return -1;
910aca7a94dSNamhyung Kim 
911aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
912aca7a94dSNamhyung Kim 		return -1;
913aca7a94dSNamhyung Kim 
914cd0cccbaSArnaldo Carvalho de Melo 	err = symbol__annotate2(sym, map, evsel, opts, &browser.arch);
915ee51d851SArnaldo Carvalho de Melo 	if (err) {
916ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
917ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
918ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
919b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
920aca7a94dSNamhyung Kim 	}
921aca7a94dSNamhyung Kim 
9227727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
923aca7a94dSNamhyung Kim 
9245bc49f61SArnaldo Carvalho de Melo 	browser.b.width = notes->max_line_len;
9251cf5f98aSArnaldo Carvalho de Melo 	browser.b.nr_entries = notes->nr_entries;
926aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
927aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
928e9823b21SArnaldo Carvalho de Melo 
92916932d77SArnaldo Carvalho de Melo 	if (notes->options->hide_src_code)
9301cf5f98aSArnaldo Carvalho de Melo 		ui_browser__init_asm_mode(&browser.b);
931e9823b21SArnaldo Carvalho de Melo 
932db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
933f8eb37bdSJiri Olsa 
934f8eb37bdSJiri Olsa 	annotated_source__purge(notes->src);
935b793a401SArnaldo Carvalho de Melo 
936b793a401SArnaldo Carvalho de Melo out_free_offsets:
9379d6bb41dSArnaldo Carvalho de Melo 	zfree(&notes->offsets);
938aca7a94dSNamhyung Kim 	return ret;
939aca7a94dSNamhyung Kim }
940