1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/util.h"
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../browser.h"
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../helpline.h"
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../libslang.h"
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../ui.h"
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../util.h"
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/annotate.h"
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/hist.h"
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/sort.h"
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/symbol.h"
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/evsel.h"
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <pthread.h>
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct browser_disasm_line {
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node	rb_node;
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u32		idx;
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		idx_asm;
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		jump_sources;
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * actual length of this array is saved on the nr_events field
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * of the struct annotate_browser
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	double		percent[1];
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct annotate_browser_opt {
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool hide_src_code,
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	     use_offset,
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	     jump_arrows,
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	     show_nr_jumps;
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} annotate_browser__opts = {
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.use_offset	= true,
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.jump_arrows	= true,
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct annotate_browser {
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct ui_browser b;
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_root	  entries;
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node	  *curr_hot;
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line  *selection;
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line  **offsets;
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		    nr_events;
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		    start;
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		    nr_asm_entries;
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		    nr_entries;
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		    max_jump_sources;
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		    nr_jumps;
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool		    searching_backwards;
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8		    addr_width;
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8		    jumps_width;
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8		    target_width;
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8		    min_addr_width;
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8		    max_addr_width;
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char		    search_bf[128];
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return (struct browser_disasm_line *)(dl + 1);
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				void *entry)
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.hide_src_code) {
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return dl->offset == -1;
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return false;
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						 int nr, bool current)
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return HE_COLORSET_SELECTED;
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (nr == browser->max_jump_sources)
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return HE_COLORSET_TOP;
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (nr > 1)
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return HE_COLORSET_MEDIUM;
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return HE_COLORSET_NORMAL;
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						     int nr, bool current)
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 int color = annotate_browser__jumps_percent_color(browser, nr, current);
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 return ui_browser__set_color(&browser->b, color);
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct browser_disasm_line *bdl = disasm_line__browser(dl);
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool current_entry = ui_browser__is_current_entry(browser, row);
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool change_color = (!annotate_browser__opts.hide_src_code &&
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     (!current_entry || (browser->use_navkeypressed &&
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					         !browser->navkeypressed)));
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int width = browser->width, printed;
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i, pcnt_width = 7 * ab->nr_events;
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	double percent_max = 0.0;
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char bf[256];
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < ab->nr_events; i++) {
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (bdl->percent[i] > percent_max)
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			percent_max = bdl->percent[i];
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (dl->offset != -1 && percent_max != 0.0) {
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for (i = 0; i < ab->nr_events; i++) {
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__set_percent_color(browser, bdl->percent[i],
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						      current_entry);
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			slsmg_printf("%6.2f ", bdl->percent[i]);
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else {
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_browser__set_percent_color(browser, 0, current_entry);
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(" ", pcnt_width);
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	SLsmg_write_char(' ');
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* The scroll bar isn't being used */
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!browser->navkeypressed)
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		width += 1;
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!*dl->line)
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(" ", width - pcnt_width);
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else if (dl->offset == -1) {
131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed = scnprintf(bf, sizeof(bf), "%*s  ",
132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    ab->addr_width, " ");
133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(bf, printed);
134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else {
136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		u64 addr = dl->offset;
137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int color = -1;
138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!annotate_browser__opts.use_offset)
140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			addr += ab->start;
141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!annotate_browser__opts.use_offset) {
143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else {
145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (bdl->jump_sources) {
146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (annotate_browser__opts.show_nr_jumps) {
147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					int prev;
148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					printed = scnprintf(bf, sizeof(bf), "%*d ",
149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							    ab->jumps_width,
150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							    bdl->jump_sources);
151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng											 current_entry);
153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					slsmg_write_nstring(bf, printed);
154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					ui_browser__set_color(browser, prev);
155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				}
156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						    ab->target_width, addr);
159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				printed = scnprintf(bf, sizeof(bf), "%*s  ",
161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						    ab->addr_width, " ");
162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (change_color)
166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(bf, printed);
168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (change_color)
169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__set_color(browser, color);
170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (dl->ins && dl->ins->ops->scnprintf) {
171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (ins__is_jump(dl->ins)) {
172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				bool fwd = dl->ops.target.offset > (u64)dl->offset;
173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng								    SLSMG_UARROW_CHAR);
176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				SLsmg_write_char(' ');
177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else if (ins__is_call(dl->ins)) {
178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				SLsmg_write_char(' ');
180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				slsmg_write_nstring(" ", 2);
182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else {
184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (strcmp(dl->name, "retq")) {
185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				slsmg_write_nstring(" ", 2);
186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				SLsmg_write_char(' ');
189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (current_entry)
197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ab->selection = dl;
198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!dl || !dl->ins || !ins__is_jump(dl->ins)
203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	    || !disasm_line__has_offset(dl)
204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	    || dl->ops.target.offset >= symbol__size(sym))
205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__draw_current_jump(struct ui_browser *browser)
211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *cursor = ab->selection, *target;
214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct browser_disasm_line *btarget, *bcursor;
215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned int from, to;
216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = ab->b.priv;
217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8 pcnt_width = 7;
219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* PLT symbols contain external offsets */
221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (strstr(sym->name, "@plt"))
222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!disasm_line__is_valid_jump(cursor, sym))
225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	target = ab->offsets[cursor->ops.target.offset];
228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!target)
229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bcursor = disasm_line__browser(cursor);
232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	btarget = disasm_line__browser(target);
233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.hide_src_code) {
235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		from = bcursor->idx_asm;
236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		to = btarget->idx_asm;
237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else {
238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		from = (u64)bcursor->idx;
239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		to = (u64)btarget->idx;
240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pcnt_width *= ab->nr_events;
243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__set_color(browser, HE_COLORSET_CODE);
245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 from, to);
247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic unsigned int annotate_browser__refresh(struct ui_browser *browser)
250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret = ui_browser__list_head_refresh(browser);
253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int pcnt_width;
254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pcnt_width = 7 * ab->nr_events;
256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.jump_arrows)
258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		annotate_browser__draw_current_jump(browser);
259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ret;
263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int disasm__cmp(struct browser_disasm_line *a,
266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		       struct browser_disasm_line *b, int nr_pcnt)
267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i;
269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < nr_pcnt; i++) {
271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (a->percent[i] == b->percent[i])
272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return a->percent[i] < b->percent[i];
274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   int nr_events)
280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node **p = &root->rb_node;
282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *parent = NULL;
283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct browser_disasm_line *l;
284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (*p != NULL) {
286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		parent = *p;
287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		l = rb_entry(parent, struct browser_disasm_line, rb_node);
288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (disasm__cmp(bdl, l, nr_events))
290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			p = &(*p)->rb_left;
291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else
292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			p = &(*p)->rb_right;
293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rb_link_node(&bdl->rb_node, parent, p);
295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rb_insert_color(&bdl->rb_node, root);
296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__set_top(struct annotate_browser *browser,
299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct disasm_line *pos, u32 idx)
300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned back;
302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__refresh_dimensions(&browser->b);
304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	back = browser->b.height / 2;
305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.top_idx = browser->b.index = idx;
306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (browser->b.top_idx != 0 && back != 0) {
308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pos = list_entry(pos->node.prev, struct disasm_line, node);
309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (disasm_line__filter(&browser->b, &pos->node))
311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		--browser->b.top_idx;
314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		--back;
315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.top = pos;
318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.navkeypressed = true;
319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__set_rb_top(struct annotate_browser *browser,
322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 struct rb_node *nd)
323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct browser_disasm_line *bpos;
325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *pos;
326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u32 idx;
327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pos = ((struct disasm_line *)bpos) - 1;
330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	idx = bpos->idx;
331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.hide_src_code)
332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		idx = bpos->idx_asm;
333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	annotate_browser__set_top(browser, pos, idx);
334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->curr_hot = nd;
335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__calc_percent(struct annotate_browser *browser,
338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   struct perf_evsel *evsel)
339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = browser->b.priv;
341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotation *notes = symbol__annotation(sym);
343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *pos, *next;
344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	s64 len = symbol__size(sym);
345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->entries = RB_ROOT;
347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_lock(&notes->lock);
349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(pos, &notes->src->source, node) {
351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct browser_disasm_line *bpos = disasm_line__browser(pos);
352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		const char *path = NULL;
353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		double max_percent = 0.0;
354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int i;
355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pos->offset == -1) {
357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			RB_CLEAR_NODE(&bpos->rb_node);
358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		next = disasm__get_next_ip_line(&notes->src->source, pos);
362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for (i = 0; i < browser->nr_events; i++) {
364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			bpos->percent[i] = disasm__calc_percent(notes,
365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						evsel->idx + i,
366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						pos->offset,
367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						next ? next->offset : len,
368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					        &path);
369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (max_percent < bpos->percent[i])
371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				max_percent = bpos->percent[i];
372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (max_percent < 0.01) {
375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			RB_CLEAR_NODE(&bpos->rb_node);
376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		disasm_rb_tree__insert(&browser->entries, bpos,
379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				       browser->nr_events);
380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_unlock(&notes->lock);
382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->curr_hot = rb_last(&browser->entries);
384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool annotate_browser__toggle_source(struct annotate_browser *browser)
387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *dl;
389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct browser_disasm_line *bdl;
390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	off_t offset = browser->b.index - browser->b.top_idx;
391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.seek(&browser->b, offset, SEEK_CUR);
393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	dl = list_entry(browser->b.top, struct disasm_line, node);
394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bdl = disasm_line__browser(dl);
395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.hide_src_code) {
397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (bdl->idx_asm < offset)
398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			offset = bdl->idx;
399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.nr_entries = browser->nr_entries;
401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		annotate_browser__opts.hide_src_code = false;
402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.seek(&browser->b, -offset, SEEK_CUR);
403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.top_idx = bdl->idx - offset;
404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.index = bdl->idx;
405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else {
406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (bdl->idx_asm < 0) {
407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_helpline__puts("Only available for assembly lines.");
408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser->b.seek(&browser->b, -offset, SEEK_CUR);
409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return false;
410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (bdl->idx_asm < offset)
413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			offset = bdl->idx_asm;
414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.nr_entries = browser->nr_asm_entries;
416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		annotate_browser__opts.hide_src_code = true;
417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.seek(&browser->b, -offset, SEEK_CUR);
418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.top_idx = bdl->idx_asm - offset;
419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.index = bdl->idx_asm;
420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__init_asm_mode(struct annotate_browser *browser)
426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__reset_index(&browser->b);
428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.nr_entries = browser->nr_asm_entries;
429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int sym_title(struct symbol *sym, struct map *map, char *title,
434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		     size_t sz)
435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool annotate_browser__callq(struct annotate_browser *browser,
440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    struct perf_evsel *evsel,
441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    struct hist_browser_timer *hbt)
442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = browser->b.priv;
444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *dl = browser->selection;
445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotation *notes;
447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *target;
448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 ip;
449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char title[SYM_TITLE_MAX_SIZE];
450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!ins__is_call(dl->ins))
452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	target = map__find_symbol(ms->map, ip, NULL);
456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (target == NULL) {
457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_helpline__puts("The called function was not found.");
458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return true;
459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	notes = symbol__annotation(target);
462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_lock(&notes->lock);
463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pthread_mutex_unlock(&notes->lock);
466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui__warning("Not enough memory for annotating '%s' symbol!\n",
467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    target->name);
468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return true;
469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_unlock(&notes->lock);
472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	symbol__tui_annotate(target, ms->map, evsel, hbt);
473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sym_title(sym, ms->map, title, sizeof(title));
474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__show_title(&browser->b, title);
475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic
479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					  s64 offset, s64 *idx)
481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = browser->b.priv;
483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotation *notes = symbol__annotation(sym);
485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *pos;
486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*idx = 0;
488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(pos, &notes->src->source, node) {
489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pos->offset == offset)
490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return pos;
491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!disasm_line__filter(&browser->b, &pos->node))
492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			++*idx;
493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return NULL;
496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool annotate_browser__jump(struct annotate_browser *browser)
499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *dl = browser->selection;
501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	s64 idx;
502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!ins__is_jump(dl->ins))
504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (dl == NULL) {
508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_helpline__puts("Invalid jump offset");
509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return true;
510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	annotate_browser__set_top(browser, dl, idx);
513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic
518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					  char *s, s64 *idx)
520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = browser->b.priv;
522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotation *notes = symbol__annotation(sym);
524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *pos = browser->selection;
525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*idx = browser->b.index;
527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry_continue(pos, &notes->src->source, node) {
528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (disasm_line__filter(&browser->b, &pos->node))
529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		++*idx;
532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pos->line && strstr(pos->line, s) != NULL)
534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return pos;
535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return NULL;
538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool __annotate_browser__search(struct annotate_browser *browser)
541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *dl;
543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	s64 idx;
544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (dl == NULL) {
547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_helpline__puts("String not found!");
548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	annotate_browser__set_top(browser, dl, idx);
552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->searching_backwards = false;
553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic
557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						  char *s, s64 *idx)
559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = browser->b.priv;
561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotation *notes = symbol__annotation(sym);
563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *pos = browser->selection;
564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*idx = browser->b.index;
566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (disasm_line__filter(&browser->b, &pos->node))
568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		--*idx;
571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
572e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pos->line && strstr(pos->line, s) != NULL)
573e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return pos;
574e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
575e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
576e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return NULL;
577e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
578e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
579e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool __annotate_browser__search_reverse(struct annotate_browser *browser)
580e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
581e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *dl;
582e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	s64 idx;
583e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
584e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
585e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (dl == NULL) {
586e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_helpline__puts("String not found!");
587e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
588e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
589e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
590e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	annotate_browser__set_top(browser, dl, idx);
591e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->searching_backwards = true;
592e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
593e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
594e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
595e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool annotate_browser__search_window(struct annotate_browser *browser,
596e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					    int delay_secs)
597e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
598e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
599e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				     "ENTER: OK, ESC: Cancel",
600e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				     delay_secs * 2) != K_ENTER ||
601e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	    !*browser->search_bf)
602e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
603e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
604e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
605e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
606e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
607e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
608e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
609e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__search_window(browser, delay_secs))
610e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return __annotate_browser__search(browser);
611e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
612e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return false;
613e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
614e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
615e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool annotate_browser__continue_search(struct annotate_browser *browser,
616e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					      int delay_secs)
617e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
618e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!*browser->search_bf)
619e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return annotate_browser__search(browser, delay_secs);
620e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
621e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return __annotate_browser__search(browser);
622e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
623e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
624e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool annotate_browser__search_reverse(struct annotate_browser *browser,
625e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   int delay_secs)
626e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
627e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__search_window(browser, delay_secs))
628e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return __annotate_browser__search_reverse(browser);
629e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
630e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return false;
631e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
632e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
633e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic
634e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
635e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					       int delay_secs)
636e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
637e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!*browser->search_bf)
638e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return annotate_browser__search_reverse(browser, delay_secs);
639e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
640e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return __annotate_browser__search_reverse(browser);
641e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
642e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
643e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__update_addr_width(struct annotate_browser *browser)
644e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
645e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.use_offset)
646e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->target_width = browser->min_addr_width;
647e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
648e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->target_width = browser->max_addr_width;
649e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
650e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->addr_width = browser->target_width;
651e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
652e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.show_nr_jumps)
653e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->addr_width += browser->jumps_width + 1;
654e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
655e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
656e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int annotate_browser__run(struct annotate_browser *browser,
657e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 struct perf_evsel *evsel,
658e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 struct hist_browser_timer *hbt)
659e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
660e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd = NULL;
661e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = browser->b.priv;
662e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
663e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *help = "Press 'h' for help on key bindings";
664e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int delay_secs = hbt ? hbt->refresh : 0;
665e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int key;
666e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char title[SYM_TITLE_MAX_SIZE];
667e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
668e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sym_title(sym, ms->map, title, sizeof(title));
669e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ui_browser__show(&browser->b, title, help) < 0)
670e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
671e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
672e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	annotate_browser__calc_percent(browser, evsel);
673e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
674e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (browser->curr_hot) {
675e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		annotate_browser__set_rb_top(browser, browser->curr_hot);
676e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.navkeypressed = false;
677e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
678e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
679e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	nd = browser->curr_hot;
680e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
681e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (1) {
682e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		key = ui_browser__run(&browser->b, delay_secs);
683e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
684e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (delay_secs != 0) {
685e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			annotate_browser__calc_percent(browser, evsel);
686e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
687e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * Current line focus got out of the list of most active
688e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * lines, NULL it so that if TAB|UNTAB is pressed, we
689e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * move to curr_hot (current hottest line).
690e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 */
691e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (nd != NULL && RB_EMPTY_NODE(nd))
692e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nd = NULL;
693e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
694e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
695e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		switch (key) {
696e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_TIMER:
697e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (hbt)
698e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hbt->timer(hbt->arg);
699e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
700e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (delay_secs != 0)
701e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				symbol__annotate_decay_histogram(sym, evsel->idx);
702e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
703e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_TAB:
704e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (nd != NULL) {
705e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nd = rb_prev(nd);
706e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (nd == NULL)
707e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					nd = rb_last(&browser->entries);
708e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else
709e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nd = browser->curr_hot;
710e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
711e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_UNTAB:
712e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (nd != NULL)
713e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nd = rb_next(nd);
714e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (nd == NULL)
715e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					nd = rb_first(&browser->entries);
716e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			else
717e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nd = browser->curr_hot;
718e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
719e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_F1:
720e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'h':
721e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__help_window(&browser->b,
722e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"UP/DOWN/PGUP\n"
723e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"PGDN/SPACE    Navigate\n"
724e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"q/ESC/CTRL+C  Exit\n\n"
725e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"->            Go to target\n"
726e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"<-            Exit\n"
727e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"H             Cycle thru hottest instructions\n"
728e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"j             Toggle showing jump to target arrows\n"
729e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"J             Toggle showing number of jump sources on targets\n"
730e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"n             Search next string\n"
731e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"o             Toggle disassembler output/simplified view\n"
732e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"s             Toggle source code view\n"
733e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"/             Search string\n"
734e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"r             Run available scripts\n"
735e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"?             Search string backwards\n");
736e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
737e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'r':
738e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			{
739e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				script_browse(NULL);
740e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
741e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
742e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'H':
743e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			nd = browser->curr_hot;
744e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
745e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 's':
746e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (annotate_browser__toggle_source(browser))
747e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__puts(help);
748e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
749e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'o':
750e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
751e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			annotate_browser__update_addr_width(browser);
752e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
753e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'j':
754e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
755e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
756e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'J':
757e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
758e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			annotate_browser__update_addr_width(browser);
759e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
760e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case '/':
761e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (annotate_browser__search(browser, delay_secs)) {
762e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengshow_help:
763e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__puts(help);
764e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
765e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
766e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'n':
767e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->searching_backwards ?
768e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    annotate_browser__continue_search_reverse(browser, delay_secs) :
769e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    annotate_browser__continue_search(browser, delay_secs))
770e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto show_help;
771e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
772e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case '?':
773e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (annotate_browser__search_reverse(browser, delay_secs))
774e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto show_help;
775e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
776e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'D': {
777e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			static int seq;
778e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_helpline__pop();
779e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
780e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   seq++, browser->b.nr_entries,
781e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->b.height,
782e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->b.index,
783e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->b.top_idx,
784e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->nr_asm_entries);
785e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
786e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
787e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_ENTER:
788e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_RIGHT:
789e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->selection == NULL)
790e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
791e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			else if (browser->selection->offset == -1)
792e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__puts("Actions are only available for assembly lines.");
793e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			else if (!browser->selection->ins) {
794e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (strcmp(browser->selection->name, "retq"))
795e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					goto show_sup_ins;
796e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto out;
797e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else if (!(annotate_browser__jump(browser) ||
798e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				     annotate_browser__callq(browser, evsel, hbt))) {
799e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengshow_sup_ins:
800e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
801e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
802e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
803e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_LEFT:
804e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_ESC:
805e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'q':
806e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case CTRL('c'):
807e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out;
808e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		default:
809e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
810e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
811e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
812e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (nd != NULL)
813e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			annotate_browser__set_rb_top(browser, nd);
814e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
815e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
816e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__hide(&browser->b);
817e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return key;
818e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
819e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
820e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
821e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     struct hist_browser_timer *hbt)
822e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
823e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
824e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
825e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
826e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
827e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						size_t size)
828e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
829e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 offset;
830e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol *ms = browser->b.priv;
831e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = ms->sym;
832e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
833e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* PLT symbols contain external offsets */
834e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (strstr(sym->name, "@plt"))
835e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
836e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
837e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (offset = 0; offset < size; ++offset) {
838e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct disasm_line *dl = browser->offsets[offset], *dlt;
839e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct browser_disasm_line *bdlt;
840e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
841e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!disasm_line__is_valid_jump(dl, sym))
842e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
843e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
844e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		dlt = browser->offsets[dl->ops.target.offset];
845e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/*
846e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
847e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 		 * have to adjust to the previous offset?
848e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 		 */
849e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (dlt == NULL)
850e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
851e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
852e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		bdlt = disasm_line__browser(dlt);
853e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (++bdlt->jump_sources > browser->max_jump_sources)
854e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser->max_jump_sources = bdlt->jump_sources;
855e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
856e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		++browser->nr_jumps;
857e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
858e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
859e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
860e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
861e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline int width_jumps(int n)
862e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
863e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (n >= 100)
864e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 5;
865e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (n / 10)
866e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 2;
867e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 1;
868e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
869e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
870e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symbol__tui_annotate(struct symbol *sym, struct map *map,
871e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 struct perf_evsel *evsel,
872e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 struct hist_browser_timer *hbt)
873e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
874e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct disasm_line *pos, *n;
875e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotation *notes;
876e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size_t size;
877e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol ms = {
878e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.map = map,
879e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.sym = sym,
880e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
881e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotate_browser browser = {
882e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.b = {
883e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.refresh = annotate_browser__refresh,
884e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.seek	 = ui_browser__list_head_seek,
885e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.write	 = annotate_browser__write,
886e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.filter  = disasm_line__filter,
887e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.priv	 = &ms,
888e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.use_navkeypressed = true,
889e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		},
890e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
891e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret = -1;
892e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int nr_pcnt = 1;
893e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size_t sizeof_bdl = sizeof(struct browser_disasm_line);
894e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
895e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sym == NULL)
896e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
897e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
898e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size = symbol__size(sym);
899e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
900e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (map->dso->annotate_warned)
901e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
902e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
903e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.offsets = zalloc(size * sizeof(struct disasm_line *));
904e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (browser.offsets == NULL) {
905e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui__error("Not enough memory!");
906e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
907e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
908e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
909e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_evsel__is_group_event(evsel)) {
910e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nr_pcnt = evsel->nr_members;
911e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
912e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
913e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
914e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
915e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui__error("%s", ui_helpline__last_msg);
916e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto out_free_offsets;
917e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
918e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
919e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_helpline__push("Press <- or ESC to exit");
920e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
921e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	notes = symbol__annotation(sym);
922e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.start = map__rip_2objdump(map, sym->start);
923e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
924e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(pos, &notes->src->source, node) {
925e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct browser_disasm_line *bpos;
926e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		size_t line_len = strlen(pos->line);
927e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
928e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (browser.b.width < line_len)
929e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser.b.width = line_len;
930e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		bpos = disasm_line__browser(pos);
931e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		bpos->idx = browser.nr_entries++;
932e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pos->offset != -1) {
933e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			bpos->idx_asm = browser.nr_asm_entries++;
934e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
935e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * FIXME: short term bandaid to cope with assembly
936e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * routines that comes with labels in the same column
937e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * as the address in objdump, sigh.
938e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 *
939e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * E.g. copy_user_generic_unrolled
940e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 			 */
941e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (pos->offset < (s64)size)
942e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser.offsets[pos->offset] = pos;
943e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else
944e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			bpos->idx_asm = -1;
945e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
946e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
947e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	annotate_browser__mark_jump_targets(&browser, size);
948e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
949e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
950e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.max_addr_width = hex_width(sym->end);
951e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.jumps_width = width_jumps(browser.max_jump_sources);
952e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.nr_events = nr_pcnt;
953e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.b.nr_entries = browser.nr_entries;
954e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.b.entries = &notes->src->source,
955e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser.b.width += 18; /* Percentage */
956e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
957e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (annotate_browser__opts.hide_src_code)
958e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		annotate_browser__init_asm_mode(&browser);
959e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
960e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	annotate_browser__update_addr_width(&browser);
961e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
962e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = annotate_browser__run(&browser, evsel, hbt);
963e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry_safe(pos, n, &notes->src->source, node) {
964e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_del(&pos->node);
965e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		disasm_line__free(pos);
966e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
967e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
968e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_offsets:
969e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(browser.offsets);
970e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ret;
971e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
972e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
973e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define ANNOTATE_CFG(n) \
974e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	{ .name = #n, .value = &annotate_browser__opts.n, }
975e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
976e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/*
977e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Keep the entries sorted, they are bsearch'ed
978e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
979e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct annotate_config {
980e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *name;
981e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool *value;
982e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} annotate__configs[] = {
983e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ANNOTATE_CFG(hide_src_code),
984e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ANNOTATE_CFG(jump_arrows),
985e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ANNOTATE_CFG(show_nr_jumps),
986e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ANNOTATE_CFG(use_offset),
987e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
988e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
989e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#undef ANNOTATE_CFG
990e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
991e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int annotate_config__cmp(const void *name, const void *cfgp)
992e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
993e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct annotate_config *cfg = cfgp;
994e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
995e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return strcmp(name, cfg->name);
996e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
997e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
998e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int annotate__config(const char *var, const char *value,
999e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    void *data __maybe_unused)
1000e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1001e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct annotate_config *cfg;
1002e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *name;
1003e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1004e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (prefixcmp(var, "annotate.") != 0)
1005e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
1006e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1007e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	name = var + 9;
1008e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
1009e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		      sizeof(struct annotate_config), annotate_config__cmp);
1010e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1011e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (cfg == NULL)
1012e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1013e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1014e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*cfg->value = perf_config_bool(name, value);
1015e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1016e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1017e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1018e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid annotate_browser__init(void)
1019e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1020e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_config(annotate__config, NULL);
1021e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1022