xref: /linux/tools/perf/ui/browsers/annotate.c (revision 5252b1aeabd0ae794cfaf323c10968443f10a363)
1aca7a94dSNamhyung Kim #include "../../util/util.h"
2aca7a94dSNamhyung Kim #include "../browser.h"
3aca7a94dSNamhyung Kim #include "../helpline.h"
4aca7a94dSNamhyung Kim #include "../ui.h"
5aca7a94dSNamhyung Kim #include "../util.h"
6aca7a94dSNamhyung Kim #include "../../util/annotate.h"
7aca7a94dSNamhyung Kim #include "../../util/hist.h"
8aca7a94dSNamhyung Kim #include "../../util/sort.h"
9aca7a94dSNamhyung Kim #include "../../util/symbol.h"
10db8fd07aSNamhyung Kim #include "../../util/evsel.h"
1141840d21STaeung Song #include "../../util/config.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 
19f8f4aaeaSAndi Kleen #define IPC_WIDTH 6
20f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6
21f8f4aaeaSAndi Kleen 
22b793a401SArnaldo Carvalho de Melo struct browser_disasm_line {
23b793a401SArnaldo Carvalho de Melo 	struct rb_node			rb_node;
24b793a401SArnaldo Carvalho de Melo 	u32				idx;
25b793a401SArnaldo Carvalho de Melo 	int				idx_asm;
267d5b12f5SArnaldo Carvalho de Melo 	int				jump_sources;
27c7e7b610SNamhyung Kim 	/*
28c7e7b610SNamhyung Kim 	 * actual length of this array is saved on the nr_events field
29c7e7b610SNamhyung Kim 	 * of the struct annotate_browser
30c7e7b610SNamhyung Kim 	 */
310c4a5bceSMartin Liška 	struct disasm_line_samples	samples[1];
32b793a401SArnaldo Carvalho de Melo };
33b793a401SArnaldo Carvalho de Melo 
34e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt {
35e9823b21SArnaldo Carvalho de Melo 	bool hide_src_code,
36e9823b21SArnaldo Carvalho de Melo 	     use_offset,
37e9823b21SArnaldo Carvalho de Melo 	     jump_arrows,
38e592488cSAndi Kleen 	     show_linenr,
390c4a5bceSMartin Liška 	     show_nr_jumps,
400c4a5bceSMartin Liška 	     show_total_period;
41e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = {
42e9823b21SArnaldo Carvalho de Melo 	.use_offset	= true,
43e9823b21SArnaldo Carvalho de Melo 	.jump_arrows	= true,
44e9823b21SArnaldo Carvalho de Melo };
45e9823b21SArnaldo Carvalho de Melo 
46aca7a94dSNamhyung Kim struct annotate_browser {
47aca7a94dSNamhyung Kim 	struct ui_browser b;
48aca7a94dSNamhyung Kim 	struct rb_root	  entries;
49aca7a94dSNamhyung Kim 	struct rb_node	  *curr_hot;
5029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line  *selection;
51b793a401SArnaldo Carvalho de Melo 	struct disasm_line  **offsets;
52c7e7b610SNamhyung Kim 	int		    nr_events;
53aca7a94dSNamhyung Kim 	u64		    start;
54aca7a94dSNamhyung Kim 	int		    nr_asm_entries;
55aca7a94dSNamhyung Kim 	int		    nr_entries;
562402e4a9SArnaldo Carvalho de Melo 	int		    max_jump_sources;
572402e4a9SArnaldo Carvalho de Melo 	int		    nr_jumps;
58aca7a94dSNamhyung Kim 	bool		    searching_backwards;
5930e863bbSAndi Kleen 	bool		    have_cycles;
6083b1f2aaSArnaldo Carvalho de Melo 	u8		    addr_width;
612402e4a9SArnaldo Carvalho de Melo 	u8		    jumps_width;
622402e4a9SArnaldo Carvalho de Melo 	u8		    target_width;
6383b1f2aaSArnaldo Carvalho de Melo 	u8		    min_addr_width;
6483b1f2aaSArnaldo Carvalho de Melo 	u8		    max_addr_width;
65aca7a94dSNamhyung Kim 	char		    search_bf[128];
66aca7a94dSNamhyung Kim };
67aca7a94dSNamhyung Kim 
68887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
69aca7a94dSNamhyung Kim {
70887c0066SArnaldo Carvalho de Melo 	return (struct browser_disasm_line *)(dl + 1);
71aca7a94dSNamhyung Kim }
72aca7a94dSNamhyung Kim 
731d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
741d037ca1SIrina Tirdea 				void *entry)
75aca7a94dSNamhyung Kim {
76e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
7729ed6e76SArnaldo Carvalho de Melo 		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
7829ed6e76SArnaldo Carvalho de Melo 		return dl->offset == -1;
79aca7a94dSNamhyung Kim 	}
80aca7a94dSNamhyung Kim 
81aca7a94dSNamhyung Kim 	return false;
82aca7a94dSNamhyung Kim }
83aca7a94dSNamhyung Kim 
842402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
852402e4a9SArnaldo Carvalho de Melo 						 int nr, bool current)
862402e4a9SArnaldo Carvalho de Melo {
872402e4a9SArnaldo Carvalho de Melo 	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
882402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_SELECTED;
892402e4a9SArnaldo Carvalho de Melo 	if (nr == browser->max_jump_sources)
902402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_TOP;
912402e4a9SArnaldo Carvalho de Melo 	if (nr > 1)
922402e4a9SArnaldo Carvalho de Melo 		return HE_COLORSET_MEDIUM;
932402e4a9SArnaldo Carvalho de Melo 	return HE_COLORSET_NORMAL;
942402e4a9SArnaldo Carvalho de Melo }
952402e4a9SArnaldo Carvalho de Melo 
962402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
972402e4a9SArnaldo Carvalho de Melo 						     int nr, bool current)
982402e4a9SArnaldo Carvalho de Melo {
992402e4a9SArnaldo Carvalho de Melo 	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
1002402e4a9SArnaldo Carvalho de Melo 	 return ui_browser__set_color(&browser->b, color);
1012402e4a9SArnaldo Carvalho de Melo }
1022402e4a9SArnaldo Carvalho de Melo 
103f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab)
104f8f4aaeaSAndi Kleen {
105f8f4aaeaSAndi Kleen 	int w = 7 * ab->nr_events;
106f8f4aaeaSAndi Kleen 
107f8f4aaeaSAndi Kleen 	if (ab->have_cycles)
108f8f4aaeaSAndi Kleen 		w += IPC_WIDTH + CYCLES_WIDTH;
109f8f4aaeaSAndi Kleen 	return w;
110f8f4aaeaSAndi Kleen }
111f8f4aaeaSAndi Kleen 
11205e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
113aca7a94dSNamhyung Kim {
11405e8b080SArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
11529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
116b793a401SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
11705e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(browser, row);
118e9823b21SArnaldo Carvalho de Melo 	bool change_color = (!annotate_browser__opts.hide_src_code &&
11905e8b080SArnaldo Carvalho de Melo 			     (!current_entry || (browser->use_navkeypressed &&
12005e8b080SArnaldo Carvalho de Melo 					         !browser->navkeypressed)));
12105e8b080SArnaldo Carvalho de Melo 	int width = browser->width, printed;
122f8f4aaeaSAndi Kleen 	int i, pcnt_width = annotate_browser__pcnt_width(ab);
123c7e7b610SNamhyung Kim 	double percent_max = 0.0;
12483b1f2aaSArnaldo Carvalho de Melo 	char bf[256];
125aca7a94dSNamhyung Kim 
126c7e7b610SNamhyung Kim 	for (i = 0; i < ab->nr_events; i++) {
1270c4a5bceSMartin Liška 		if (bdl->samples[i].percent > percent_max)
1280c4a5bceSMartin Liška 			percent_max = bdl->samples[i].percent;
129c7e7b610SNamhyung Kim 	}
130c7e7b610SNamhyung Kim 
131c7e7b610SNamhyung Kim 	if (dl->offset != -1 && percent_max != 0.0) {
132f8f4aaeaSAndi Kleen 		if (percent_max != 0.0) {
133c7e7b610SNamhyung Kim 			for (i = 0; i < ab->nr_events; i++) {
1340c4a5bceSMartin Liška 				ui_browser__set_percent_color(browser,
1350c4a5bceSMartin Liška 							bdl->samples[i].percent,
136c7e7b610SNamhyung Kim 							current_entry);
137517dfdb3SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_total_period) {
138517dfdb3SArnaldo Carvalho de Melo 					ui_browser__printf(browser, "%6" PRIu64 " ",
1390c4a5bceSMartin Liška 							   bdl->samples[i].nr);
140517dfdb3SArnaldo Carvalho de Melo 				} else {
141517dfdb3SArnaldo Carvalho de Melo 					ui_browser__printf(browser, "%6.2f ",
142517dfdb3SArnaldo Carvalho de Melo 							   bdl->samples[i].percent);
143517dfdb3SArnaldo Carvalho de Melo 				}
144c7e7b610SNamhyung Kim 			}
145aca7a94dSNamhyung Kim 		} else {
14626270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
147f8f4aaeaSAndi Kleen 		}
148f8f4aaeaSAndi Kleen 	} else {
14905e8b080SArnaldo Carvalho de Melo 		ui_browser__set_percent_color(browser, 0, current_entry);
15026270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
151f8f4aaeaSAndi Kleen 	}
152f8f4aaeaSAndi Kleen 	if (ab->have_cycles) {
153f8f4aaeaSAndi Kleen 		if (dl->ipc)
154517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
155f8f4aaeaSAndi Kleen 		else
15626270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", IPC_WIDTH);
157f8f4aaeaSAndi Kleen 		if (dl->cycles)
158517dfdb3SArnaldo Carvalho de Melo 			ui_browser__printf(browser, "%*" PRIu64 " ",
159f8f4aaeaSAndi Kleen 					   CYCLES_WIDTH - 1, dl->cycles);
160f8f4aaeaSAndi Kleen 		else
16126270a00SArnaldo Carvalho de Melo 			ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
162aca7a94dSNamhyung Kim 	}
163aca7a94dSNamhyung Kim 
164cf2dacc5SArnaldo Carvalho de Melo 	SLsmg_write_char(' ');
165aca7a94dSNamhyung Kim 
166aca7a94dSNamhyung Kim 	/* The scroll bar isn't being used */
16705e8b080SArnaldo Carvalho de Melo 	if (!browser->navkeypressed)
168aca7a94dSNamhyung Kim 		width += 1;
169aca7a94dSNamhyung Kim 
17029ed6e76SArnaldo Carvalho de Melo 	if (!*dl->line)
17126270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, " ", width - pcnt_width);
17283b1f2aaSArnaldo Carvalho de Melo 	else if (dl->offset == -1) {
173e592488cSAndi Kleen 		if (dl->line_nr && annotate_browser__opts.show_linenr)
174e592488cSAndi Kleen 			printed = scnprintf(bf, sizeof(bf), "%-*d ",
175e592488cSAndi Kleen 					ab->addr_width + 1, dl->line_nr);
176e592488cSAndi Kleen 		else
17783b1f2aaSArnaldo Carvalho de Melo 			printed = scnprintf(bf, sizeof(bf), "%*s  ",
17883b1f2aaSArnaldo Carvalho de Melo 				    ab->addr_width, " ");
17926270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
18026270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
18183b1f2aaSArnaldo Carvalho de Melo 	} else {
18229ed6e76SArnaldo Carvalho de Melo 		u64 addr = dl->offset;
18383b1f2aaSArnaldo Carvalho de Melo 		int color = -1;
184aca7a94dSNamhyung Kim 
185e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset)
186aca7a94dSNamhyung Kim 			addr += ab->start;
187aca7a94dSNamhyung Kim 
188e9823b21SArnaldo Carvalho de Melo 		if (!annotate_browser__opts.use_offset) {
189aca7a94dSNamhyung Kim 			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
19061e04b33SArnaldo Carvalho de Melo 		} else {
1917d5b12f5SArnaldo Carvalho de Melo 			if (bdl->jump_sources) {
192e9823b21SArnaldo Carvalho de Melo 				if (annotate_browser__opts.show_nr_jumps) {
1932402e4a9SArnaldo Carvalho de Melo 					int prev;
1942402e4a9SArnaldo Carvalho de Melo 					printed = scnprintf(bf, sizeof(bf), "%*d ",
1952402e4a9SArnaldo Carvalho de Melo 							    ab->jumps_width,
1962402e4a9SArnaldo Carvalho de Melo 							    bdl->jump_sources);
1972402e4a9SArnaldo Carvalho de Melo 					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
1982402e4a9SArnaldo Carvalho de Melo 											 current_entry);
19926270a00SArnaldo Carvalho de Melo 					ui_browser__write_nstring(browser, bf, printed);
20005e8b080SArnaldo Carvalho de Melo 					ui_browser__set_color(browser, prev);
2012402e4a9SArnaldo Carvalho de Melo 				}
2022402e4a9SArnaldo Carvalho de Melo 
20361e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2042402e4a9SArnaldo Carvalho de Melo 						    ab->target_width, addr);
20561e04b33SArnaldo Carvalho de Melo 			} else {
20661e04b33SArnaldo Carvalho de Melo 				printed = scnprintf(bf, sizeof(bf), "%*s  ",
20783b1f2aaSArnaldo Carvalho de Melo 						    ab->addr_width, " ");
20861e04b33SArnaldo Carvalho de Melo 			}
20961e04b33SArnaldo Carvalho de Melo 		}
210b793a401SArnaldo Carvalho de Melo 
211aca7a94dSNamhyung Kim 		if (change_color)
21205e8b080SArnaldo Carvalho de Melo 			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
21326270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, printed);
214aca7a94dSNamhyung Kim 		if (change_color)
21505e8b080SArnaldo Carvalho de Melo 			ui_browser__set_color(browser, color);
21675b49202SArnaldo Carvalho de Melo 		if (dl->ins.ops && dl->ins.ops->scnprintf) {
21775b49202SArnaldo Carvalho de Melo 			if (ins__is_jump(&dl->ins)) {
21844d1a3edSArnaldo Carvalho de Melo 				bool fwd = dl->ops.target.offset > (u64)dl->offset;
21951a0d455SArnaldo Carvalho de Melo 
22005e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
22151a0d455SArnaldo Carvalho de Melo 								    SLSMG_UARROW_CHAR);
22251a0d455SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
22375b49202SArnaldo Carvalho de Melo 			} else if (ins__is_call(&dl->ins)) {
22405e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
22588298f5aSArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
22675b49202SArnaldo Carvalho de Melo 			} else if (ins__is_ret(&dl->ins)) {
22705e8b080SArnaldo Carvalho de Melo 				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
2284ea08b52SArnaldo Carvalho de Melo 				SLsmg_write_char(' ');
2296ef94929SNaveen N. Rao 			} else {
2306ef94929SNaveen N. Rao 				ui_browser__write_nstring(browser, " ", 2);
2314ea08b52SArnaldo Carvalho de Melo 			}
2326ef94929SNaveen N. Rao 		} else {
2336ef94929SNaveen N. Rao 			ui_browser__write_nstring(browser, " ", 2);
2344ea08b52SArnaldo Carvalho de Melo 		}
2354ea08b52SArnaldo Carvalho de Melo 
236e9823b21SArnaldo Carvalho de Melo 		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
23726270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
238aca7a94dSNamhyung Kim 	}
239aca7a94dSNamhyung Kim 
240aca7a94dSNamhyung Kim 	if (current_entry)
24129ed6e76SArnaldo Carvalho de Melo 		ab->selection = dl;
242aca7a94dSNamhyung Kim }
243aca7a94dSNamhyung Kim 
244865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
245865c66c4SFrederik Deweerdt {
24675b49202SArnaldo Carvalho de Melo 	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
247865c66c4SFrederik Deweerdt 	    || !disasm_line__has_offset(dl)
248865c66c4SFrederik Deweerdt 	    || dl->ops.target.offset >= symbol__size(sym))
249865c66c4SFrederik Deweerdt 		return false;
250865c66c4SFrederik Deweerdt 
251865c66c4SFrederik Deweerdt 	return true;
252865c66c4SFrederik Deweerdt }
253865c66c4SFrederik Deweerdt 
2549d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser)
255a3f895beSArnaldo Carvalho de Melo {
256a3f895beSArnaldo Carvalho de Melo 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
2579d1ef56dSArnaldo Carvalho de Melo 	struct disasm_line *cursor = ab->selection, *target;
2589d1ef56dSArnaldo Carvalho de Melo 	struct browser_disasm_line *btarget, *bcursor;
25983b1f2aaSArnaldo Carvalho de Melo 	unsigned int from, to;
26032ae1efdSNamhyung Kim 	struct map_symbol *ms = ab->b.priv;
26132ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
262f8f4aaeaSAndi Kleen 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
26332ae1efdSNamhyung Kim 
26432ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
26532ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
26632ae1efdSNamhyung Kim 		return;
267a3f895beSArnaldo Carvalho de Melo 
268865c66c4SFrederik Deweerdt 	if (!disasm_line__is_valid_jump(cursor, sym))
269a3f895beSArnaldo Carvalho de Melo 		return;
270a3f895beSArnaldo Carvalho de Melo 
2719d1ef56dSArnaldo Carvalho de Melo 	target = ab->offsets[cursor->ops.target.offset];
2729d1ef56dSArnaldo Carvalho de Melo 	if (!target)
2739d1ef56dSArnaldo Carvalho de Melo 		return;
2749d1ef56dSArnaldo Carvalho de Melo 
2759d1ef56dSArnaldo Carvalho de Melo 	bcursor = disasm_line__browser(cursor);
2769d1ef56dSArnaldo Carvalho de Melo 	btarget = disasm_line__browser(target);
2779d1ef56dSArnaldo Carvalho de Melo 
278e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
2799d1ef56dSArnaldo Carvalho de Melo 		from = bcursor->idx_asm;
280a3f895beSArnaldo Carvalho de Melo 		to = btarget->idx_asm;
281a3f895beSArnaldo Carvalho de Melo 	} else {
2829d1ef56dSArnaldo Carvalho de Melo 		from = (u64)bcursor->idx;
283a3f895beSArnaldo Carvalho de Melo 		to = (u64)btarget->idx;
284a3f895beSArnaldo Carvalho de Melo 	}
285a3f895beSArnaldo Carvalho de Melo 
28678ce08dfSTaeung Song 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
287c7e7b610SNamhyung Kim 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
288c7e7b610SNamhyung Kim 				 from, to);
289a3f895beSArnaldo Carvalho de Melo }
290a3f895beSArnaldo Carvalho de Melo 
291a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser)
292a3f895beSArnaldo Carvalho de Melo {
293c7e7b610SNamhyung Kim 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
294a3f895beSArnaldo Carvalho de Melo 	int ret = ui_browser__list_head_refresh(browser);
295f8f4aaeaSAndi Kleen 	int pcnt_width = annotate_browser__pcnt_width(ab);
296a3f895beSArnaldo Carvalho de Melo 
297e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.jump_arrows)
2989d1ef56dSArnaldo Carvalho de Melo 		annotate_browser__draw_current_jump(browser);
299a3f895beSArnaldo Carvalho de Melo 
30083b1f2aaSArnaldo Carvalho de Melo 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
301c7e7b610SNamhyung Kim 	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
302a3f895beSArnaldo Carvalho de Melo 	return ret;
303a3f895beSArnaldo Carvalho de Melo }
304a3f895beSArnaldo Carvalho de Melo 
305c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a,
306c7e7b610SNamhyung Kim 		       struct browser_disasm_line *b, int nr_pcnt)
307c7e7b610SNamhyung Kim {
308c7e7b610SNamhyung Kim 	int i;
309c7e7b610SNamhyung Kim 
310c7e7b610SNamhyung Kim 	for (i = 0; i < nr_pcnt; i++) {
3110c4a5bceSMartin Liška 		if (a->samples[i].percent == b->samples[i].percent)
312c7e7b610SNamhyung Kim 			continue;
3130c4a5bceSMartin Liška 		return a->samples[i].percent < b->samples[i].percent;
314c7e7b610SNamhyung Kim 	}
315c7e7b610SNamhyung Kim 	return 0;
316c7e7b610SNamhyung Kim }
317c7e7b610SNamhyung Kim 
318c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
319c7e7b610SNamhyung Kim 				   int nr_events)
320aca7a94dSNamhyung Kim {
32129ed6e76SArnaldo Carvalho de Melo 	struct rb_node **p = &root->rb_node;
322aca7a94dSNamhyung Kim 	struct rb_node *parent = NULL;
323887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *l;
324aca7a94dSNamhyung Kim 
325aca7a94dSNamhyung Kim 	while (*p != NULL) {
326aca7a94dSNamhyung Kim 		parent = *p;
327887c0066SArnaldo Carvalho de Melo 		l = rb_entry(parent, struct browser_disasm_line, rb_node);
328c7e7b610SNamhyung Kim 
329c7e7b610SNamhyung Kim 		if (disasm__cmp(bdl, l, nr_events))
330aca7a94dSNamhyung Kim 			p = &(*p)->rb_left;
331aca7a94dSNamhyung Kim 		else
332aca7a94dSNamhyung Kim 			p = &(*p)->rb_right;
333aca7a94dSNamhyung Kim 	}
334887c0066SArnaldo Carvalho de Melo 	rb_link_node(&bdl->rb_node, parent, p);
335887c0066SArnaldo Carvalho de Melo 	rb_insert_color(&bdl->rb_node, root);
336aca7a94dSNamhyung Kim }
337aca7a94dSNamhyung Kim 
33805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser,
33929ed6e76SArnaldo Carvalho de Melo 				      struct disasm_line *pos, u32 idx)
340aca7a94dSNamhyung Kim {
341aca7a94dSNamhyung Kim 	unsigned back;
342aca7a94dSNamhyung Kim 
34305e8b080SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(&browser->b);
34405e8b080SArnaldo Carvalho de Melo 	back = browser->b.height / 2;
34505e8b080SArnaldo Carvalho de Melo 	browser->b.top_idx = browser->b.index = idx;
346aca7a94dSNamhyung Kim 
34705e8b080SArnaldo Carvalho de Melo 	while (browser->b.top_idx != 0 && back != 0) {
34829ed6e76SArnaldo Carvalho de Melo 		pos = list_entry(pos->node.prev, struct disasm_line, node);
349aca7a94dSNamhyung Kim 
35005e8b080SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
351aca7a94dSNamhyung Kim 			continue;
352aca7a94dSNamhyung Kim 
35305e8b080SArnaldo Carvalho de Melo 		--browser->b.top_idx;
354aca7a94dSNamhyung Kim 		--back;
355aca7a94dSNamhyung Kim 	}
356aca7a94dSNamhyung Kim 
35705e8b080SArnaldo Carvalho de Melo 	browser->b.top = pos;
35805e8b080SArnaldo Carvalho de Melo 	browser->b.navkeypressed = true;
359aca7a94dSNamhyung Kim }
360aca7a94dSNamhyung Kim 
361aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser,
362aca7a94dSNamhyung Kim 					 struct rb_node *nd)
363aca7a94dSNamhyung Kim {
364887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bpos;
36529ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
366a44b45f2SArnaldo Carvalho de Melo 	u32 idx;
367aca7a94dSNamhyung Kim 
368887c0066SArnaldo Carvalho de Melo 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
369887c0066SArnaldo Carvalho de Melo 	pos = ((struct disasm_line *)bpos) - 1;
370a44b45f2SArnaldo Carvalho de Melo 	idx = bpos->idx;
371e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
372a44b45f2SArnaldo Carvalho de Melo 		idx = bpos->idx_asm;
373a44b45f2SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, pos, idx);
374aca7a94dSNamhyung Kim 	browser->curr_hot = nd;
375aca7a94dSNamhyung Kim }
376aca7a94dSNamhyung Kim 
377aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser,
378db8fd07aSNamhyung Kim 					   struct perf_evsel *evsel)
379aca7a94dSNamhyung Kim {
380aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
381aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
382aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
383e64aa75bSNamhyung Kim 	struct disasm_line *pos, *next;
384e64aa75bSNamhyung Kim 	s64 len = symbol__size(sym);
385aca7a94dSNamhyung Kim 
386aca7a94dSNamhyung Kim 	browser->entries = RB_ROOT;
387aca7a94dSNamhyung Kim 
388aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
389aca7a94dSNamhyung Kim 
390aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
391887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos = disasm_line__browser(pos);
392e64aa75bSNamhyung Kim 		const char *path = NULL;
393c7e7b610SNamhyung Kim 		double max_percent = 0.0;
394c7e7b610SNamhyung Kim 		int i;
395e64aa75bSNamhyung Kim 
396e64aa75bSNamhyung Kim 		if (pos->offset == -1) {
397e64aa75bSNamhyung Kim 			RB_CLEAR_NODE(&bpos->rb_node);
398e64aa75bSNamhyung Kim 			continue;
399e64aa75bSNamhyung Kim 		}
400e64aa75bSNamhyung Kim 
401e64aa75bSNamhyung Kim 		next = disasm__get_next_ip_line(&notes->src->source, pos);
402c7e7b610SNamhyung Kim 
403c7e7b610SNamhyung Kim 		for (i = 0; i < browser->nr_events; i++) {
4040c4a5bceSMartin Liška 			u64 nr_samples;
4050c4a5bceSMartin Liška 
4060c4a5bceSMartin Liška 			bpos->samples[i].percent = disasm__calc_percent(notes,
407c7e7b610SNamhyung Kim 						evsel->idx + i,
408c7e7b610SNamhyung Kim 						pos->offset,
409c7e7b610SNamhyung Kim 						next ? next->offset : len,
4100c4a5bceSMartin Liška 						&path, &nr_samples);
4110c4a5bceSMartin Liška 			bpos->samples[i].nr = nr_samples;
412e64aa75bSNamhyung Kim 
4130c4a5bceSMartin Liška 			if (max_percent < bpos->samples[i].percent)
4140c4a5bceSMartin Liška 				max_percent = bpos->samples[i].percent;
415c7e7b610SNamhyung Kim 		}
416c7e7b610SNamhyung Kim 
41730e863bbSAndi Kleen 		if (max_percent < 0.01 && pos->ipc == 0) {
418887c0066SArnaldo Carvalho de Melo 			RB_CLEAR_NODE(&bpos->rb_node);
419aca7a94dSNamhyung Kim 			continue;
420aca7a94dSNamhyung Kim 		}
421c7e7b610SNamhyung Kim 		disasm_rb_tree__insert(&browser->entries, bpos,
422c7e7b610SNamhyung Kim 				       browser->nr_events);
423aca7a94dSNamhyung Kim 	}
424aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
425aca7a94dSNamhyung Kim 
426aca7a94dSNamhyung Kim 	browser->curr_hot = rb_last(&browser->entries);
427aca7a94dSNamhyung Kim }
428aca7a94dSNamhyung Kim 
429aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser)
430aca7a94dSNamhyung Kim {
43129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
432887c0066SArnaldo Carvalho de Melo 	struct browser_disasm_line *bdl;
433aca7a94dSNamhyung Kim 	off_t offset = browser->b.index - browser->b.top_idx;
434aca7a94dSNamhyung Kim 
435aca7a94dSNamhyung Kim 	browser->b.seek(&browser->b, offset, SEEK_CUR);
43629ed6e76SArnaldo Carvalho de Melo 	dl = list_entry(browser->b.top, struct disasm_line, node);
437887c0066SArnaldo Carvalho de Melo 	bdl = disasm_line__browser(dl);
438aca7a94dSNamhyung Kim 
439e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code) {
440887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
441887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx;
442aca7a94dSNamhyung Kim 
443aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_entries;
444e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = false;
445aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
446887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx - offset;
447887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx;
448aca7a94dSNamhyung Kim 	} else {
449887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < 0) {
450aca7a94dSNamhyung Kim 			ui_helpline__puts("Only available for assembly lines.");
451aca7a94dSNamhyung Kim 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
452aca7a94dSNamhyung Kim 			return false;
453aca7a94dSNamhyung Kim 		}
454aca7a94dSNamhyung Kim 
455887c0066SArnaldo Carvalho de Melo 		if (bdl->idx_asm < offset)
456887c0066SArnaldo Carvalho de Melo 			offset = bdl->idx_asm;
457aca7a94dSNamhyung Kim 
458aca7a94dSNamhyung Kim 		browser->b.nr_entries = browser->nr_asm_entries;
459e9823b21SArnaldo Carvalho de Melo 		annotate_browser__opts.hide_src_code = true;
460aca7a94dSNamhyung Kim 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
461887c0066SArnaldo Carvalho de Melo 		browser->b.top_idx = bdl->idx_asm - offset;
462887c0066SArnaldo Carvalho de Melo 		browser->b.index = bdl->idx_asm;
463aca7a94dSNamhyung Kim 	}
464aca7a94dSNamhyung Kim 
465aca7a94dSNamhyung Kim 	return true;
466aca7a94dSNamhyung Kim }
467aca7a94dSNamhyung Kim 
468e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
469e9823b21SArnaldo Carvalho de Melo {
470e9823b21SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
471e9823b21SArnaldo Carvalho de Melo 	browser->b.nr_entries = browser->nr_asm_entries;
472e9823b21SArnaldo Carvalho de Melo }
473e9823b21SArnaldo Carvalho de Melo 
47434f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
47534f77abcSAdrian Hunter 
47634f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title,
47734f77abcSAdrian Hunter 		     size_t sz)
47834f77abcSAdrian Hunter {
47934f77abcSAdrian Hunter 	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
48034f77abcSAdrian Hunter }
48134f77abcSAdrian Hunter 
482db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser,
483db8fd07aSNamhyung Kim 				    struct perf_evsel *evsel,
4849783adf7SNamhyung Kim 				    struct hist_browser_timer *hbt)
485aca7a94dSNamhyung Kim {
486aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
487657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
488aca7a94dSNamhyung Kim 	struct annotation *notes;
4891179e11bSAdrian Hunter 	struct addr_map_symbol target = {
4901179e11bSAdrian Hunter 		.map = ms->map,
4911d5077bdSAdrian Hunter 		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
4921179e11bSAdrian Hunter 	};
49334f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
494aca7a94dSNamhyung Kim 
49575b49202SArnaldo Carvalho de Melo 	if (!ins__is_call(&dl->ins))
496aca7a94dSNamhyung Kim 		return false;
497aca7a94dSNamhyung Kim 
498be39db9fSArnaldo Carvalho de Melo 	if (map_groups__find_ams(&target) ||
4991d5077bdSAdrian Hunter 	    map__rip_2objdump(target.map, target.map->map_ip(target.map,
5001d5077bdSAdrian Hunter 							     target.addr)) !=
5011d5077bdSAdrian Hunter 	    dl->ops.target.addr) {
502aca7a94dSNamhyung Kim 		ui_helpline__puts("The called function was not found.");
503aca7a94dSNamhyung Kim 		return true;
504aca7a94dSNamhyung Kim 	}
505aca7a94dSNamhyung Kim 
5061179e11bSAdrian Hunter 	notes = symbol__annotation(target.sym);
507aca7a94dSNamhyung Kim 	pthread_mutex_lock(&notes->lock);
508aca7a94dSNamhyung Kim 
5091179e11bSAdrian Hunter 	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
510aca7a94dSNamhyung Kim 		pthread_mutex_unlock(&notes->lock);
511aca7a94dSNamhyung Kim 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
5121179e11bSAdrian Hunter 			    target.sym->name);
513aca7a94dSNamhyung Kim 		return true;
514aca7a94dSNamhyung Kim 	}
515aca7a94dSNamhyung Kim 
516aca7a94dSNamhyung Kim 	pthread_mutex_unlock(&notes->lock);
5171179e11bSAdrian Hunter 	symbol__tui_annotate(target.sym, target.map, evsel, hbt);
5181179e11bSAdrian Hunter 	sym_title(ms->sym, ms->map, title, sizeof(title));
51934f77abcSAdrian Hunter 	ui_browser__show_title(&browser->b, title);
520aca7a94dSNamhyung Kim 	return true;
521aca7a94dSNamhyung Kim }
522aca7a94dSNamhyung Kim 
52329ed6e76SArnaldo Carvalho de Melo static
52429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
525aca7a94dSNamhyung Kim 					  s64 offset, s64 *idx)
526aca7a94dSNamhyung Kim {
527aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
528aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
529aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
53029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos;
531aca7a94dSNamhyung Kim 
532aca7a94dSNamhyung Kim 	*idx = 0;
533aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
534aca7a94dSNamhyung Kim 		if (pos->offset == offset)
535aca7a94dSNamhyung Kim 			return pos;
53629ed6e76SArnaldo Carvalho de Melo 		if (!disasm_line__filter(&browser->b, &pos->node))
537aca7a94dSNamhyung Kim 			++*idx;
538aca7a94dSNamhyung Kim 	}
539aca7a94dSNamhyung Kim 
540aca7a94dSNamhyung Kim 	return NULL;
541aca7a94dSNamhyung Kim }
542aca7a94dSNamhyung Kim 
543aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser)
544aca7a94dSNamhyung Kim {
545657bcaf5SArnaldo Carvalho de Melo 	struct disasm_line *dl = browser->selection;
546*5252b1aeSArnaldo Carvalho de Melo 	u64 offset;
5474f9d0325SArnaldo Carvalho de Melo 	s64 idx;
548aca7a94dSNamhyung Kim 
54975b49202SArnaldo Carvalho de Melo 	if (!ins__is_jump(&dl->ins))
550aca7a94dSNamhyung Kim 		return false;
551aca7a94dSNamhyung Kim 
552*5252b1aeSArnaldo Carvalho de Melo 	offset = dl->ops.target.offset;
553*5252b1aeSArnaldo Carvalho de Melo 	dl = annotate_browser__find_offset(browser, offset, &idx);
55429ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
555*5252b1aeSArnaldo Carvalho de Melo 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
556aca7a94dSNamhyung Kim 		return true;
557aca7a94dSNamhyung Kim 	}
558aca7a94dSNamhyung Kim 
55929ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
560aca7a94dSNamhyung Kim 
561aca7a94dSNamhyung Kim 	return true;
562aca7a94dSNamhyung Kim }
563aca7a94dSNamhyung Kim 
56429ed6e76SArnaldo Carvalho de Melo static
56529ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
566aca7a94dSNamhyung Kim 					  char *s, s64 *idx)
567aca7a94dSNamhyung Kim {
568aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
569aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
570aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
57129ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
572aca7a94dSNamhyung Kim 
573aca7a94dSNamhyung Kim 	*idx = browser->b.index;
574aca7a94dSNamhyung Kim 	list_for_each_entry_continue(pos, &notes->src->source, node) {
57529ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
576aca7a94dSNamhyung Kim 			continue;
577aca7a94dSNamhyung Kim 
578aca7a94dSNamhyung Kim 		++*idx;
579aca7a94dSNamhyung Kim 
580aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
581aca7a94dSNamhyung Kim 			return pos;
582aca7a94dSNamhyung Kim 	}
583aca7a94dSNamhyung Kim 
584aca7a94dSNamhyung Kim 	return NULL;
585aca7a94dSNamhyung Kim }
586aca7a94dSNamhyung Kim 
587aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser)
588aca7a94dSNamhyung Kim {
58929ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
590aca7a94dSNamhyung Kim 	s64 idx;
591aca7a94dSNamhyung Kim 
59229ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
59329ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
594aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
595aca7a94dSNamhyung Kim 		return false;
596aca7a94dSNamhyung Kim 	}
597aca7a94dSNamhyung Kim 
59829ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
599aca7a94dSNamhyung Kim 	browser->searching_backwards = false;
600aca7a94dSNamhyung Kim 	return true;
601aca7a94dSNamhyung Kim }
602aca7a94dSNamhyung Kim 
60329ed6e76SArnaldo Carvalho de Melo static
60429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
605aca7a94dSNamhyung Kim 						  char *s, s64 *idx)
606aca7a94dSNamhyung Kim {
607aca7a94dSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
608aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
609aca7a94dSNamhyung Kim 	struct annotation *notes = symbol__annotation(sym);
61029ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos = browser->selection;
611aca7a94dSNamhyung Kim 
612aca7a94dSNamhyung Kim 	*idx = browser->b.index;
613aca7a94dSNamhyung Kim 	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
61429ed6e76SArnaldo Carvalho de Melo 		if (disasm_line__filter(&browser->b, &pos->node))
615aca7a94dSNamhyung Kim 			continue;
616aca7a94dSNamhyung Kim 
617aca7a94dSNamhyung Kim 		--*idx;
618aca7a94dSNamhyung Kim 
619aca7a94dSNamhyung Kim 		if (pos->line && strstr(pos->line, s) != NULL)
620aca7a94dSNamhyung Kim 			return pos;
621aca7a94dSNamhyung Kim 	}
622aca7a94dSNamhyung Kim 
623aca7a94dSNamhyung Kim 	return NULL;
624aca7a94dSNamhyung Kim }
625aca7a94dSNamhyung Kim 
626aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
627aca7a94dSNamhyung Kim {
62829ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *dl;
629aca7a94dSNamhyung Kim 	s64 idx;
630aca7a94dSNamhyung Kim 
63129ed6e76SArnaldo Carvalho de Melo 	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
63229ed6e76SArnaldo Carvalho de Melo 	if (dl == NULL) {
633aca7a94dSNamhyung Kim 		ui_helpline__puts("String not found!");
634aca7a94dSNamhyung Kim 		return false;
635aca7a94dSNamhyung Kim 	}
636aca7a94dSNamhyung Kim 
63729ed6e76SArnaldo Carvalho de Melo 	annotate_browser__set_top(browser, dl, idx);
638aca7a94dSNamhyung Kim 	browser->searching_backwards = true;
639aca7a94dSNamhyung Kim 	return true;
640aca7a94dSNamhyung Kim }
641aca7a94dSNamhyung Kim 
642aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser,
643aca7a94dSNamhyung Kim 					    int delay_secs)
644aca7a94dSNamhyung Kim {
645aca7a94dSNamhyung Kim 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
646aca7a94dSNamhyung Kim 				     "ENTER: OK, ESC: Cancel",
647aca7a94dSNamhyung Kim 				     delay_secs * 2) != K_ENTER ||
648aca7a94dSNamhyung Kim 	    !*browser->search_bf)
649aca7a94dSNamhyung Kim 		return false;
650aca7a94dSNamhyung Kim 
651aca7a94dSNamhyung Kim 	return true;
652aca7a94dSNamhyung Kim }
653aca7a94dSNamhyung Kim 
654aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
655aca7a94dSNamhyung Kim {
656aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
657aca7a94dSNamhyung Kim 		return __annotate_browser__search(browser);
658aca7a94dSNamhyung Kim 
659aca7a94dSNamhyung Kim 	return false;
660aca7a94dSNamhyung Kim }
661aca7a94dSNamhyung Kim 
662aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser,
663aca7a94dSNamhyung Kim 					      int delay_secs)
664aca7a94dSNamhyung Kim {
665aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
666aca7a94dSNamhyung Kim 		return annotate_browser__search(browser, delay_secs);
667aca7a94dSNamhyung Kim 
668aca7a94dSNamhyung Kim 	return __annotate_browser__search(browser);
669aca7a94dSNamhyung Kim }
670aca7a94dSNamhyung Kim 
671aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser,
672aca7a94dSNamhyung Kim 					   int delay_secs)
673aca7a94dSNamhyung Kim {
674aca7a94dSNamhyung Kim 	if (annotate_browser__search_window(browser, delay_secs))
675aca7a94dSNamhyung Kim 		return __annotate_browser__search_reverse(browser);
676aca7a94dSNamhyung Kim 
677aca7a94dSNamhyung Kim 	return false;
678aca7a94dSNamhyung Kim }
679aca7a94dSNamhyung Kim 
680aca7a94dSNamhyung Kim static
681aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
682aca7a94dSNamhyung Kim 					       int delay_secs)
683aca7a94dSNamhyung Kim {
684aca7a94dSNamhyung Kim 	if (!*browser->search_bf)
685aca7a94dSNamhyung Kim 		return annotate_browser__search_reverse(browser, delay_secs);
686aca7a94dSNamhyung Kim 
687aca7a94dSNamhyung Kim 	return __annotate_browser__search_reverse(browser);
688aca7a94dSNamhyung Kim }
689aca7a94dSNamhyung Kim 
690e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser)
691e9823b21SArnaldo Carvalho de Melo {
692e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.use_offset)
693e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->min_addr_width;
694e9823b21SArnaldo Carvalho de Melo 	else
695e9823b21SArnaldo Carvalho de Melo 		browser->target_width = browser->max_addr_width;
696e9823b21SArnaldo Carvalho de Melo 
697e9823b21SArnaldo Carvalho de Melo 	browser->addr_width = browser->target_width;
698e9823b21SArnaldo Carvalho de Melo 
699e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.show_nr_jumps)
700e9823b21SArnaldo Carvalho de Melo 		browser->addr_width += browser->jumps_width + 1;
701e9823b21SArnaldo Carvalho de Melo }
702e9823b21SArnaldo Carvalho de Melo 
703db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser,
704db8fd07aSNamhyung Kim 				 struct perf_evsel *evsel,
7059783adf7SNamhyung Kim 				 struct hist_browser_timer *hbt)
706aca7a94dSNamhyung Kim {
707aca7a94dSNamhyung Kim 	struct rb_node *nd = NULL;
70805e8b080SArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->b.priv;
709aca7a94dSNamhyung Kim 	struct symbol *sym = ms->sym;
71054e7a4e8SArnaldo Carvalho de Melo 	const char *help = "Press 'h' for help on key bindings";
7119783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
712aca7a94dSNamhyung Kim 	int key;
71334f77abcSAdrian Hunter 	char title[SYM_TITLE_MAX_SIZE];
714aca7a94dSNamhyung Kim 
71534f77abcSAdrian Hunter 	sym_title(sym, ms->map, title, sizeof(title));
71634f77abcSAdrian Hunter 	if (ui_browser__show(&browser->b, title, help) < 0)
717aca7a94dSNamhyung Kim 		return -1;
718aca7a94dSNamhyung Kim 
719db8fd07aSNamhyung Kim 	annotate_browser__calc_percent(browser, evsel);
720aca7a94dSNamhyung Kim 
72105e8b080SArnaldo Carvalho de Melo 	if (browser->curr_hot) {
72205e8b080SArnaldo Carvalho de Melo 		annotate_browser__set_rb_top(browser, browser->curr_hot);
72305e8b080SArnaldo Carvalho de Melo 		browser->b.navkeypressed = false;
724aca7a94dSNamhyung Kim 	}
725aca7a94dSNamhyung Kim 
72605e8b080SArnaldo Carvalho de Melo 	nd = browser->curr_hot;
727aca7a94dSNamhyung Kim 
728aca7a94dSNamhyung Kim 	while (1) {
72905e8b080SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
730aca7a94dSNamhyung Kim 
731aca7a94dSNamhyung Kim 		if (delay_secs != 0) {
732db8fd07aSNamhyung Kim 			annotate_browser__calc_percent(browser, evsel);
733aca7a94dSNamhyung Kim 			/*
734aca7a94dSNamhyung Kim 			 * Current line focus got out of the list of most active
735aca7a94dSNamhyung Kim 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
736aca7a94dSNamhyung Kim 			 * move to curr_hot (current hottest line).
737aca7a94dSNamhyung Kim 			 */
738aca7a94dSNamhyung Kim 			if (nd != NULL && RB_EMPTY_NODE(nd))
739aca7a94dSNamhyung Kim 				nd = NULL;
740aca7a94dSNamhyung Kim 		}
741aca7a94dSNamhyung Kim 
742aca7a94dSNamhyung Kim 		switch (key) {
743aca7a94dSNamhyung Kim 		case K_TIMER:
7449783adf7SNamhyung Kim 			if (hbt)
7459783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
746aca7a94dSNamhyung Kim 
747aca7a94dSNamhyung Kim 			if (delay_secs != 0)
748db8fd07aSNamhyung Kim 				symbol__annotate_decay_histogram(sym, evsel->idx);
749aca7a94dSNamhyung Kim 			continue;
750aca7a94dSNamhyung Kim 		case K_TAB:
751aca7a94dSNamhyung Kim 			if (nd != NULL) {
752aca7a94dSNamhyung Kim 				nd = rb_prev(nd);
753aca7a94dSNamhyung Kim 				if (nd == NULL)
75405e8b080SArnaldo Carvalho de Melo 					nd = rb_last(&browser->entries);
755aca7a94dSNamhyung Kim 			} else
75605e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
757aca7a94dSNamhyung Kim 			break;
758aca7a94dSNamhyung Kim 		case K_UNTAB:
759d4913cbdSMarkus Trippelsdorf 			if (nd != NULL) {
760aca7a94dSNamhyung Kim 				nd = rb_next(nd);
761aca7a94dSNamhyung Kim 				if (nd == NULL)
76205e8b080SArnaldo Carvalho de Melo 					nd = rb_first(&browser->entries);
763d4913cbdSMarkus Trippelsdorf 			} else
76405e8b080SArnaldo Carvalho de Melo 				nd = browser->curr_hot;
765aca7a94dSNamhyung Kim 			break;
76654e7a4e8SArnaldo Carvalho de Melo 		case K_F1:
767aca7a94dSNamhyung Kim 		case 'h':
76805e8b080SArnaldo Carvalho de Melo 			ui_browser__help_window(&browser->b,
76954e7a4e8SArnaldo Carvalho de Melo 		"UP/DOWN/PGUP\n"
77054e7a4e8SArnaldo Carvalho de Melo 		"PGDN/SPACE    Navigate\n"
77154e7a4e8SArnaldo Carvalho de Melo 		"q/ESC/CTRL+C  Exit\n\n"
7727727a925SArnaldo Carvalho de Melo 		"ENTER         Go to target\n"
7737727a925SArnaldo Carvalho de Melo 		"ESC           Exit\n"
774107baecaSArnaldo Carvalho de Melo 		"H             Cycle thru hottest instructions\n"
77554e7a4e8SArnaldo Carvalho de Melo 		"j             Toggle showing jump to target arrows\n"
77654e7a4e8SArnaldo Carvalho de Melo 		"J             Toggle showing number of jump sources on targets\n"
77754e7a4e8SArnaldo Carvalho de Melo 		"n             Search next string\n"
77854e7a4e8SArnaldo Carvalho de Melo 		"o             Toggle disassembler output/simplified view\n"
77954e7a4e8SArnaldo Carvalho de Melo 		"s             Toggle source code view\n"
7800c4a5bceSMartin Liška 		"t             Toggle total period view\n"
78154e7a4e8SArnaldo Carvalho de Melo 		"/             Search string\n"
782e592488cSAndi Kleen 		"k             Toggle line numbers\n"
78379ee47faSFeng Tang 		"r             Run available scripts\n"
784fcd9fef9SArnaldo Carvalho de Melo 		"?             Search string backwards\n");
78554e7a4e8SArnaldo Carvalho de Melo 			continue;
78679ee47faSFeng Tang 		case 'r':
78779ee47faSFeng Tang 			{
78879ee47faSFeng Tang 				script_browse(NULL);
78979ee47faSFeng Tang 				continue;
79079ee47faSFeng Tang 			}
791e592488cSAndi Kleen 		case 'k':
792e592488cSAndi Kleen 			annotate_browser__opts.show_linenr =
793e592488cSAndi Kleen 				!annotate_browser__opts.show_linenr;
794e592488cSAndi Kleen 			break;
79554e7a4e8SArnaldo Carvalho de Melo 		case 'H':
79605e8b080SArnaldo Carvalho de Melo 			nd = browser->curr_hot;
797aca7a94dSNamhyung Kim 			break;
798aca7a94dSNamhyung Kim 		case 's':
79905e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__toggle_source(browser))
800aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
801aca7a94dSNamhyung Kim 			continue;
802aca7a94dSNamhyung Kim 		case 'o':
803e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
80405e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
805aca7a94dSNamhyung Kim 			continue;
8069d1ef56dSArnaldo Carvalho de Melo 		case 'j':
807e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
8089d1ef56dSArnaldo Carvalho de Melo 			continue;
8092402e4a9SArnaldo Carvalho de Melo 		case 'J':
810e9823b21SArnaldo Carvalho de Melo 			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
81105e8b080SArnaldo Carvalho de Melo 			annotate_browser__update_addr_width(browser);
812e9823b21SArnaldo Carvalho de Melo 			continue;
813aca7a94dSNamhyung Kim 		case '/':
81405e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search(browser, delay_secs)) {
815aca7a94dSNamhyung Kim show_help:
816aca7a94dSNamhyung Kim 				ui_helpline__puts(help);
817aca7a94dSNamhyung Kim 			}
818aca7a94dSNamhyung Kim 			continue;
819aca7a94dSNamhyung Kim 		case 'n':
82005e8b080SArnaldo Carvalho de Melo 			if (browser->searching_backwards ?
82105e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
82205e8b080SArnaldo Carvalho de Melo 			    annotate_browser__continue_search(browser, delay_secs))
823aca7a94dSNamhyung Kim 				goto show_help;
824aca7a94dSNamhyung Kim 			continue;
825aca7a94dSNamhyung Kim 		case '?':
82605e8b080SArnaldo Carvalho de Melo 			if (annotate_browser__search_reverse(browser, delay_secs))
827aca7a94dSNamhyung Kim 				goto show_help;
828aca7a94dSNamhyung Kim 			continue;
829e9823b21SArnaldo Carvalho de Melo 		case 'D': {
830e9823b21SArnaldo Carvalho de Melo 			static int seq;
831e9823b21SArnaldo Carvalho de Melo 			ui_helpline__pop();
832e9823b21SArnaldo Carvalho de Melo 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
83305e8b080SArnaldo Carvalho de Melo 					   seq++, browser->b.nr_entries,
83405e8b080SArnaldo Carvalho de Melo 					   browser->b.height,
83505e8b080SArnaldo Carvalho de Melo 					   browser->b.index,
83605e8b080SArnaldo Carvalho de Melo 					   browser->b.top_idx,
83705e8b080SArnaldo Carvalho de Melo 					   browser->nr_asm_entries);
838e9823b21SArnaldo Carvalho de Melo 		}
839e9823b21SArnaldo Carvalho de Melo 			continue;
840aca7a94dSNamhyung Kim 		case K_ENTER:
841aca7a94dSNamhyung Kim 		case K_RIGHT:
84205e8b080SArnaldo Carvalho de Melo 			if (browser->selection == NULL)
843aca7a94dSNamhyung Kim 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
84405e8b080SArnaldo Carvalho de Melo 			else if (browser->selection->offset == -1)
845aca7a94dSNamhyung Kim 				ui_helpline__puts("Actions are only available for assembly lines.");
84675b49202SArnaldo Carvalho de Melo 			else if (!browser->selection->ins.ops)
847c4cceae3SArnaldo Carvalho de Melo 				goto show_sup_ins;
84875b49202SArnaldo Carvalho de Melo 			else if (ins__is_ret(&browser->selection->ins))
849c4cceae3SArnaldo Carvalho de Melo 				goto out;
8506ef94929SNaveen N. Rao 			else if (!(annotate_browser__jump(browser) ||
851db8fd07aSNamhyung Kim 				     annotate_browser__callq(browser, evsel, hbt))) {
852c4cceae3SArnaldo Carvalho de Melo show_sup_ins:
8536ef94929SNaveen N. Rao 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
854c4cceae3SArnaldo Carvalho de Melo 			}
855aca7a94dSNamhyung Kim 			continue;
8560c4a5bceSMartin Liška 		case 't':
8570c4a5bceSMartin Liška 			annotate_browser__opts.show_total_period =
8580c4a5bceSMartin Liška 			  !annotate_browser__opts.show_total_period;
8590c4a5bceSMartin Liška 			annotate_browser__update_addr_width(browser);
8600c4a5bceSMartin Liška 			continue;
861aca7a94dSNamhyung Kim 		case K_LEFT:
862aca7a94dSNamhyung Kim 		case K_ESC:
863aca7a94dSNamhyung Kim 		case 'q':
864aca7a94dSNamhyung Kim 		case CTRL('c'):
865aca7a94dSNamhyung Kim 			goto out;
866aca7a94dSNamhyung Kim 		default:
867aca7a94dSNamhyung Kim 			continue;
868aca7a94dSNamhyung Kim 		}
869aca7a94dSNamhyung Kim 
870aca7a94dSNamhyung Kim 		if (nd != NULL)
87105e8b080SArnaldo Carvalho de Melo 			annotate_browser__set_rb_top(browser, nd);
872aca7a94dSNamhyung Kim 	}
873aca7a94dSNamhyung Kim out:
87405e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
875aca7a94dSNamhyung Kim 	return key;
876aca7a94dSNamhyung Kim }
877aca7a94dSNamhyung Kim 
878d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
879d5dbc518SArnaldo Carvalho de Melo 			     struct hist_browser_timer *hbt)
880d5dbc518SArnaldo Carvalho de Melo {
8810c4a5bceSMartin Liška 	/* Set default value for show_total_period.  */
8820c4a5bceSMartin Liška 	annotate_browser__opts.show_total_period =
8830c4a5bceSMartin Liška 	  symbol_conf.show_total_period;
8840c4a5bceSMartin Liška 
885d5dbc518SArnaldo Carvalho de Melo 	return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
886d5dbc518SArnaldo Carvalho de Melo }
887d5dbc518SArnaldo Carvalho de Melo 
888db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
8899783adf7SNamhyung Kim 			     struct hist_browser_timer *hbt)
890aca7a94dSNamhyung Kim {
891ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
892ed426915SNamhyung Kim 	SLang_reset_tty();
893ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
894ed426915SNamhyung Kim 
895d5dbc518SArnaldo Carvalho de Melo 	return map_symbol__tui_annotate(&he->ms, evsel, hbt);
896aca7a94dSNamhyung Kim }
897aca7a94dSNamhyung Kim 
89830e863bbSAndi Kleen 
89930e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
90030e863bbSAndi Kleen {
90130e863bbSAndi Kleen 	unsigned n_insn = 0;
90230e863bbSAndi Kleen 	u64 offset;
90330e863bbSAndi Kleen 
90430e863bbSAndi Kleen 	for (offset = start; offset <= end; offset++) {
90530e863bbSAndi Kleen 		if (browser->offsets[offset])
90630e863bbSAndi Kleen 			n_insn++;
90730e863bbSAndi Kleen 	}
90830e863bbSAndi Kleen 	return n_insn;
90930e863bbSAndi Kleen }
91030e863bbSAndi Kleen 
91130e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
91230e863bbSAndi Kleen 			   struct cyc_hist *ch)
91330e863bbSAndi Kleen {
91430e863bbSAndi Kleen 	unsigned n_insn;
91530e863bbSAndi Kleen 	u64 offset;
91630e863bbSAndi Kleen 
91730e863bbSAndi Kleen 	n_insn = count_insn(browser, start, end);
91830e863bbSAndi Kleen 	if (n_insn && ch->num && ch->cycles) {
91930e863bbSAndi Kleen 		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
92030e863bbSAndi Kleen 
92130e863bbSAndi Kleen 		/* Hide data when there are too many overlaps. */
92230e863bbSAndi Kleen 		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
92330e863bbSAndi Kleen 			return;
92430e863bbSAndi Kleen 
92530e863bbSAndi Kleen 		for (offset = start; offset <= end; offset++) {
92630e863bbSAndi Kleen 			struct disasm_line *dl = browser->offsets[offset];
92730e863bbSAndi Kleen 
92830e863bbSAndi Kleen 			if (dl)
92930e863bbSAndi Kleen 				dl->ipc = ipc;
93030e863bbSAndi Kleen 		}
93130e863bbSAndi Kleen 	}
93230e863bbSAndi Kleen }
93330e863bbSAndi Kleen 
93430e863bbSAndi Kleen /*
93530e863bbSAndi Kleen  * This should probably be in util/annotate.c to share with the tty
93630e863bbSAndi Kleen  * annotate, but right now we need the per byte offsets arrays,
93730e863bbSAndi Kleen  * which are only here.
93830e863bbSAndi Kleen  */
93930e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
94030e863bbSAndi Kleen 			   struct symbol *sym)
94130e863bbSAndi Kleen {
94230e863bbSAndi Kleen 	u64 offset;
94330e863bbSAndi Kleen 	struct annotation *notes = symbol__annotation(sym);
94430e863bbSAndi Kleen 
94530e863bbSAndi Kleen 	if (!notes->src || !notes->src->cycles_hist)
94630e863bbSAndi Kleen 		return;
94730e863bbSAndi Kleen 
94830e863bbSAndi Kleen 	pthread_mutex_lock(&notes->lock);
94930e863bbSAndi Kleen 	for (offset = 0; offset < size; ++offset) {
95030e863bbSAndi Kleen 		struct cyc_hist *ch;
95130e863bbSAndi Kleen 
95230e863bbSAndi Kleen 		ch = &notes->src->cycles_hist[offset];
95330e863bbSAndi Kleen 		if (ch && ch->cycles) {
95430e863bbSAndi Kleen 			struct disasm_line *dl;
95530e863bbSAndi Kleen 
95630e863bbSAndi Kleen 			if (ch->have_start)
95730e863bbSAndi Kleen 				count_and_fill(browser, ch->start, offset, ch);
95830e863bbSAndi Kleen 			dl = browser->offsets[offset];
95930e863bbSAndi Kleen 			if (dl && ch->num_aggr)
96030e863bbSAndi Kleen 				dl->cycles = ch->cycles_aggr / ch->num_aggr;
96130e863bbSAndi Kleen 			browser->have_cycles = true;
96230e863bbSAndi Kleen 		}
96330e863bbSAndi Kleen 	}
96430e863bbSAndi Kleen 	pthread_mutex_unlock(&notes->lock);
96530e863bbSAndi Kleen }
96630e863bbSAndi Kleen 
967b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
968b793a401SArnaldo Carvalho de Melo 						size_t size)
969b793a401SArnaldo Carvalho de Melo {
970b793a401SArnaldo Carvalho de Melo 	u64 offset;
97132ae1efdSNamhyung Kim 	struct map_symbol *ms = browser->b.priv;
97232ae1efdSNamhyung Kim 	struct symbol *sym = ms->sym;
97332ae1efdSNamhyung Kim 
97432ae1efdSNamhyung Kim 	/* PLT symbols contain external offsets */
97532ae1efdSNamhyung Kim 	if (strstr(sym->name, "@plt"))
97632ae1efdSNamhyung Kim 		return;
977b793a401SArnaldo Carvalho de Melo 
978b793a401SArnaldo Carvalho de Melo 	for (offset = 0; offset < size; ++offset) {
979b793a401SArnaldo Carvalho de Melo 		struct disasm_line *dl = browser->offsets[offset], *dlt;
980b793a401SArnaldo Carvalho de Melo 		struct browser_disasm_line *bdlt;
981b793a401SArnaldo Carvalho de Melo 
982865c66c4SFrederik Deweerdt 		if (!disasm_line__is_valid_jump(dl, sym))
983b793a401SArnaldo Carvalho de Melo 			continue;
984b793a401SArnaldo Carvalho de Melo 
98544d1a3edSArnaldo Carvalho de Melo 		dlt = browser->offsets[dl->ops.target.offset];
9869481ede9SArnaldo Carvalho de Melo 		/*
9879481ede9SArnaldo Carvalho de Melo  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
9889481ede9SArnaldo Carvalho de Melo  		 * have to adjust to the previous offset?
9899481ede9SArnaldo Carvalho de Melo  		 */
9909481ede9SArnaldo Carvalho de Melo 		if (dlt == NULL)
9919481ede9SArnaldo Carvalho de Melo 			continue;
9929481ede9SArnaldo Carvalho de Melo 
993b793a401SArnaldo Carvalho de Melo 		bdlt = disasm_line__browser(dlt);
9942402e4a9SArnaldo Carvalho de Melo 		if (++bdlt->jump_sources > browser->max_jump_sources)
9952402e4a9SArnaldo Carvalho de Melo 			browser->max_jump_sources = bdlt->jump_sources;
9962402e4a9SArnaldo Carvalho de Melo 
9972402e4a9SArnaldo Carvalho de Melo 		++browser->nr_jumps;
998b793a401SArnaldo Carvalho de Melo 	}
999b793a401SArnaldo Carvalho de Melo }
1000b793a401SArnaldo Carvalho de Melo 
10012402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n)
10022402e4a9SArnaldo Carvalho de Melo {
10032402e4a9SArnaldo Carvalho de Melo 	if (n >= 100)
10042402e4a9SArnaldo Carvalho de Melo 		return 5;
10052402e4a9SArnaldo Carvalho de Melo 	if (n / 10)
10062402e4a9SArnaldo Carvalho de Melo 		return 2;
10072402e4a9SArnaldo Carvalho de Melo 	return 1;
10082402e4a9SArnaldo Carvalho de Melo }
10092402e4a9SArnaldo Carvalho de Melo 
1010db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map,
1011db8fd07aSNamhyung Kim 			 struct perf_evsel *evsel,
10129783adf7SNamhyung Kim 			 struct hist_browser_timer *hbt)
1013aca7a94dSNamhyung Kim {
101429ed6e76SArnaldo Carvalho de Melo 	struct disasm_line *pos, *n;
1015aca7a94dSNamhyung Kim 	struct annotation *notes;
1016c0a58fb2SSamuel Liao 	size_t size;
1017aca7a94dSNamhyung Kim 	struct map_symbol ms = {
1018aca7a94dSNamhyung Kim 		.map = map,
1019aca7a94dSNamhyung Kim 		.sym = sym,
1020aca7a94dSNamhyung Kim 	};
1021aca7a94dSNamhyung Kim 	struct annotate_browser browser = {
1022aca7a94dSNamhyung Kim 		.b = {
1023a3f895beSArnaldo Carvalho de Melo 			.refresh = annotate_browser__refresh,
1024aca7a94dSNamhyung Kim 			.seek	 = ui_browser__list_head_seek,
1025aca7a94dSNamhyung Kim 			.write	 = annotate_browser__write,
102629ed6e76SArnaldo Carvalho de Melo 			.filter  = disasm_line__filter,
1027aca7a94dSNamhyung Kim 			.priv	 = &ms,
1028aca7a94dSNamhyung Kim 			.use_navkeypressed = true,
1029aca7a94dSNamhyung Kim 		},
1030aca7a94dSNamhyung Kim 	};
1031ee51d851SArnaldo Carvalho de Melo 	int ret = -1, err;
1032c7e7b610SNamhyung Kim 	int nr_pcnt = 1;
1033c7e7b610SNamhyung Kim 	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
1034aca7a94dSNamhyung Kim 
1035aca7a94dSNamhyung Kim 	if (sym == NULL)
1036aca7a94dSNamhyung Kim 		return -1;
1037aca7a94dSNamhyung Kim 
1038c0a58fb2SSamuel Liao 	size = symbol__size(sym);
1039c0a58fb2SSamuel Liao 
1040aca7a94dSNamhyung Kim 	if (map->dso->annotate_warned)
1041aca7a94dSNamhyung Kim 		return -1;
1042aca7a94dSNamhyung Kim 
1043b793a401SArnaldo Carvalho de Melo 	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1044b793a401SArnaldo Carvalho de Melo 	if (browser.offsets == NULL) {
1045b793a401SArnaldo Carvalho de Melo 		ui__error("Not enough memory!");
1046b793a401SArnaldo Carvalho de Melo 		return -1;
1047b793a401SArnaldo Carvalho de Melo 	}
1048b793a401SArnaldo Carvalho de Melo 
1049c7e7b610SNamhyung Kim 	if (perf_evsel__is_group_event(evsel)) {
1050c7e7b610SNamhyung Kim 		nr_pcnt = evsel->nr_members;
10510c4a5bceSMartin Liška 		sizeof_bdl += sizeof(struct disasm_line_samples) *
10520c4a5bceSMartin Liška 		  (nr_pcnt - 1);
1053c7e7b610SNamhyung Kim 	}
1054c7e7b610SNamhyung Kim 
1055786c1b51SArnaldo Carvalho de Melo 	err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl);
1056ee51d851SArnaldo Carvalho de Melo 	if (err) {
1057ee51d851SArnaldo Carvalho de Melo 		char msg[BUFSIZ];
1058ee51d851SArnaldo Carvalho de Melo 		symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1059ee51d851SArnaldo Carvalho de Melo 		ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
1060b793a401SArnaldo Carvalho de Melo 		goto out_free_offsets;
1061aca7a94dSNamhyung Kim 	}
1062aca7a94dSNamhyung Kim 
10637727a925SArnaldo Carvalho de Melo 	ui_helpline__push("Press ESC to exit");
1064aca7a94dSNamhyung Kim 
1065aca7a94dSNamhyung Kim 	notes = symbol__annotation(sym);
1066aca7a94dSNamhyung Kim 	browser.start = map__rip_2objdump(map, sym->start);
1067aca7a94dSNamhyung Kim 
1068aca7a94dSNamhyung Kim 	list_for_each_entry(pos, &notes->src->source, node) {
1069887c0066SArnaldo Carvalho de Melo 		struct browser_disasm_line *bpos;
1070aca7a94dSNamhyung Kim 		size_t line_len = strlen(pos->line);
1071aca7a94dSNamhyung Kim 
1072aca7a94dSNamhyung Kim 		if (browser.b.width < line_len)
1073aca7a94dSNamhyung Kim 			browser.b.width = line_len;
1074887c0066SArnaldo Carvalho de Melo 		bpos = disasm_line__browser(pos);
1075887c0066SArnaldo Carvalho de Melo 		bpos->idx = browser.nr_entries++;
1076b793a401SArnaldo Carvalho de Melo 		if (pos->offset != -1) {
1077887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = browser.nr_asm_entries++;
107897148a97SArnaldo Carvalho de Melo 			/*
107997148a97SArnaldo Carvalho de Melo 			 * FIXME: short term bandaid to cope with assembly
108097148a97SArnaldo Carvalho de Melo 			 * routines that comes with labels in the same column
108197148a97SArnaldo Carvalho de Melo 			 * as the address in objdump, sigh.
108297148a97SArnaldo Carvalho de Melo 			 *
108397148a97SArnaldo Carvalho de Melo 			 * E.g. copy_user_generic_unrolled
108497148a97SArnaldo Carvalho de Melo  			 */
108597148a97SArnaldo Carvalho de Melo 			if (pos->offset < (s64)size)
1086b793a401SArnaldo Carvalho de Melo 				browser.offsets[pos->offset] = pos;
1087b793a401SArnaldo Carvalho de Melo 		} else
1088887c0066SArnaldo Carvalho de Melo 			bpos->idx_asm = -1;
1089aca7a94dSNamhyung Kim 	}
1090aca7a94dSNamhyung Kim 
1091b793a401SArnaldo Carvalho de Melo 	annotate_browser__mark_jump_targets(&browser, size);
109230e863bbSAndi Kleen 	annotate__compute_ipc(&browser, size, sym);
1093b793a401SArnaldo Carvalho de Melo 
10942402e4a9SArnaldo Carvalho de Melo 	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
109583b1f2aaSArnaldo Carvalho de Melo 	browser.max_addr_width = hex_width(sym->end);
10962402e4a9SArnaldo Carvalho de Melo 	browser.jumps_width = width_jumps(browser.max_jump_sources);
1097c7e7b610SNamhyung Kim 	browser.nr_events = nr_pcnt;
1098aca7a94dSNamhyung Kim 	browser.b.nr_entries = browser.nr_entries;
1099aca7a94dSNamhyung Kim 	browser.b.entries = &notes->src->source,
1100aca7a94dSNamhyung Kim 	browser.b.width += 18; /* Percentage */
1101e9823b21SArnaldo Carvalho de Melo 
1102e9823b21SArnaldo Carvalho de Melo 	if (annotate_browser__opts.hide_src_code)
1103e9823b21SArnaldo Carvalho de Melo 		annotate_browser__init_asm_mode(&browser);
1104e9823b21SArnaldo Carvalho de Melo 
1105e9823b21SArnaldo Carvalho de Melo 	annotate_browser__update_addr_width(&browser);
1106e9823b21SArnaldo Carvalho de Melo 
1107db8fd07aSNamhyung Kim 	ret = annotate_browser__run(&browser, evsel, hbt);
1108aca7a94dSNamhyung Kim 	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
1109aca7a94dSNamhyung Kim 		list_del(&pos->node);
111029ed6e76SArnaldo Carvalho de Melo 		disasm_line__free(pos);
1111aca7a94dSNamhyung Kim 	}
1112b793a401SArnaldo Carvalho de Melo 
1113b793a401SArnaldo Carvalho de Melo out_free_offsets:
1114b793a401SArnaldo Carvalho de Melo 	free(browser.offsets);
1115aca7a94dSNamhyung Kim 	return ret;
1116aca7a94dSNamhyung Kim }
1117c323cf04SArnaldo Carvalho de Melo 
1118c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \
1119c323cf04SArnaldo Carvalho de Melo 	{ .name = #n, .value = &annotate_browser__opts.n, }
1120c323cf04SArnaldo Carvalho de Melo 
1121c323cf04SArnaldo Carvalho de Melo /*
1122c323cf04SArnaldo Carvalho de Melo  * Keep the entries sorted, they are bsearch'ed
1123c323cf04SArnaldo Carvalho de Melo  */
11247c3102b8SArnaldo Carvalho de Melo static struct annotate_config {
1125c323cf04SArnaldo Carvalho de Melo 	const char *name;
1126c323cf04SArnaldo Carvalho de Melo 	bool *value;
1127c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = {
1128c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(hide_src_code),
1129c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(jump_arrows),
1130e592488cSAndi Kleen 	ANNOTATE_CFG(show_linenr),
1131c323cf04SArnaldo Carvalho de Melo 	ANNOTATE_CFG(show_nr_jumps),
11320c4a5bceSMartin Liška 	ANNOTATE_CFG(show_total_period),
113339ff7cdbSNamhyung Kim 	ANNOTATE_CFG(use_offset),
1134c323cf04SArnaldo Carvalho de Melo };
1135c323cf04SArnaldo Carvalho de Melo 
1136c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG
1137c323cf04SArnaldo Carvalho de Melo 
1138c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp)
1139c323cf04SArnaldo Carvalho de Melo {
11407c3102b8SArnaldo Carvalho de Melo 	const struct annotate_config *cfg = cfgp;
1141c323cf04SArnaldo Carvalho de Melo 
1142c323cf04SArnaldo Carvalho de Melo 	return strcmp(name, cfg->name);
1143c323cf04SArnaldo Carvalho de Melo }
1144c323cf04SArnaldo Carvalho de Melo 
11451d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value,
11461d037ca1SIrina Tirdea 			    void *data __maybe_unused)
1147c323cf04SArnaldo Carvalho de Melo {
11487c3102b8SArnaldo Carvalho de Melo 	struct annotate_config *cfg;
1149c323cf04SArnaldo Carvalho de Melo 	const char *name;
1150c323cf04SArnaldo Carvalho de Melo 
1151c323cf04SArnaldo Carvalho de Melo 	if (prefixcmp(var, "annotate.") != 0)
1152c323cf04SArnaldo Carvalho de Melo 		return 0;
1153c323cf04SArnaldo Carvalho de Melo 
1154c323cf04SArnaldo Carvalho de Melo 	name = var + 9;
1155c323cf04SArnaldo Carvalho de Melo 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
11567c3102b8SArnaldo Carvalho de Melo 		      sizeof(struct annotate_config), annotate_config__cmp);
1157c323cf04SArnaldo Carvalho de Melo 
1158c323cf04SArnaldo Carvalho de Melo 	if (cfg == NULL)
1159f06cff7cSArnaldo Carvalho de Melo 		ui__warning("%s variable unknown, ignoring...", var);
1160f06cff7cSArnaldo Carvalho de Melo 	else
1161c323cf04SArnaldo Carvalho de Melo 		*cfg->value = perf_config_bool(name, value);
1162c323cf04SArnaldo Carvalho de Melo 	return 0;
1163c323cf04SArnaldo Carvalho de Melo }
1164c323cf04SArnaldo Carvalho de Melo 
1165c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void)
1166c323cf04SArnaldo Carvalho de Melo {
1167c323cf04SArnaldo Carvalho de Melo 	perf_config(annotate__config, NULL);
1168c323cf04SArnaldo Carvalho de Melo }
1169