xref: /linux/tools/perf/ui/browsers/annotate.c (revision 83b1f2aad46c4af7df5ba6071fbba2d5cb025985)
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;
19b793a401SArnaldo Carvalho de Melo 	bool		jump_target;
20b793a401SArnaldo Carvalho de Melo };
21b793a401SArnaldo Carvalho de Melo 
22aca7a94dSNamhyung Kim struct annotate_browser {
23aca7a94dSNamhyung Kim 	struct ui_browser b;
24aca7a94dSNamhyung Kim 	struct rb_root	  entries;
25aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
2629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line	  *selection;
27b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
28aca7a94dSNamhyung Kim 	u64		    start;
29aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
30aca7a94dSNamhyung Kim 	int		    nr_entries;
31aca7a94dSNamhyung Kim 	bool		    hide_src_code;
32aca7a94dSNamhyung Kim 	bool		    use_offset;
339d1ef56dSArnaldo Carvalho de Melo 	bool		    jump_arrows;
34aca7a94dSNamhyung Kim 	bool		    searching_backwards;
35*83b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
36*83b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
37*83b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
38aca7a94dSNamhyung Kim 	char		    search_bf[128];
39aca7a94dSNamhyung Kim };
40aca7a94dSNamhyung Kim 
41887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
42aca7a94dSNamhyung Kim {
43887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
44aca7a94dSNamhyung Kim }
45aca7a94dSNamhyung Kim 
4629ed6e76SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry)
47aca7a94dSNamhyung Kim {
48aca7a94dSNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
49aca7a94dSNamhyung Kim 
50aca7a94dSNamhyung Kim 	if (ab->hide_src_code) {
5129ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
5229ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
53aca7a94dSNamhyung Kim 	}
54aca7a94dSNamhyung Kim 
55aca7a94dSNamhyung Kim 	return false;
56aca7a94dSNamhyung Kim }
57aca7a94dSNamhyung Kim 
58aca7a94dSNamhyung Kim static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
59aca7a94dSNamhyung Kim {
60aca7a94dSNamhyung Kim 	struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
6129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
62b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
63aca7a94dSNamhyung Kim 	bool current_entry = ui_browser__is_current_entry(self, row);
64aca7a94dSNamhyung Kim 	bool change_color = (!ab->hide_src_code &&
65aca7a94dSNamhyung Kim 			     (!current_entry || (self->use_navkeypressed &&
66aca7a94dSNamhyung Kim 					         !self->navkeypressed)));
67*83b1f2aaSArnaldo Carvalho de Melo 	int width = self->width, printed;
68*83b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
69aca7a94dSNamhyung Kim 
700822cc80SArnaldo Carvalho de Melo 	if (dl->offset != -1 && bdl->percent != 0.0) {
71887c0066SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(self, bdl->percent, current_entry);
720822cc80SArnaldo Carvalho de Melo 		slsmg_printf("%6.2f ", bdl->percent);
73aca7a94dSNamhyung Kim 	} else {
74aca7a94dSNamhyung Kim 		ui_browser__set_percent_color(self, 0, current_entry);
750822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", 7);
76aca7a94dSNamhyung Kim 	}
77aca7a94dSNamhyung Kim 
78cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
79aca7a94dSNamhyung Kim 
80aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
81aca7a94dSNamhyung Kim 	if (!self->navkeypressed)
82aca7a94dSNamhyung Kim 		width += 1;
83aca7a94dSNamhyung Kim 
8429ed6e76SArnaldo Carvalho de Melo 	if (dl->offset != -1 && change_color)
85aca7a94dSNamhyung Kim 		ui_browser__set_color(self, HE_COLORSET_CODE);
86aca7a94dSNamhyung Kim 
8729ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
880822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", width - 7);
89*83b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
90*83b1f2aaSArnaldo Carvalho de Melo 		printed = scnprintf(bf, sizeof(bf), "%*s  ",
91*83b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
92*83b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, printed);
93*83b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(dl->line, width - printed - 6);
94*83b1f2aaSArnaldo Carvalho de Melo 	} else {
9529ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
96*83b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
97aca7a94dSNamhyung Kim 
98aca7a94dSNamhyung Kim 		if (!ab->use_offset)
99aca7a94dSNamhyung Kim 			addr += ab->start;
100aca7a94dSNamhyung Kim 
10161e04b33SArnaldo Carvalho de Melo 		if (!ab->use_offset) {
102aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
10361e04b33SArnaldo Carvalho de Melo 		} else {
10461e04b33SArnaldo Carvalho de Melo 			if (bdl->jump_target) {
10561e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
106*83b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, addr);
10761e04b33SArnaldo Carvalho de Melo 			} else {
10861e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
109*83b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
11061e04b33SArnaldo Carvalho de Melo 			}
11161e04b33SArnaldo Carvalho de Melo 		}
112b793a401SArnaldo Carvalho de Melo 
113aca7a94dSNamhyung Kim 		if (change_color)
114aca7a94dSNamhyung Kim 			color = ui_browser__set_color(self, HE_COLORSET_ADDR);
115aca7a94dSNamhyung Kim 		slsmg_write_nstring(bf, printed);
116aca7a94dSNamhyung Kim 		if (change_color)
117aca7a94dSNamhyung Kim 			ui_browser__set_color(self, color);
11828548d78SArnaldo Carvalho de Melo 		if (dl->ins && dl->ins->ops->scnprintf) {
11951a0d455SArnaldo Carvalho de Melo 			if (ins__is_jump(dl->ins)) {
12044d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
12151a0d455SArnaldo Carvalho de Melo 
12259d038d5SArnaldo Carvalho de Melo 				ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR :
12351a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
12451a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
12588298f5aSArnaldo Carvalho de Melo 			} else if (ins__is_call(dl->ins)) {
12688298f5aSArnaldo Carvalho de Melo 				ui_browser__write_graph(self, SLSMG_RARROW_CHAR);
12788298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
12851a0d455SArnaldo Carvalho de Melo 			} else {
12951a0d455SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
13051a0d455SArnaldo Carvalho de Melo 			}
13151a0d455SArnaldo Carvalho de Melo 
132c7e6ead7SArnaldo Carvalho de Melo 			dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), &dl->ops,
133c7e6ead7SArnaldo Carvalho de Melo 						!ab->use_offset);
1344ea08b52SArnaldo Carvalho de Melo 		} else {
1354ea08b52SArnaldo Carvalho de Melo 			if (strcmp(dl->name, "retq")) {
1364ea08b52SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
1374ea08b52SArnaldo Carvalho de Melo 			} else {
13859d038d5SArnaldo Carvalho de Melo 				ui_browser__write_graph(self, SLSMG_LARROW_CHAR);
1394ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
1404ea08b52SArnaldo Carvalho de Melo 			}
14128548d78SArnaldo Carvalho de Melo 
1424ea08b52SArnaldo Carvalho de Melo 			scnprintf(bf, sizeof(bf), "%-6.6s %s", dl->name, dl->ops.raw);
1434ea08b52SArnaldo Carvalho de Melo 		}
1444ea08b52SArnaldo Carvalho de Melo 
145*83b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, width - 10 - printed);
146aca7a94dSNamhyung Kim 	}
147aca7a94dSNamhyung Kim 
148aca7a94dSNamhyung Kim 	if (current_entry)
14929ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
150aca7a94dSNamhyung Kim }
151aca7a94dSNamhyung Kim 
1529d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
153a3f895beSArnaldo Carvalho de Melo {
154a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1559d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
1569d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
157*83b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
158a3f895beSArnaldo Carvalho de Melo 
1599d1ef56dSArnaldo Carvalho de Melo 	if (!cursor->ins || !ins__is_jump(cursor->ins) ||
1609d1ef56dSArnaldo Carvalho de Melo 	    !disasm_line__has_offset(cursor))
161a3f895beSArnaldo Carvalho de Melo 		return;
162a3f895beSArnaldo Carvalho de Melo 
1639d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
1649d1ef56dSArnaldo Carvalho de Melo 	if (!target)
1659d1ef56dSArnaldo Carvalho de Melo 		return;
1669d1ef56dSArnaldo Carvalho de Melo 
1679d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
1689d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
1699d1ef56dSArnaldo Carvalho de Melo 
170a3f895beSArnaldo Carvalho de Melo 	if (ab->hide_src_code) {
1719d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
172a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
173a3f895beSArnaldo Carvalho de Melo 	} else {
1749d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
175a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
176a3f895beSArnaldo Carvalho de Melo 	}
177a3f895beSArnaldo Carvalho de Melo 
178a3f895beSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_CODE);
179*83b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
180a3f895beSArnaldo Carvalho de Melo }
181a3f895beSArnaldo Carvalho de Melo 
182a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
183a3f895beSArnaldo Carvalho de Melo {
1849d1ef56dSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
185a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
186a3f895beSArnaldo Carvalho de Melo 
1879d1ef56dSArnaldo Carvalho de Melo 	if (ab->jump_arrows)
1889d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
189a3f895beSArnaldo Carvalho de Melo 
190*83b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
191*83b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__vline(browser, 7, 0, browser->height - 1);
192a3f895beSArnaldo Carvalho de Melo 	return ret;
193a3f895beSArnaldo Carvalho de Melo }
194a3f895beSArnaldo Carvalho de Melo 
19529ed6e76SArnaldo Carvalho de Melo static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
196aca7a94dSNamhyung Kim {
197aca7a94dSNamhyung Kim 	double percent = 0.0;
198aca7a94dSNamhyung Kim 
19929ed6e76SArnaldo Carvalho de Melo 	if (dl->offset != -1) {
200aca7a94dSNamhyung Kim 		int len = sym->end - sym->start;
201aca7a94dSNamhyung Kim 		unsigned int hits = 0;
202aca7a94dSNamhyung Kim 		struct annotation *notes = symbol__annotation(sym);
203aca7a94dSNamhyung Kim 		struct source_line *src_line = notes->src->lines;
204aca7a94dSNamhyung Kim 		struct sym_hist *h = annotation__histogram(notes, evidx);
20529ed6e76SArnaldo Carvalho de Melo 		s64 offset = dl->offset;
20629ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *next;
207aca7a94dSNamhyung Kim 
20829ed6e76SArnaldo Carvalho de Melo 		next = disasm__get_next_ip_line(&notes->src->source, dl);
209aca7a94dSNamhyung Kim 		while (offset < (s64)len &&
210aca7a94dSNamhyung Kim 		       (next == NULL || offset < next->offset)) {
211aca7a94dSNamhyung Kim 			if (src_line) {
212aca7a94dSNamhyung Kim 				percent += src_line[offset].percent;
213aca7a94dSNamhyung Kim 			} else
214aca7a94dSNamhyung Kim 				hits += h->addr[offset];
215aca7a94dSNamhyung Kim 
216aca7a94dSNamhyung Kim 			++offset;
217aca7a94dSNamhyung Kim 		}
218aca7a94dSNamhyung Kim 		/*
219aca7a94dSNamhyung Kim  		 * If the percentage wasn't already calculated in
220aca7a94dSNamhyung Kim  		 * symbol__get_source_line, do it now:
221aca7a94dSNamhyung Kim  		 */
222aca7a94dSNamhyung Kim 		if (src_line == NULL && h->sum)
223aca7a94dSNamhyung Kim 			percent = 100.0 * hits / h->sum;
224aca7a94dSNamhyung Kim 	}
225aca7a94dSNamhyung Kim 
226aca7a94dSNamhyung Kim 	return percent;
227aca7a94dSNamhyung Kim }
228aca7a94dSNamhyung Kim 
229887c0066SArnaldo Carvalho de Melo static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
230aca7a94dSNamhyung Kim {
23129ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
232aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
233887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
234aca7a94dSNamhyung Kim 
235aca7a94dSNamhyung Kim 	while (*p != NULL) {
236aca7a94dSNamhyung Kim 		parent = *p;
237887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
238887c0066SArnaldo Carvalho de Melo 		if (bdl->percent < l->percent)
239aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
240aca7a94dSNamhyung Kim 		else
241aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
242aca7a94dSNamhyung Kim 	}
243887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
244887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
245aca7a94dSNamhyung Kim }
246aca7a94dSNamhyung Kim 
247aca7a94dSNamhyung Kim static void annotate_browser__set_top(struct annotate_browser *self,
24829ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
249aca7a94dSNamhyung Kim {
250aca7a94dSNamhyung Kim 	unsigned back;
251aca7a94dSNamhyung Kim 
252aca7a94dSNamhyung Kim 	ui_browser__refresh_dimensions(&self->b);
253aca7a94dSNamhyung Kim 	back = self->b.height / 2;
254aca7a94dSNamhyung Kim 	self->b.top_idx = self->b.index = idx;
255aca7a94dSNamhyung Kim 
256aca7a94dSNamhyung Kim 	while (self->b.top_idx != 0 && back != 0) {
25729ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
258aca7a94dSNamhyung Kim 
25929ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&self->b, &pos->node))
260aca7a94dSNamhyung Kim 			continue;
261aca7a94dSNamhyung Kim 
262aca7a94dSNamhyung Kim 		--self->b.top_idx;
263aca7a94dSNamhyung Kim 		--back;
264aca7a94dSNamhyung Kim 	}
265aca7a94dSNamhyung Kim 
266aca7a94dSNamhyung Kim 	self->b.top = pos;
267aca7a94dSNamhyung Kim 	self->b.navkeypressed = true;
268aca7a94dSNamhyung Kim }
269aca7a94dSNamhyung Kim 
270aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
271aca7a94dSNamhyung Kim 					 struct rb_node *nd)
272aca7a94dSNamhyung Kim {
273887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
27429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
275aca7a94dSNamhyung Kim 
276887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
277887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
278887c0066SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, bpos->idx);
279aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
280aca7a94dSNamhyung Kim }
281aca7a94dSNamhyung Kim 
282aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
283aca7a94dSNamhyung Kim 					   int evidx)
284aca7a94dSNamhyung Kim {
285aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
286aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
287aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
28829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
289aca7a94dSNamhyung Kim 
290aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
291aca7a94dSNamhyung Kim 
292aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
293aca7a94dSNamhyung Kim 
294aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
295887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
296887c0066SArnaldo Carvalho de Melo 		bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
297887c0066SArnaldo Carvalho de Melo 		if (bpos->percent < 0.01) {
298887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
299aca7a94dSNamhyung Kim 			continue;
300aca7a94dSNamhyung Kim 		}
301887c0066SArnaldo Carvalho de Melo 		disasm_rb_tree__insert(&browser->entries, bpos);
302aca7a94dSNamhyung Kim 	}
303aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
304aca7a94dSNamhyung Kim 
305aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
306aca7a94dSNamhyung Kim }
307aca7a94dSNamhyung Kim 
308aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
309aca7a94dSNamhyung Kim {
31029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
311887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
312aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
313aca7a94dSNamhyung Kim 
314aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
31529ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
316887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
317aca7a94dSNamhyung Kim 
318aca7a94dSNamhyung Kim 	if (browser->hide_src_code) {
319887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
320887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
321aca7a94dSNamhyung Kim 
322aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
323aca7a94dSNamhyung Kim 		browser->hide_src_code = false;
324aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
325887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
326887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
327aca7a94dSNamhyung Kim 	} else {
328887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
329aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
330aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
331aca7a94dSNamhyung Kim 			return false;
332aca7a94dSNamhyung Kim 		}
333aca7a94dSNamhyung Kim 
334887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
335887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
336aca7a94dSNamhyung Kim 
337aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
338aca7a94dSNamhyung Kim 		browser->hide_src_code = true;
339aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
340887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
341887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
342aca7a94dSNamhyung Kim 	}
343aca7a94dSNamhyung Kim 
344aca7a94dSNamhyung Kim 	return true;
345aca7a94dSNamhyung Kim }
346aca7a94dSNamhyung Kim 
347aca7a94dSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
348aca7a94dSNamhyung Kim 				    int evidx, void (*timer)(void *arg),
349aca7a94dSNamhyung Kim 				    void *arg, int delay_secs)
350aca7a94dSNamhyung Kim {
351aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
352657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
353aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
354aca7a94dSNamhyung Kim 	struct annotation *notes;
355aca7a94dSNamhyung Kim 	struct symbol *target;
356aca7a94dSNamhyung Kim 	u64 ip;
357aca7a94dSNamhyung Kim 
358d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_call(dl->ins))
359aca7a94dSNamhyung Kim 		return false;
360aca7a94dSNamhyung Kim 
36144d1a3edSArnaldo Carvalho de Melo 	ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
362aca7a94dSNamhyung Kim 	target = map__find_symbol(ms->map, ip, NULL);
363aca7a94dSNamhyung Kim 	if (target == NULL) {
364aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
365aca7a94dSNamhyung Kim 		return true;
366aca7a94dSNamhyung Kim 	}
367aca7a94dSNamhyung Kim 
368aca7a94dSNamhyung Kim 	notes = symbol__annotation(target);
369aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
370aca7a94dSNamhyung Kim 
371aca7a94dSNamhyung Kim 	if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
372aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
373aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
374aca7a94dSNamhyung Kim 			    target->name);
375aca7a94dSNamhyung Kim 		return true;
376aca7a94dSNamhyung Kim 	}
377aca7a94dSNamhyung Kim 
378aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
379aca7a94dSNamhyung Kim 	symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
380aca7a94dSNamhyung Kim 	ui_browser__show_title(&browser->b, sym->name);
381aca7a94dSNamhyung Kim 	return true;
382aca7a94dSNamhyung Kim }
383aca7a94dSNamhyung Kim 
38429ed6e76SArnaldo Carvalho de Melo static
38529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
386aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
387aca7a94dSNamhyung Kim {
388aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
389aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
390aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
39129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
392aca7a94dSNamhyung Kim 
393aca7a94dSNamhyung Kim 	*idx = 0;
394aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
395aca7a94dSNamhyung Kim 		if (pos->offset == offset)
396aca7a94dSNamhyung Kim 			return pos;
39729ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
398aca7a94dSNamhyung Kim 			++*idx;
399aca7a94dSNamhyung Kim 	}
400aca7a94dSNamhyung Kim 
401aca7a94dSNamhyung Kim 	return NULL;
402aca7a94dSNamhyung Kim }
403aca7a94dSNamhyung Kim 
404aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
405aca7a94dSNamhyung Kim {
406657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
4074f9d0325SArnaldo Carvalho de Melo 	s64 idx;
408aca7a94dSNamhyung Kim 
409d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_jump(dl->ins))
410aca7a94dSNamhyung Kim 		return false;
411aca7a94dSNamhyung Kim 
41244d1a3edSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
41329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
414aca7a94dSNamhyung Kim 		ui_helpline__puts("Invallid jump offset");
415aca7a94dSNamhyung Kim 		return true;
416aca7a94dSNamhyung Kim 	}
417aca7a94dSNamhyung Kim 
41829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
419aca7a94dSNamhyung Kim 
420aca7a94dSNamhyung Kim 	return true;
421aca7a94dSNamhyung Kim }
422aca7a94dSNamhyung Kim 
42329ed6e76SArnaldo Carvalho de Melo static
42429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
425aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
426aca7a94dSNamhyung Kim {
427aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
428aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
429aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
43029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
431aca7a94dSNamhyung Kim 
432aca7a94dSNamhyung Kim 	*idx = browser->b.index;
433aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
43429ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
435aca7a94dSNamhyung Kim 			continue;
436aca7a94dSNamhyung Kim 
437aca7a94dSNamhyung Kim 		++*idx;
438aca7a94dSNamhyung Kim 
439aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
440aca7a94dSNamhyung Kim 			return pos;
441aca7a94dSNamhyung Kim 	}
442aca7a94dSNamhyung Kim 
443aca7a94dSNamhyung Kim 	return NULL;
444aca7a94dSNamhyung Kim }
445aca7a94dSNamhyung Kim 
446aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
447aca7a94dSNamhyung Kim {
44829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
449aca7a94dSNamhyung Kim 	s64 idx;
450aca7a94dSNamhyung Kim 
45129ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
45229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
453aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
454aca7a94dSNamhyung Kim 		return false;
455aca7a94dSNamhyung Kim 	}
456aca7a94dSNamhyung Kim 
45729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
458aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
459aca7a94dSNamhyung Kim 	return true;
460aca7a94dSNamhyung Kim }
461aca7a94dSNamhyung Kim 
46229ed6e76SArnaldo Carvalho de Melo static
46329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
464aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
465aca7a94dSNamhyung Kim {
466aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
467aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
468aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
46929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
470aca7a94dSNamhyung Kim 
471aca7a94dSNamhyung Kim 	*idx = browser->b.index;
472aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
47329ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
474aca7a94dSNamhyung Kim 			continue;
475aca7a94dSNamhyung Kim 
476aca7a94dSNamhyung Kim 		--*idx;
477aca7a94dSNamhyung Kim 
478aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
479aca7a94dSNamhyung Kim 			return pos;
480aca7a94dSNamhyung Kim 	}
481aca7a94dSNamhyung Kim 
482aca7a94dSNamhyung Kim 	return NULL;
483aca7a94dSNamhyung Kim }
484aca7a94dSNamhyung Kim 
485aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
486aca7a94dSNamhyung Kim {
48729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
488aca7a94dSNamhyung Kim 	s64 idx;
489aca7a94dSNamhyung Kim 
49029ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
49129ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
492aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
493aca7a94dSNamhyung Kim 		return false;
494aca7a94dSNamhyung Kim 	}
495aca7a94dSNamhyung Kim 
49629ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
497aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
498aca7a94dSNamhyung Kim 	return true;
499aca7a94dSNamhyung Kim }
500aca7a94dSNamhyung Kim 
501aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
502aca7a94dSNamhyung Kim 					    int delay_secs)
503aca7a94dSNamhyung Kim {
504aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
505aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
506aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
507aca7a94dSNamhyung Kim 	    !*browser->search_bf)
508aca7a94dSNamhyung Kim 		return false;
509aca7a94dSNamhyung Kim 
510aca7a94dSNamhyung Kim 	return true;
511aca7a94dSNamhyung Kim }
512aca7a94dSNamhyung Kim 
513aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
514aca7a94dSNamhyung Kim {
515aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
516aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
517aca7a94dSNamhyung Kim 
518aca7a94dSNamhyung Kim 	return false;
519aca7a94dSNamhyung Kim }
520aca7a94dSNamhyung Kim 
521aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
522aca7a94dSNamhyung Kim 					      int delay_secs)
523aca7a94dSNamhyung Kim {
524aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
525aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
526aca7a94dSNamhyung Kim 
527aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
528aca7a94dSNamhyung Kim }
529aca7a94dSNamhyung Kim 
530aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
531aca7a94dSNamhyung Kim 					   int delay_secs)
532aca7a94dSNamhyung Kim {
533aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
534aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
535aca7a94dSNamhyung Kim 
536aca7a94dSNamhyung Kim 	return false;
537aca7a94dSNamhyung Kim }
538aca7a94dSNamhyung Kim 
539aca7a94dSNamhyung Kim static
540aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
541aca7a94dSNamhyung Kim 					       int delay_secs)
542aca7a94dSNamhyung Kim {
543aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
544aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
545aca7a94dSNamhyung Kim 
546aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
547aca7a94dSNamhyung Kim }
548aca7a94dSNamhyung Kim 
549aca7a94dSNamhyung Kim static int annotate_browser__run(struct annotate_browser *self, int evidx,
550aca7a94dSNamhyung Kim 				 void(*timer)(void *arg),
551aca7a94dSNamhyung Kim 				 void *arg, int delay_secs)
552aca7a94dSNamhyung Kim {
553aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
554aca7a94dSNamhyung Kim 	struct map_symbol *ms = self->b.priv;
555aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
556aca7a94dSNamhyung Kim 	const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
557aca7a94dSNamhyung Kim 			   "H: Go to hottest line, ->/ENTER: Line action, "
558aca7a94dSNamhyung Kim 			   "O: Toggle offset view, "
559aca7a94dSNamhyung Kim 			   "S: Toggle source code view";
560aca7a94dSNamhyung Kim 	int key;
561aca7a94dSNamhyung Kim 
562aca7a94dSNamhyung Kim 	if (ui_browser__show(&self->b, sym->name, help) < 0)
563aca7a94dSNamhyung Kim 		return -1;
564aca7a94dSNamhyung Kim 
565aca7a94dSNamhyung Kim 	annotate_browser__calc_percent(self, evidx);
566aca7a94dSNamhyung Kim 
567aca7a94dSNamhyung Kim 	if (self->curr_hot) {
568aca7a94dSNamhyung Kim 		annotate_browser__set_rb_top(self, self->curr_hot);
569aca7a94dSNamhyung Kim 		self->b.navkeypressed = false;
570aca7a94dSNamhyung Kim 	}
571aca7a94dSNamhyung Kim 
572aca7a94dSNamhyung Kim 	nd = self->curr_hot;
573aca7a94dSNamhyung Kim 
574aca7a94dSNamhyung Kim 	while (1) {
575aca7a94dSNamhyung Kim 		key = ui_browser__run(&self->b, delay_secs);
576aca7a94dSNamhyung Kim 
577aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
578aca7a94dSNamhyung Kim 			annotate_browser__calc_percent(self, evidx);
579aca7a94dSNamhyung Kim 			/*
580aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
581aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
582aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
583aca7a94dSNamhyung Kim 			 */
584aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
585aca7a94dSNamhyung Kim 				nd = NULL;
586aca7a94dSNamhyung Kim 		}
587aca7a94dSNamhyung Kim 
588aca7a94dSNamhyung Kim 		switch (key) {
589aca7a94dSNamhyung Kim 		case K_TIMER:
590aca7a94dSNamhyung Kim 			if (timer != NULL)
591aca7a94dSNamhyung Kim 				timer(arg);
592aca7a94dSNamhyung Kim 
593aca7a94dSNamhyung Kim 			if (delay_secs != 0)
594aca7a94dSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evidx);
595aca7a94dSNamhyung Kim 			continue;
596aca7a94dSNamhyung Kim 		case K_TAB:
597aca7a94dSNamhyung Kim 			if (nd != NULL) {
598aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
599aca7a94dSNamhyung Kim 				if (nd == NULL)
600aca7a94dSNamhyung Kim 					nd = rb_last(&self->entries);
601aca7a94dSNamhyung Kim 			} else
602aca7a94dSNamhyung Kim 				nd = self->curr_hot;
603aca7a94dSNamhyung Kim 			break;
604aca7a94dSNamhyung Kim 		case K_UNTAB:
605aca7a94dSNamhyung Kim 			if (nd != NULL)
606aca7a94dSNamhyung Kim 				nd = rb_next(nd);
607aca7a94dSNamhyung Kim 				if (nd == NULL)
608aca7a94dSNamhyung Kim 					nd = rb_first(&self->entries);
609aca7a94dSNamhyung Kim 			else
610aca7a94dSNamhyung Kim 				nd = self->curr_hot;
611aca7a94dSNamhyung Kim 			break;
612aca7a94dSNamhyung Kim 		case 'H':
613aca7a94dSNamhyung Kim 		case 'h':
614aca7a94dSNamhyung Kim 			nd = self->curr_hot;
615aca7a94dSNamhyung Kim 			break;
616aca7a94dSNamhyung Kim 		case 'S':
617aca7a94dSNamhyung Kim 		case 's':
618aca7a94dSNamhyung Kim 			if (annotate_browser__toggle_source(self))
619aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
620aca7a94dSNamhyung Kim 			continue;
621aca7a94dSNamhyung Kim 		case 'O':
622aca7a94dSNamhyung Kim 		case 'o':
623aca7a94dSNamhyung Kim 			self->use_offset = !self->use_offset;
624*83b1f2aaSArnaldo Carvalho de Melo 			if (self->use_offset)
625*83b1f2aaSArnaldo Carvalho de Melo 				self->addr_width = self->min_addr_width;
626*83b1f2aaSArnaldo Carvalho de Melo 			else
627*83b1f2aaSArnaldo Carvalho de Melo 				self->addr_width = self->max_addr_width;
628aca7a94dSNamhyung Kim 			continue;
6299d1ef56dSArnaldo Carvalho de Melo 		case 'j':
6309d1ef56dSArnaldo Carvalho de Melo 			self->jump_arrows = !self->jump_arrows;
6319d1ef56dSArnaldo Carvalho de Melo 			continue;
632aca7a94dSNamhyung Kim 		case '/':
633aca7a94dSNamhyung Kim 			if (annotate_browser__search(self, delay_secs)) {
634aca7a94dSNamhyung Kim show_help:
635aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
636aca7a94dSNamhyung Kim 			}
637aca7a94dSNamhyung Kim 			continue;
638aca7a94dSNamhyung Kim 		case 'n':
639aca7a94dSNamhyung Kim 			if (self->searching_backwards ?
640aca7a94dSNamhyung Kim 			    annotate_browser__continue_search_reverse(self, delay_secs) :
641aca7a94dSNamhyung Kim 			    annotate_browser__continue_search(self, delay_secs))
642aca7a94dSNamhyung Kim 				goto show_help;
643aca7a94dSNamhyung Kim 			continue;
644aca7a94dSNamhyung Kim 		case '?':
645aca7a94dSNamhyung Kim 			if (annotate_browser__search_reverse(self, delay_secs))
646aca7a94dSNamhyung Kim 				goto show_help;
647aca7a94dSNamhyung Kim 			continue;
648aca7a94dSNamhyung Kim 		case K_ENTER:
649aca7a94dSNamhyung Kim 		case K_RIGHT:
650aca7a94dSNamhyung Kim 			if (self->selection == NULL)
651aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
652aca7a94dSNamhyung Kim 			else if (self->selection->offset == -1)
653aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
654c4cceae3SArnaldo Carvalho de Melo 			else if (!self->selection->ins) {
655c4cceae3SArnaldo Carvalho de Melo 				if (strcmp(self->selection->name, "retq"))
656c4cceae3SArnaldo Carvalho de Melo 					goto show_sup_ins;
657c4cceae3SArnaldo Carvalho de Melo 				goto out;
658c4cceae3SArnaldo Carvalho de Melo 			} else if (!(annotate_browser__jump(self) ||
659c4cceae3SArnaldo Carvalho de Melo 				     annotate_browser__callq(self, evidx, timer, arg, delay_secs))) {
660c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
661c4cceae3SArnaldo Carvalho de Melo 				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
662c4cceae3SArnaldo Carvalho de Melo 			}
663aca7a94dSNamhyung Kim 			continue;
664aca7a94dSNamhyung Kim 		case K_LEFT:
665aca7a94dSNamhyung Kim 		case K_ESC:
666aca7a94dSNamhyung Kim 		case 'q':
667aca7a94dSNamhyung Kim 		case CTRL('c'):
668aca7a94dSNamhyung Kim 			goto out;
669aca7a94dSNamhyung Kim 		default:
670aca7a94dSNamhyung Kim 			continue;
671aca7a94dSNamhyung Kim 		}
672aca7a94dSNamhyung Kim 
673aca7a94dSNamhyung Kim 		if (nd != NULL)
674aca7a94dSNamhyung Kim 			annotate_browser__set_rb_top(self, nd);
675aca7a94dSNamhyung Kim 	}
676aca7a94dSNamhyung Kim out:
677aca7a94dSNamhyung Kim 	ui_browser__hide(&self->b);
678aca7a94dSNamhyung Kim 	return key;
679aca7a94dSNamhyung Kim }
680aca7a94dSNamhyung Kim 
681aca7a94dSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
682aca7a94dSNamhyung Kim 			     void(*timer)(void *arg), void *arg, int delay_secs)
683aca7a94dSNamhyung Kim {
684aca7a94dSNamhyung Kim 	return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
685aca7a94dSNamhyung Kim 				    timer, arg, delay_secs);
686aca7a94dSNamhyung Kim }
687aca7a94dSNamhyung Kim 
688b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
689b793a401SArnaldo Carvalho de Melo 						size_t size)
690b793a401SArnaldo Carvalho de Melo {
691b793a401SArnaldo Carvalho de Melo 	u64 offset;
692b793a401SArnaldo Carvalho de Melo 
693b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
694b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
695b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
696b793a401SArnaldo Carvalho de Melo 
69738b31bd0SArnaldo Carvalho de Melo 		if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
69838b31bd0SArnaldo Carvalho de Melo 		    !disasm_line__has_offset(dl))
699b793a401SArnaldo Carvalho de Melo 			continue;
700b793a401SArnaldo Carvalho de Melo 
70144d1a3edSArnaldo Carvalho de Melo 		if (dl->ops.target.offset >= size) {
702b793a401SArnaldo Carvalho de Melo 			ui__error("jump to after symbol!\n"
703b793a401SArnaldo Carvalho de Melo 				  "size: %zx, jump target: %" PRIx64,
70444d1a3edSArnaldo Carvalho de Melo 				  size, dl->ops.target.offset);
705b793a401SArnaldo Carvalho de Melo 			continue;
706b793a401SArnaldo Carvalho de Melo 		}
707b793a401SArnaldo Carvalho de Melo 
70844d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
7099481ede9SArnaldo Carvalho de Melo 		/*
7109481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
7119481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
7129481ede9SArnaldo Carvalho de Melo  		 */
7139481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
7149481ede9SArnaldo Carvalho de Melo 			continue;
7159481ede9SArnaldo Carvalho de Melo 
716b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
717b793a401SArnaldo Carvalho de Melo 		bdlt->jump_target = true;
718b793a401SArnaldo Carvalho de Melo 	}
719b793a401SArnaldo Carvalho de Melo 
720b793a401SArnaldo Carvalho de Melo }
721b793a401SArnaldo Carvalho de Melo 
722aca7a94dSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
723aca7a94dSNamhyung Kim 			 void(*timer)(void *arg), void *arg,
724aca7a94dSNamhyung Kim 			 int delay_secs)
725aca7a94dSNamhyung Kim {
72629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
727aca7a94dSNamhyung Kim 	struct annotation *notes;
728b793a401SArnaldo Carvalho de Melo 	const size_t size = symbol__size(sym);
729aca7a94dSNamhyung Kim 	struct map_symbol ms = {
730aca7a94dSNamhyung Kim 		.map = map,
731aca7a94dSNamhyung Kim 		.sym = sym,
732aca7a94dSNamhyung Kim 	};
733aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
734aca7a94dSNamhyung Kim 		.b = {
735a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
736aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
737aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
73829ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
739aca7a94dSNamhyung Kim 			.priv	 = &ms,
740aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
741aca7a94dSNamhyung Kim 		},
7428bf39cb8SArnaldo Carvalho de Melo 		.use_offset = true,
7439d1ef56dSArnaldo Carvalho de Melo 		.jump_arrows = true,
744aca7a94dSNamhyung Kim 	};
745b793a401SArnaldo Carvalho de Melo 	int ret = -1;
746aca7a94dSNamhyung Kim 
747aca7a94dSNamhyung Kim 	if (sym == NULL)
748aca7a94dSNamhyung Kim 		return -1;
749aca7a94dSNamhyung Kim 
750aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
751aca7a94dSNamhyung Kim 		return -1;
752aca7a94dSNamhyung Kim 
753b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
754b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
755b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
756b793a401SArnaldo Carvalho de Melo 		return -1;
757b793a401SArnaldo Carvalho de Melo 	}
758b793a401SArnaldo Carvalho de Melo 
759887c0066SArnaldo Carvalho de Melo 	if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
760aca7a94dSNamhyung Kim 		ui__error("%s", ui_helpline__last_msg);
761b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
762aca7a94dSNamhyung Kim 	}
763aca7a94dSNamhyung Kim 
764aca7a94dSNamhyung Kim 	ui_helpline__push("Press <- or ESC to exit");
765aca7a94dSNamhyung Kim 
766aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
767aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
768aca7a94dSNamhyung Kim 
769aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
770887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
771aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
772aca7a94dSNamhyung Kim 
773aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
774aca7a94dSNamhyung Kim 			browser.b.width = line_len;
775887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
776887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
777b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
778887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
77997148a97SArnaldo Carvalho de Melo 			/*
78097148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
78197148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
78297148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
78397148a97SArnaldo Carvalho de Melo 			 *
78497148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
78597148a97SArnaldo Carvalho de Melo  			 */
78697148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
787b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
788b793a401SArnaldo Carvalho de Melo 		} else
789887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
790aca7a94dSNamhyung Kim 	}
791aca7a94dSNamhyung Kim 
792b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
793b793a401SArnaldo Carvalho de Melo 
794*83b1f2aaSArnaldo Carvalho de Melo 	browser.addr_width = browser.min_addr_width = hex_width(size);
795*83b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
796aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
797aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
798aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
799aca7a94dSNamhyung Kim 	ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
800aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
801aca7a94dSNamhyung Kim 		list_del(&pos->node);
80229ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
803aca7a94dSNamhyung Kim 	}
804b793a401SArnaldo Carvalho de Melo 
805b793a401SArnaldo Carvalho de Melo out_free_offsets:
806b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
807aca7a94dSNamhyung Kim 	return ret;
808aca7a94dSNamhyung Kim }
809