xref: /linux/tools/perf/ui/browsers/annotate.c (revision e9823b21bab7ff0c39e14a7a970a40fad74ce778)
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 
22*e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
23*e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
24*e9823b21SArnaldo Carvalho de Melo 	     use_offset,
25*e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
26*e9823b21SArnaldo Carvalho de Melo 	     show_nr_jumps;
27*e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
28*e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
29*e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
30*e9823b21SArnaldo Carvalho de Melo };
31*e9823b21SArnaldo 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*e9823b21SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser __used, void *entry)
58aca7a94dSNamhyung Kim {
59*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
6029ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
6129ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
62aca7a94dSNamhyung Kim 	}
63aca7a94dSNamhyung Kim 
64aca7a94dSNamhyung Kim 	return false;
65aca7a94dSNamhyung Kim }
66aca7a94dSNamhyung Kim 
672402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
682402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
692402e4a9SArnaldo Carvalho de Melo {
702402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
712402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
722402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
732402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
742402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
752402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
762402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
772402e4a9SArnaldo Carvalho de Melo }
782402e4a9SArnaldo Carvalho de Melo 
792402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
802402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
812402e4a9SArnaldo Carvalho de Melo {
822402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
832402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
842402e4a9SArnaldo Carvalho de Melo }
852402e4a9SArnaldo Carvalho de Melo 
86aca7a94dSNamhyung Kim static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
87aca7a94dSNamhyung Kim {
88aca7a94dSNamhyung Kim 	struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
8929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
90b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
91aca7a94dSNamhyung Kim 	bool current_entry = ui_browser__is_current_entry(self, row);
92*e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
93aca7a94dSNamhyung Kim 			     (!current_entry || (self->use_navkeypressed &&
94aca7a94dSNamhyung Kim 					         !self->navkeypressed)));
9583b1f2aaSArnaldo Carvalho de Melo 	int width = self->width, printed;
9683b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
97aca7a94dSNamhyung Kim 
980822cc80SArnaldo Carvalho de Melo 	if (dl->offset != -1 && bdl->percent != 0.0) {
99887c0066SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(self, bdl->percent, current_entry);
1000822cc80SArnaldo Carvalho de Melo 		slsmg_printf("%6.2f ", bdl->percent);
101aca7a94dSNamhyung Kim 	} else {
102aca7a94dSNamhyung Kim 		ui_browser__set_percent_color(self, 0, current_entry);
1030822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", 7);
104aca7a94dSNamhyung Kim 	}
105aca7a94dSNamhyung Kim 
106cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
107aca7a94dSNamhyung Kim 
108aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
109aca7a94dSNamhyung Kim 	if (!self->navkeypressed)
110aca7a94dSNamhyung Kim 		width += 1;
111aca7a94dSNamhyung Kim 
11229ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
1130822cc80SArnaldo Carvalho de Melo 		slsmg_write_nstring(" ", width - 7);
11483b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
11583b1f2aaSArnaldo Carvalho de Melo 		printed = scnprintf(bf, sizeof(bf), "%*s  ",
11683b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
11783b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, printed);
11883b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(dl->line, width - printed - 6);
11983b1f2aaSArnaldo Carvalho de Melo 	} else {
12029ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
12183b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
122aca7a94dSNamhyung Kim 
123*e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
124aca7a94dSNamhyung Kim 			addr += ab->start;
125aca7a94dSNamhyung Kim 
126*e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
127aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
12861e04b33SArnaldo Carvalho de Melo 		} else {
1297d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
130*e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
1312402e4a9SArnaldo Carvalho de Melo 					int prev;
1322402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
1332402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
1342402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
1352402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
1362402e4a9SArnaldo Carvalho de Melo 											 current_entry);
1372402e4a9SArnaldo Carvalho de Melo 					slsmg_write_nstring(bf, printed);
1382402e4a9SArnaldo Carvalho de Melo 					ui_browser__set_color(self, prev);
1392402e4a9SArnaldo Carvalho de Melo 				}
1402402e4a9SArnaldo Carvalho de Melo 
14161e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
1422402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
14361e04b33SArnaldo Carvalho de Melo 			} else {
14461e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
14583b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
14661e04b33SArnaldo Carvalho de Melo 			}
14761e04b33SArnaldo Carvalho de Melo 		}
148b793a401SArnaldo Carvalho de Melo 
149aca7a94dSNamhyung Kim 		if (change_color)
150aca7a94dSNamhyung Kim 			color = ui_browser__set_color(self, HE_COLORSET_ADDR);
151aca7a94dSNamhyung Kim 		slsmg_write_nstring(bf, printed);
152aca7a94dSNamhyung Kim 		if (change_color)
153aca7a94dSNamhyung Kim 			ui_browser__set_color(self, color);
15428548d78SArnaldo Carvalho de Melo 		if (dl->ins && dl->ins->ops->scnprintf) {
15551a0d455SArnaldo Carvalho de Melo 			if (ins__is_jump(dl->ins)) {
15644d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
15751a0d455SArnaldo Carvalho de Melo 
15859d038d5SArnaldo Carvalho de Melo 				ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR :
15951a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
16051a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
16188298f5aSArnaldo Carvalho de Melo 			} else if (ins__is_call(dl->ins)) {
16288298f5aSArnaldo Carvalho de Melo 				ui_browser__write_graph(self, SLSMG_RARROW_CHAR);
16388298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
16451a0d455SArnaldo Carvalho de Melo 			} else {
16551a0d455SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
16651a0d455SArnaldo Carvalho de Melo 			}
1674ea08b52SArnaldo Carvalho de Melo 		} else {
1684ea08b52SArnaldo Carvalho de Melo 			if (strcmp(dl->name, "retq")) {
1694ea08b52SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
1704ea08b52SArnaldo Carvalho de Melo 			} else {
17159d038d5SArnaldo Carvalho de Melo 				ui_browser__write_graph(self, SLSMG_LARROW_CHAR);
1724ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
1734ea08b52SArnaldo Carvalho de Melo 			}
1744ea08b52SArnaldo Carvalho de Melo 		}
1754ea08b52SArnaldo Carvalho de Melo 
176*e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
17783b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, width - 10 - printed);
178aca7a94dSNamhyung Kim 	}
179aca7a94dSNamhyung Kim 
180aca7a94dSNamhyung Kim 	if (current_entry)
18129ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
182aca7a94dSNamhyung Kim }
183aca7a94dSNamhyung Kim 
1849d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
185a3f895beSArnaldo Carvalho de Melo {
186a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
1879d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
1889d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
18983b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
190a3f895beSArnaldo Carvalho de Melo 
191*e9823b21SArnaldo Carvalho de Melo 	if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
1929d1ef56dSArnaldo Carvalho de Melo 	    !disasm_line__has_offset(cursor))
193a3f895beSArnaldo Carvalho de Melo 		return;
194a3f895beSArnaldo Carvalho de Melo 
1959d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
1969d1ef56dSArnaldo Carvalho de Melo 	if (!target)
1979d1ef56dSArnaldo Carvalho de Melo 		return;
1989d1ef56dSArnaldo Carvalho de Melo 
1999d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2009d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2019d1ef56dSArnaldo Carvalho de Melo 
202*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2039d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
204a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
205a3f895beSArnaldo Carvalho de Melo 	} else {
2069d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
207a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
208a3f895beSArnaldo Carvalho de Melo 	}
209a3f895beSArnaldo Carvalho de Melo 
210a3f895beSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_CODE);
21183b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
212a3f895beSArnaldo Carvalho de Melo }
213a3f895beSArnaldo Carvalho de Melo 
214a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
215a3f895beSArnaldo Carvalho de Melo {
216a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
217a3f895beSArnaldo Carvalho de Melo 
218*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
2199d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
220a3f895beSArnaldo Carvalho de Melo 
22183b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
22283b1f2aaSArnaldo Carvalho de Melo 	__ui_browser__vline(browser, 7, 0, browser->height - 1);
223a3f895beSArnaldo Carvalho de Melo 	return ret;
224a3f895beSArnaldo Carvalho de Melo }
225a3f895beSArnaldo Carvalho de Melo 
22629ed6e76SArnaldo Carvalho de Melo static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
227aca7a94dSNamhyung Kim {
228aca7a94dSNamhyung Kim 	double percent = 0.0;
229aca7a94dSNamhyung Kim 
23029ed6e76SArnaldo Carvalho de Melo 	if (dl->offset != -1) {
231aca7a94dSNamhyung Kim 		int len = sym->end - sym->start;
232aca7a94dSNamhyung Kim 		unsigned int hits = 0;
233aca7a94dSNamhyung Kim 		struct annotation *notes = symbol__annotation(sym);
234aca7a94dSNamhyung Kim 		struct source_line *src_line = notes->src->lines;
235aca7a94dSNamhyung Kim 		struct sym_hist *h = annotation__histogram(notes, evidx);
23629ed6e76SArnaldo Carvalho de Melo 		s64 offset = dl->offset;
23729ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *next;
238aca7a94dSNamhyung Kim 
23929ed6e76SArnaldo Carvalho de Melo 		next = disasm__get_next_ip_line(&notes->src->source, dl);
240aca7a94dSNamhyung Kim 		while (offset < (s64)len &&
241aca7a94dSNamhyung Kim 		       (next == NULL || offset < next->offset)) {
242aca7a94dSNamhyung Kim 			if (src_line) {
243aca7a94dSNamhyung Kim 				percent += src_line[offset].percent;
244aca7a94dSNamhyung Kim 			} else
245aca7a94dSNamhyung Kim 				hits += h->addr[offset];
246aca7a94dSNamhyung Kim 
247aca7a94dSNamhyung Kim 			++offset;
248aca7a94dSNamhyung Kim 		}
249aca7a94dSNamhyung Kim 		/*
250aca7a94dSNamhyung Kim  		 * If the percentage wasn't already calculated in
251aca7a94dSNamhyung Kim  		 * symbol__get_source_line, do it now:
252aca7a94dSNamhyung Kim  		 */
253aca7a94dSNamhyung Kim 		if (src_line == NULL && h->sum)
254aca7a94dSNamhyung Kim 			percent = 100.0 * hits / h->sum;
255aca7a94dSNamhyung Kim 	}
256aca7a94dSNamhyung Kim 
257aca7a94dSNamhyung Kim 	return percent;
258aca7a94dSNamhyung Kim }
259aca7a94dSNamhyung Kim 
260887c0066SArnaldo Carvalho de Melo static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
261aca7a94dSNamhyung Kim {
26229ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
263aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
264887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
265aca7a94dSNamhyung Kim 
266aca7a94dSNamhyung Kim 	while (*p != NULL) {
267aca7a94dSNamhyung Kim 		parent = *p;
268887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
269887c0066SArnaldo Carvalho de Melo 		if (bdl->percent < l->percent)
270aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
271aca7a94dSNamhyung Kim 		else
272aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
273aca7a94dSNamhyung Kim 	}
274887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
275887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
276aca7a94dSNamhyung Kim }
277aca7a94dSNamhyung Kim 
278aca7a94dSNamhyung Kim static void annotate_browser__set_top(struct annotate_browser *self,
27929ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
280aca7a94dSNamhyung Kim {
281aca7a94dSNamhyung Kim 	unsigned back;
282aca7a94dSNamhyung Kim 
283aca7a94dSNamhyung Kim 	ui_browser__refresh_dimensions(&self->b);
284aca7a94dSNamhyung Kim 	back = self->b.height / 2;
285aca7a94dSNamhyung Kim 	self->b.top_idx = self->b.index = idx;
286aca7a94dSNamhyung Kim 
287aca7a94dSNamhyung Kim 	while (self->b.top_idx != 0 && back != 0) {
28829ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
289aca7a94dSNamhyung Kim 
29029ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&self->b, &pos->node))
291aca7a94dSNamhyung Kim 			continue;
292aca7a94dSNamhyung Kim 
293aca7a94dSNamhyung Kim 		--self->b.top_idx;
294aca7a94dSNamhyung Kim 		--back;
295aca7a94dSNamhyung Kim 	}
296aca7a94dSNamhyung Kim 
297aca7a94dSNamhyung Kim 	self->b.top = pos;
298aca7a94dSNamhyung Kim 	self->b.navkeypressed = true;
299aca7a94dSNamhyung Kim }
300aca7a94dSNamhyung Kim 
301aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
302aca7a94dSNamhyung Kim 					 struct rb_node *nd)
303aca7a94dSNamhyung Kim {
304887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
30529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
306a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
307aca7a94dSNamhyung Kim 
308887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
309887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
310a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
311*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
312a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
313a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
314aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
315aca7a94dSNamhyung Kim }
316aca7a94dSNamhyung Kim 
317aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
318aca7a94dSNamhyung Kim 					   int evidx)
319aca7a94dSNamhyung Kim {
320aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
321aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
322aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
32329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
324aca7a94dSNamhyung Kim 
325aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
326aca7a94dSNamhyung Kim 
327aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
328aca7a94dSNamhyung Kim 
329aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
330887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
331887c0066SArnaldo Carvalho de Melo 		bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
332887c0066SArnaldo Carvalho de Melo 		if (bpos->percent < 0.01) {
333887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
334aca7a94dSNamhyung Kim 			continue;
335aca7a94dSNamhyung Kim 		}
336887c0066SArnaldo Carvalho de Melo 		disasm_rb_tree__insert(&browser->entries, bpos);
337aca7a94dSNamhyung Kim 	}
338aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
339aca7a94dSNamhyung Kim 
340aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
341aca7a94dSNamhyung Kim }
342aca7a94dSNamhyung Kim 
343aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
344aca7a94dSNamhyung Kim {
34529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
346887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
347aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
348aca7a94dSNamhyung Kim 
349aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
35029ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
351887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
352aca7a94dSNamhyung Kim 
353*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
354887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
355887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
356aca7a94dSNamhyung Kim 
357aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
358*e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
359aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
360887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
361887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
362aca7a94dSNamhyung Kim 	} else {
363887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
364aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
365aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
366aca7a94dSNamhyung Kim 			return false;
367aca7a94dSNamhyung Kim 		}
368aca7a94dSNamhyung Kim 
369887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
370887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
371aca7a94dSNamhyung Kim 
372aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
373*e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
374aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
375887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
376887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
377aca7a94dSNamhyung Kim 	}
378aca7a94dSNamhyung Kim 
379aca7a94dSNamhyung Kim 	return true;
380aca7a94dSNamhyung Kim }
381aca7a94dSNamhyung Kim 
382*e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
383*e9823b21SArnaldo Carvalho de Melo {
384*e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
385*e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
386*e9823b21SArnaldo Carvalho de Melo }
387*e9823b21SArnaldo Carvalho de Melo 
388aca7a94dSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
389aca7a94dSNamhyung Kim 				    int evidx, void (*timer)(void *arg),
390aca7a94dSNamhyung Kim 				    void *arg, int delay_secs)
391aca7a94dSNamhyung Kim {
392aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
393657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
394aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
395aca7a94dSNamhyung Kim 	struct annotation *notes;
396aca7a94dSNamhyung Kim 	struct symbol *target;
397aca7a94dSNamhyung Kim 	u64 ip;
398aca7a94dSNamhyung Kim 
399d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_call(dl->ins))
400aca7a94dSNamhyung Kim 		return false;
401aca7a94dSNamhyung Kim 
40244d1a3edSArnaldo Carvalho de Melo 	ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
403aca7a94dSNamhyung Kim 	target = map__find_symbol(ms->map, ip, NULL);
404aca7a94dSNamhyung Kim 	if (target == NULL) {
405aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
406aca7a94dSNamhyung Kim 		return true;
407aca7a94dSNamhyung Kim 	}
408aca7a94dSNamhyung Kim 
409aca7a94dSNamhyung Kim 	notes = symbol__annotation(target);
410aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
411aca7a94dSNamhyung Kim 
412aca7a94dSNamhyung Kim 	if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
413aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
414aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
415aca7a94dSNamhyung Kim 			    target->name);
416aca7a94dSNamhyung Kim 		return true;
417aca7a94dSNamhyung Kim 	}
418aca7a94dSNamhyung Kim 
419aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
420aca7a94dSNamhyung Kim 	symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
421aca7a94dSNamhyung Kim 	ui_browser__show_title(&browser->b, sym->name);
422aca7a94dSNamhyung Kim 	return true;
423aca7a94dSNamhyung Kim }
424aca7a94dSNamhyung Kim 
42529ed6e76SArnaldo Carvalho de Melo static
42629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
427aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
428aca7a94dSNamhyung Kim {
429aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
430aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
431aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
43229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
433aca7a94dSNamhyung Kim 
434aca7a94dSNamhyung Kim 	*idx = 0;
435aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
436aca7a94dSNamhyung Kim 		if (pos->offset == offset)
437aca7a94dSNamhyung Kim 			return pos;
43829ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
439aca7a94dSNamhyung Kim 			++*idx;
440aca7a94dSNamhyung Kim 	}
441aca7a94dSNamhyung Kim 
442aca7a94dSNamhyung Kim 	return NULL;
443aca7a94dSNamhyung Kim }
444aca7a94dSNamhyung Kim 
445aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
446aca7a94dSNamhyung Kim {
447657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
4484f9d0325SArnaldo Carvalho de Melo 	s64 idx;
449aca7a94dSNamhyung Kim 
450d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_jump(dl->ins))
451aca7a94dSNamhyung Kim 		return false;
452aca7a94dSNamhyung Kim 
45344d1a3edSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
45429ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
455aca7a94dSNamhyung Kim 		ui_helpline__puts("Invallid jump offset");
456aca7a94dSNamhyung Kim 		return true;
457aca7a94dSNamhyung Kim 	}
458aca7a94dSNamhyung Kim 
45929ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
460aca7a94dSNamhyung Kim 
461aca7a94dSNamhyung Kim 	return true;
462aca7a94dSNamhyung Kim }
463aca7a94dSNamhyung Kim 
46429ed6e76SArnaldo Carvalho de Melo static
46529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
466aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
467aca7a94dSNamhyung Kim {
468aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
469aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
470aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
47129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
472aca7a94dSNamhyung Kim 
473aca7a94dSNamhyung Kim 	*idx = browser->b.index;
474aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
47529ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
476aca7a94dSNamhyung Kim 			continue;
477aca7a94dSNamhyung Kim 
478aca7a94dSNamhyung Kim 		++*idx;
479aca7a94dSNamhyung Kim 
480aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
481aca7a94dSNamhyung Kim 			return pos;
482aca7a94dSNamhyung Kim 	}
483aca7a94dSNamhyung Kim 
484aca7a94dSNamhyung Kim 	return NULL;
485aca7a94dSNamhyung Kim }
486aca7a94dSNamhyung Kim 
487aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
488aca7a94dSNamhyung Kim {
48929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
490aca7a94dSNamhyung Kim 	s64 idx;
491aca7a94dSNamhyung Kim 
49229ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
49329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
494aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
495aca7a94dSNamhyung Kim 		return false;
496aca7a94dSNamhyung Kim 	}
497aca7a94dSNamhyung Kim 
49829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
499aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
500aca7a94dSNamhyung Kim 	return true;
501aca7a94dSNamhyung Kim }
502aca7a94dSNamhyung Kim 
50329ed6e76SArnaldo Carvalho de Melo static
50429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
505aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
506aca7a94dSNamhyung Kim {
507aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
508aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
509aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
51029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
511aca7a94dSNamhyung Kim 
512aca7a94dSNamhyung Kim 	*idx = browser->b.index;
513aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
51429ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
515aca7a94dSNamhyung Kim 			continue;
516aca7a94dSNamhyung Kim 
517aca7a94dSNamhyung Kim 		--*idx;
518aca7a94dSNamhyung Kim 
519aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
520aca7a94dSNamhyung Kim 			return pos;
521aca7a94dSNamhyung Kim 	}
522aca7a94dSNamhyung Kim 
523aca7a94dSNamhyung Kim 	return NULL;
524aca7a94dSNamhyung Kim }
525aca7a94dSNamhyung Kim 
526aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
527aca7a94dSNamhyung Kim {
52829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
529aca7a94dSNamhyung Kim 	s64 idx;
530aca7a94dSNamhyung Kim 
53129ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
53229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
533aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
534aca7a94dSNamhyung Kim 		return false;
535aca7a94dSNamhyung Kim 	}
536aca7a94dSNamhyung Kim 
53729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
538aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
539aca7a94dSNamhyung Kim 	return true;
540aca7a94dSNamhyung Kim }
541aca7a94dSNamhyung Kim 
542aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
543aca7a94dSNamhyung Kim 					    int delay_secs)
544aca7a94dSNamhyung Kim {
545aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
546aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
547aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
548aca7a94dSNamhyung Kim 	    !*browser->search_bf)
549aca7a94dSNamhyung Kim 		return false;
550aca7a94dSNamhyung Kim 
551aca7a94dSNamhyung Kim 	return true;
552aca7a94dSNamhyung Kim }
553aca7a94dSNamhyung Kim 
554aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
555aca7a94dSNamhyung Kim {
556aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
557aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
558aca7a94dSNamhyung Kim 
559aca7a94dSNamhyung Kim 	return false;
560aca7a94dSNamhyung Kim }
561aca7a94dSNamhyung Kim 
562aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
563aca7a94dSNamhyung Kim 					      int delay_secs)
564aca7a94dSNamhyung Kim {
565aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
566aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
567aca7a94dSNamhyung Kim 
568aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
569aca7a94dSNamhyung Kim }
570aca7a94dSNamhyung Kim 
571aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
572aca7a94dSNamhyung Kim 					   int delay_secs)
573aca7a94dSNamhyung Kim {
574aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
575aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
576aca7a94dSNamhyung Kim 
577aca7a94dSNamhyung Kim 	return false;
578aca7a94dSNamhyung Kim }
579aca7a94dSNamhyung Kim 
580aca7a94dSNamhyung Kim static
581aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
582aca7a94dSNamhyung Kim 					       int delay_secs)
583aca7a94dSNamhyung Kim {
584aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
585aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
586aca7a94dSNamhyung Kim 
587aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
588aca7a94dSNamhyung Kim }
589aca7a94dSNamhyung Kim 
590*e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
591*e9823b21SArnaldo Carvalho de Melo {
592*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
593*e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
594*e9823b21SArnaldo Carvalho de Melo 	else
595*e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
596*e9823b21SArnaldo Carvalho de Melo 
597*e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
598*e9823b21SArnaldo Carvalho de Melo 
599*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
600*e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
601*e9823b21SArnaldo Carvalho de Melo }
602*e9823b21SArnaldo Carvalho de Melo 
603aca7a94dSNamhyung Kim static int annotate_browser__run(struct annotate_browser *self, int evidx,
604aca7a94dSNamhyung Kim 				 void(*timer)(void *arg),
605aca7a94dSNamhyung Kim 				 void *arg, int delay_secs)
606aca7a94dSNamhyung Kim {
607aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
608aca7a94dSNamhyung Kim 	struct map_symbol *ms = self->b.priv;
609aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
61054e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
611aca7a94dSNamhyung Kim 	int key;
612aca7a94dSNamhyung Kim 
613aca7a94dSNamhyung Kim 	if (ui_browser__show(&self->b, sym->name, help) < 0)
614aca7a94dSNamhyung Kim 		return -1;
615aca7a94dSNamhyung Kim 
616aca7a94dSNamhyung Kim 	annotate_browser__calc_percent(self, evidx);
617aca7a94dSNamhyung Kim 
618aca7a94dSNamhyung Kim 	if (self->curr_hot) {
619aca7a94dSNamhyung Kim 		annotate_browser__set_rb_top(self, self->curr_hot);
620aca7a94dSNamhyung Kim 		self->b.navkeypressed = false;
621aca7a94dSNamhyung Kim 	}
622aca7a94dSNamhyung Kim 
623aca7a94dSNamhyung Kim 	nd = self->curr_hot;
624aca7a94dSNamhyung Kim 
625aca7a94dSNamhyung Kim 	while (1) {
626aca7a94dSNamhyung Kim 		key = ui_browser__run(&self->b, delay_secs);
627aca7a94dSNamhyung Kim 
628aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
629aca7a94dSNamhyung Kim 			annotate_browser__calc_percent(self, evidx);
630aca7a94dSNamhyung Kim 			/*
631aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
632aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
633aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
634aca7a94dSNamhyung Kim 			 */
635aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
636aca7a94dSNamhyung Kim 				nd = NULL;
637aca7a94dSNamhyung Kim 		}
638aca7a94dSNamhyung Kim 
639aca7a94dSNamhyung Kim 		switch (key) {
640aca7a94dSNamhyung Kim 		case K_TIMER:
641aca7a94dSNamhyung Kim 			if (timer != NULL)
642aca7a94dSNamhyung Kim 				timer(arg);
643aca7a94dSNamhyung Kim 
644aca7a94dSNamhyung Kim 			if (delay_secs != 0)
645aca7a94dSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evidx);
646aca7a94dSNamhyung Kim 			continue;
647aca7a94dSNamhyung Kim 		case K_TAB:
648aca7a94dSNamhyung Kim 			if (nd != NULL) {
649aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
650aca7a94dSNamhyung Kim 				if (nd == NULL)
651aca7a94dSNamhyung Kim 					nd = rb_last(&self->entries);
652aca7a94dSNamhyung Kim 			} else
653aca7a94dSNamhyung Kim 				nd = self->curr_hot;
654aca7a94dSNamhyung Kim 			break;
655aca7a94dSNamhyung Kim 		case K_UNTAB:
656aca7a94dSNamhyung Kim 			if (nd != NULL)
657aca7a94dSNamhyung Kim 				nd = rb_next(nd);
658aca7a94dSNamhyung Kim 				if (nd == NULL)
659aca7a94dSNamhyung Kim 					nd = rb_first(&self->entries);
660aca7a94dSNamhyung Kim 			else
661aca7a94dSNamhyung Kim 				nd = self->curr_hot;
662aca7a94dSNamhyung Kim 			break;
66354e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
664aca7a94dSNamhyung Kim 		case 'h':
66554e7a4e8SArnaldo Carvalho de Melo 			ui_browser__help_window(&self->b,
66654e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
66754e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
66854e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
66954e7a4e8SArnaldo Carvalho de Melo 		"->            Go to target\n"
67054e7a4e8SArnaldo Carvalho de Melo 		"<-            Exit\n"
67154e7a4e8SArnaldo Carvalho de Melo 		"h             Cycle thru hottest instructions\n"
67254e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
67354e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
67454e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
67554e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
67654e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
67754e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
67854e7a4e8SArnaldo Carvalho de Melo 		"?             Search previous string\n");
67954e7a4e8SArnaldo Carvalho de Melo 			continue;
68054e7a4e8SArnaldo Carvalho de Melo 		case 'H':
681aca7a94dSNamhyung Kim 			nd = self->curr_hot;
682aca7a94dSNamhyung Kim 			break;
683aca7a94dSNamhyung Kim 		case 's':
684aca7a94dSNamhyung Kim 			if (annotate_browser__toggle_source(self))
685aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
686aca7a94dSNamhyung Kim 			continue;
687aca7a94dSNamhyung Kim 		case 'o':
688*e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
689*e9823b21SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(self);
690aca7a94dSNamhyung Kim 			continue;
6919d1ef56dSArnaldo Carvalho de Melo 		case 'j':
692*e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
6939d1ef56dSArnaldo Carvalho de Melo 			continue;
6942402e4a9SArnaldo Carvalho de Melo 		case 'J':
695*e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
696*e9823b21SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(self);
697*e9823b21SArnaldo Carvalho de Melo 			continue;
698aca7a94dSNamhyung Kim 		case '/':
699aca7a94dSNamhyung Kim 			if (annotate_browser__search(self, delay_secs)) {
700aca7a94dSNamhyung Kim show_help:
701aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
702aca7a94dSNamhyung Kim 			}
703aca7a94dSNamhyung Kim 			continue;
704aca7a94dSNamhyung Kim 		case 'n':
705aca7a94dSNamhyung Kim 			if (self->searching_backwards ?
706aca7a94dSNamhyung Kim 			    annotate_browser__continue_search_reverse(self, delay_secs) :
707aca7a94dSNamhyung Kim 			    annotate_browser__continue_search(self, delay_secs))
708aca7a94dSNamhyung Kim 				goto show_help;
709aca7a94dSNamhyung Kim 			continue;
710aca7a94dSNamhyung Kim 		case '?':
711aca7a94dSNamhyung Kim 			if (annotate_browser__search_reverse(self, delay_secs))
712aca7a94dSNamhyung Kim 				goto show_help;
713aca7a94dSNamhyung Kim 			continue;
714*e9823b21SArnaldo Carvalho de Melo 		case 'D': {
715*e9823b21SArnaldo Carvalho de Melo 			static int seq;
716*e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
717*e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
718*e9823b21SArnaldo Carvalho de Melo 					   seq++, self->b.nr_entries,
719*e9823b21SArnaldo Carvalho de Melo 					   self->b.height,
720*e9823b21SArnaldo Carvalho de Melo 					   self->b.index,
721*e9823b21SArnaldo Carvalho de Melo 					   self->b.top_idx,
722*e9823b21SArnaldo Carvalho de Melo 					   self->nr_asm_entries);
723*e9823b21SArnaldo Carvalho de Melo 		}
724*e9823b21SArnaldo Carvalho de Melo 			continue;
725aca7a94dSNamhyung Kim 		case K_ENTER:
726aca7a94dSNamhyung Kim 		case K_RIGHT:
727aca7a94dSNamhyung Kim 			if (self->selection == NULL)
728aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
729aca7a94dSNamhyung Kim 			else if (self->selection->offset == -1)
730aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
731c4cceae3SArnaldo Carvalho de Melo 			else if (!self->selection->ins) {
732c4cceae3SArnaldo Carvalho de Melo 				if (strcmp(self->selection->name, "retq"))
733c4cceae3SArnaldo Carvalho de Melo 					goto show_sup_ins;
734c4cceae3SArnaldo Carvalho de Melo 				goto out;
735c4cceae3SArnaldo Carvalho de Melo 			} else if (!(annotate_browser__jump(self) ||
736c4cceae3SArnaldo Carvalho de Melo 				     annotate_browser__callq(self, evidx, timer, arg, delay_secs))) {
737c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
738c4cceae3SArnaldo Carvalho de Melo 				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
739c4cceae3SArnaldo Carvalho de Melo 			}
740aca7a94dSNamhyung Kim 			continue;
741aca7a94dSNamhyung Kim 		case K_LEFT:
742aca7a94dSNamhyung Kim 		case K_ESC:
743aca7a94dSNamhyung Kim 		case 'q':
744aca7a94dSNamhyung Kim 		case CTRL('c'):
745aca7a94dSNamhyung Kim 			goto out;
746aca7a94dSNamhyung Kim 		default:
747aca7a94dSNamhyung Kim 			continue;
748aca7a94dSNamhyung Kim 		}
749aca7a94dSNamhyung Kim 
750aca7a94dSNamhyung Kim 		if (nd != NULL)
751aca7a94dSNamhyung Kim 			annotate_browser__set_rb_top(self, nd);
752aca7a94dSNamhyung Kim 	}
753aca7a94dSNamhyung Kim out:
754aca7a94dSNamhyung Kim 	ui_browser__hide(&self->b);
755aca7a94dSNamhyung Kim 	return key;
756aca7a94dSNamhyung Kim }
757aca7a94dSNamhyung Kim 
758aca7a94dSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
759aca7a94dSNamhyung Kim 			     void(*timer)(void *arg), void *arg, int delay_secs)
760aca7a94dSNamhyung Kim {
761aca7a94dSNamhyung Kim 	return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
762aca7a94dSNamhyung Kim 				    timer, arg, delay_secs);
763aca7a94dSNamhyung Kim }
764aca7a94dSNamhyung Kim 
765b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
766b793a401SArnaldo Carvalho de Melo 						size_t size)
767b793a401SArnaldo Carvalho de Melo {
768b793a401SArnaldo Carvalho de Melo 	u64 offset;
769b793a401SArnaldo Carvalho de Melo 
770b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
771b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
772b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
773b793a401SArnaldo Carvalho de Melo 
77438b31bd0SArnaldo Carvalho de Melo 		if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
77538b31bd0SArnaldo Carvalho de Melo 		    !disasm_line__has_offset(dl))
776b793a401SArnaldo Carvalho de Melo 			continue;
777b793a401SArnaldo Carvalho de Melo 
77844d1a3edSArnaldo Carvalho de Melo 		if (dl->ops.target.offset >= size) {
779b793a401SArnaldo Carvalho de Melo 			ui__error("jump to after symbol!\n"
780b793a401SArnaldo Carvalho de Melo 				  "size: %zx, jump target: %" PRIx64,
78144d1a3edSArnaldo Carvalho de Melo 				  size, dl->ops.target.offset);
782b793a401SArnaldo Carvalho de Melo 			continue;
783b793a401SArnaldo Carvalho de Melo 		}
784b793a401SArnaldo Carvalho de Melo 
78544d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
7869481ede9SArnaldo Carvalho de Melo 		/*
7879481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
7889481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
7899481ede9SArnaldo Carvalho de Melo  		 */
7909481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
7919481ede9SArnaldo Carvalho de Melo 			continue;
7929481ede9SArnaldo Carvalho de Melo 
793b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
7942402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
7952402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
7962402e4a9SArnaldo Carvalho de Melo 
7972402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
798b793a401SArnaldo Carvalho de Melo 	}
799b793a401SArnaldo Carvalho de Melo 
800b793a401SArnaldo Carvalho de Melo }
801b793a401SArnaldo Carvalho de Melo 
8022402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
8032402e4a9SArnaldo Carvalho de Melo {
8042402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
8052402e4a9SArnaldo Carvalho de Melo 		return 5;
8062402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
8072402e4a9SArnaldo Carvalho de Melo 		return 2;
8082402e4a9SArnaldo Carvalho de Melo 	return 1;
8092402e4a9SArnaldo Carvalho de Melo }
8102402e4a9SArnaldo Carvalho de Melo 
811aca7a94dSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
812aca7a94dSNamhyung Kim 			 void(*timer)(void *arg), void *arg,
813aca7a94dSNamhyung Kim 			 int delay_secs)
814aca7a94dSNamhyung Kim {
81529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
816aca7a94dSNamhyung Kim 	struct annotation *notes;
817b793a401SArnaldo Carvalho de Melo 	const size_t size = symbol__size(sym);
818aca7a94dSNamhyung Kim 	struct map_symbol ms = {
819aca7a94dSNamhyung Kim 		.map = map,
820aca7a94dSNamhyung Kim 		.sym = sym,
821aca7a94dSNamhyung Kim 	};
822aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
823aca7a94dSNamhyung Kim 		.b = {
824a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
825aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
826aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
82729ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
828aca7a94dSNamhyung Kim 			.priv	 = &ms,
829aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
830aca7a94dSNamhyung Kim 		},
831aca7a94dSNamhyung Kim 	};
832b793a401SArnaldo Carvalho de Melo 	int ret = -1;
833aca7a94dSNamhyung Kim 
834aca7a94dSNamhyung Kim 	if (sym == NULL)
835aca7a94dSNamhyung Kim 		return -1;
836aca7a94dSNamhyung Kim 
837aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
838aca7a94dSNamhyung Kim 		return -1;
839aca7a94dSNamhyung Kim 
840b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
841b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
842b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
843b793a401SArnaldo Carvalho de Melo 		return -1;
844b793a401SArnaldo Carvalho de Melo 	}
845b793a401SArnaldo Carvalho de Melo 
846887c0066SArnaldo Carvalho de Melo 	if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
847aca7a94dSNamhyung Kim 		ui__error("%s", ui_helpline__last_msg);
848b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
849aca7a94dSNamhyung Kim 	}
850aca7a94dSNamhyung Kim 
851aca7a94dSNamhyung Kim 	ui_helpline__push("Press <- or ESC to exit");
852aca7a94dSNamhyung Kim 
853aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
854aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
855aca7a94dSNamhyung Kim 
856aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
857887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
858aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
859aca7a94dSNamhyung Kim 
860aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
861aca7a94dSNamhyung Kim 			browser.b.width = line_len;
862887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
863887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
864b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
865887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
86697148a97SArnaldo Carvalho de Melo 			/*
86797148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
86897148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
86997148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
87097148a97SArnaldo Carvalho de Melo 			 *
87197148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
87297148a97SArnaldo Carvalho de Melo  			 */
87397148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
874b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
875b793a401SArnaldo Carvalho de Melo 		} else
876887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
877aca7a94dSNamhyung Kim 	}
878aca7a94dSNamhyung Kim 
879b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
880b793a401SArnaldo Carvalho de Melo 
8812402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
88283b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
8832402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
884aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
885aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
886aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
887*e9823b21SArnaldo Carvalho de Melo 
888*e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
889*e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
890*e9823b21SArnaldo Carvalho de Melo 
891*e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
892*e9823b21SArnaldo Carvalho de Melo 
893aca7a94dSNamhyung Kim 	ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
894aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
895aca7a94dSNamhyung Kim 		list_del(&pos->node);
89629ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
897aca7a94dSNamhyung Kim 	}
898b793a401SArnaldo Carvalho de Melo 
899b793a401SArnaldo Carvalho de Melo out_free_offsets:
900b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
901aca7a94dSNamhyung Kim 	return ret;
902aca7a94dSNamhyung Kim }
903