xref: /linux/tools/perf/ui/browsers/annotate.c (revision e64aa75bf5559be3ce72e53ae28b76a2f633ca06)
1aca7a94dSNamhyung Kim #include "../../util/util.h"
2aca7a94dSNamhyung Kim #include "../browser.h"
3aca7a94dSNamhyung Kim #include "../helpline.h"
4aca7a94dSNamhyung Kim #include "../libslang.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"
12aca7a94dSNamhyung Kim #include <pthread.h>
13aca7a94dSNamhyung Kim #include <newt.h>
14aca7a94dSNamhyung Kim 
15b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
16b793a401SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
17b793a401SArnaldo Carvalho de Melo 	u32		idx;
18b793a401SArnaldo Carvalho de Melo 	int		idx_asm;
197d5b12f5SArnaldo Carvalho de Melo 	int		jump_sources;
20ab77df67SNamhyung Kim 	double		percent[1];
21b793a401SArnaldo Carvalho de Melo };
22b793a401SArnaldo Carvalho de Melo 
23e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
24e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
25e9823b21SArnaldo Carvalho de Melo 	     use_offset,
26e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
27e9823b21SArnaldo Carvalho de Melo 	     show_nr_jumps;
28e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
29e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
30e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
31e9823b21SArnaldo Carvalho de Melo };
32e9823b21SArnaldo Carvalho de Melo 
33aca7a94dSNamhyung Kim struct annotate_browser {
34aca7a94dSNamhyung Kim 	struct ui_browser b;
35aca7a94dSNamhyung Kim 	struct rb_root	  entries;
36aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
3729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line	  *selection;
38b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
39aca7a94dSNamhyung Kim 	u64		    start;
40aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
41aca7a94dSNamhyung Kim 	int		    nr_entries;
422402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
432402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
44aca7a94dSNamhyung Kim 	bool		    searching_backwards;
4583b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
462402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
472402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
4883b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
4983b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
50aca7a94dSNamhyung Kim 	char		    search_bf[128];
51aca7a94dSNamhyung Kim };
52aca7a94dSNamhyung Kim 
53887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
54aca7a94dSNamhyung Kim {
55887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
56aca7a94dSNamhyung Kim }
57aca7a94dSNamhyung Kim 
581d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
591d037ca1SIrina Tirdea 				void *entry)
60aca7a94dSNamhyung Kim {
61e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
6229ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
6329ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
64aca7a94dSNamhyung Kim 	}
65aca7a94dSNamhyung Kim 
66aca7a94dSNamhyung Kim 	return false;
67aca7a94dSNamhyung Kim }
68aca7a94dSNamhyung Kim 
692402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
702402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
712402e4a9SArnaldo Carvalho de Melo {
722402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
732402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
742402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
752402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
762402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
772402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
782402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
792402e4a9SArnaldo Carvalho de Melo }
802402e4a9SArnaldo Carvalho de Melo 
812402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
822402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
832402e4a9SArnaldo Carvalho de Melo {
842402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
852402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
862402e4a9SArnaldo Carvalho de Melo }
872402e4a9SArnaldo Carvalho de Melo 
8805e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
89aca7a94dSNamhyung Kim {
9005e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
92b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
9305e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
94e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
9505e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
9605e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
9705e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
9883b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
99aca7a94dSNamhyung Kim 
100ab77df67SNamhyung Kim 	if (dl->offset != -1 && bdl->percent[0] != 0.0) {
101ab77df67SNamhyung Kim 		ui_browser__set_percent_color(browser, bdl->percent[0], current_entry);
102ab77df67SNamhyung Kim 		slsmg_printf("%6.2f ", bdl->percent[0]);
103aca7a94dSNamhyung Kim 	} else {
10405e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
1050822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", 7);
106aca7a94dSNamhyung Kim 	}
107aca7a94dSNamhyung Kim 
108cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
109aca7a94dSNamhyung Kim 
110aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
11105e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
112aca7a94dSNamhyung Kim 		width += 1;
113aca7a94dSNamhyung Kim 
11429ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
1150822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", width - 7);
11683b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
11783b1f2aaSArnaldo Carvalho de Melo 		printed = scnprintf(bf, sizeof(bf), "%*s  ",
11883b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
11983b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, printed);
12083b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(dl->line, width - printed - 6);
12183b1f2aaSArnaldo Carvalho de Melo 	} else {
12229ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
12383b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
124aca7a94dSNamhyung Kim 
125e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
126aca7a94dSNamhyung Kim 			addr += ab->start;
127aca7a94dSNamhyung Kim 
128e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
129aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
13061e04b33SArnaldo Carvalho de Melo 		} else {
1317d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
132e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
1332402e4a9SArnaldo Carvalho de Melo 					int prev;
1342402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
1352402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
1362402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
1372402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
1382402e4a9SArnaldo Carvalho de Melo 											 current_entry);
1392402e4a9SArnaldo Carvalho de Melo 					slsmg_write_nstring(bf, printed);
14005e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
1412402e4a9SArnaldo Carvalho de Melo 				}
1422402e4a9SArnaldo Carvalho de Melo 
14361e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
1442402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
14561e04b33SArnaldo Carvalho de Melo 			} else {
14661e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
14783b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
14861e04b33SArnaldo Carvalho de Melo 			}
14961e04b33SArnaldo Carvalho de Melo 		}
150b793a401SArnaldo Carvalho de Melo 
151aca7a94dSNamhyung Kim 		if (change_color)
15205e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
153aca7a94dSNamhyung Kim 		slsmg_write_nstring(bf, printed);
154aca7a94dSNamhyung Kim 		if (change_color)
15505e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
15628548d78SArnaldo Carvalho de Melo 		if (dl->ins && dl->ins->ops->scnprintf) {
15751a0d455SArnaldo Carvalho de Melo 			if (ins__is_jump(dl->ins)) {
15844d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
15951a0d455SArnaldo Carvalho de Melo 
16005e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
16151a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
16251a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
16388298f5aSArnaldo Carvalho de Melo 			} else if (ins__is_call(dl->ins)) {
16405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
16588298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
16651a0d455SArnaldo Carvalho de Melo 			} else {
16751a0d455SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
16851a0d455SArnaldo Carvalho de Melo 			}
1694ea08b52SArnaldo Carvalho de Melo 		} else {
1704ea08b52SArnaldo Carvalho de Melo 			if (strcmp(dl->name, "retq")) {
1714ea08b52SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
1724ea08b52SArnaldo Carvalho de Melo 			} else {
17305e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
1744ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
1754ea08b52SArnaldo Carvalho de Melo 			}
1764ea08b52SArnaldo Carvalho de Melo 		}
1774ea08b52SArnaldo Carvalho de Melo 
178e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
17983b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, width - 10 - printed);
180aca7a94dSNamhyung Kim 	}
181aca7a94dSNamhyung Kim 
182aca7a94dSNamhyung Kim 	if (current_entry)
18329ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
184aca7a94dSNamhyung Kim }
185aca7a94dSNamhyung Kim 
186865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
187865c66c4SFrederik Deweerdt {
188865c66c4SFrederik Deweerdt 	if (!dl || !dl->ins || !ins__is_jump(dl->ins)
189865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
190865c66c4SFrederik Deweerdt 	    || dl->ops.target.offset >= symbol__size(sym))
191865c66c4SFrederik Deweerdt 		return false;
192865c66c4SFrederik Deweerdt 
193865c66c4SFrederik Deweerdt 	return true;
194865c66c4SFrederik Deweerdt }
195865c66c4SFrederik Deweerdt 
1969d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
197a3f895beSArnaldo Carvalho de Melo {
198a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1999d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
2009d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
20183b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
20232ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
20332ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
20432ae1efdSNamhyung Kim 
20532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
20632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
20732ae1efdSNamhyung Kim 		return;
208a3f895beSArnaldo Carvalho de Melo 
209865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
210a3f895beSArnaldo Carvalho de Melo 		return;
211a3f895beSArnaldo Carvalho de Melo 
2129d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
2139d1ef56dSArnaldo Carvalho de Melo 	if (!target)
2149d1ef56dSArnaldo Carvalho de Melo 		return;
2159d1ef56dSArnaldo Carvalho de Melo 
2169d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2179d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2189d1ef56dSArnaldo Carvalho de Melo 
219e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2209d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
221a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
222a3f895beSArnaldo Carvalho de Melo 	} else {
2239d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
224a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
225a3f895beSArnaldo Carvalho de Melo 	}
226a3f895beSArnaldo Carvalho de Melo 
227a3f895beSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_CODE);
22883b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
229a3f895beSArnaldo Carvalho de Melo }
230a3f895beSArnaldo Carvalho de Melo 
231a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
232a3f895beSArnaldo Carvalho de Melo {
233a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
234a3f895beSArnaldo Carvalho de Melo 
235e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
2369d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
237a3f895beSArnaldo Carvalho de Melo 
23883b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
23983b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__vline(browser, 7, 0, browser->height - 1);
240a3f895beSArnaldo Carvalho de Melo 	return ret;
241a3f895beSArnaldo Carvalho de Melo }
242a3f895beSArnaldo Carvalho de Melo 
243887c0066SArnaldo Carvalho de Melo static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
244aca7a94dSNamhyung Kim {
24529ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
246aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
247887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
248aca7a94dSNamhyung Kim 
249aca7a94dSNamhyung Kim 	while (*p != NULL) {
250aca7a94dSNamhyung Kim 		parent = *p;
251887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
252ab77df67SNamhyung Kim 		if (bdl->percent[0] < l->percent[0])
253aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
254aca7a94dSNamhyung Kim 		else
255aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
256aca7a94dSNamhyung Kim 	}
257887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
258887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
259aca7a94dSNamhyung Kim }
260aca7a94dSNamhyung Kim 
26105e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
26229ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
263aca7a94dSNamhyung Kim {
264aca7a94dSNamhyung Kim 	unsigned back;
265aca7a94dSNamhyung Kim 
26605e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
26705e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
26805e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
269aca7a94dSNamhyung Kim 
27005e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
27129ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
272aca7a94dSNamhyung Kim 
27305e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
274aca7a94dSNamhyung Kim 			continue;
275aca7a94dSNamhyung Kim 
27605e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
277aca7a94dSNamhyung Kim 		--back;
278aca7a94dSNamhyung Kim 	}
279aca7a94dSNamhyung Kim 
28005e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
28105e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
282aca7a94dSNamhyung Kim }
283aca7a94dSNamhyung Kim 
284aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
285aca7a94dSNamhyung Kim 					 struct rb_node *nd)
286aca7a94dSNamhyung Kim {
287887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
28829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
289a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
290aca7a94dSNamhyung Kim 
291887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
292887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
293a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
294e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
295a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
296a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
297aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
298aca7a94dSNamhyung Kim }
299aca7a94dSNamhyung Kim 
300aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
301db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
302aca7a94dSNamhyung Kim {
303aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
304aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
305aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
306*e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
307*e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
308aca7a94dSNamhyung Kim 
309aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
310aca7a94dSNamhyung Kim 
311aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
312aca7a94dSNamhyung Kim 
313aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
314887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
315*e64aa75bSNamhyung Kim 		const char *path = NULL;
316*e64aa75bSNamhyung Kim 
317*e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
318*e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
319*e64aa75bSNamhyung Kim 			continue;
320*e64aa75bSNamhyung Kim 		}
321*e64aa75bSNamhyung Kim 
322*e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
323*e64aa75bSNamhyung Kim 		bpos->percent[0] = disasm__calc_percent(notes, evsel->idx,
324*e64aa75bSNamhyung Kim 					pos->offset, next ? next->offset : len,
325*e64aa75bSNamhyung Kim 				        &path);
326*e64aa75bSNamhyung Kim 
327ab77df67SNamhyung Kim 		if (bpos->percent[0] < 0.01) {
328887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
329aca7a94dSNamhyung Kim 			continue;
330aca7a94dSNamhyung Kim 		}
331887c0066SArnaldo Carvalho de Melo 		disasm_rb_tree__insert(&browser->entries, bpos);
332aca7a94dSNamhyung Kim 	}
333aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
334aca7a94dSNamhyung Kim 
335aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
336aca7a94dSNamhyung Kim }
337aca7a94dSNamhyung Kim 
338aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
339aca7a94dSNamhyung Kim {
34029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
341887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
342aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
343aca7a94dSNamhyung Kim 
344aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
34529ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
346887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
347aca7a94dSNamhyung Kim 
348e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
349887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
350887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
351aca7a94dSNamhyung Kim 
352aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
353e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
354aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
355887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
356887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
357aca7a94dSNamhyung Kim 	} else {
358887c0066SArnaldo Carvalho de Melo 		if (bdl->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 
364887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
365887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
366aca7a94dSNamhyung Kim 
367aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
368e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
369aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
370887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
371887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
372aca7a94dSNamhyung Kim 	}
373aca7a94dSNamhyung Kim 
374aca7a94dSNamhyung Kim 	return true;
375aca7a94dSNamhyung Kim }
376aca7a94dSNamhyung Kim 
377e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
378e9823b21SArnaldo Carvalho de Melo {
379e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
380e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
381e9823b21SArnaldo Carvalho de Melo }
382e9823b21SArnaldo Carvalho de Melo 
383db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
384db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
3859783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
386aca7a94dSNamhyung Kim {
387aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
388657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
389aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
390aca7a94dSNamhyung Kim 	struct annotation *notes;
391aca7a94dSNamhyung Kim 	struct symbol *target;
392aca7a94dSNamhyung Kim 	u64 ip;
393aca7a94dSNamhyung Kim 
394d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_call(dl->ins))
395aca7a94dSNamhyung Kim 		return false;
396aca7a94dSNamhyung Kim 
39744d1a3edSArnaldo Carvalho de Melo 	ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
398aca7a94dSNamhyung Kim 	target = map__find_symbol(ms->map, ip, NULL);
399aca7a94dSNamhyung Kim 	if (target == NULL) {
400aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
401aca7a94dSNamhyung Kim 		return true;
402aca7a94dSNamhyung Kim 	}
403aca7a94dSNamhyung Kim 
404aca7a94dSNamhyung Kim 	notes = symbol__annotation(target);
405aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
406aca7a94dSNamhyung Kim 
407aca7a94dSNamhyung Kim 	if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
408aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
409aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
410aca7a94dSNamhyung Kim 			    target->name);
411aca7a94dSNamhyung Kim 		return true;
412aca7a94dSNamhyung Kim 	}
413aca7a94dSNamhyung Kim 
414aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
415db8fd07aSNamhyung Kim 	symbol__tui_annotate(target, ms->map, evsel, hbt);
416aca7a94dSNamhyung Kim 	ui_browser__show_title(&browser->b, sym->name);
417aca7a94dSNamhyung Kim 	return true;
418aca7a94dSNamhyung Kim }
419aca7a94dSNamhyung Kim 
42029ed6e76SArnaldo Carvalho de Melo static
42129ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
422aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
423aca7a94dSNamhyung Kim {
424aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
425aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
426aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
42729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
428aca7a94dSNamhyung Kim 
429aca7a94dSNamhyung Kim 	*idx = 0;
430aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
431aca7a94dSNamhyung Kim 		if (pos->offset == offset)
432aca7a94dSNamhyung Kim 			return pos;
43329ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
434aca7a94dSNamhyung Kim 			++*idx;
435aca7a94dSNamhyung Kim 	}
436aca7a94dSNamhyung Kim 
437aca7a94dSNamhyung Kim 	return NULL;
438aca7a94dSNamhyung Kim }
439aca7a94dSNamhyung Kim 
440aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
441aca7a94dSNamhyung Kim {
442657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
4434f9d0325SArnaldo Carvalho de Melo 	s64 idx;
444aca7a94dSNamhyung Kim 
445d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_jump(dl->ins))
446aca7a94dSNamhyung Kim 		return false;
447aca7a94dSNamhyung Kim 
44844d1a3edSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
44929ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
450aca7a94dSNamhyung Kim 		ui_helpline__puts("Invallid jump offset");
451aca7a94dSNamhyung Kim 		return true;
452aca7a94dSNamhyung Kim 	}
453aca7a94dSNamhyung Kim 
45429ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
455aca7a94dSNamhyung Kim 
456aca7a94dSNamhyung Kim 	return true;
457aca7a94dSNamhyung Kim }
458aca7a94dSNamhyung Kim 
45929ed6e76SArnaldo Carvalho de Melo static
46029ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
461aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
462aca7a94dSNamhyung Kim {
463aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
464aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
465aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
46629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
467aca7a94dSNamhyung Kim 
468aca7a94dSNamhyung Kim 	*idx = browser->b.index;
469aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
47029ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
471aca7a94dSNamhyung Kim 			continue;
472aca7a94dSNamhyung Kim 
473aca7a94dSNamhyung Kim 		++*idx;
474aca7a94dSNamhyung Kim 
475aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
476aca7a94dSNamhyung Kim 			return pos;
477aca7a94dSNamhyung Kim 	}
478aca7a94dSNamhyung Kim 
479aca7a94dSNamhyung Kim 	return NULL;
480aca7a94dSNamhyung Kim }
481aca7a94dSNamhyung Kim 
482aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
483aca7a94dSNamhyung Kim {
48429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
485aca7a94dSNamhyung Kim 	s64 idx;
486aca7a94dSNamhyung Kim 
48729ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
48829ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
489aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
490aca7a94dSNamhyung Kim 		return false;
491aca7a94dSNamhyung Kim 	}
492aca7a94dSNamhyung Kim 
49329ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
494aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
495aca7a94dSNamhyung Kim 	return true;
496aca7a94dSNamhyung Kim }
497aca7a94dSNamhyung Kim 
49829ed6e76SArnaldo Carvalho de Melo static
49929ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
500aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
501aca7a94dSNamhyung Kim {
502aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
503aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
504aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
50529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
506aca7a94dSNamhyung Kim 
507aca7a94dSNamhyung Kim 	*idx = browser->b.index;
508aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
50929ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
510aca7a94dSNamhyung Kim 			continue;
511aca7a94dSNamhyung Kim 
512aca7a94dSNamhyung Kim 		--*idx;
513aca7a94dSNamhyung Kim 
514aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
515aca7a94dSNamhyung Kim 			return pos;
516aca7a94dSNamhyung Kim 	}
517aca7a94dSNamhyung Kim 
518aca7a94dSNamhyung Kim 	return NULL;
519aca7a94dSNamhyung Kim }
520aca7a94dSNamhyung Kim 
521aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
522aca7a94dSNamhyung Kim {
52329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
524aca7a94dSNamhyung Kim 	s64 idx;
525aca7a94dSNamhyung Kim 
52629ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
52729ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
528aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
529aca7a94dSNamhyung Kim 		return false;
530aca7a94dSNamhyung Kim 	}
531aca7a94dSNamhyung Kim 
53229ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
533aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
534aca7a94dSNamhyung Kim 	return true;
535aca7a94dSNamhyung Kim }
536aca7a94dSNamhyung Kim 
537aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
538aca7a94dSNamhyung Kim 					    int delay_secs)
539aca7a94dSNamhyung Kim {
540aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
541aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
542aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
543aca7a94dSNamhyung Kim 	    !*browser->search_bf)
544aca7a94dSNamhyung Kim 		return false;
545aca7a94dSNamhyung Kim 
546aca7a94dSNamhyung Kim 	return true;
547aca7a94dSNamhyung Kim }
548aca7a94dSNamhyung Kim 
549aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
550aca7a94dSNamhyung Kim {
551aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
552aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
553aca7a94dSNamhyung Kim 
554aca7a94dSNamhyung Kim 	return false;
555aca7a94dSNamhyung Kim }
556aca7a94dSNamhyung Kim 
557aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
558aca7a94dSNamhyung Kim 					      int delay_secs)
559aca7a94dSNamhyung Kim {
560aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
561aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
562aca7a94dSNamhyung Kim 
563aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
564aca7a94dSNamhyung Kim }
565aca7a94dSNamhyung Kim 
566aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
567aca7a94dSNamhyung Kim 					   int delay_secs)
568aca7a94dSNamhyung Kim {
569aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
570aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
571aca7a94dSNamhyung Kim 
572aca7a94dSNamhyung Kim 	return false;
573aca7a94dSNamhyung Kim }
574aca7a94dSNamhyung Kim 
575aca7a94dSNamhyung Kim static
576aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
577aca7a94dSNamhyung Kim 					       int delay_secs)
578aca7a94dSNamhyung Kim {
579aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
580aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
581aca7a94dSNamhyung Kim 
582aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
583aca7a94dSNamhyung Kim }
584aca7a94dSNamhyung Kim 
585e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
586e9823b21SArnaldo Carvalho de Melo {
587e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
588e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
589e9823b21SArnaldo Carvalho de Melo 	else
590e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
591e9823b21SArnaldo Carvalho de Melo 
592e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
593e9823b21SArnaldo Carvalho de Melo 
594e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
595e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
596e9823b21SArnaldo Carvalho de Melo }
597e9823b21SArnaldo Carvalho de Melo 
598db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
599db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
6009783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
601aca7a94dSNamhyung Kim {
602aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
60305e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
604aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
60554e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
6069783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
607aca7a94dSNamhyung Kim 	int key;
608aca7a94dSNamhyung Kim 
60905e8b080SArnaldo Carvalho de Melo 	if (ui_browser__show(&browser->b, sym->name, help) < 0)
610aca7a94dSNamhyung Kim 		return -1;
611aca7a94dSNamhyung Kim 
612db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
613aca7a94dSNamhyung Kim 
61405e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
61505e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
61605e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
617aca7a94dSNamhyung Kim 	}
618aca7a94dSNamhyung Kim 
61905e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
620aca7a94dSNamhyung Kim 
621aca7a94dSNamhyung Kim 	while (1) {
62205e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
623aca7a94dSNamhyung Kim 
624aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
625db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
626aca7a94dSNamhyung Kim 			/*
627aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
628aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
629aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
630aca7a94dSNamhyung Kim 			 */
631aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
632aca7a94dSNamhyung Kim 				nd = NULL;
633aca7a94dSNamhyung Kim 		}
634aca7a94dSNamhyung Kim 
635aca7a94dSNamhyung Kim 		switch (key) {
636aca7a94dSNamhyung Kim 		case K_TIMER:
6379783adf7SNamhyung Kim 			if (hbt)
6389783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
639aca7a94dSNamhyung Kim 
640aca7a94dSNamhyung Kim 			if (delay_secs != 0)
641db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
642aca7a94dSNamhyung Kim 			continue;
643aca7a94dSNamhyung Kim 		case K_TAB:
644aca7a94dSNamhyung Kim 			if (nd != NULL) {
645aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
646aca7a94dSNamhyung Kim 				if (nd == NULL)
64705e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
648aca7a94dSNamhyung Kim 			} else
64905e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
650aca7a94dSNamhyung Kim 			break;
651aca7a94dSNamhyung Kim 		case K_UNTAB:
652aca7a94dSNamhyung Kim 			if (nd != NULL)
653aca7a94dSNamhyung Kim 				nd = rb_next(nd);
654aca7a94dSNamhyung Kim 				if (nd == NULL)
65505e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
656aca7a94dSNamhyung Kim 			else
65705e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
658aca7a94dSNamhyung Kim 			break;
65954e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
660aca7a94dSNamhyung Kim 		case 'h':
66105e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
66254e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
66354e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
66454e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
66554e7a4e8SArnaldo Carvalho de Melo 		"->            Go to target\n"
66654e7a4e8SArnaldo Carvalho de Melo 		"<-            Exit\n"
667107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
66854e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
66954e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
67054e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
67154e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
67254e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
67354e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
67479ee47faSFeng Tang 		"r             Run available scripts\n"
67554e7a4e8SArnaldo Carvalho de Melo 		"?             Search previous string\n");
67654e7a4e8SArnaldo Carvalho de Melo 			continue;
67779ee47faSFeng Tang 		case 'r':
67879ee47faSFeng Tang 			{
67979ee47faSFeng Tang 				script_browse(NULL);
68079ee47faSFeng Tang 				continue;
68179ee47faSFeng Tang 			}
68254e7a4e8SArnaldo Carvalho de Melo 		case 'H':
68305e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
684aca7a94dSNamhyung Kim 			break;
685aca7a94dSNamhyung Kim 		case 's':
68605e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
687aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
688aca7a94dSNamhyung Kim 			continue;
689aca7a94dSNamhyung Kim 		case 'o':
690e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
69105e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
692aca7a94dSNamhyung Kim 			continue;
6939d1ef56dSArnaldo Carvalho de Melo 		case 'j':
694e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
6959d1ef56dSArnaldo Carvalho de Melo 			continue;
6962402e4a9SArnaldo Carvalho de Melo 		case 'J':
697e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
69805e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
699e9823b21SArnaldo Carvalho de Melo 			continue;
700aca7a94dSNamhyung Kim 		case '/':
70105e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
702aca7a94dSNamhyung Kim show_help:
703aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
704aca7a94dSNamhyung Kim 			}
705aca7a94dSNamhyung Kim 			continue;
706aca7a94dSNamhyung Kim 		case 'n':
70705e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
70805e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
70905e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
710aca7a94dSNamhyung Kim 				goto show_help;
711aca7a94dSNamhyung Kim 			continue;
712aca7a94dSNamhyung Kim 		case '?':
71305e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
714aca7a94dSNamhyung Kim 				goto show_help;
715aca7a94dSNamhyung Kim 			continue;
716e9823b21SArnaldo Carvalho de Melo 		case 'D': {
717e9823b21SArnaldo Carvalho de Melo 			static int seq;
718e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
719e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
72005e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
72105e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
72205e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
72305e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
72405e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
725e9823b21SArnaldo Carvalho de Melo 		}
726e9823b21SArnaldo Carvalho de Melo 			continue;
727aca7a94dSNamhyung Kim 		case K_ENTER:
728aca7a94dSNamhyung Kim 		case K_RIGHT:
72905e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
730aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
73105e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
732aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
73305e8b080SArnaldo Carvalho de Melo 			else if (!browser->selection->ins) {
73405e8b080SArnaldo Carvalho de Melo 				if (strcmp(browser->selection->name, "retq"))
735c4cceae3SArnaldo Carvalho de Melo 					goto show_sup_ins;
736c4cceae3SArnaldo Carvalho de Melo 				goto out;
73705e8b080SArnaldo Carvalho de Melo 			} else if (!(annotate_browser__jump(browser) ||
738db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
739c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
740c4cceae3SArnaldo Carvalho de Melo 				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
741c4cceae3SArnaldo Carvalho de Melo 			}
742aca7a94dSNamhyung Kim 			continue;
743aca7a94dSNamhyung Kim 		case K_LEFT:
744aca7a94dSNamhyung Kim 		case K_ESC:
745aca7a94dSNamhyung Kim 		case 'q':
746aca7a94dSNamhyung Kim 		case CTRL('c'):
747aca7a94dSNamhyung Kim 			goto out;
748aca7a94dSNamhyung Kim 		default:
749aca7a94dSNamhyung Kim 			continue;
750aca7a94dSNamhyung Kim 		}
751aca7a94dSNamhyung Kim 
752aca7a94dSNamhyung Kim 		if (nd != NULL)
75305e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
754aca7a94dSNamhyung Kim 	}
755aca7a94dSNamhyung Kim out:
75605e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
757aca7a94dSNamhyung Kim 	return key;
758aca7a94dSNamhyung Kim }
759aca7a94dSNamhyung Kim 
760db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
7619783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
762aca7a94dSNamhyung Kim {
763db8fd07aSNamhyung Kim 	return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
764aca7a94dSNamhyung Kim }
765aca7a94dSNamhyung Kim 
766b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
767b793a401SArnaldo Carvalho de Melo 						size_t size)
768b793a401SArnaldo Carvalho de Melo {
769b793a401SArnaldo Carvalho de Melo 	u64 offset;
77032ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
77132ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
77232ae1efdSNamhyung Kim 
77332ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
77432ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
77532ae1efdSNamhyung Kim 		return;
776b793a401SArnaldo Carvalho de Melo 
777b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
778b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
779b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
780b793a401SArnaldo Carvalho de Melo 
781865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
782b793a401SArnaldo Carvalho de Melo 			continue;
783b793a401SArnaldo Carvalho de Melo 
78444d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
7859481ede9SArnaldo Carvalho de Melo 		/*
7869481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
7879481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
7889481ede9SArnaldo Carvalho de Melo  		 */
7899481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
7909481ede9SArnaldo Carvalho de Melo 			continue;
7919481ede9SArnaldo Carvalho de Melo 
792b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
7932402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
7942402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
7952402e4a9SArnaldo Carvalho de Melo 
7962402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
797b793a401SArnaldo Carvalho de Melo 	}
798b793a401SArnaldo Carvalho de Melo 
799b793a401SArnaldo Carvalho de Melo }
800b793a401SArnaldo Carvalho de Melo 
8012402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
8022402e4a9SArnaldo Carvalho de Melo {
8032402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
8042402e4a9SArnaldo Carvalho de Melo 		return 5;
8052402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
8062402e4a9SArnaldo Carvalho de Melo 		return 2;
8072402e4a9SArnaldo Carvalho de Melo 	return 1;
8082402e4a9SArnaldo Carvalho de Melo }
8092402e4a9SArnaldo Carvalho de Melo 
810db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
811db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
8129783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
813aca7a94dSNamhyung Kim {
81429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
815aca7a94dSNamhyung Kim 	struct annotation *notes;
816c0a58fb2SSamuel Liao 	size_t size;
817aca7a94dSNamhyung Kim 	struct map_symbol ms = {
818aca7a94dSNamhyung Kim 		.map = map,
819aca7a94dSNamhyung Kim 		.sym = sym,
820aca7a94dSNamhyung Kim 	};
821aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
822aca7a94dSNamhyung Kim 		.b = {
823a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
824aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
825aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
82629ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
827aca7a94dSNamhyung Kim 			.priv	 = &ms,
828aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
829aca7a94dSNamhyung Kim 		},
830aca7a94dSNamhyung Kim 	};
831b793a401SArnaldo Carvalho de Melo 	int ret = -1;
832aca7a94dSNamhyung Kim 
833aca7a94dSNamhyung Kim 	if (sym == NULL)
834aca7a94dSNamhyung Kim 		return -1;
835aca7a94dSNamhyung Kim 
836c0a58fb2SSamuel Liao 	size = symbol__size(sym);
837c0a58fb2SSamuel Liao 
838aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
839aca7a94dSNamhyung Kim 		return -1;
840aca7a94dSNamhyung Kim 
841b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
842b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
843b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
844b793a401SArnaldo Carvalho de Melo 		return -1;
845b793a401SArnaldo Carvalho de Melo 	}
846b793a401SArnaldo Carvalho de Melo 
847887c0066SArnaldo Carvalho de Melo 	if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
848aca7a94dSNamhyung Kim 		ui__error("%s", ui_helpline__last_msg);
849b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
850aca7a94dSNamhyung Kim 	}
851aca7a94dSNamhyung Kim 
852aca7a94dSNamhyung Kim 	ui_helpline__push("Press <- or ESC to exit");
853aca7a94dSNamhyung Kim 
854aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
855aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
856aca7a94dSNamhyung Kim 
857aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
858887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
859aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
860aca7a94dSNamhyung Kim 
861aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
862aca7a94dSNamhyung Kim 			browser.b.width = line_len;
863887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
864887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
865b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
866887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
86797148a97SArnaldo Carvalho de Melo 			/*
86897148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
86997148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
87097148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
87197148a97SArnaldo Carvalho de Melo 			 *
87297148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
87397148a97SArnaldo Carvalho de Melo  			 */
87497148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
875b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
876b793a401SArnaldo Carvalho de Melo 		} else
877887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
878aca7a94dSNamhyung Kim 	}
879aca7a94dSNamhyung Kim 
880b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
881b793a401SArnaldo Carvalho de Melo 
8822402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
88383b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
8842402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
885aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
886aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
887aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
888e9823b21SArnaldo Carvalho de Melo 
889e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
890e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
891e9823b21SArnaldo Carvalho de Melo 
892e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
893e9823b21SArnaldo Carvalho de Melo 
894db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
895aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
896aca7a94dSNamhyung Kim 		list_del(&pos->node);
89729ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
898aca7a94dSNamhyung Kim 	}
899b793a401SArnaldo Carvalho de Melo 
900b793a401SArnaldo Carvalho de Melo out_free_offsets:
901b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
902aca7a94dSNamhyung Kim 	return ret;
903aca7a94dSNamhyung Kim }
904c323cf04SArnaldo Carvalho de Melo 
905c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
906c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
907c323cf04SArnaldo Carvalho de Melo 
908c323cf04SArnaldo Carvalho de Melo /*
909c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
910c323cf04SArnaldo Carvalho de Melo  */
9117c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
912c323cf04SArnaldo Carvalho de Melo 	const char *name;
913c323cf04SArnaldo Carvalho de Melo 	bool *value;
914c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
915c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
916c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
917c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
918c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(use_offset),
919c323cf04SArnaldo Carvalho de Melo };
920c323cf04SArnaldo Carvalho de Melo 
921c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
922c323cf04SArnaldo Carvalho de Melo 
923c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
924c323cf04SArnaldo Carvalho de Melo {
9257c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
926c323cf04SArnaldo Carvalho de Melo 
927c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
928c323cf04SArnaldo Carvalho de Melo }
929c323cf04SArnaldo Carvalho de Melo 
9301d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
9311d037ca1SIrina Tirdea 			    void *data __maybe_unused)
932c323cf04SArnaldo Carvalho de Melo {
9337c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
934c323cf04SArnaldo Carvalho de Melo 	const char *name;
935c323cf04SArnaldo Carvalho de Melo 
936c323cf04SArnaldo Carvalho de Melo 	if (prefixcmp(var, "annotate.") != 0)
937c323cf04SArnaldo Carvalho de Melo 		return 0;
938c323cf04SArnaldo Carvalho de Melo 
939c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
940c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
9417c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
942c323cf04SArnaldo Carvalho de Melo 
943c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
944c323cf04SArnaldo Carvalho de Melo 		return -1;
945c323cf04SArnaldo Carvalho de Melo 
946c323cf04SArnaldo Carvalho de Melo 	*cfg->value = perf_config_bool(name, value);
947c323cf04SArnaldo Carvalho de Melo 	return 0;
948c323cf04SArnaldo Carvalho de Melo }
949c323cf04SArnaldo Carvalho de Melo 
950c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
951c323cf04SArnaldo Carvalho de Melo {
952c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
953c323cf04SArnaldo Carvalho de Melo }
954