xref: /linux/tools/perf/ui/browsers/annotate.c (revision 1d037ca1648b775277fc96401ec2aa233724906c)
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"
11aca7a94dSNamhyung Kim #include <pthread.h>
12aca7a94dSNamhyung Kim #include <newt.h>
13aca7a94dSNamhyung Kim 
14b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
15b793a401SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
16b793a401SArnaldo Carvalho de Melo 	double		percent;
17b793a401SArnaldo Carvalho de Melo 	u32		idx;
18b793a401SArnaldo Carvalho de Melo 	int		idx_asm;
197d5b12f5SArnaldo Carvalho de Melo 	int		jump_sources;
20b793a401SArnaldo Carvalho de Melo };
21b793a401SArnaldo Carvalho de Melo 
22e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
23e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
24e9823b21SArnaldo Carvalho de Melo 	     use_offset,
25e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
26e9823b21SArnaldo Carvalho de Melo 	     show_nr_jumps;
27e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
28e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
29e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
30e9823b21SArnaldo Carvalho de Melo };
31e9823b21SArnaldo Carvalho de Melo 
32aca7a94dSNamhyung Kim struct annotate_browser {
33aca7a94dSNamhyung Kim 	struct ui_browser b;
34aca7a94dSNamhyung Kim 	struct rb_root	  entries;
35aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
3629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line	  *selection;
37b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
38aca7a94dSNamhyung Kim 	u64		    start;
39aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
40aca7a94dSNamhyung Kim 	int		    nr_entries;
412402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
422402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
43aca7a94dSNamhyung Kim 	bool		    searching_backwards;
4483b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
452402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
462402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
4783b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
4883b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
49aca7a94dSNamhyung Kim 	char		    search_bf[128];
50aca7a94dSNamhyung Kim };
51aca7a94dSNamhyung Kim 
52887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
53aca7a94dSNamhyung Kim {
54887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
55aca7a94dSNamhyung Kim }
56aca7a94dSNamhyung Kim 
57*1d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
58*1d037ca1SIrina Tirdea 				void *entry)
59aca7a94dSNamhyung Kim {
60e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
6129ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
6229ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
63aca7a94dSNamhyung Kim 	}
64aca7a94dSNamhyung Kim 
65aca7a94dSNamhyung Kim 	return false;
66aca7a94dSNamhyung Kim }
67aca7a94dSNamhyung Kim 
682402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
692402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
702402e4a9SArnaldo Carvalho de Melo {
712402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
722402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
732402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
742402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
752402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
762402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
772402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
782402e4a9SArnaldo Carvalho de Melo }
792402e4a9SArnaldo Carvalho de Melo 
802402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
812402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
822402e4a9SArnaldo Carvalho de Melo {
832402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
842402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
852402e4a9SArnaldo Carvalho de Melo }
862402e4a9SArnaldo Carvalho de Melo 
8705e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
88aca7a94dSNamhyung Kim {
8905e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
91b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
9205e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
93e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
9405e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
9505e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
9605e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
9783b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
98aca7a94dSNamhyung Kim 
990822cc80SArnaldo Carvalho de Melo 	if (dl->offset != -1 && bdl->percent != 0.0) {
10005e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, bdl->percent, current_entry);
1010822cc80SArnaldo Carvalho de Melo 		slsmg_printf("%6.2f ", bdl->percent);
102aca7a94dSNamhyung Kim 	} else {
10305e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
1040822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", 7);
105aca7a94dSNamhyung Kim 	}
106aca7a94dSNamhyung Kim 
107cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
108aca7a94dSNamhyung Kim 
109aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
11005e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
111aca7a94dSNamhyung Kim 		width += 1;
112aca7a94dSNamhyung Kim 
11329ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
1140822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", width - 7);
11583b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
11683b1f2aaSArnaldo Carvalho de Melo 		printed = scnprintf(bf, sizeof(bf), "%*s  ",
11783b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
11883b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, printed);
11983b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(dl->line, width - printed - 6);
12083b1f2aaSArnaldo Carvalho de Melo 	} else {
12129ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
12283b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
123aca7a94dSNamhyung Kim 
124e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
125aca7a94dSNamhyung Kim 			addr += ab->start;
126aca7a94dSNamhyung Kim 
127e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
128aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
12961e04b33SArnaldo Carvalho de Melo 		} else {
1307d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
131e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
1322402e4a9SArnaldo Carvalho de Melo 					int prev;
1332402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
1342402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
1352402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
1362402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
1372402e4a9SArnaldo Carvalho de Melo 											 current_entry);
1382402e4a9SArnaldo Carvalho de Melo 					slsmg_write_nstring(bf, printed);
13905e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
1402402e4a9SArnaldo Carvalho de Melo 				}
1412402e4a9SArnaldo Carvalho de Melo 
14261e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
1432402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
14461e04b33SArnaldo Carvalho de Melo 			} else {
14561e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
14683b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
14761e04b33SArnaldo Carvalho de Melo 			}
14861e04b33SArnaldo Carvalho de Melo 		}
149b793a401SArnaldo Carvalho de Melo 
150aca7a94dSNamhyung Kim 		if (change_color)
15105e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
152aca7a94dSNamhyung Kim 		slsmg_write_nstring(bf, printed);
153aca7a94dSNamhyung Kim 		if (change_color)
15405e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
15528548d78SArnaldo Carvalho de Melo 		if (dl->ins && dl->ins->ops->scnprintf) {
15651a0d455SArnaldo Carvalho de Melo 			if (ins__is_jump(dl->ins)) {
15744d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
15851a0d455SArnaldo Carvalho de Melo 
15905e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
16051a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
16151a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
16288298f5aSArnaldo Carvalho de Melo 			} else if (ins__is_call(dl->ins)) {
16305e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
16488298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
16551a0d455SArnaldo Carvalho de Melo 			} else {
16651a0d455SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
16751a0d455SArnaldo Carvalho de Melo 			}
1684ea08b52SArnaldo Carvalho de Melo 		} else {
1694ea08b52SArnaldo Carvalho de Melo 			if (strcmp(dl->name, "retq")) {
1704ea08b52SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
1714ea08b52SArnaldo Carvalho de Melo 			} else {
17205e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
1734ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
1744ea08b52SArnaldo Carvalho de Melo 			}
1754ea08b52SArnaldo Carvalho de Melo 		}
1764ea08b52SArnaldo Carvalho de Melo 
177e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
17883b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, width - 10 - printed);
179aca7a94dSNamhyung Kim 	}
180aca7a94dSNamhyung Kim 
181aca7a94dSNamhyung Kim 	if (current_entry)
18229ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
183aca7a94dSNamhyung Kim }
184aca7a94dSNamhyung Kim 
1859d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
186a3f895beSArnaldo Carvalho de Melo {
187a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1889d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
1899d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
19083b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
191a3f895beSArnaldo Carvalho de Melo 
192e9823b21SArnaldo Carvalho de Melo 	if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
1939d1ef56dSArnaldo Carvalho de Melo 	    !disasm_line__has_offset(cursor))
194a3f895beSArnaldo Carvalho de Melo 		return;
195a3f895beSArnaldo Carvalho de Melo 
1969d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
1979d1ef56dSArnaldo Carvalho de Melo 	if (!target)
1989d1ef56dSArnaldo Carvalho de Melo 		return;
1999d1ef56dSArnaldo Carvalho de Melo 
2009d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2019d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2029d1ef56dSArnaldo Carvalho de Melo 
203e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2049d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
205a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
206a3f895beSArnaldo Carvalho de Melo 	} else {
2079d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
208a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
209a3f895beSArnaldo Carvalho de Melo 	}
210a3f895beSArnaldo Carvalho de Melo 
211a3f895beSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_CODE);
21283b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
213a3f895beSArnaldo Carvalho de Melo }
214a3f895beSArnaldo Carvalho de Melo 
215a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
216a3f895beSArnaldo Carvalho de Melo {
217a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
218a3f895beSArnaldo Carvalho de Melo 
219e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.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);
22383b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__vline(browser, 7, 0, browser->height - 1);
224a3f895beSArnaldo Carvalho de Melo 	return ret;
225a3f895beSArnaldo Carvalho de Melo }
226a3f895beSArnaldo Carvalho de Melo 
22729ed6e76SArnaldo Carvalho de Melo static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
228aca7a94dSNamhyung Kim {
229aca7a94dSNamhyung Kim 	double percent = 0.0;
230aca7a94dSNamhyung Kim 
23129ed6e76SArnaldo Carvalho de Melo 	if (dl->offset != -1) {
232aca7a94dSNamhyung Kim 		int len = sym->end - sym->start;
233aca7a94dSNamhyung Kim 		unsigned int hits = 0;
234aca7a94dSNamhyung Kim 		struct annotation *notes = symbol__annotation(sym);
235aca7a94dSNamhyung Kim 		struct source_line *src_line = notes->src->lines;
236aca7a94dSNamhyung Kim 		struct sym_hist *h = annotation__histogram(notes, evidx);
23729ed6e76SArnaldo Carvalho de Melo 		s64 offset = dl->offset;
23829ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *next;
239aca7a94dSNamhyung Kim 
24029ed6e76SArnaldo Carvalho de Melo 		next = disasm__get_next_ip_line(&notes->src->source, dl);
241aca7a94dSNamhyung Kim 		while (offset < (s64)len &&
242aca7a94dSNamhyung Kim 		       (next == NULL || offset < next->offset)) {
243aca7a94dSNamhyung Kim 			if (src_line) {
244aca7a94dSNamhyung Kim 				percent += src_line[offset].percent;
245aca7a94dSNamhyung Kim 			} else
246aca7a94dSNamhyung Kim 				hits += h->addr[offset];
247aca7a94dSNamhyung Kim 
248aca7a94dSNamhyung Kim 			++offset;
249aca7a94dSNamhyung Kim 		}
250aca7a94dSNamhyung Kim 		/*
251aca7a94dSNamhyung Kim  		 * If the percentage wasn't already calculated in
252aca7a94dSNamhyung Kim  		 * symbol__get_source_line, do it now:
253aca7a94dSNamhyung Kim  		 */
254aca7a94dSNamhyung Kim 		if (src_line == NULL && h->sum)
255aca7a94dSNamhyung Kim 			percent = 100.0 * hits / h->sum;
256aca7a94dSNamhyung Kim 	}
257aca7a94dSNamhyung Kim 
258aca7a94dSNamhyung Kim 	return percent;
259aca7a94dSNamhyung Kim }
260aca7a94dSNamhyung Kim 
261887c0066SArnaldo Carvalho de Melo static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
262aca7a94dSNamhyung Kim {
26329ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
264aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
265887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
266aca7a94dSNamhyung Kim 
267aca7a94dSNamhyung Kim 	while (*p != NULL) {
268aca7a94dSNamhyung Kim 		parent = *p;
269887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
270887c0066SArnaldo Carvalho de Melo 		if (bdl->percent < l->percent)
271aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
272aca7a94dSNamhyung Kim 		else
273aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
274aca7a94dSNamhyung Kim 	}
275887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
276887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
277aca7a94dSNamhyung Kim }
278aca7a94dSNamhyung Kim 
27905e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
28029ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
281aca7a94dSNamhyung Kim {
282aca7a94dSNamhyung Kim 	unsigned back;
283aca7a94dSNamhyung Kim 
28405e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
28505e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
28605e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
287aca7a94dSNamhyung Kim 
28805e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
28929ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
290aca7a94dSNamhyung Kim 
29105e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
292aca7a94dSNamhyung Kim 			continue;
293aca7a94dSNamhyung Kim 
29405e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
295aca7a94dSNamhyung Kim 		--back;
296aca7a94dSNamhyung Kim 	}
297aca7a94dSNamhyung Kim 
29805e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
29905e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
300aca7a94dSNamhyung Kim }
301aca7a94dSNamhyung Kim 
302aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
303aca7a94dSNamhyung Kim 					 struct rb_node *nd)
304aca7a94dSNamhyung Kim {
305887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
30629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
307a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
308aca7a94dSNamhyung Kim 
309887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
310887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
311a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
312e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
313a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
314a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
315aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
316aca7a94dSNamhyung Kim }
317aca7a94dSNamhyung Kim 
318aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
319aca7a94dSNamhyung Kim 					   int evidx)
320aca7a94dSNamhyung Kim {
321aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
322aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
323aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
32429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
325aca7a94dSNamhyung Kim 
326aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
327aca7a94dSNamhyung Kim 
328aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
329aca7a94dSNamhyung Kim 
330aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
331887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
332887c0066SArnaldo Carvalho de Melo 		bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
333887c0066SArnaldo Carvalho de Melo 		if (bpos->percent < 0.01) {
334887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
335aca7a94dSNamhyung Kim 			continue;
336aca7a94dSNamhyung Kim 		}
337887c0066SArnaldo Carvalho de Melo 		disasm_rb_tree__insert(&browser->entries, bpos);
338aca7a94dSNamhyung Kim 	}
339aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
340aca7a94dSNamhyung Kim 
341aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
342aca7a94dSNamhyung Kim }
343aca7a94dSNamhyung Kim 
344aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
345aca7a94dSNamhyung Kim {
34629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
347887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
348aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
349aca7a94dSNamhyung Kim 
350aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
35129ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
352887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
353aca7a94dSNamhyung Kim 
354e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
355887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
356887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
357aca7a94dSNamhyung Kim 
358aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
359e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
360aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
361887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
362887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
363aca7a94dSNamhyung Kim 	} else {
364887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
365aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
366aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
367aca7a94dSNamhyung Kim 			return false;
368aca7a94dSNamhyung Kim 		}
369aca7a94dSNamhyung Kim 
370887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
371887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
372aca7a94dSNamhyung Kim 
373aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
374e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
375aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
376887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
377887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
378aca7a94dSNamhyung Kim 	}
379aca7a94dSNamhyung Kim 
380aca7a94dSNamhyung Kim 	return true;
381aca7a94dSNamhyung Kim }
382aca7a94dSNamhyung Kim 
383e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
384e9823b21SArnaldo Carvalho de Melo {
385e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
386e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
387e9823b21SArnaldo Carvalho de Melo }
388e9823b21SArnaldo Carvalho de Melo 
389aca7a94dSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
390aca7a94dSNamhyung Kim 				    int evidx, void (*timer)(void *arg),
391aca7a94dSNamhyung Kim 				    void *arg, int delay_secs)
392aca7a94dSNamhyung Kim {
393aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
394657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
395aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
396aca7a94dSNamhyung Kim 	struct annotation *notes;
397aca7a94dSNamhyung Kim 	struct symbol *target;
398aca7a94dSNamhyung Kim 	u64 ip;
399aca7a94dSNamhyung Kim 
400d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_call(dl->ins))
401aca7a94dSNamhyung Kim 		return false;
402aca7a94dSNamhyung Kim 
40344d1a3edSArnaldo Carvalho de Melo 	ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
404aca7a94dSNamhyung Kim 	target = map__find_symbol(ms->map, ip, NULL);
405aca7a94dSNamhyung Kim 	if (target == NULL) {
406aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
407aca7a94dSNamhyung Kim 		return true;
408aca7a94dSNamhyung Kim 	}
409aca7a94dSNamhyung Kim 
410aca7a94dSNamhyung Kim 	notes = symbol__annotation(target);
411aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
412aca7a94dSNamhyung Kim 
413aca7a94dSNamhyung Kim 	if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
414aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
415aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
416aca7a94dSNamhyung Kim 			    target->name);
417aca7a94dSNamhyung Kim 		return true;
418aca7a94dSNamhyung Kim 	}
419aca7a94dSNamhyung Kim 
420aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
421aca7a94dSNamhyung Kim 	symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
422aca7a94dSNamhyung Kim 	ui_browser__show_title(&browser->b, sym->name);
423aca7a94dSNamhyung Kim 	return true;
424aca7a94dSNamhyung Kim }
425aca7a94dSNamhyung Kim 
42629ed6e76SArnaldo Carvalho de Melo static
42729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
428aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
429aca7a94dSNamhyung Kim {
430aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
431aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
432aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
43329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
434aca7a94dSNamhyung Kim 
435aca7a94dSNamhyung Kim 	*idx = 0;
436aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
437aca7a94dSNamhyung Kim 		if (pos->offset == offset)
438aca7a94dSNamhyung Kim 			return pos;
43929ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
440aca7a94dSNamhyung Kim 			++*idx;
441aca7a94dSNamhyung Kim 	}
442aca7a94dSNamhyung Kim 
443aca7a94dSNamhyung Kim 	return NULL;
444aca7a94dSNamhyung Kim }
445aca7a94dSNamhyung Kim 
446aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
447aca7a94dSNamhyung Kim {
448657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
4494f9d0325SArnaldo Carvalho de Melo 	s64 idx;
450aca7a94dSNamhyung Kim 
451d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_jump(dl->ins))
452aca7a94dSNamhyung Kim 		return false;
453aca7a94dSNamhyung Kim 
45444d1a3edSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
45529ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
456aca7a94dSNamhyung Kim 		ui_helpline__puts("Invallid jump offset");
457aca7a94dSNamhyung Kim 		return true;
458aca7a94dSNamhyung Kim 	}
459aca7a94dSNamhyung Kim 
46029ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
461aca7a94dSNamhyung Kim 
462aca7a94dSNamhyung Kim 	return true;
463aca7a94dSNamhyung Kim }
464aca7a94dSNamhyung Kim 
46529ed6e76SArnaldo Carvalho de Melo static
46629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
467aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
468aca7a94dSNamhyung Kim {
469aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
470aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
471aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
47229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
473aca7a94dSNamhyung Kim 
474aca7a94dSNamhyung Kim 	*idx = browser->b.index;
475aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
47629ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
477aca7a94dSNamhyung Kim 			continue;
478aca7a94dSNamhyung Kim 
479aca7a94dSNamhyung Kim 		++*idx;
480aca7a94dSNamhyung Kim 
481aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
482aca7a94dSNamhyung Kim 			return pos;
483aca7a94dSNamhyung Kim 	}
484aca7a94dSNamhyung Kim 
485aca7a94dSNamhyung Kim 	return NULL;
486aca7a94dSNamhyung Kim }
487aca7a94dSNamhyung Kim 
488aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
489aca7a94dSNamhyung Kim {
49029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
491aca7a94dSNamhyung Kim 	s64 idx;
492aca7a94dSNamhyung Kim 
49329ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
49429ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
495aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
496aca7a94dSNamhyung Kim 		return false;
497aca7a94dSNamhyung Kim 	}
498aca7a94dSNamhyung Kim 
49929ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
500aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
501aca7a94dSNamhyung Kim 	return true;
502aca7a94dSNamhyung Kim }
503aca7a94dSNamhyung Kim 
50429ed6e76SArnaldo Carvalho de Melo static
50529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
506aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
507aca7a94dSNamhyung Kim {
508aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
509aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
510aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
51129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
512aca7a94dSNamhyung Kim 
513aca7a94dSNamhyung Kim 	*idx = browser->b.index;
514aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
51529ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
516aca7a94dSNamhyung Kim 			continue;
517aca7a94dSNamhyung Kim 
518aca7a94dSNamhyung Kim 		--*idx;
519aca7a94dSNamhyung Kim 
520aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
521aca7a94dSNamhyung Kim 			return pos;
522aca7a94dSNamhyung Kim 	}
523aca7a94dSNamhyung Kim 
524aca7a94dSNamhyung Kim 	return NULL;
525aca7a94dSNamhyung Kim }
526aca7a94dSNamhyung Kim 
527aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
528aca7a94dSNamhyung Kim {
52929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
530aca7a94dSNamhyung Kim 	s64 idx;
531aca7a94dSNamhyung Kim 
53229ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
53329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
534aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
535aca7a94dSNamhyung Kim 		return false;
536aca7a94dSNamhyung Kim 	}
537aca7a94dSNamhyung Kim 
53829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
539aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
540aca7a94dSNamhyung Kim 	return true;
541aca7a94dSNamhyung Kim }
542aca7a94dSNamhyung Kim 
543aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
544aca7a94dSNamhyung Kim 					    int delay_secs)
545aca7a94dSNamhyung Kim {
546aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
547aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
548aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
549aca7a94dSNamhyung Kim 	    !*browser->search_bf)
550aca7a94dSNamhyung Kim 		return false;
551aca7a94dSNamhyung Kim 
552aca7a94dSNamhyung Kim 	return true;
553aca7a94dSNamhyung Kim }
554aca7a94dSNamhyung Kim 
555aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
556aca7a94dSNamhyung Kim {
557aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
558aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
559aca7a94dSNamhyung Kim 
560aca7a94dSNamhyung Kim 	return false;
561aca7a94dSNamhyung Kim }
562aca7a94dSNamhyung Kim 
563aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
564aca7a94dSNamhyung Kim 					      int delay_secs)
565aca7a94dSNamhyung Kim {
566aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
567aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
568aca7a94dSNamhyung Kim 
569aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
570aca7a94dSNamhyung Kim }
571aca7a94dSNamhyung Kim 
572aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
573aca7a94dSNamhyung Kim 					   int delay_secs)
574aca7a94dSNamhyung Kim {
575aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
576aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
577aca7a94dSNamhyung Kim 
578aca7a94dSNamhyung Kim 	return false;
579aca7a94dSNamhyung Kim }
580aca7a94dSNamhyung Kim 
581aca7a94dSNamhyung Kim static
582aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
583aca7a94dSNamhyung Kim 					       int delay_secs)
584aca7a94dSNamhyung Kim {
585aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
586aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
587aca7a94dSNamhyung Kim 
588aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
589aca7a94dSNamhyung Kim }
590aca7a94dSNamhyung Kim 
591e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
592e9823b21SArnaldo Carvalho de Melo {
593e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
594e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
595e9823b21SArnaldo Carvalho de Melo 	else
596e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
597e9823b21SArnaldo Carvalho de Melo 
598e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
599e9823b21SArnaldo Carvalho de Melo 
600e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
601e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
602e9823b21SArnaldo Carvalho de Melo }
603e9823b21SArnaldo Carvalho de Melo 
60405e8b080SArnaldo Carvalho de Melo static int annotate_browser__run(struct annotate_browser *browser, int evidx,
605aca7a94dSNamhyung Kim 				 void(*timer)(void *arg),
606aca7a94dSNamhyung Kim 				 void *arg, int delay_secs)
607aca7a94dSNamhyung Kim {
608aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
60905e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
610aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
61154e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
612aca7a94dSNamhyung Kim 	int key;
613aca7a94dSNamhyung Kim 
61405e8b080SArnaldo Carvalho de Melo 	if (ui_browser__show(&browser->b, sym->name, help) < 0)
615aca7a94dSNamhyung Kim 		return -1;
616aca7a94dSNamhyung Kim 
61705e8b080SArnaldo Carvalho de Melo 	annotate_browser__calc_percent(browser, evidx);
618aca7a94dSNamhyung Kim 
61905e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
62005e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
62105e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
622aca7a94dSNamhyung Kim 	}
623aca7a94dSNamhyung Kim 
62405e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
625aca7a94dSNamhyung Kim 
626aca7a94dSNamhyung Kim 	while (1) {
62705e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
628aca7a94dSNamhyung Kim 
629aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
63005e8b080SArnaldo Carvalho de Melo 			annotate_browser__calc_percent(browser, evidx);
631aca7a94dSNamhyung Kim 			/*
632aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
633aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
634aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
635aca7a94dSNamhyung Kim 			 */
636aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
637aca7a94dSNamhyung Kim 				nd = NULL;
638aca7a94dSNamhyung Kim 		}
639aca7a94dSNamhyung Kim 
640aca7a94dSNamhyung Kim 		switch (key) {
641aca7a94dSNamhyung Kim 		case K_TIMER:
642aca7a94dSNamhyung Kim 			if (timer != NULL)
643aca7a94dSNamhyung Kim 				timer(arg);
644aca7a94dSNamhyung Kim 
645aca7a94dSNamhyung Kim 			if (delay_secs != 0)
646aca7a94dSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evidx);
647aca7a94dSNamhyung Kim 			continue;
648aca7a94dSNamhyung Kim 		case K_TAB:
649aca7a94dSNamhyung Kim 			if (nd != NULL) {
650aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
651aca7a94dSNamhyung Kim 				if (nd == NULL)
65205e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
653aca7a94dSNamhyung Kim 			} else
65405e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
655aca7a94dSNamhyung Kim 			break;
656aca7a94dSNamhyung Kim 		case K_UNTAB:
657aca7a94dSNamhyung Kim 			if (nd != NULL)
658aca7a94dSNamhyung Kim 				nd = rb_next(nd);
659aca7a94dSNamhyung Kim 				if (nd == NULL)
66005e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
661aca7a94dSNamhyung Kim 			else
66205e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
663aca7a94dSNamhyung Kim 			break;
66454e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
665aca7a94dSNamhyung Kim 		case 'h':
66605e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
66754e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
66854e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
66954e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
67054e7a4e8SArnaldo Carvalho de Melo 		"->            Go to target\n"
67154e7a4e8SArnaldo Carvalho de Melo 		"<-            Exit\n"
672107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
67354e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
67454e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
67554e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
67654e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
67754e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
67854e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
67954e7a4e8SArnaldo Carvalho de Melo 		"?             Search previous string\n");
68054e7a4e8SArnaldo Carvalho de Melo 			continue;
68154e7a4e8SArnaldo Carvalho de Melo 		case 'H':
68205e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
683aca7a94dSNamhyung Kim 			break;
684aca7a94dSNamhyung Kim 		case 's':
68505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
686aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
687aca7a94dSNamhyung Kim 			continue;
688aca7a94dSNamhyung Kim 		case 'o':
689e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
69005e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
691aca7a94dSNamhyung Kim 			continue;
6929d1ef56dSArnaldo Carvalho de Melo 		case 'j':
693e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
6949d1ef56dSArnaldo Carvalho de Melo 			continue;
6952402e4a9SArnaldo Carvalho de Melo 		case 'J':
696e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
69705e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
698e9823b21SArnaldo Carvalho de Melo 			continue;
699aca7a94dSNamhyung Kim 		case '/':
70005e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
701aca7a94dSNamhyung Kim show_help:
702aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
703aca7a94dSNamhyung Kim 			}
704aca7a94dSNamhyung Kim 			continue;
705aca7a94dSNamhyung Kim 		case 'n':
70605e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
70705e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
70805e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
709aca7a94dSNamhyung Kim 				goto show_help;
710aca7a94dSNamhyung Kim 			continue;
711aca7a94dSNamhyung Kim 		case '?':
71205e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
713aca7a94dSNamhyung Kim 				goto show_help;
714aca7a94dSNamhyung Kim 			continue;
715e9823b21SArnaldo Carvalho de Melo 		case 'D': {
716e9823b21SArnaldo Carvalho de Melo 			static int seq;
717e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
718e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
71905e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
72005e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
72105e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
72205e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
72305e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
724e9823b21SArnaldo Carvalho de Melo 		}
725e9823b21SArnaldo Carvalho de Melo 			continue;
726aca7a94dSNamhyung Kim 		case K_ENTER:
727aca7a94dSNamhyung Kim 		case K_RIGHT:
72805e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
729aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
73005e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
731aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
73205e8b080SArnaldo Carvalho de Melo 			else if (!browser->selection->ins) {
73305e8b080SArnaldo Carvalho de Melo 				if (strcmp(browser->selection->name, "retq"))
734c4cceae3SArnaldo Carvalho de Melo 					goto show_sup_ins;
735c4cceae3SArnaldo Carvalho de Melo 				goto out;
73605e8b080SArnaldo Carvalho de Melo 			} else if (!(annotate_browser__jump(browser) ||
73705e8b080SArnaldo Carvalho de Melo 				     annotate_browser__callq(browser, evidx, timer, arg, delay_secs))) {
738c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
739c4cceae3SArnaldo Carvalho de Melo 				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
740c4cceae3SArnaldo Carvalho de Melo 			}
741aca7a94dSNamhyung Kim 			continue;
742aca7a94dSNamhyung Kim 		case K_LEFT:
743aca7a94dSNamhyung Kim 		case K_ESC:
744aca7a94dSNamhyung Kim 		case 'q':
745aca7a94dSNamhyung Kim 		case CTRL('c'):
746aca7a94dSNamhyung Kim 			goto out;
747aca7a94dSNamhyung Kim 		default:
748aca7a94dSNamhyung Kim 			continue;
749aca7a94dSNamhyung Kim 		}
750aca7a94dSNamhyung Kim 
751aca7a94dSNamhyung Kim 		if (nd != NULL)
75205e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
753aca7a94dSNamhyung Kim 	}
754aca7a94dSNamhyung Kim out:
75505e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
756aca7a94dSNamhyung Kim 	return key;
757aca7a94dSNamhyung Kim }
758aca7a94dSNamhyung Kim 
759aca7a94dSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
760aca7a94dSNamhyung Kim 			     void(*timer)(void *arg), void *arg, int delay_secs)
761aca7a94dSNamhyung Kim {
762aca7a94dSNamhyung Kim 	return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
763aca7a94dSNamhyung Kim 				    timer, arg, delay_secs);
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;
770b793a401SArnaldo Carvalho de Melo 
771b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
772b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
773b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
774b793a401SArnaldo Carvalho de Melo 
77538b31bd0SArnaldo Carvalho de Melo 		if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
77638b31bd0SArnaldo Carvalho de Melo 		    !disasm_line__has_offset(dl))
777b793a401SArnaldo Carvalho de Melo 			continue;
778b793a401SArnaldo Carvalho de Melo 
77944d1a3edSArnaldo Carvalho de Melo 		if (dl->ops.target.offset >= size) {
780b793a401SArnaldo Carvalho de Melo 			ui__error("jump to after symbol!\n"
781b793a401SArnaldo Carvalho de Melo 				  "size: %zx, jump target: %" PRIx64,
78244d1a3edSArnaldo Carvalho de Melo 				  size, dl->ops.target.offset);
783b793a401SArnaldo Carvalho de Melo 			continue;
784b793a401SArnaldo Carvalho de Melo 		}
785b793a401SArnaldo Carvalho de Melo 
78644d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
7879481ede9SArnaldo Carvalho de Melo 		/*
7889481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
7899481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
7909481ede9SArnaldo Carvalho de Melo  		 */
7919481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
7929481ede9SArnaldo Carvalho de Melo 			continue;
7939481ede9SArnaldo Carvalho de Melo 
794b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
7952402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
7962402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
7972402e4a9SArnaldo Carvalho de Melo 
7982402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
799b793a401SArnaldo Carvalho de Melo 	}
800b793a401SArnaldo Carvalho de Melo 
801b793a401SArnaldo Carvalho de Melo }
802b793a401SArnaldo Carvalho de Melo 
8032402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
8042402e4a9SArnaldo Carvalho de Melo {
8052402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
8062402e4a9SArnaldo Carvalho de Melo 		return 5;
8072402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
8082402e4a9SArnaldo Carvalho de Melo 		return 2;
8092402e4a9SArnaldo Carvalho de Melo 	return 1;
8102402e4a9SArnaldo Carvalho de Melo }
8112402e4a9SArnaldo Carvalho de Melo 
812aca7a94dSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
813aca7a94dSNamhyung Kim 			 void(*timer)(void *arg), void *arg,
814aca7a94dSNamhyung Kim 			 int delay_secs)
815aca7a94dSNamhyung Kim {
81629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
817aca7a94dSNamhyung Kim 	struct annotation *notes;
818c0a58fb2SSamuel Liao 	size_t size;
819aca7a94dSNamhyung Kim 	struct map_symbol ms = {
820aca7a94dSNamhyung Kim 		.map = map,
821aca7a94dSNamhyung Kim 		.sym = sym,
822aca7a94dSNamhyung Kim 	};
823aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
824aca7a94dSNamhyung Kim 		.b = {
825a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
826aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
827aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
82829ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
829aca7a94dSNamhyung Kim 			.priv	 = &ms,
830aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
831aca7a94dSNamhyung Kim 		},
832aca7a94dSNamhyung Kim 	};
833b793a401SArnaldo Carvalho de Melo 	int ret = -1;
834aca7a94dSNamhyung Kim 
835aca7a94dSNamhyung Kim 	if (sym == NULL)
836aca7a94dSNamhyung Kim 		return -1;
837aca7a94dSNamhyung Kim 
838c0a58fb2SSamuel Liao 	size = symbol__size(sym);
839c0a58fb2SSamuel Liao 
840aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
841aca7a94dSNamhyung Kim 		return -1;
842aca7a94dSNamhyung Kim 
843b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
844b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
845b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
846b793a401SArnaldo Carvalho de Melo 		return -1;
847b793a401SArnaldo Carvalho de Melo 	}
848b793a401SArnaldo Carvalho de Melo 
849887c0066SArnaldo Carvalho de Melo 	if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
850aca7a94dSNamhyung Kim 		ui__error("%s", ui_helpline__last_msg);
851b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
852aca7a94dSNamhyung Kim 	}
853aca7a94dSNamhyung Kim 
854aca7a94dSNamhyung Kim 	ui_helpline__push("Press <- or ESC to exit");
855aca7a94dSNamhyung Kim 
856aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
857aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
858aca7a94dSNamhyung Kim 
859aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
860887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
861aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
862aca7a94dSNamhyung Kim 
863aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
864aca7a94dSNamhyung Kim 			browser.b.width = line_len;
865887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
866887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
867b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
868887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
86997148a97SArnaldo Carvalho de Melo 			/*
87097148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
87197148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
87297148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
87397148a97SArnaldo Carvalho de Melo 			 *
87497148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
87597148a97SArnaldo Carvalho de Melo  			 */
87697148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
877b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
878b793a401SArnaldo Carvalho de Melo 		} else
879887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
880aca7a94dSNamhyung Kim 	}
881aca7a94dSNamhyung Kim 
882b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
883b793a401SArnaldo Carvalho de Melo 
8842402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
88583b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
8862402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
887aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
888aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
889aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
890e9823b21SArnaldo Carvalho de Melo 
891e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
892e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
893e9823b21SArnaldo Carvalho de Melo 
894e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
895e9823b21SArnaldo Carvalho de Melo 
896aca7a94dSNamhyung Kim 	ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
897aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
898aca7a94dSNamhyung Kim 		list_del(&pos->node);
89929ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
900aca7a94dSNamhyung Kim 	}
901b793a401SArnaldo Carvalho de Melo 
902b793a401SArnaldo Carvalho de Melo out_free_offsets:
903b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
904aca7a94dSNamhyung Kim 	return ret;
905aca7a94dSNamhyung Kim }
906c323cf04SArnaldo Carvalho de Melo 
907c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
908c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
909c323cf04SArnaldo Carvalho de Melo 
910c323cf04SArnaldo Carvalho de Melo /*
911c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
912c323cf04SArnaldo Carvalho de Melo  */
913c323cf04SArnaldo Carvalho de Melo static struct annotate__config {
914c323cf04SArnaldo Carvalho de Melo 	const char *name;
915c323cf04SArnaldo Carvalho de Melo 	bool *value;
916c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
917c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
918c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
919c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
920c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(use_offset),
921c323cf04SArnaldo Carvalho de Melo };
922c323cf04SArnaldo Carvalho de Melo 
923c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
924c323cf04SArnaldo Carvalho de Melo 
925c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
926c323cf04SArnaldo Carvalho de Melo {
927c323cf04SArnaldo Carvalho de Melo 	const struct annotate__config *cfg = cfgp;
928c323cf04SArnaldo Carvalho de Melo 
929c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
930c323cf04SArnaldo Carvalho de Melo }
931c323cf04SArnaldo Carvalho de Melo 
932*1d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
933*1d037ca1SIrina Tirdea 			    void *data __maybe_unused)
934c323cf04SArnaldo Carvalho de Melo {
935c323cf04SArnaldo Carvalho de Melo 	struct annotate__config *cfg;
936c323cf04SArnaldo Carvalho de Melo 	const char *name;
937c323cf04SArnaldo Carvalho de Melo 
938c323cf04SArnaldo Carvalho de Melo 	if (prefixcmp(var, "annotate.") != 0)
939c323cf04SArnaldo Carvalho de Melo 		return 0;
940c323cf04SArnaldo Carvalho de Melo 
941c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
942c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
943c323cf04SArnaldo Carvalho de Melo 		      sizeof(struct annotate__config), annotate_config__cmp);
944c323cf04SArnaldo Carvalho de Melo 
945c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
946c323cf04SArnaldo Carvalho de Melo 		return -1;
947c323cf04SArnaldo Carvalho de Melo 
948c323cf04SArnaldo Carvalho de Melo 	*cfg->value = perf_config_bool(name, value);
949c323cf04SArnaldo Carvalho de Melo 	return 0;
950c323cf04SArnaldo Carvalho de Melo }
951c323cf04SArnaldo Carvalho de Melo 
952c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
953c323cf04SArnaldo Carvalho de Melo {
954c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
955c323cf04SArnaldo Carvalho de Melo }
956