xref: /linux/tools/perf/ui/browsers/annotate.c (revision 30e863bb6f708c0abd422fbb0e6b295f5ee6407b)
1aca7a94dSNamhyung Kim #include "../../util/util.h"
2aca7a94dSNamhyung Kim #include "../browser.h"
3aca7a94dSNamhyung Kim #include "../helpline.h"
4aca7a94dSNamhyung Kim #include "../libslang.h"
5aca7a94dSNamhyung Kim #include "../ui.h"
6aca7a94dSNamhyung Kim #include "../util.h"
7aca7a94dSNamhyung Kim #include "../../util/annotate.h"
8aca7a94dSNamhyung Kim #include "../../util/hist.h"
9aca7a94dSNamhyung Kim #include "../../util/sort.h"
10aca7a94dSNamhyung Kim #include "../../util/symbol.h"
11db8fd07aSNamhyung Kim #include "../../util/evsel.h"
12aca7a94dSNamhyung Kim #include <pthread.h>
13aca7a94dSNamhyung Kim 
140c4a5bceSMartin Liška struct disasm_line_samples {
150c4a5bceSMartin Liška 	double		percent;
160c4a5bceSMartin Liška 	u64		nr;
170c4a5bceSMartin Liška };
180c4a5bceSMartin Liška 
19b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
20b793a401SArnaldo Carvalho de Melo 	struct rb_node			rb_node;
21b793a401SArnaldo Carvalho de Melo 	u32				idx;
22b793a401SArnaldo Carvalho de Melo 	int				idx_asm;
237d5b12f5SArnaldo Carvalho de Melo 	int				jump_sources;
24c7e7b610SNamhyung Kim 	/*
25c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
26c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
27c7e7b610SNamhyung Kim 	 */
280c4a5bceSMartin Liška 	struct disasm_line_samples	samples[1];
29b793a401SArnaldo Carvalho de Melo };
30b793a401SArnaldo Carvalho de Melo 
31e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
32e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
33e9823b21SArnaldo Carvalho de Melo 	     use_offset,
34e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
35e592488cSAndi Kleen 	     show_linenr,
360c4a5bceSMartin Liška 	     show_nr_jumps,
370c4a5bceSMartin Liška 	     show_total_period;
38e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
39e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
40e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
41e9823b21SArnaldo Carvalho de Melo };
42e9823b21SArnaldo Carvalho de Melo 
43aca7a94dSNamhyung Kim struct annotate_browser {
44aca7a94dSNamhyung Kim 	struct ui_browser b;
45aca7a94dSNamhyung Kim 	struct rb_root	  entries;
46aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
4729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
48b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
49c7e7b610SNamhyung Kim 	int		    nr_events;
50aca7a94dSNamhyung Kim 	u64		    start;
51aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
52aca7a94dSNamhyung Kim 	int		    nr_entries;
532402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
542402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
55aca7a94dSNamhyung Kim 	bool		    searching_backwards;
56*30e863bbSAndi Kleen 	bool		    have_cycles;
5783b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
582402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
592402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
6083b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
6183b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
62aca7a94dSNamhyung Kim 	char		    search_bf[128];
63aca7a94dSNamhyung Kim };
64aca7a94dSNamhyung Kim 
65887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
66aca7a94dSNamhyung Kim {
67887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
68aca7a94dSNamhyung Kim }
69aca7a94dSNamhyung Kim 
701d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
711d037ca1SIrina Tirdea 				void *entry)
72aca7a94dSNamhyung Kim {
73e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
7429ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
7529ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
76aca7a94dSNamhyung Kim 	}
77aca7a94dSNamhyung Kim 
78aca7a94dSNamhyung Kim 	return false;
79aca7a94dSNamhyung Kim }
80aca7a94dSNamhyung Kim 
812402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
822402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
832402e4a9SArnaldo Carvalho de Melo {
842402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
852402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
862402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
872402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
882402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
892402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
902402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
912402e4a9SArnaldo Carvalho de Melo }
922402e4a9SArnaldo Carvalho de Melo 
932402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
942402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
952402e4a9SArnaldo Carvalho de Melo {
962402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
972402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
982402e4a9SArnaldo Carvalho de Melo }
992402e4a9SArnaldo Carvalho de Melo 
10005e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
101aca7a94dSNamhyung Kim {
10205e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
10329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
104b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
10505e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
106e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
10705e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
10805e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
10905e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
110c7e7b610SNamhyung Kim 	int i, pcnt_width = 7 * ab->nr_events;
111c7e7b610SNamhyung Kim 	double percent_max = 0.0;
11283b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
113aca7a94dSNamhyung Kim 
114c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1150c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1160c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
117c7e7b610SNamhyung Kim 	}
118c7e7b610SNamhyung Kim 
119c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
120c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
1210c4a5bceSMartin Liška 			ui_browser__set_percent_color(browser,
1220c4a5bceSMartin Liška 						      bdl->samples[i].percent,
123c7e7b610SNamhyung Kim 						      current_entry);
1240c4a5bceSMartin Liška 			if (annotate_browser__opts.show_total_period)
1250c4a5bceSMartin Liška 				slsmg_printf("%6" PRIu64 " ",
1260c4a5bceSMartin Liška 					     bdl->samples[i].nr);
1270c4a5bceSMartin Liška 			else
1280c4a5bceSMartin Liška 				slsmg_printf("%6.2f ", bdl->samples[i].percent);
129c7e7b610SNamhyung Kim 		}
130aca7a94dSNamhyung Kim 	} else {
13105e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
132c7e7b610SNamhyung Kim 		slsmg_write_nstring(" ", pcnt_width);
133aca7a94dSNamhyung Kim 	}
134aca7a94dSNamhyung Kim 
135cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
136aca7a94dSNamhyung Kim 
137aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
13805e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
139aca7a94dSNamhyung Kim 		width += 1;
140aca7a94dSNamhyung Kim 
14129ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
142c7e7b610SNamhyung Kim 		slsmg_write_nstring(" ", width - pcnt_width);
14383b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
144e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
145e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
146e592488cSAndi Kleen 					ab->addr_width + 1, dl->line_nr);
147e592488cSAndi Kleen 		else
14883b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
14983b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
15083b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, printed);
151c7e7b610SNamhyung Kim 		slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
15283b1f2aaSArnaldo Carvalho de Melo 	} else {
15329ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
15483b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
155aca7a94dSNamhyung Kim 
156e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
157aca7a94dSNamhyung Kim 			addr += ab->start;
158aca7a94dSNamhyung Kim 
159e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
160aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
16161e04b33SArnaldo Carvalho de Melo 		} else {
1627d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
163e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
1642402e4a9SArnaldo Carvalho de Melo 					int prev;
1652402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
1662402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
1672402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
1682402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
1692402e4a9SArnaldo Carvalho de Melo 											 current_entry);
1702402e4a9SArnaldo Carvalho de Melo 					slsmg_write_nstring(bf, printed);
17105e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
1722402e4a9SArnaldo Carvalho de Melo 				}
1732402e4a9SArnaldo Carvalho de Melo 
17461e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
1752402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
17661e04b33SArnaldo Carvalho de Melo 			} else {
17761e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
17883b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
17961e04b33SArnaldo Carvalho de Melo 			}
18061e04b33SArnaldo Carvalho de Melo 		}
181b793a401SArnaldo Carvalho de Melo 
182aca7a94dSNamhyung Kim 		if (change_color)
18305e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
184aca7a94dSNamhyung Kim 		slsmg_write_nstring(bf, printed);
185aca7a94dSNamhyung Kim 		if (change_color)
18605e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
18728548d78SArnaldo Carvalho de Melo 		if (dl->ins && dl->ins->ops->scnprintf) {
18851a0d455SArnaldo Carvalho de Melo 			if (ins__is_jump(dl->ins)) {
18944d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
19051a0d455SArnaldo Carvalho de Melo 
19105e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
19251a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
19351a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
19488298f5aSArnaldo Carvalho de Melo 			} else if (ins__is_call(dl->ins)) {
19505e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
19688298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
19751a0d455SArnaldo Carvalho de Melo 			} else {
19851a0d455SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
19951a0d455SArnaldo Carvalho de Melo 			}
2004ea08b52SArnaldo Carvalho de Melo 		} else {
2014ea08b52SArnaldo Carvalho de Melo 			if (strcmp(dl->name, "retq")) {
2024ea08b52SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
2034ea08b52SArnaldo Carvalho de Melo 			} else {
20405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2054ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2064ea08b52SArnaldo Carvalho de Melo 			}
2074ea08b52SArnaldo Carvalho de Melo 		}
2084ea08b52SArnaldo Carvalho de Melo 
209e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
210c7e7b610SNamhyung Kim 		slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
211aca7a94dSNamhyung Kim 	}
212aca7a94dSNamhyung Kim 
213aca7a94dSNamhyung Kim 	if (current_entry)
21429ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
215aca7a94dSNamhyung Kim }
216aca7a94dSNamhyung Kim 
217865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
218865c66c4SFrederik Deweerdt {
219865c66c4SFrederik Deweerdt 	if (!dl || !dl->ins || !ins__is_jump(dl->ins)
220865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
221865c66c4SFrederik Deweerdt 	    || dl->ops.target.offset >= symbol__size(sym))
222865c66c4SFrederik Deweerdt 		return false;
223865c66c4SFrederik Deweerdt 
224865c66c4SFrederik Deweerdt 	return true;
225865c66c4SFrederik Deweerdt }
226865c66c4SFrederik Deweerdt 
2279d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
228a3f895beSArnaldo Carvalho de Melo {
229a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
2309d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
2319d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
23283b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
23332ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
23432ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
235c7e7b610SNamhyung Kim 	u8 pcnt_width = 7;
23632ae1efdSNamhyung Kim 
23732ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
23832ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
23932ae1efdSNamhyung Kim 		return;
240a3f895beSArnaldo Carvalho de Melo 
241865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
242a3f895beSArnaldo Carvalho de Melo 		return;
243a3f895beSArnaldo Carvalho de Melo 
2449d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
2459d1ef56dSArnaldo Carvalho de Melo 	if (!target)
2469d1ef56dSArnaldo Carvalho de Melo 		return;
2479d1ef56dSArnaldo Carvalho de Melo 
2489d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2499d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2509d1ef56dSArnaldo Carvalho de Melo 
251e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2529d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
253a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
254a3f895beSArnaldo Carvalho de Melo 	} else {
2559d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
256a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
257a3f895beSArnaldo Carvalho de Melo 	}
258a3f895beSArnaldo Carvalho de Melo 
259c7e7b610SNamhyung Kim 	pcnt_width *= ab->nr_events;
260c7e7b610SNamhyung Kim 
261a3f895beSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_CODE);
262c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
263c7e7b610SNamhyung Kim 				 from, to);
264a3f895beSArnaldo Carvalho de Melo }
265a3f895beSArnaldo Carvalho de Melo 
266a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
267a3f895beSArnaldo Carvalho de Melo {
268c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
269a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
270c7e7b610SNamhyung Kim 	int pcnt_width;
271c7e7b610SNamhyung Kim 
272c7e7b610SNamhyung Kim 	pcnt_width = 7 * ab->nr_events;
273a3f895beSArnaldo Carvalho de Melo 
274e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
2759d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
276a3f895beSArnaldo Carvalho de Melo 
27783b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
278c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
279a3f895beSArnaldo Carvalho de Melo 	return ret;
280a3f895beSArnaldo Carvalho de Melo }
281a3f895beSArnaldo Carvalho de Melo 
282c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
283c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
284c7e7b610SNamhyung Kim {
285c7e7b610SNamhyung Kim 	int i;
286c7e7b610SNamhyung Kim 
287c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
2880c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
289c7e7b610SNamhyung Kim 			continue;
2900c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
291c7e7b610SNamhyung Kim 	}
292c7e7b610SNamhyung Kim 	return 0;
293c7e7b610SNamhyung Kim }
294c7e7b610SNamhyung Kim 
295c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
296c7e7b610SNamhyung Kim 				   int nr_events)
297aca7a94dSNamhyung Kim {
29829ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
299aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
300887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
301aca7a94dSNamhyung Kim 
302aca7a94dSNamhyung Kim 	while (*p != NULL) {
303aca7a94dSNamhyung Kim 		parent = *p;
304887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
305c7e7b610SNamhyung Kim 
306c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
307aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
308aca7a94dSNamhyung Kim 		else
309aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
310aca7a94dSNamhyung Kim 	}
311887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
312887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
313aca7a94dSNamhyung Kim }
314aca7a94dSNamhyung Kim 
31505e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
31629ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
317aca7a94dSNamhyung Kim {
318aca7a94dSNamhyung Kim 	unsigned back;
319aca7a94dSNamhyung Kim 
32005e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
32105e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
32205e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
323aca7a94dSNamhyung Kim 
32405e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
32529ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
326aca7a94dSNamhyung Kim 
32705e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
328aca7a94dSNamhyung Kim 			continue;
329aca7a94dSNamhyung Kim 
33005e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
331aca7a94dSNamhyung Kim 		--back;
332aca7a94dSNamhyung Kim 	}
333aca7a94dSNamhyung Kim 
33405e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
33505e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
336aca7a94dSNamhyung Kim }
337aca7a94dSNamhyung Kim 
338aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
339aca7a94dSNamhyung Kim 					 struct rb_node *nd)
340aca7a94dSNamhyung Kim {
341887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
34229ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
343a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
344aca7a94dSNamhyung Kim 
345887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
346887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
347a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
348e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
349a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
350a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
351aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
352aca7a94dSNamhyung Kim }
353aca7a94dSNamhyung Kim 
354aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
355db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
356aca7a94dSNamhyung Kim {
357aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
358aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
359aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
360e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
361e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
362aca7a94dSNamhyung Kim 
363aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
364aca7a94dSNamhyung Kim 
365aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
366aca7a94dSNamhyung Kim 
367aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
368887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
369e64aa75bSNamhyung Kim 		const char *path = NULL;
370c7e7b610SNamhyung Kim 		double max_percent = 0.0;
371c7e7b610SNamhyung Kim 		int i;
372e64aa75bSNamhyung Kim 
373e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
374e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
375e64aa75bSNamhyung Kim 			continue;
376e64aa75bSNamhyung Kim 		}
377e64aa75bSNamhyung Kim 
378e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
379c7e7b610SNamhyung Kim 
380c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
3810c4a5bceSMartin Liška 			u64 nr_samples;
3820c4a5bceSMartin Liška 
3830c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
384c7e7b610SNamhyung Kim 						evsel->idx + i,
385c7e7b610SNamhyung Kim 						pos->offset,
386c7e7b610SNamhyung Kim 						next ? next->offset : len,
3870c4a5bceSMartin Liška 						&path, &nr_samples);
3880c4a5bceSMartin Liška 			bpos->samples[i].nr = nr_samples;
389e64aa75bSNamhyung Kim 
3900c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
3910c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
392c7e7b610SNamhyung Kim 		}
393c7e7b610SNamhyung Kim 
394*30e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
395887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
396aca7a94dSNamhyung Kim 			continue;
397aca7a94dSNamhyung Kim 		}
398c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
399c7e7b610SNamhyung Kim 				       browser->nr_events);
400aca7a94dSNamhyung Kim 	}
401aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
402aca7a94dSNamhyung Kim 
403aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
404aca7a94dSNamhyung Kim }
405aca7a94dSNamhyung Kim 
406aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
407aca7a94dSNamhyung Kim {
40829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
409887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
410aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
411aca7a94dSNamhyung Kim 
412aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
41329ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
414887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
415aca7a94dSNamhyung Kim 
416e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
417887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
418887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
419aca7a94dSNamhyung Kim 
420aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
421e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
422aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
423887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
424887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
425aca7a94dSNamhyung Kim 	} else {
426887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
427aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
428aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
429aca7a94dSNamhyung Kim 			return false;
430aca7a94dSNamhyung Kim 		}
431aca7a94dSNamhyung Kim 
432887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
433887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
434aca7a94dSNamhyung Kim 
435aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
436e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
437aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
438887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
439887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
440aca7a94dSNamhyung Kim 	}
441aca7a94dSNamhyung Kim 
442aca7a94dSNamhyung Kim 	return true;
443aca7a94dSNamhyung Kim }
444aca7a94dSNamhyung Kim 
445e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
446e9823b21SArnaldo Carvalho de Melo {
447e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
448e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
449e9823b21SArnaldo Carvalho de Melo }
450e9823b21SArnaldo Carvalho de Melo 
45134f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
45234f77abcSAdrian Hunter 
45334f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
45434f77abcSAdrian Hunter 		     size_t sz)
45534f77abcSAdrian Hunter {
45634f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
45734f77abcSAdrian Hunter }
45834f77abcSAdrian Hunter 
459db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
460db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
4619783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
462aca7a94dSNamhyung Kim {
463aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
464657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
465aca7a94dSNamhyung Kim 	struct annotation *notes;
4661179e11bSAdrian Hunter 	struct addr_map_symbol target = {
4671179e11bSAdrian Hunter 		.map = ms->map,
4681d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
4691179e11bSAdrian Hunter 	};
47034f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
471aca7a94dSNamhyung Kim 
472d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_call(dl->ins))
473aca7a94dSNamhyung Kim 		return false;
474aca7a94dSNamhyung Kim 
4751d5077bdSAdrian Hunter 	if (map_groups__find_ams(&target, NULL) ||
4761d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
4771d5077bdSAdrian Hunter 							     target.addr)) !=
4781d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
479aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
480aca7a94dSNamhyung Kim 		return true;
481aca7a94dSNamhyung Kim 	}
482aca7a94dSNamhyung Kim 
4831179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
484aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
485aca7a94dSNamhyung Kim 
4861179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
487aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
488aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
4891179e11bSAdrian Hunter 			    target.sym->name);
490aca7a94dSNamhyung Kim 		return true;
491aca7a94dSNamhyung Kim 	}
492aca7a94dSNamhyung Kim 
493aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
4941179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
4951179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
49634f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
497aca7a94dSNamhyung Kim 	return true;
498aca7a94dSNamhyung Kim }
499aca7a94dSNamhyung Kim 
50029ed6e76SArnaldo Carvalho de Melo static
50129ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
502aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
503aca7a94dSNamhyung Kim {
504aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
505aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
506aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
50729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
508aca7a94dSNamhyung Kim 
509aca7a94dSNamhyung Kim 	*idx = 0;
510aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
511aca7a94dSNamhyung Kim 		if (pos->offset == offset)
512aca7a94dSNamhyung Kim 			return pos;
51329ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
514aca7a94dSNamhyung Kim 			++*idx;
515aca7a94dSNamhyung Kim 	}
516aca7a94dSNamhyung Kim 
517aca7a94dSNamhyung Kim 	return NULL;
518aca7a94dSNamhyung Kim }
519aca7a94dSNamhyung Kim 
520aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
521aca7a94dSNamhyung Kim {
522657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
5234f9d0325SArnaldo Carvalho de Melo 	s64 idx;
524aca7a94dSNamhyung Kim 
525d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_jump(dl->ins))
526aca7a94dSNamhyung Kim 		return false;
527aca7a94dSNamhyung Kim 
52844d1a3edSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
52929ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
530e6f65388SIngo Molnar 		ui_helpline__puts("Invalid jump offset");
531aca7a94dSNamhyung Kim 		return true;
532aca7a94dSNamhyung Kim 	}
533aca7a94dSNamhyung Kim 
53429ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
535aca7a94dSNamhyung Kim 
536aca7a94dSNamhyung Kim 	return true;
537aca7a94dSNamhyung Kim }
538aca7a94dSNamhyung Kim 
53929ed6e76SArnaldo Carvalho de Melo static
54029ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
541aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
542aca7a94dSNamhyung Kim {
543aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
544aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
545aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
54629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
547aca7a94dSNamhyung Kim 
548aca7a94dSNamhyung Kim 	*idx = browser->b.index;
549aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
55029ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
551aca7a94dSNamhyung Kim 			continue;
552aca7a94dSNamhyung Kim 
553aca7a94dSNamhyung Kim 		++*idx;
554aca7a94dSNamhyung Kim 
555aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
556aca7a94dSNamhyung Kim 			return pos;
557aca7a94dSNamhyung Kim 	}
558aca7a94dSNamhyung Kim 
559aca7a94dSNamhyung Kim 	return NULL;
560aca7a94dSNamhyung Kim }
561aca7a94dSNamhyung Kim 
562aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
563aca7a94dSNamhyung Kim {
56429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
565aca7a94dSNamhyung Kim 	s64 idx;
566aca7a94dSNamhyung Kim 
56729ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
56829ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
569aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
570aca7a94dSNamhyung Kim 		return false;
571aca7a94dSNamhyung Kim 	}
572aca7a94dSNamhyung Kim 
57329ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
574aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
575aca7a94dSNamhyung Kim 	return true;
576aca7a94dSNamhyung Kim }
577aca7a94dSNamhyung Kim 
57829ed6e76SArnaldo Carvalho de Melo static
57929ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
580aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
581aca7a94dSNamhyung Kim {
582aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
583aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
584aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
58529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
586aca7a94dSNamhyung Kim 
587aca7a94dSNamhyung Kim 	*idx = browser->b.index;
588aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
58929ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
590aca7a94dSNamhyung Kim 			continue;
591aca7a94dSNamhyung Kim 
592aca7a94dSNamhyung Kim 		--*idx;
593aca7a94dSNamhyung Kim 
594aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
595aca7a94dSNamhyung Kim 			return pos;
596aca7a94dSNamhyung Kim 	}
597aca7a94dSNamhyung Kim 
598aca7a94dSNamhyung Kim 	return NULL;
599aca7a94dSNamhyung Kim }
600aca7a94dSNamhyung Kim 
601aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
602aca7a94dSNamhyung Kim {
60329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
604aca7a94dSNamhyung Kim 	s64 idx;
605aca7a94dSNamhyung Kim 
60629ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
60729ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
608aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
609aca7a94dSNamhyung Kim 		return false;
610aca7a94dSNamhyung Kim 	}
611aca7a94dSNamhyung Kim 
61229ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
613aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
614aca7a94dSNamhyung Kim 	return true;
615aca7a94dSNamhyung Kim }
616aca7a94dSNamhyung Kim 
617aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
618aca7a94dSNamhyung Kim 					    int delay_secs)
619aca7a94dSNamhyung Kim {
620aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
621aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
622aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
623aca7a94dSNamhyung Kim 	    !*browser->search_bf)
624aca7a94dSNamhyung Kim 		return false;
625aca7a94dSNamhyung Kim 
626aca7a94dSNamhyung Kim 	return true;
627aca7a94dSNamhyung Kim }
628aca7a94dSNamhyung Kim 
629aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
630aca7a94dSNamhyung Kim {
631aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
632aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
633aca7a94dSNamhyung Kim 
634aca7a94dSNamhyung Kim 	return false;
635aca7a94dSNamhyung Kim }
636aca7a94dSNamhyung Kim 
637aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
638aca7a94dSNamhyung Kim 					      int delay_secs)
639aca7a94dSNamhyung Kim {
640aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
641aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
642aca7a94dSNamhyung Kim 
643aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
644aca7a94dSNamhyung Kim }
645aca7a94dSNamhyung Kim 
646aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
647aca7a94dSNamhyung Kim 					   int delay_secs)
648aca7a94dSNamhyung Kim {
649aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
650aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
651aca7a94dSNamhyung Kim 
652aca7a94dSNamhyung Kim 	return false;
653aca7a94dSNamhyung Kim }
654aca7a94dSNamhyung Kim 
655aca7a94dSNamhyung Kim static
656aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
657aca7a94dSNamhyung Kim 					       int delay_secs)
658aca7a94dSNamhyung Kim {
659aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
660aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
661aca7a94dSNamhyung Kim 
662aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
663aca7a94dSNamhyung Kim }
664aca7a94dSNamhyung Kim 
665e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
666e9823b21SArnaldo Carvalho de Melo {
667e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
668e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
669e9823b21SArnaldo Carvalho de Melo 	else
670e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
671e9823b21SArnaldo Carvalho de Melo 
672e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
673e9823b21SArnaldo Carvalho de Melo 
674e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
675e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
676e9823b21SArnaldo Carvalho de Melo }
677e9823b21SArnaldo Carvalho de Melo 
678db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
679db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
6809783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
681aca7a94dSNamhyung Kim {
682aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
68305e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
684aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
68554e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
6869783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
687aca7a94dSNamhyung Kim 	int key;
68834f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
689aca7a94dSNamhyung Kim 
69034f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
69134f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
692aca7a94dSNamhyung Kim 		return -1;
693aca7a94dSNamhyung Kim 
694db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
695aca7a94dSNamhyung Kim 
69605e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
69705e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
69805e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
699aca7a94dSNamhyung Kim 	}
700aca7a94dSNamhyung Kim 
70105e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
702aca7a94dSNamhyung Kim 
703aca7a94dSNamhyung Kim 	while (1) {
70405e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
705aca7a94dSNamhyung Kim 
706aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
707db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
708aca7a94dSNamhyung Kim 			/*
709aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
710aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
711aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
712aca7a94dSNamhyung Kim 			 */
713aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
714aca7a94dSNamhyung Kim 				nd = NULL;
715aca7a94dSNamhyung Kim 		}
716aca7a94dSNamhyung Kim 
717aca7a94dSNamhyung Kim 		switch (key) {
718aca7a94dSNamhyung Kim 		case K_TIMER:
7199783adf7SNamhyung Kim 			if (hbt)
7209783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
721aca7a94dSNamhyung Kim 
722aca7a94dSNamhyung Kim 			if (delay_secs != 0)
723db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
724aca7a94dSNamhyung Kim 			continue;
725aca7a94dSNamhyung Kim 		case K_TAB:
726aca7a94dSNamhyung Kim 			if (nd != NULL) {
727aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
728aca7a94dSNamhyung Kim 				if (nd == NULL)
72905e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
730aca7a94dSNamhyung Kim 			} else
73105e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
732aca7a94dSNamhyung Kim 			break;
733aca7a94dSNamhyung Kim 		case K_UNTAB:
734aca7a94dSNamhyung Kim 			if (nd != NULL)
735aca7a94dSNamhyung Kim 				nd = rb_next(nd);
736aca7a94dSNamhyung Kim 				if (nd == NULL)
73705e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
738aca7a94dSNamhyung Kim 			else
73905e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
740aca7a94dSNamhyung Kim 			break;
74154e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
742aca7a94dSNamhyung Kim 		case 'h':
74305e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
74454e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
74554e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
74654e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
74754e7a4e8SArnaldo Carvalho de Melo 		"->            Go to target\n"
74854e7a4e8SArnaldo Carvalho de Melo 		"<-            Exit\n"
749107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
75054e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
75154e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
75254e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
75354e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
75454e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
7550c4a5bceSMartin Liška 		"t             Toggle total period view\n"
75654e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
757e592488cSAndi Kleen 		"k             Toggle line numbers\n"
75879ee47faSFeng Tang 		"r             Run available scripts\n"
759fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
76054e7a4e8SArnaldo Carvalho de Melo 			continue;
76179ee47faSFeng Tang 		case 'r':
76279ee47faSFeng Tang 			{
76379ee47faSFeng Tang 				script_browse(NULL);
76479ee47faSFeng Tang 				continue;
76579ee47faSFeng Tang 			}
766e592488cSAndi Kleen 		case 'k':
767e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
768e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
769e592488cSAndi Kleen 			break;
77054e7a4e8SArnaldo Carvalho de Melo 		case 'H':
77105e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
772aca7a94dSNamhyung Kim 			break;
773aca7a94dSNamhyung Kim 		case 's':
77405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
775aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
776aca7a94dSNamhyung Kim 			continue;
777aca7a94dSNamhyung Kim 		case 'o':
778e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
77905e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
780aca7a94dSNamhyung Kim 			continue;
7819d1ef56dSArnaldo Carvalho de Melo 		case 'j':
782e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
7839d1ef56dSArnaldo Carvalho de Melo 			continue;
7842402e4a9SArnaldo Carvalho de Melo 		case 'J':
785e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
78605e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
787e9823b21SArnaldo Carvalho de Melo 			continue;
788aca7a94dSNamhyung Kim 		case '/':
78905e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
790aca7a94dSNamhyung Kim show_help:
791aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
792aca7a94dSNamhyung Kim 			}
793aca7a94dSNamhyung Kim 			continue;
794aca7a94dSNamhyung Kim 		case 'n':
79505e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
79605e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
79705e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
798aca7a94dSNamhyung Kim 				goto show_help;
799aca7a94dSNamhyung Kim 			continue;
800aca7a94dSNamhyung Kim 		case '?':
80105e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
802aca7a94dSNamhyung Kim 				goto show_help;
803aca7a94dSNamhyung Kim 			continue;
804e9823b21SArnaldo Carvalho de Melo 		case 'D': {
805e9823b21SArnaldo Carvalho de Melo 			static int seq;
806e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
807e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
80805e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
80905e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
81005e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
81105e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
81205e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
813e9823b21SArnaldo Carvalho de Melo 		}
814e9823b21SArnaldo Carvalho de Melo 			continue;
815aca7a94dSNamhyung Kim 		case K_ENTER:
816aca7a94dSNamhyung Kim 		case K_RIGHT:
81705e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
818aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
81905e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
820aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
82105e8b080SArnaldo Carvalho de Melo 			else if (!browser->selection->ins) {
82205e8b080SArnaldo Carvalho de Melo 				if (strcmp(browser->selection->name, "retq"))
823c4cceae3SArnaldo Carvalho de Melo 					goto show_sup_ins;
824c4cceae3SArnaldo Carvalho de Melo 				goto out;
82505e8b080SArnaldo Carvalho de Melo 			} else if (!(annotate_browser__jump(browser) ||
826db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
827c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
828c4cceae3SArnaldo Carvalho de Melo 				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
829c4cceae3SArnaldo Carvalho de Melo 			}
830aca7a94dSNamhyung Kim 			continue;
8310c4a5bceSMartin Liška 		case 't':
8320c4a5bceSMartin Liška 			annotate_browser__opts.show_total_period =
8330c4a5bceSMartin Liška 			  !annotate_browser__opts.show_total_period;
8340c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
8350c4a5bceSMartin Liška 			continue;
836aca7a94dSNamhyung Kim 		case K_LEFT:
837aca7a94dSNamhyung Kim 		case K_ESC:
838aca7a94dSNamhyung Kim 		case 'q':
839aca7a94dSNamhyung Kim 		case CTRL('c'):
840aca7a94dSNamhyung Kim 			goto out;
841aca7a94dSNamhyung Kim 		default:
842aca7a94dSNamhyung Kim 			continue;
843aca7a94dSNamhyung Kim 		}
844aca7a94dSNamhyung Kim 
845aca7a94dSNamhyung Kim 		if (nd != NULL)
84605e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
847aca7a94dSNamhyung Kim 	}
848aca7a94dSNamhyung Kim out:
84905e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
850aca7a94dSNamhyung Kim 	return key;
851aca7a94dSNamhyung Kim }
852aca7a94dSNamhyung Kim 
853d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
854d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
855d5dbc518SArnaldo Carvalho de Melo {
8560c4a5bceSMartin Liška 	/* Set default value for show_total_period.  */
8570c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
8580c4a5bceSMartin Liška 	  symbol_conf.show_total_period;
8590c4a5bceSMartin Liška 
860d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
861d5dbc518SArnaldo Carvalho de Melo }
862d5dbc518SArnaldo Carvalho de Melo 
863db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
8649783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
865aca7a94dSNamhyung Kim {
866ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
867ed426915SNamhyung Kim 	SLang_reset_tty();
868ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
869ed426915SNamhyung Kim 
870d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
871aca7a94dSNamhyung Kim }
872aca7a94dSNamhyung Kim 
873*30e863bbSAndi Kleen 
874*30e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
875*30e863bbSAndi Kleen {
876*30e863bbSAndi Kleen 	unsigned n_insn = 0;
877*30e863bbSAndi Kleen 	u64 offset;
878*30e863bbSAndi Kleen 
879*30e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
880*30e863bbSAndi Kleen 		if (browser->offsets[offset])
881*30e863bbSAndi Kleen 			n_insn++;
882*30e863bbSAndi Kleen 	}
883*30e863bbSAndi Kleen 	return n_insn;
884*30e863bbSAndi Kleen }
885*30e863bbSAndi Kleen 
886*30e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
887*30e863bbSAndi Kleen 			   struct cyc_hist *ch)
888*30e863bbSAndi Kleen {
889*30e863bbSAndi Kleen 	unsigned n_insn;
890*30e863bbSAndi Kleen 	u64 offset;
891*30e863bbSAndi Kleen 
892*30e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
893*30e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
894*30e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
895*30e863bbSAndi Kleen 
896*30e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
897*30e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
898*30e863bbSAndi Kleen 			return;
899*30e863bbSAndi Kleen 
900*30e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
901*30e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
902*30e863bbSAndi Kleen 
903*30e863bbSAndi Kleen 			if (dl)
904*30e863bbSAndi Kleen 				dl->ipc = ipc;
905*30e863bbSAndi Kleen 		}
906*30e863bbSAndi Kleen 	}
907*30e863bbSAndi Kleen }
908*30e863bbSAndi Kleen 
909*30e863bbSAndi Kleen /*
910*30e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
911*30e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
912*30e863bbSAndi Kleen  * which are only here.
913*30e863bbSAndi Kleen  */
914*30e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
915*30e863bbSAndi Kleen 			   struct symbol *sym)
916*30e863bbSAndi Kleen {
917*30e863bbSAndi Kleen 	u64 offset;
918*30e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
919*30e863bbSAndi Kleen 
920*30e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
921*30e863bbSAndi Kleen 		return;
922*30e863bbSAndi Kleen 
923*30e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
924*30e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
925*30e863bbSAndi Kleen 		struct cyc_hist *ch;
926*30e863bbSAndi Kleen 
927*30e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
928*30e863bbSAndi Kleen 		if (ch && ch->cycles) {
929*30e863bbSAndi Kleen 			struct disasm_line *dl;
930*30e863bbSAndi Kleen 
931*30e863bbSAndi Kleen 			if (ch->have_start)
932*30e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
933*30e863bbSAndi Kleen 			dl = browser->offsets[offset];
934*30e863bbSAndi Kleen 			if (dl && ch->num_aggr)
935*30e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
936*30e863bbSAndi Kleen 			browser->have_cycles = true;
937*30e863bbSAndi Kleen 		}
938*30e863bbSAndi Kleen 	}
939*30e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
940*30e863bbSAndi Kleen }
941*30e863bbSAndi Kleen 
942b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
943b793a401SArnaldo Carvalho de Melo 						size_t size)
944b793a401SArnaldo Carvalho de Melo {
945b793a401SArnaldo Carvalho de Melo 	u64 offset;
94632ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
94732ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
94832ae1efdSNamhyung Kim 
94932ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
95032ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
95132ae1efdSNamhyung Kim 		return;
952b793a401SArnaldo Carvalho de Melo 
953b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
954b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
955b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
956b793a401SArnaldo Carvalho de Melo 
957865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
958b793a401SArnaldo Carvalho de Melo 			continue;
959b793a401SArnaldo Carvalho de Melo 
96044d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
9619481ede9SArnaldo Carvalho de Melo 		/*
9629481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
9639481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
9649481ede9SArnaldo Carvalho de Melo  		 */
9659481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
9669481ede9SArnaldo Carvalho de Melo 			continue;
9679481ede9SArnaldo Carvalho de Melo 
968b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
9692402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
9702402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
9712402e4a9SArnaldo Carvalho de Melo 
9722402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
973b793a401SArnaldo Carvalho de Melo 	}
974b793a401SArnaldo Carvalho de Melo }
975b793a401SArnaldo Carvalho de Melo 
9762402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
9772402e4a9SArnaldo Carvalho de Melo {
9782402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
9792402e4a9SArnaldo Carvalho de Melo 		return 5;
9802402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
9812402e4a9SArnaldo Carvalho de Melo 		return 2;
9822402e4a9SArnaldo Carvalho de Melo 	return 1;
9832402e4a9SArnaldo Carvalho de Melo }
9842402e4a9SArnaldo Carvalho de Melo 
985db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
986db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
9879783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
988aca7a94dSNamhyung Kim {
98929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
990aca7a94dSNamhyung Kim 	struct annotation *notes;
991c0a58fb2SSamuel Liao 	size_t size;
992aca7a94dSNamhyung Kim 	struct map_symbol ms = {
993aca7a94dSNamhyung Kim 		.map = map,
994aca7a94dSNamhyung Kim 		.sym = sym,
995aca7a94dSNamhyung Kim 	};
996aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
997aca7a94dSNamhyung Kim 		.b = {
998a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
999aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1000aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
100129ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1002aca7a94dSNamhyung Kim 			.priv	 = &ms,
1003aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1004aca7a94dSNamhyung Kim 		},
1005aca7a94dSNamhyung Kim 	};
1006b793a401SArnaldo Carvalho de Melo 	int ret = -1;
1007c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1008c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1009aca7a94dSNamhyung Kim 
1010aca7a94dSNamhyung Kim 	if (sym == NULL)
1011aca7a94dSNamhyung Kim 		return -1;
1012aca7a94dSNamhyung Kim 
1013c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1014c0a58fb2SSamuel Liao 
1015aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1016aca7a94dSNamhyung Kim 		return -1;
1017aca7a94dSNamhyung Kim 
1018b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1019b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1020b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1021b793a401SArnaldo Carvalho de Melo 		return -1;
1022b793a401SArnaldo Carvalho de Melo 	}
1023b793a401SArnaldo Carvalho de Melo 
1024c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1025c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
10260c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
10270c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1028c7e7b610SNamhyung Kim 	}
1029c7e7b610SNamhyung Kim 
1030c7e7b610SNamhyung Kim 	if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
1031aca7a94dSNamhyung Kim 		ui__error("%s", ui_helpline__last_msg);
1032b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1033aca7a94dSNamhyung Kim 	}
1034aca7a94dSNamhyung Kim 
1035aca7a94dSNamhyung Kim 	ui_helpline__push("Press <- or ESC to exit");
1036aca7a94dSNamhyung Kim 
1037aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1038aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1039aca7a94dSNamhyung Kim 
1040aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1041887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1042aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1043aca7a94dSNamhyung Kim 
1044aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1045aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1046887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1047887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1048b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1049887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
105097148a97SArnaldo Carvalho de Melo 			/*
105197148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
105297148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
105397148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
105497148a97SArnaldo Carvalho de Melo 			 *
105597148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
105697148a97SArnaldo Carvalho de Melo  			 */
105797148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1058b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1059b793a401SArnaldo Carvalho de Melo 		} else
1060887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1061aca7a94dSNamhyung Kim 	}
1062aca7a94dSNamhyung Kim 
1063b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
1064*30e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1065b793a401SArnaldo Carvalho de Melo 
10662402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
106783b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
10682402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1069c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1070aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1071aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1072aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1073e9823b21SArnaldo Carvalho de Melo 
1074e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1075e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1076e9823b21SArnaldo Carvalho de Melo 
1077e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1078e9823b21SArnaldo Carvalho de Melo 
1079db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1080aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1081aca7a94dSNamhyung Kim 		list_del(&pos->node);
108229ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1083aca7a94dSNamhyung Kim 	}
1084b793a401SArnaldo Carvalho de Melo 
1085b793a401SArnaldo Carvalho de Melo out_free_offsets:
1086b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1087aca7a94dSNamhyung Kim 	return ret;
1088aca7a94dSNamhyung Kim }
1089c323cf04SArnaldo Carvalho de Melo 
1090c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1091c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1092c323cf04SArnaldo Carvalho de Melo 
1093c323cf04SArnaldo Carvalho de Melo /*
1094c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1095c323cf04SArnaldo Carvalho de Melo  */
10967c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1097c323cf04SArnaldo Carvalho de Melo 	const char *name;
1098c323cf04SArnaldo Carvalho de Melo 	bool *value;
1099c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1100c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1101c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1102e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1103c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
1104c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(use_offset),
11050c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
1106c323cf04SArnaldo Carvalho de Melo };
1107c323cf04SArnaldo Carvalho de Melo 
1108c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1109c323cf04SArnaldo Carvalho de Melo 
1110c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1111c323cf04SArnaldo Carvalho de Melo {
11127c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1113c323cf04SArnaldo Carvalho de Melo 
1114c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1115c323cf04SArnaldo Carvalho de Melo }
1116c323cf04SArnaldo Carvalho de Melo 
11171d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11181d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1119c323cf04SArnaldo Carvalho de Melo {
11207c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1121c323cf04SArnaldo Carvalho de Melo 	const char *name;
1122c323cf04SArnaldo Carvalho de Melo 
1123c323cf04SArnaldo Carvalho de Melo 	if (prefixcmp(var, "annotate.") != 0)
1124c323cf04SArnaldo Carvalho de Melo 		return 0;
1125c323cf04SArnaldo Carvalho de Melo 
1126c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1127c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
11287c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1129c323cf04SArnaldo Carvalho de Melo 
1130c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1131c323cf04SArnaldo Carvalho de Melo 		return -1;
1132c323cf04SArnaldo Carvalho de Melo 
1133c323cf04SArnaldo Carvalho de Melo 	*cfg->value = perf_config_bool(name, value);
1134c323cf04SArnaldo Carvalho de Melo 	return 0;
1135c323cf04SArnaldo Carvalho de Melo }
1136c323cf04SArnaldo Carvalho de Melo 
1137c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1138c323cf04SArnaldo Carvalho de Melo {
1139c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1140c323cf04SArnaldo Carvalho de Melo }
1141