xref: /linux/tools/perf/ui/browsers/annotate.c (revision 1d5077bdd9a10c4297cded139989bb9ee2998a6c)
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 
14b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
15b793a401SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
16b793a401SArnaldo Carvalho de Melo 	u32		idx;
17b793a401SArnaldo Carvalho de Melo 	int		idx_asm;
187d5b12f5SArnaldo Carvalho de Melo 	int		jump_sources;
19c7e7b610SNamhyung Kim 	/*
20c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
21c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
22c7e7b610SNamhyung Kim 	 */
23ab77df67SNamhyung Kim 	double		percent[1];
24b793a401SArnaldo Carvalho de Melo };
25b793a401SArnaldo Carvalho de Melo 
26e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
27e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
28e9823b21SArnaldo Carvalho de Melo 	     use_offset,
29e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
30e9823b21SArnaldo Carvalho de Melo 	     show_nr_jumps;
31e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
32e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
33e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
34e9823b21SArnaldo Carvalho de Melo };
35e9823b21SArnaldo Carvalho de Melo 
36aca7a94dSNamhyung Kim struct annotate_browser {
37aca7a94dSNamhyung Kim 	struct ui_browser b;
38aca7a94dSNamhyung Kim 	struct rb_root	  entries;
39aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
4029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
41b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
42c7e7b610SNamhyung Kim 	int		    nr_events;
43aca7a94dSNamhyung Kim 	u64		    start;
44aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
45aca7a94dSNamhyung Kim 	int		    nr_entries;
462402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
472402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
48aca7a94dSNamhyung Kim 	bool		    searching_backwards;
4983b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
502402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
512402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
5283b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
5383b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
54aca7a94dSNamhyung Kim 	char		    search_bf[128];
55aca7a94dSNamhyung Kim };
56aca7a94dSNamhyung Kim 
57887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
58aca7a94dSNamhyung Kim {
59887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
60aca7a94dSNamhyung Kim }
61aca7a94dSNamhyung Kim 
621d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
631d037ca1SIrina Tirdea 				void *entry)
64aca7a94dSNamhyung Kim {
65e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
6629ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
6729ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
68aca7a94dSNamhyung Kim 	}
69aca7a94dSNamhyung Kim 
70aca7a94dSNamhyung Kim 	return false;
71aca7a94dSNamhyung Kim }
72aca7a94dSNamhyung Kim 
732402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
742402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
752402e4a9SArnaldo Carvalho de Melo {
762402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
772402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
782402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
792402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
802402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
812402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
822402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
832402e4a9SArnaldo Carvalho de Melo }
842402e4a9SArnaldo Carvalho de Melo 
852402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
862402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
872402e4a9SArnaldo Carvalho de Melo {
882402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
892402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
902402e4a9SArnaldo Carvalho de Melo }
912402e4a9SArnaldo Carvalho de Melo 
9205e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
93aca7a94dSNamhyung Kim {
9405e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
96b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
9705e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
98e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
9905e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
10005e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
10105e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
102c7e7b610SNamhyung Kim 	int i, pcnt_width = 7 * ab->nr_events;
103c7e7b610SNamhyung Kim 	double percent_max = 0.0;
10483b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
105aca7a94dSNamhyung Kim 
106c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
107c7e7b610SNamhyung Kim 		if (bdl->percent[i] > percent_max)
108c7e7b610SNamhyung Kim 			percent_max = bdl->percent[i];
109c7e7b610SNamhyung Kim 	}
110c7e7b610SNamhyung Kim 
111c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
112c7e7b610SNamhyung Kim 		for (i = 0; i < ab->nr_events; i++) {
113c7e7b610SNamhyung Kim 			ui_browser__set_percent_color(browser, bdl->percent[i],
114c7e7b610SNamhyung Kim 						      current_entry);
115c7e7b610SNamhyung Kim 			slsmg_printf("%6.2f ", bdl->percent[i]);
116c7e7b610SNamhyung Kim 		}
117aca7a94dSNamhyung Kim 	} else {
11805e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
119c7e7b610SNamhyung Kim 		slsmg_write_nstring(" ", pcnt_width);
120aca7a94dSNamhyung Kim 	}
121aca7a94dSNamhyung Kim 
122cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
123aca7a94dSNamhyung Kim 
124aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
12505e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
126aca7a94dSNamhyung Kim 		width += 1;
127aca7a94dSNamhyung Kim 
12829ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
129c7e7b610SNamhyung Kim 		slsmg_write_nstring(" ", width - pcnt_width);
13083b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
13183b1f2aaSArnaldo Carvalho de Melo 		printed = scnprintf(bf, sizeof(bf), "%*s  ",
13283b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
13383b1f2aaSArnaldo Carvalho de Melo 		slsmg_write_nstring(bf, printed);
134c7e7b610SNamhyung Kim 		slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
13583b1f2aaSArnaldo Carvalho de Melo 	} else {
13629ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
13783b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
138aca7a94dSNamhyung Kim 
139e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
140aca7a94dSNamhyung Kim 			addr += ab->start;
141aca7a94dSNamhyung Kim 
142e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
143aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
14461e04b33SArnaldo Carvalho de Melo 		} else {
1457d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
146e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
1472402e4a9SArnaldo Carvalho de Melo 					int prev;
1482402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
1492402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
1502402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
1512402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
1522402e4a9SArnaldo Carvalho de Melo 											 current_entry);
1532402e4a9SArnaldo Carvalho de Melo 					slsmg_write_nstring(bf, printed);
15405e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
1552402e4a9SArnaldo Carvalho de Melo 				}
1562402e4a9SArnaldo Carvalho de Melo 
15761e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
1582402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
15961e04b33SArnaldo Carvalho de Melo 			} else {
16061e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
16183b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
16261e04b33SArnaldo Carvalho de Melo 			}
16361e04b33SArnaldo Carvalho de Melo 		}
164b793a401SArnaldo Carvalho de Melo 
165aca7a94dSNamhyung Kim 		if (change_color)
16605e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
167aca7a94dSNamhyung Kim 		slsmg_write_nstring(bf, printed);
168aca7a94dSNamhyung Kim 		if (change_color)
16905e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
17028548d78SArnaldo Carvalho de Melo 		if (dl->ins && dl->ins->ops->scnprintf) {
17151a0d455SArnaldo Carvalho de Melo 			if (ins__is_jump(dl->ins)) {
17244d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
17351a0d455SArnaldo Carvalho de Melo 
17405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
17551a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
17651a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
17788298f5aSArnaldo Carvalho de Melo 			} else if (ins__is_call(dl->ins)) {
17805e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
17988298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
18051a0d455SArnaldo Carvalho de Melo 			} else {
18151a0d455SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
18251a0d455SArnaldo Carvalho de Melo 			}
1834ea08b52SArnaldo Carvalho de Melo 		} else {
1844ea08b52SArnaldo Carvalho de Melo 			if (strcmp(dl->name, "retq")) {
1854ea08b52SArnaldo Carvalho de Melo 				slsmg_write_nstring(" ", 2);
1864ea08b52SArnaldo Carvalho de Melo 			} else {
18705e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
1884ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
1894ea08b52SArnaldo Carvalho de Melo 			}
1904ea08b52SArnaldo Carvalho de Melo 		}
1914ea08b52SArnaldo Carvalho de Melo 
192e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
193c7e7b610SNamhyung Kim 		slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
194aca7a94dSNamhyung Kim 	}
195aca7a94dSNamhyung Kim 
196aca7a94dSNamhyung Kim 	if (current_entry)
19729ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
198aca7a94dSNamhyung Kim }
199aca7a94dSNamhyung Kim 
200865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
201865c66c4SFrederik Deweerdt {
202865c66c4SFrederik Deweerdt 	if (!dl || !dl->ins || !ins__is_jump(dl->ins)
203865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
204865c66c4SFrederik Deweerdt 	    || dl->ops.target.offset >= symbol__size(sym))
205865c66c4SFrederik Deweerdt 		return false;
206865c66c4SFrederik Deweerdt 
207865c66c4SFrederik Deweerdt 	return true;
208865c66c4SFrederik Deweerdt }
209865c66c4SFrederik Deweerdt 
2109d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
211a3f895beSArnaldo Carvalho de Melo {
212a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
2139d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
2149d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
21583b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
21632ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
21732ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
218c7e7b610SNamhyung Kim 	u8 pcnt_width = 7;
21932ae1efdSNamhyung Kim 
22032ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
22132ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
22232ae1efdSNamhyung Kim 		return;
223a3f895beSArnaldo Carvalho de Melo 
224865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
225a3f895beSArnaldo Carvalho de Melo 		return;
226a3f895beSArnaldo Carvalho de Melo 
2279d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
2289d1ef56dSArnaldo Carvalho de Melo 	if (!target)
2299d1ef56dSArnaldo Carvalho de Melo 		return;
2309d1ef56dSArnaldo Carvalho de Melo 
2319d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2329d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2339d1ef56dSArnaldo Carvalho de Melo 
234e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2359d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
236a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
237a3f895beSArnaldo Carvalho de Melo 	} else {
2389d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
239a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
240a3f895beSArnaldo Carvalho de Melo 	}
241a3f895beSArnaldo Carvalho de Melo 
242c7e7b610SNamhyung Kim 	pcnt_width *= ab->nr_events;
243c7e7b610SNamhyung Kim 
244a3f895beSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_CODE);
245c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
246c7e7b610SNamhyung Kim 				 from, to);
247a3f895beSArnaldo Carvalho de Melo }
248a3f895beSArnaldo Carvalho de Melo 
249a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
250a3f895beSArnaldo Carvalho de Melo {
251c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
252a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
253c7e7b610SNamhyung Kim 	int pcnt_width;
254c7e7b610SNamhyung Kim 
255c7e7b610SNamhyung Kim 	pcnt_width = 7 * ab->nr_events;
256a3f895beSArnaldo Carvalho de Melo 
257e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
2589d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
259a3f895beSArnaldo Carvalho de Melo 
26083b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
261c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
262a3f895beSArnaldo Carvalho de Melo 	return ret;
263a3f895beSArnaldo Carvalho de Melo }
264a3f895beSArnaldo Carvalho de Melo 
265c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
266c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
267c7e7b610SNamhyung Kim {
268c7e7b610SNamhyung Kim 	int i;
269c7e7b610SNamhyung Kim 
270c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
271c7e7b610SNamhyung Kim 		if (a->percent[i] == b->percent[i])
272c7e7b610SNamhyung Kim 			continue;
273c7e7b610SNamhyung Kim 		return a->percent[i] < b->percent[i];
274c7e7b610SNamhyung Kim 	}
275c7e7b610SNamhyung Kim 	return 0;
276c7e7b610SNamhyung Kim }
277c7e7b610SNamhyung Kim 
278c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
279c7e7b610SNamhyung Kim 				   int nr_events)
280aca7a94dSNamhyung Kim {
28129ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
282aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
283887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
284aca7a94dSNamhyung Kim 
285aca7a94dSNamhyung Kim 	while (*p != NULL) {
286aca7a94dSNamhyung Kim 		parent = *p;
287887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
288c7e7b610SNamhyung Kim 
289c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
290aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
291aca7a94dSNamhyung Kim 		else
292aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
293aca7a94dSNamhyung Kim 	}
294887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
295887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
296aca7a94dSNamhyung Kim }
297aca7a94dSNamhyung Kim 
29805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
29929ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
300aca7a94dSNamhyung Kim {
301aca7a94dSNamhyung Kim 	unsigned back;
302aca7a94dSNamhyung Kim 
30305e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
30405e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
30505e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
306aca7a94dSNamhyung Kim 
30705e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
30829ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
309aca7a94dSNamhyung Kim 
31005e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
311aca7a94dSNamhyung Kim 			continue;
312aca7a94dSNamhyung Kim 
31305e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
314aca7a94dSNamhyung Kim 		--back;
315aca7a94dSNamhyung Kim 	}
316aca7a94dSNamhyung Kim 
31705e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
31805e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
319aca7a94dSNamhyung Kim }
320aca7a94dSNamhyung Kim 
321aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
322aca7a94dSNamhyung Kim 					 struct rb_node *nd)
323aca7a94dSNamhyung Kim {
324887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
32529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
326a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
327aca7a94dSNamhyung Kim 
328887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
329887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
330a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
331e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
332a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
333a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
334aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
335aca7a94dSNamhyung Kim }
336aca7a94dSNamhyung Kim 
337aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
338db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
339aca7a94dSNamhyung Kim {
340aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
341aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
342aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
343e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
344e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
345aca7a94dSNamhyung Kim 
346aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
347aca7a94dSNamhyung Kim 
348aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
349aca7a94dSNamhyung Kim 
350aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
351887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
352e64aa75bSNamhyung Kim 		const char *path = NULL;
353c7e7b610SNamhyung Kim 		double max_percent = 0.0;
354c7e7b610SNamhyung Kim 		int i;
355e64aa75bSNamhyung Kim 
356e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
357e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
358e64aa75bSNamhyung Kim 			continue;
359e64aa75bSNamhyung Kim 		}
360e64aa75bSNamhyung Kim 
361e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
362c7e7b610SNamhyung Kim 
363c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
364c7e7b610SNamhyung Kim 			bpos->percent[i] = disasm__calc_percent(notes,
365c7e7b610SNamhyung Kim 						evsel->idx + i,
366c7e7b610SNamhyung Kim 						pos->offset,
367c7e7b610SNamhyung Kim 						next ? next->offset : len,
368e64aa75bSNamhyung Kim 					        &path);
369e64aa75bSNamhyung Kim 
370c7e7b610SNamhyung Kim 			if (max_percent < bpos->percent[i])
371c7e7b610SNamhyung Kim 				max_percent = bpos->percent[i];
372c7e7b610SNamhyung Kim 		}
373c7e7b610SNamhyung Kim 
374c7e7b610SNamhyung Kim 		if (max_percent < 0.01) {
375887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
376aca7a94dSNamhyung Kim 			continue;
377aca7a94dSNamhyung Kim 		}
378c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
379c7e7b610SNamhyung Kim 				       browser->nr_events);
380aca7a94dSNamhyung Kim 	}
381aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
382aca7a94dSNamhyung Kim 
383aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
384aca7a94dSNamhyung Kim }
385aca7a94dSNamhyung Kim 
386aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
387aca7a94dSNamhyung Kim {
38829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
389887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
390aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
391aca7a94dSNamhyung Kim 
392aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
39329ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
394887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
395aca7a94dSNamhyung Kim 
396e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
397887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
398887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
399aca7a94dSNamhyung Kim 
400aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
401e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
402aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
403887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
404887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
405aca7a94dSNamhyung Kim 	} else {
406887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
407aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
408aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
409aca7a94dSNamhyung Kim 			return false;
410aca7a94dSNamhyung Kim 		}
411aca7a94dSNamhyung Kim 
412887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
413887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
414aca7a94dSNamhyung Kim 
415aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
416e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
417aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
418887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
419887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
420aca7a94dSNamhyung Kim 	}
421aca7a94dSNamhyung Kim 
422aca7a94dSNamhyung Kim 	return true;
423aca7a94dSNamhyung Kim }
424aca7a94dSNamhyung Kim 
425e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
426e9823b21SArnaldo Carvalho de Melo {
427e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
428e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
429e9823b21SArnaldo Carvalho de Melo }
430e9823b21SArnaldo Carvalho de Melo 
43134f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
43234f77abcSAdrian Hunter 
43334f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
43434f77abcSAdrian Hunter 		     size_t sz)
43534f77abcSAdrian Hunter {
43634f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
43734f77abcSAdrian Hunter }
43834f77abcSAdrian Hunter 
439db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
440db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
4419783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
442aca7a94dSNamhyung Kim {
443aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
444657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
445aca7a94dSNamhyung Kim 	struct annotation *notes;
4461179e11bSAdrian Hunter 	struct addr_map_symbol target = {
4471179e11bSAdrian Hunter 		.map = ms->map,
448*1d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
4491179e11bSAdrian Hunter 	};
45034f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
451aca7a94dSNamhyung Kim 
452d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_call(dl->ins))
453aca7a94dSNamhyung Kim 		return false;
454aca7a94dSNamhyung Kim 
455*1d5077bdSAdrian Hunter 	if (map_groups__find_ams(&target, NULL) ||
456*1d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
457*1d5077bdSAdrian Hunter 							     target.addr)) !=
458*1d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
459aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
460aca7a94dSNamhyung Kim 		return true;
461aca7a94dSNamhyung Kim 	}
462aca7a94dSNamhyung Kim 
4631179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
464aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
465aca7a94dSNamhyung Kim 
4661179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
467aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
468aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
4691179e11bSAdrian Hunter 			    target.sym->name);
470aca7a94dSNamhyung Kim 		return true;
471aca7a94dSNamhyung Kim 	}
472aca7a94dSNamhyung Kim 
473aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
4741179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
4751179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
47634f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
477aca7a94dSNamhyung Kim 	return true;
478aca7a94dSNamhyung Kim }
479aca7a94dSNamhyung Kim 
48029ed6e76SArnaldo Carvalho de Melo static
48129ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
482aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
483aca7a94dSNamhyung Kim {
484aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
485aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
486aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
48729ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
488aca7a94dSNamhyung Kim 
489aca7a94dSNamhyung Kim 	*idx = 0;
490aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
491aca7a94dSNamhyung Kim 		if (pos->offset == offset)
492aca7a94dSNamhyung Kim 			return pos;
49329ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
494aca7a94dSNamhyung Kim 			++*idx;
495aca7a94dSNamhyung Kim 	}
496aca7a94dSNamhyung Kim 
497aca7a94dSNamhyung Kim 	return NULL;
498aca7a94dSNamhyung Kim }
499aca7a94dSNamhyung Kim 
500aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
501aca7a94dSNamhyung Kim {
502657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
5034f9d0325SArnaldo Carvalho de Melo 	s64 idx;
504aca7a94dSNamhyung Kim 
505d86b0597SArnaldo Carvalho de Melo 	if (!ins__is_jump(dl->ins))
506aca7a94dSNamhyung Kim 		return false;
507aca7a94dSNamhyung Kim 
50844d1a3edSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
50929ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
510e6f65388SIngo Molnar 		ui_helpline__puts("Invalid jump offset");
511aca7a94dSNamhyung Kim 		return true;
512aca7a94dSNamhyung Kim 	}
513aca7a94dSNamhyung Kim 
51429ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
515aca7a94dSNamhyung Kim 
516aca7a94dSNamhyung Kim 	return true;
517aca7a94dSNamhyung Kim }
518aca7a94dSNamhyung Kim 
51929ed6e76SArnaldo Carvalho de Melo static
52029ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
521aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
522aca7a94dSNamhyung Kim {
523aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
524aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
525aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
52629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
527aca7a94dSNamhyung Kim 
528aca7a94dSNamhyung Kim 	*idx = browser->b.index;
529aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
53029ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
531aca7a94dSNamhyung Kim 			continue;
532aca7a94dSNamhyung Kim 
533aca7a94dSNamhyung Kim 		++*idx;
534aca7a94dSNamhyung Kim 
535aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
536aca7a94dSNamhyung Kim 			return pos;
537aca7a94dSNamhyung Kim 	}
538aca7a94dSNamhyung Kim 
539aca7a94dSNamhyung Kim 	return NULL;
540aca7a94dSNamhyung Kim }
541aca7a94dSNamhyung Kim 
542aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
543aca7a94dSNamhyung Kim {
54429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
545aca7a94dSNamhyung Kim 	s64 idx;
546aca7a94dSNamhyung Kim 
54729ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
54829ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
549aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
550aca7a94dSNamhyung Kim 		return false;
551aca7a94dSNamhyung Kim 	}
552aca7a94dSNamhyung Kim 
55329ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
554aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
555aca7a94dSNamhyung Kim 	return true;
556aca7a94dSNamhyung Kim }
557aca7a94dSNamhyung Kim 
55829ed6e76SArnaldo Carvalho de Melo static
55929ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
560aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
561aca7a94dSNamhyung Kim {
562aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
563aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
564aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
56529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
566aca7a94dSNamhyung Kim 
567aca7a94dSNamhyung Kim 	*idx = browser->b.index;
568aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
56929ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
570aca7a94dSNamhyung Kim 			continue;
571aca7a94dSNamhyung Kim 
572aca7a94dSNamhyung Kim 		--*idx;
573aca7a94dSNamhyung Kim 
574aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
575aca7a94dSNamhyung Kim 			return pos;
576aca7a94dSNamhyung Kim 	}
577aca7a94dSNamhyung Kim 
578aca7a94dSNamhyung Kim 	return NULL;
579aca7a94dSNamhyung Kim }
580aca7a94dSNamhyung Kim 
581aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
582aca7a94dSNamhyung Kim {
58329ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
584aca7a94dSNamhyung Kim 	s64 idx;
585aca7a94dSNamhyung Kim 
58629ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
58729ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
588aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
589aca7a94dSNamhyung Kim 		return false;
590aca7a94dSNamhyung Kim 	}
591aca7a94dSNamhyung Kim 
59229ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
593aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
594aca7a94dSNamhyung Kim 	return true;
595aca7a94dSNamhyung Kim }
596aca7a94dSNamhyung Kim 
597aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
598aca7a94dSNamhyung Kim 					    int delay_secs)
599aca7a94dSNamhyung Kim {
600aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
601aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
602aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
603aca7a94dSNamhyung Kim 	    !*browser->search_bf)
604aca7a94dSNamhyung Kim 		return false;
605aca7a94dSNamhyung Kim 
606aca7a94dSNamhyung Kim 	return true;
607aca7a94dSNamhyung Kim }
608aca7a94dSNamhyung Kim 
609aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
610aca7a94dSNamhyung Kim {
611aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
612aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
613aca7a94dSNamhyung Kim 
614aca7a94dSNamhyung Kim 	return false;
615aca7a94dSNamhyung Kim }
616aca7a94dSNamhyung Kim 
617aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
618aca7a94dSNamhyung Kim 					      int delay_secs)
619aca7a94dSNamhyung Kim {
620aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
621aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
622aca7a94dSNamhyung Kim 
623aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
624aca7a94dSNamhyung Kim }
625aca7a94dSNamhyung Kim 
626aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
627aca7a94dSNamhyung Kim 					   int delay_secs)
628aca7a94dSNamhyung Kim {
629aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
630aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
631aca7a94dSNamhyung Kim 
632aca7a94dSNamhyung Kim 	return false;
633aca7a94dSNamhyung Kim }
634aca7a94dSNamhyung Kim 
635aca7a94dSNamhyung Kim static
636aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
637aca7a94dSNamhyung Kim 					       int delay_secs)
638aca7a94dSNamhyung Kim {
639aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
640aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
641aca7a94dSNamhyung Kim 
642aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
643aca7a94dSNamhyung Kim }
644aca7a94dSNamhyung Kim 
645e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
646e9823b21SArnaldo Carvalho de Melo {
647e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
648e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
649e9823b21SArnaldo Carvalho de Melo 	else
650e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
651e9823b21SArnaldo Carvalho de Melo 
652e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
653e9823b21SArnaldo Carvalho de Melo 
654e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
655e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
656e9823b21SArnaldo Carvalho de Melo }
657e9823b21SArnaldo Carvalho de Melo 
658db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
659db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
6609783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
661aca7a94dSNamhyung Kim {
662aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
66305e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
664aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
66554e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
6669783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
667aca7a94dSNamhyung Kim 	int key;
66834f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
669aca7a94dSNamhyung Kim 
67034f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
67134f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
672aca7a94dSNamhyung Kim 		return -1;
673aca7a94dSNamhyung Kim 
674db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
675aca7a94dSNamhyung Kim 
67605e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
67705e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
67805e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
679aca7a94dSNamhyung Kim 	}
680aca7a94dSNamhyung Kim 
68105e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
682aca7a94dSNamhyung Kim 
683aca7a94dSNamhyung Kim 	while (1) {
68405e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
685aca7a94dSNamhyung Kim 
686aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
687db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
688aca7a94dSNamhyung Kim 			/*
689aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
690aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
691aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
692aca7a94dSNamhyung Kim 			 */
693aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
694aca7a94dSNamhyung Kim 				nd = NULL;
695aca7a94dSNamhyung Kim 		}
696aca7a94dSNamhyung Kim 
697aca7a94dSNamhyung Kim 		switch (key) {
698aca7a94dSNamhyung Kim 		case K_TIMER:
6999783adf7SNamhyung Kim 			if (hbt)
7009783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
701aca7a94dSNamhyung Kim 
702aca7a94dSNamhyung Kim 			if (delay_secs != 0)
703db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
704aca7a94dSNamhyung Kim 			continue;
705aca7a94dSNamhyung Kim 		case K_TAB:
706aca7a94dSNamhyung Kim 			if (nd != NULL) {
707aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
708aca7a94dSNamhyung Kim 				if (nd == NULL)
70905e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
710aca7a94dSNamhyung Kim 			} else
71105e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
712aca7a94dSNamhyung Kim 			break;
713aca7a94dSNamhyung Kim 		case K_UNTAB:
714aca7a94dSNamhyung Kim 			if (nd != NULL)
715aca7a94dSNamhyung Kim 				nd = rb_next(nd);
716aca7a94dSNamhyung Kim 				if (nd == NULL)
71705e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
718aca7a94dSNamhyung Kim 			else
71905e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
720aca7a94dSNamhyung Kim 			break;
72154e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
722aca7a94dSNamhyung Kim 		case 'h':
72305e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
72454e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
72554e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
72654e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
72754e7a4e8SArnaldo Carvalho de Melo 		"->            Go to target\n"
72854e7a4e8SArnaldo Carvalho de Melo 		"<-            Exit\n"
729107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
73054e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
73154e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
73254e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
73354e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
73454e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
73554e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
73679ee47faSFeng Tang 		"r             Run available scripts\n"
737fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
73854e7a4e8SArnaldo Carvalho de Melo 			continue;
73979ee47faSFeng Tang 		case 'r':
74079ee47faSFeng Tang 			{
74179ee47faSFeng Tang 				script_browse(NULL);
74279ee47faSFeng Tang 				continue;
74379ee47faSFeng Tang 			}
74454e7a4e8SArnaldo Carvalho de Melo 		case 'H':
74505e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
746aca7a94dSNamhyung Kim 			break;
747aca7a94dSNamhyung Kim 		case 's':
74805e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
749aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
750aca7a94dSNamhyung Kim 			continue;
751aca7a94dSNamhyung Kim 		case 'o':
752e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
75305e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
754aca7a94dSNamhyung Kim 			continue;
7559d1ef56dSArnaldo Carvalho de Melo 		case 'j':
756e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
7579d1ef56dSArnaldo Carvalho de Melo 			continue;
7582402e4a9SArnaldo Carvalho de Melo 		case 'J':
759e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
76005e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
761e9823b21SArnaldo Carvalho de Melo 			continue;
762aca7a94dSNamhyung Kim 		case '/':
76305e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
764aca7a94dSNamhyung Kim show_help:
765aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
766aca7a94dSNamhyung Kim 			}
767aca7a94dSNamhyung Kim 			continue;
768aca7a94dSNamhyung Kim 		case 'n':
76905e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
77005e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
77105e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
772aca7a94dSNamhyung Kim 				goto show_help;
773aca7a94dSNamhyung Kim 			continue;
774aca7a94dSNamhyung Kim 		case '?':
77505e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
776aca7a94dSNamhyung Kim 				goto show_help;
777aca7a94dSNamhyung Kim 			continue;
778e9823b21SArnaldo Carvalho de Melo 		case 'D': {
779e9823b21SArnaldo Carvalho de Melo 			static int seq;
780e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
781e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
78205e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
78305e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
78405e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
78505e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
78605e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
787e9823b21SArnaldo Carvalho de Melo 		}
788e9823b21SArnaldo Carvalho de Melo 			continue;
789aca7a94dSNamhyung Kim 		case K_ENTER:
790aca7a94dSNamhyung Kim 		case K_RIGHT:
79105e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
792aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
79305e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
794aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
79505e8b080SArnaldo Carvalho de Melo 			else if (!browser->selection->ins) {
79605e8b080SArnaldo Carvalho de Melo 				if (strcmp(browser->selection->name, "retq"))
797c4cceae3SArnaldo Carvalho de Melo 					goto show_sup_ins;
798c4cceae3SArnaldo Carvalho de Melo 				goto out;
79905e8b080SArnaldo Carvalho de Melo 			} else if (!(annotate_browser__jump(browser) ||
800db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
801c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
802c4cceae3SArnaldo Carvalho de Melo 				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
803c4cceae3SArnaldo Carvalho de Melo 			}
804aca7a94dSNamhyung Kim 			continue;
805aca7a94dSNamhyung Kim 		case K_LEFT:
806aca7a94dSNamhyung Kim 		case K_ESC:
807aca7a94dSNamhyung Kim 		case 'q':
808aca7a94dSNamhyung Kim 		case CTRL('c'):
809aca7a94dSNamhyung Kim 			goto out;
810aca7a94dSNamhyung Kim 		default:
811aca7a94dSNamhyung Kim 			continue;
812aca7a94dSNamhyung Kim 		}
813aca7a94dSNamhyung Kim 
814aca7a94dSNamhyung Kim 		if (nd != NULL)
81505e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
816aca7a94dSNamhyung Kim 	}
817aca7a94dSNamhyung Kim out:
81805e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
819aca7a94dSNamhyung Kim 	return key;
820aca7a94dSNamhyung Kim }
821aca7a94dSNamhyung Kim 
822db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
8239783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
824aca7a94dSNamhyung Kim {
825db8fd07aSNamhyung Kim 	return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
826aca7a94dSNamhyung Kim }
827aca7a94dSNamhyung Kim 
828b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
829b793a401SArnaldo Carvalho de Melo 						size_t size)
830b793a401SArnaldo Carvalho de Melo {
831b793a401SArnaldo Carvalho de Melo 	u64 offset;
83232ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
83332ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
83432ae1efdSNamhyung Kim 
83532ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
83632ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
83732ae1efdSNamhyung Kim 		return;
838b793a401SArnaldo Carvalho de Melo 
839b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
840b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
841b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
842b793a401SArnaldo Carvalho de Melo 
843865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
844b793a401SArnaldo Carvalho de Melo 			continue;
845b793a401SArnaldo Carvalho de Melo 
84644d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
8479481ede9SArnaldo Carvalho de Melo 		/*
8489481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
8499481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
8509481ede9SArnaldo Carvalho de Melo  		 */
8519481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
8529481ede9SArnaldo Carvalho de Melo 			continue;
8539481ede9SArnaldo Carvalho de Melo 
854b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
8552402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
8562402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
8572402e4a9SArnaldo Carvalho de Melo 
8582402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
859b793a401SArnaldo Carvalho de Melo 	}
860b793a401SArnaldo Carvalho de Melo 
861b793a401SArnaldo Carvalho de Melo }
862b793a401SArnaldo Carvalho de Melo 
8632402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
8642402e4a9SArnaldo Carvalho de Melo {
8652402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
8662402e4a9SArnaldo Carvalho de Melo 		return 5;
8672402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
8682402e4a9SArnaldo Carvalho de Melo 		return 2;
8692402e4a9SArnaldo Carvalho de Melo 	return 1;
8702402e4a9SArnaldo Carvalho de Melo }
8712402e4a9SArnaldo Carvalho de Melo 
872db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
873db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
8749783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
875aca7a94dSNamhyung Kim {
87629ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
877aca7a94dSNamhyung Kim 	struct annotation *notes;
878c0a58fb2SSamuel Liao 	size_t size;
879aca7a94dSNamhyung Kim 	struct map_symbol ms = {
880aca7a94dSNamhyung Kim 		.map = map,
881aca7a94dSNamhyung Kim 		.sym = sym,
882aca7a94dSNamhyung Kim 	};
883aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
884aca7a94dSNamhyung Kim 		.b = {
885a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
886aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
887aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
88829ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
889aca7a94dSNamhyung Kim 			.priv	 = &ms,
890aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
891aca7a94dSNamhyung Kim 		},
892aca7a94dSNamhyung Kim 	};
893b793a401SArnaldo Carvalho de Melo 	int ret = -1;
894c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
895c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
896aca7a94dSNamhyung Kim 
897aca7a94dSNamhyung Kim 	if (sym == NULL)
898aca7a94dSNamhyung Kim 		return -1;
899aca7a94dSNamhyung Kim 
900c0a58fb2SSamuel Liao 	size = symbol__size(sym);
901c0a58fb2SSamuel Liao 
902aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
903aca7a94dSNamhyung Kim 		return -1;
904aca7a94dSNamhyung Kim 
905b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
906b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
907b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
908b793a401SArnaldo Carvalho de Melo 		return -1;
909b793a401SArnaldo Carvalho de Melo 	}
910b793a401SArnaldo Carvalho de Melo 
911c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
912c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
913c7e7b610SNamhyung Kim 		sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
914c7e7b610SNamhyung Kim 	}
915c7e7b610SNamhyung Kim 
916c7e7b610SNamhyung Kim 	if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
917aca7a94dSNamhyung Kim 		ui__error("%s", ui_helpline__last_msg);
918b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
919aca7a94dSNamhyung Kim 	}
920aca7a94dSNamhyung Kim 
921aca7a94dSNamhyung Kim 	ui_helpline__push("Press <- or ESC to exit");
922aca7a94dSNamhyung Kim 
923aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
924aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
925aca7a94dSNamhyung Kim 
926aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
927887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
928aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
929aca7a94dSNamhyung Kim 
930aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
931aca7a94dSNamhyung Kim 			browser.b.width = line_len;
932887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
933887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
934b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
935887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
93697148a97SArnaldo Carvalho de Melo 			/*
93797148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
93897148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
93997148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
94097148a97SArnaldo Carvalho de Melo 			 *
94197148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
94297148a97SArnaldo Carvalho de Melo  			 */
94397148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
944b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
945b793a401SArnaldo Carvalho de Melo 		} else
946887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
947aca7a94dSNamhyung Kim 	}
948aca7a94dSNamhyung Kim 
949b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
950b793a401SArnaldo Carvalho de Melo 
9512402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
95283b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
9532402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
954c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
955aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
956aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
957aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
958e9823b21SArnaldo Carvalho de Melo 
959e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
960e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
961e9823b21SArnaldo Carvalho de Melo 
962e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
963e9823b21SArnaldo Carvalho de Melo 
964db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
965aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
966aca7a94dSNamhyung Kim 		list_del(&pos->node);
96729ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
968aca7a94dSNamhyung Kim 	}
969b793a401SArnaldo Carvalho de Melo 
970b793a401SArnaldo Carvalho de Melo out_free_offsets:
971b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
972aca7a94dSNamhyung Kim 	return ret;
973aca7a94dSNamhyung Kim }
974c323cf04SArnaldo Carvalho de Melo 
975c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
976c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
977c323cf04SArnaldo Carvalho de Melo 
978c323cf04SArnaldo Carvalho de Melo /*
979c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
980c323cf04SArnaldo Carvalho de Melo  */
9817c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
982c323cf04SArnaldo Carvalho de Melo 	const char *name;
983c323cf04SArnaldo Carvalho de Melo 	bool *value;
984c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
985c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
986c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
987c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
988c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(use_offset),
989c323cf04SArnaldo Carvalho de Melo };
990c323cf04SArnaldo Carvalho de Melo 
991c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
992c323cf04SArnaldo Carvalho de Melo 
993c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
994c323cf04SArnaldo Carvalho de Melo {
9957c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
996c323cf04SArnaldo Carvalho de Melo 
997c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
998c323cf04SArnaldo Carvalho de Melo }
999c323cf04SArnaldo Carvalho de Melo 
10001d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
10011d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1002c323cf04SArnaldo Carvalho de Melo {
10037c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1004c323cf04SArnaldo Carvalho de Melo 	const char *name;
1005c323cf04SArnaldo Carvalho de Melo 
1006c323cf04SArnaldo Carvalho de Melo 	if (prefixcmp(var, "annotate.") != 0)
1007c323cf04SArnaldo Carvalho de Melo 		return 0;
1008c323cf04SArnaldo Carvalho de Melo 
1009c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1010c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
10117c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1012c323cf04SArnaldo Carvalho de Melo 
1013c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1014c323cf04SArnaldo Carvalho de Melo 		return -1;
1015c323cf04SArnaldo Carvalho de Melo 
1016c323cf04SArnaldo Carvalho de Melo 	*cfg->value = perf_config_bool(name, value);
1017c323cf04SArnaldo Carvalho de Melo 	return 0;
1018c323cf04SArnaldo Carvalho de Melo }
1019c323cf04SArnaldo Carvalho de Melo 
1020c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1021c323cf04SArnaldo Carvalho de Melo {
1022c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1023c323cf04SArnaldo Carvalho de Melo }
1024