1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include "../browser.h"
3*4882a593Smuzhiyun #include "../helpline.h"
4*4882a593Smuzhiyun #include "../ui.h"
5*4882a593Smuzhiyun #include "../../util/annotate.h"
6*4882a593Smuzhiyun #include "../../util/debug.h"
7*4882a593Smuzhiyun #include "../../util/dso.h"
8*4882a593Smuzhiyun #include "../../util/hist.h"
9*4882a593Smuzhiyun #include "../../util/sort.h"
10*4882a593Smuzhiyun #include "../../util/map.h"
11*4882a593Smuzhiyun #include "../../util/symbol.h"
12*4882a593Smuzhiyun #include "../../util/evsel.h"
13*4882a593Smuzhiyun #include "../../util/evlist.h"
14*4882a593Smuzhiyun #include <inttypes.h>
15*4882a593Smuzhiyun #include <pthread.h>
16*4882a593Smuzhiyun #include <linux/kernel.h>
17*4882a593Smuzhiyun #include <linux/string.h>
18*4882a593Smuzhiyun #include <linux/zalloc.h>
19*4882a593Smuzhiyun #include <sys/ttydefaults.h>
20*4882a593Smuzhiyun #include <asm/bug.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun struct disasm_line_samples {
23*4882a593Smuzhiyun double percent;
24*4882a593Smuzhiyun struct sym_hist_entry he;
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct arch;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun struct annotate_browser {
30*4882a593Smuzhiyun struct ui_browser b;
31*4882a593Smuzhiyun struct rb_root entries;
32*4882a593Smuzhiyun struct rb_node *curr_hot;
33*4882a593Smuzhiyun struct annotation_line *selection;
34*4882a593Smuzhiyun struct arch *arch;
35*4882a593Smuzhiyun struct annotation_options *opts;
36*4882a593Smuzhiyun bool searching_backwards;
37*4882a593Smuzhiyun char search_bf[128];
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
browser__annotation(struct ui_browser * browser)40*4882a593Smuzhiyun static inline struct annotation *browser__annotation(struct ui_browser *browser)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun struct map_symbol *ms = browser->priv;
43*4882a593Smuzhiyun return symbol__annotation(ms->sym);
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
disasm_line__filter(struct ui_browser * browser,void * entry)46*4882a593Smuzhiyun static bool disasm_line__filter(struct ui_browser *browser, void *entry)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun struct annotation *notes = browser__annotation(browser);
49*4882a593Smuzhiyun struct annotation_line *al = list_entry(entry, struct annotation_line, node);
50*4882a593Smuzhiyun return annotation_line__filter(al, notes);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
ui_browser__jumps_percent_color(struct ui_browser * browser,int nr,bool current)53*4882a593Smuzhiyun static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun struct annotation *notes = browser__annotation(browser);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun if (current && (!browser->use_navkeypressed || browser->navkeypressed))
58*4882a593Smuzhiyun return HE_COLORSET_SELECTED;
59*4882a593Smuzhiyun if (nr == notes->max_jump_sources)
60*4882a593Smuzhiyun return HE_COLORSET_TOP;
61*4882a593Smuzhiyun if (nr > 1)
62*4882a593Smuzhiyun return HE_COLORSET_MEDIUM;
63*4882a593Smuzhiyun return HE_COLORSET_NORMAL;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
ui_browser__set_jumps_percent_color(void * browser,int nr,bool current)66*4882a593Smuzhiyun static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun int color = ui_browser__jumps_percent_color(browser, nr, current);
69*4882a593Smuzhiyun return ui_browser__set_color(browser, color);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
annotate_browser__set_color(void * browser,int color)72*4882a593Smuzhiyun static int annotate_browser__set_color(void *browser, int color)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun return ui_browser__set_color(browser, color);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
annotate_browser__write_graph(void * browser,int graph)77*4882a593Smuzhiyun static void annotate_browser__write_graph(void *browser, int graph)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun ui_browser__write_graph(browser, graph);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
annotate_browser__set_percent_color(void * browser,double percent,bool current)82*4882a593Smuzhiyun static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun ui_browser__set_percent_color(browser, percent, current);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
annotate_browser__printf(void * browser,const char * fmt,...)87*4882a593Smuzhiyun static void annotate_browser__printf(void *browser, const char *fmt, ...)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun va_list args;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun va_start(args, fmt);
92*4882a593Smuzhiyun ui_browser__vprintf(browser, fmt, args);
93*4882a593Smuzhiyun va_end(args);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
annotate_browser__write(struct ui_browser * browser,void * entry,int row)96*4882a593Smuzhiyun static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
99*4882a593Smuzhiyun struct annotation *notes = browser__annotation(browser);
100*4882a593Smuzhiyun struct annotation_line *al = list_entry(entry, struct annotation_line, node);
101*4882a593Smuzhiyun const bool is_current_entry = ui_browser__is_current_entry(browser, row);
102*4882a593Smuzhiyun struct annotation_write_ops ops = {
103*4882a593Smuzhiyun .first_line = row == 0,
104*4882a593Smuzhiyun .current_entry = is_current_entry,
105*4882a593Smuzhiyun .change_color = (!notes->options->hide_src_code &&
106*4882a593Smuzhiyun (!is_current_entry ||
107*4882a593Smuzhiyun (browser->use_navkeypressed &&
108*4882a593Smuzhiyun !browser->navkeypressed))),
109*4882a593Smuzhiyun .width = browser->width,
110*4882a593Smuzhiyun .obj = browser,
111*4882a593Smuzhiyun .set_color = annotate_browser__set_color,
112*4882a593Smuzhiyun .set_percent_color = annotate_browser__set_percent_color,
113*4882a593Smuzhiyun .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
114*4882a593Smuzhiyun .printf = annotate_browser__printf,
115*4882a593Smuzhiyun .write_graph = annotate_browser__write_graph,
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /* The scroll bar isn't being used */
119*4882a593Smuzhiyun if (!browser->navkeypressed)
120*4882a593Smuzhiyun ops.width += 1;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun annotation_line__write(al, notes, &ops, ab->opts);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (ops.current_entry)
125*4882a593Smuzhiyun ab->selection = al;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
is_fused(struct annotate_browser * ab,struct disasm_line * cursor)128*4882a593Smuzhiyun static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun struct disasm_line *pos = list_prev_entry(cursor, al.node);
131*4882a593Smuzhiyun const char *name;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (!pos)
134*4882a593Smuzhiyun return false;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun if (ins__is_lock(&pos->ins))
137*4882a593Smuzhiyun name = pos->ops.locked.ins.name;
138*4882a593Smuzhiyun else
139*4882a593Smuzhiyun name = pos->ins.name;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (!name || !cursor->ins.name)
142*4882a593Smuzhiyun return false;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun return ins__is_fused(ab->arch, name, cursor->ins.name);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
annotate_browser__draw_current_jump(struct ui_browser * browser)147*4882a593Smuzhiyun static void annotate_browser__draw_current_jump(struct ui_browser *browser)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
150*4882a593Smuzhiyun struct disasm_line *cursor = disasm_line(ab->selection);
151*4882a593Smuzhiyun struct annotation_line *target;
152*4882a593Smuzhiyun unsigned int from, to;
153*4882a593Smuzhiyun struct map_symbol *ms = ab->b.priv;
154*4882a593Smuzhiyun struct symbol *sym = ms->sym;
155*4882a593Smuzhiyun struct annotation *notes = symbol__annotation(sym);
156*4882a593Smuzhiyun u8 pcnt_width = annotation__pcnt_width(notes);
157*4882a593Smuzhiyun int width;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /* PLT symbols contain external offsets */
160*4882a593Smuzhiyun if (strstr(sym->name, "@plt"))
161*4882a593Smuzhiyun return;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (!disasm_line__is_valid_local_jump(cursor, sym))
164*4882a593Smuzhiyun return;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /*
167*4882a593Smuzhiyun * This first was seen with a gcc function, _cpp_lex_token, that
168*4882a593Smuzhiyun * has the usual jumps:
169*4882a593Smuzhiyun *
170*4882a593Smuzhiyun * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92>
171*4882a593Smuzhiyun *
172*4882a593Smuzhiyun * I.e. jumps to a label inside that function (_cpp_lex_token), and
173*4882a593Smuzhiyun * those works, but also this kind:
174*4882a593Smuzhiyun *
175*4882a593Smuzhiyun * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72>
176*4882a593Smuzhiyun *
177*4882a593Smuzhiyun * I.e. jumps to another function, outside _cpp_lex_token, which
178*4882a593Smuzhiyun * are not being correctly handled generating as a side effect references
179*4882a593Smuzhiyun * to ab->offset[] entries that are set to NULL, so to make this code
180*4882a593Smuzhiyun * more robust, check that here.
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * A proper fix for will be put in place, looking at the function
183*4882a593Smuzhiyun * name right after the '<' token and probably treating this like a
184*4882a593Smuzhiyun * 'call' instruction.
185*4882a593Smuzhiyun */
186*4882a593Smuzhiyun target = notes->offsets[cursor->ops.target.offset];
187*4882a593Smuzhiyun if (target == NULL) {
188*4882a593Smuzhiyun ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
189*4882a593Smuzhiyun cursor->ops.target.offset);
190*4882a593Smuzhiyun return;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (notes->options->hide_src_code) {
194*4882a593Smuzhiyun from = cursor->al.idx_asm;
195*4882a593Smuzhiyun to = target->idx_asm;
196*4882a593Smuzhiyun } else {
197*4882a593Smuzhiyun from = (u64)cursor->al.idx;
198*4882a593Smuzhiyun to = (u64)target->idx;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun width = annotation__cycles_width(notes);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
204*4882a593Smuzhiyun __ui_browser__line_arrow(browser,
205*4882a593Smuzhiyun pcnt_width + 2 + notes->widths.addr + width,
206*4882a593Smuzhiyun from, to);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (is_fused(ab, cursor)) {
209*4882a593Smuzhiyun ui_browser__mark_fused(browser,
210*4882a593Smuzhiyun pcnt_width + 3 + notes->widths.addr + width,
211*4882a593Smuzhiyun from - 1,
212*4882a593Smuzhiyun to > from);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
annotate_browser__refresh(struct ui_browser * browser)216*4882a593Smuzhiyun static unsigned int annotate_browser__refresh(struct ui_browser *browser)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun struct annotation *notes = browser__annotation(browser);
219*4882a593Smuzhiyun int ret = ui_browser__list_head_refresh(browser);
220*4882a593Smuzhiyun int pcnt_width = annotation__pcnt_width(notes);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (notes->options->jump_arrows)
223*4882a593Smuzhiyun annotate_browser__draw_current_jump(browser);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun ui_browser__set_color(browser, HE_COLORSET_NORMAL);
226*4882a593Smuzhiyun __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
227*4882a593Smuzhiyun return ret;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
disasm__cmp(struct annotation_line * a,struct annotation_line * b,int percent_type)230*4882a593Smuzhiyun static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
231*4882a593Smuzhiyun int percent_type)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun int i;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun for (i = 0; i < a->data_nr; i++) {
236*4882a593Smuzhiyun if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
237*4882a593Smuzhiyun continue;
238*4882a593Smuzhiyun return a->data[i].percent[percent_type] -
239*4882a593Smuzhiyun b->data[i].percent[percent_type];
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun return 0;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
disasm_rb_tree__insert(struct annotate_browser * browser,struct annotation_line * al)244*4882a593Smuzhiyun static void disasm_rb_tree__insert(struct annotate_browser *browser,
245*4882a593Smuzhiyun struct annotation_line *al)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun struct rb_root *root = &browser->entries;
248*4882a593Smuzhiyun struct rb_node **p = &root->rb_node;
249*4882a593Smuzhiyun struct rb_node *parent = NULL;
250*4882a593Smuzhiyun struct annotation_line *l;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun while (*p != NULL) {
253*4882a593Smuzhiyun parent = *p;
254*4882a593Smuzhiyun l = rb_entry(parent, struct annotation_line, rb_node);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
257*4882a593Smuzhiyun p = &(*p)->rb_left;
258*4882a593Smuzhiyun else
259*4882a593Smuzhiyun p = &(*p)->rb_right;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun rb_link_node(&al->rb_node, parent, p);
262*4882a593Smuzhiyun rb_insert_color(&al->rb_node, root);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
annotate_browser__set_top(struct annotate_browser * browser,struct annotation_line * pos,u32 idx)265*4882a593Smuzhiyun static void annotate_browser__set_top(struct annotate_browser *browser,
266*4882a593Smuzhiyun struct annotation_line *pos, u32 idx)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun struct annotation *notes = browser__annotation(&browser->b);
269*4882a593Smuzhiyun unsigned back;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun ui_browser__refresh_dimensions(&browser->b);
272*4882a593Smuzhiyun back = browser->b.height / 2;
273*4882a593Smuzhiyun browser->b.top_idx = browser->b.index = idx;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun while (browser->b.top_idx != 0 && back != 0) {
276*4882a593Smuzhiyun pos = list_entry(pos->node.prev, struct annotation_line, node);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (annotation_line__filter(pos, notes))
279*4882a593Smuzhiyun continue;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun --browser->b.top_idx;
282*4882a593Smuzhiyun --back;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun browser->b.top = pos;
286*4882a593Smuzhiyun browser->b.navkeypressed = true;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
annotate_browser__set_rb_top(struct annotate_browser * browser,struct rb_node * nd)289*4882a593Smuzhiyun static void annotate_browser__set_rb_top(struct annotate_browser *browser,
290*4882a593Smuzhiyun struct rb_node *nd)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun struct annotation *notes = browser__annotation(&browser->b);
293*4882a593Smuzhiyun struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
294*4882a593Smuzhiyun u32 idx = pos->idx;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (notes->options->hide_src_code)
297*4882a593Smuzhiyun idx = pos->idx_asm;
298*4882a593Smuzhiyun annotate_browser__set_top(browser, pos, idx);
299*4882a593Smuzhiyun browser->curr_hot = nd;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
annotate_browser__calc_percent(struct annotate_browser * browser,struct evsel * evsel)302*4882a593Smuzhiyun static void annotate_browser__calc_percent(struct annotate_browser *browser,
303*4882a593Smuzhiyun struct evsel *evsel)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun struct map_symbol *ms = browser->b.priv;
306*4882a593Smuzhiyun struct symbol *sym = ms->sym;
307*4882a593Smuzhiyun struct annotation *notes = symbol__annotation(sym);
308*4882a593Smuzhiyun struct disasm_line *pos;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun browser->entries = RB_ROOT;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun pthread_mutex_lock(¬es->lock);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun symbol__calc_percent(sym, evsel);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun list_for_each_entry(pos, ¬es->src->source, al.node) {
317*4882a593Smuzhiyun double max_percent = 0.0;
318*4882a593Smuzhiyun int i;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (pos->al.offset == -1) {
321*4882a593Smuzhiyun RB_CLEAR_NODE(&pos->al.rb_node);
322*4882a593Smuzhiyun continue;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun for (i = 0; i < pos->al.data_nr; i++) {
326*4882a593Smuzhiyun double percent;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun percent = annotation_data__percent(&pos->al.data[i],
329*4882a593Smuzhiyun browser->opts->percent_type);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun if (max_percent < percent)
332*4882a593Smuzhiyun max_percent = percent;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (max_percent < 0.01 && pos->al.ipc == 0) {
336*4882a593Smuzhiyun RB_CLEAR_NODE(&pos->al.rb_node);
337*4882a593Smuzhiyun continue;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun disasm_rb_tree__insert(browser, &pos->al);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun pthread_mutex_unlock(¬es->lock);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun browser->curr_hot = rb_last(&browser->entries);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
annotate_browser__toggle_source(struct annotate_browser * browser)346*4882a593Smuzhiyun static bool annotate_browser__toggle_source(struct annotate_browser *browser)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun struct annotation *notes = browser__annotation(&browser->b);
349*4882a593Smuzhiyun struct annotation_line *al;
350*4882a593Smuzhiyun off_t offset = browser->b.index - browser->b.top_idx;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun browser->b.seek(&browser->b, offset, SEEK_CUR);
353*4882a593Smuzhiyun al = list_entry(browser->b.top, struct annotation_line, node);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun if (notes->options->hide_src_code) {
356*4882a593Smuzhiyun if (al->idx_asm < offset)
357*4882a593Smuzhiyun offset = al->idx;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun browser->b.nr_entries = notes->nr_entries;
360*4882a593Smuzhiyun notes->options->hide_src_code = false;
361*4882a593Smuzhiyun browser->b.seek(&browser->b, -offset, SEEK_CUR);
362*4882a593Smuzhiyun browser->b.top_idx = al->idx - offset;
363*4882a593Smuzhiyun browser->b.index = al->idx;
364*4882a593Smuzhiyun } else {
365*4882a593Smuzhiyun if (al->idx_asm < 0) {
366*4882a593Smuzhiyun ui_helpline__puts("Only available for assembly lines.");
367*4882a593Smuzhiyun browser->b.seek(&browser->b, -offset, SEEK_CUR);
368*4882a593Smuzhiyun return false;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (al->idx_asm < offset)
372*4882a593Smuzhiyun offset = al->idx_asm;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun browser->b.nr_entries = notes->nr_asm_entries;
375*4882a593Smuzhiyun notes->options->hide_src_code = true;
376*4882a593Smuzhiyun browser->b.seek(&browser->b, -offset, SEEK_CUR);
377*4882a593Smuzhiyun browser->b.top_idx = al->idx_asm - offset;
378*4882a593Smuzhiyun browser->b.index = al->idx_asm;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun return true;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
ui_browser__init_asm_mode(struct ui_browser * browser)384*4882a593Smuzhiyun static void ui_browser__init_asm_mode(struct ui_browser *browser)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun struct annotation *notes = browser__annotation(browser);
387*4882a593Smuzhiyun ui_browser__reset_index(browser);
388*4882a593Smuzhiyun browser->nr_entries = notes->nr_asm_entries;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
392*4882a593Smuzhiyun
sym_title(struct symbol * sym,struct map * map,char * title,size_t sz,int percent_type)393*4882a593Smuzhiyun static int sym_title(struct symbol *sym, struct map *map, char *title,
394*4882a593Smuzhiyun size_t sz, int percent_type)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name,
397*4882a593Smuzhiyun percent_type_str(percent_type));
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /*
401*4882a593Smuzhiyun * This can be called from external jumps, i.e. jumps from one functon
402*4882a593Smuzhiyun * to another, like from the kernel's entry_SYSCALL_64 function to the
403*4882a593Smuzhiyun * swapgs_restore_regs_and_return_to_usermode() function.
404*4882a593Smuzhiyun *
405*4882a593Smuzhiyun * So all we check here is that dl->ops.target.sym is set, if it is, just
406*4882a593Smuzhiyun * go to that function and when exiting from its disassembly, come back
407*4882a593Smuzhiyun * to the calling function.
408*4882a593Smuzhiyun */
annotate_browser__callq(struct annotate_browser * browser,struct evsel * evsel,struct hist_browser_timer * hbt)409*4882a593Smuzhiyun static bool annotate_browser__callq(struct annotate_browser *browser,
410*4882a593Smuzhiyun struct evsel *evsel,
411*4882a593Smuzhiyun struct hist_browser_timer *hbt)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun struct map_symbol *ms = browser->b.priv, target_ms;
414*4882a593Smuzhiyun struct disasm_line *dl = disasm_line(browser->selection);
415*4882a593Smuzhiyun struct annotation *notes;
416*4882a593Smuzhiyun char title[SYM_TITLE_MAX_SIZE];
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun if (!dl->ops.target.sym) {
419*4882a593Smuzhiyun ui_helpline__puts("The called function was not found.");
420*4882a593Smuzhiyun return true;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun notes = symbol__annotation(dl->ops.target.sym);
424*4882a593Smuzhiyun pthread_mutex_lock(¬es->lock);
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
427*4882a593Smuzhiyun pthread_mutex_unlock(¬es->lock);
428*4882a593Smuzhiyun ui__warning("Not enough memory for annotating '%s' symbol!\n",
429*4882a593Smuzhiyun dl->ops.target.sym->name);
430*4882a593Smuzhiyun return true;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun target_ms.maps = ms->maps;
434*4882a593Smuzhiyun target_ms.map = ms->map;
435*4882a593Smuzhiyun target_ms.sym = dl->ops.target.sym;
436*4882a593Smuzhiyun pthread_mutex_unlock(¬es->lock);
437*4882a593Smuzhiyun symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);
438*4882a593Smuzhiyun sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
439*4882a593Smuzhiyun ui_browser__show_title(&browser->b, title);
440*4882a593Smuzhiyun return true;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun static
annotate_browser__find_offset(struct annotate_browser * browser,s64 offset,s64 * idx)444*4882a593Smuzhiyun struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
445*4882a593Smuzhiyun s64 offset, s64 *idx)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun struct annotation *notes = browser__annotation(&browser->b);
448*4882a593Smuzhiyun struct disasm_line *pos;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun *idx = 0;
451*4882a593Smuzhiyun list_for_each_entry(pos, ¬es->src->source, al.node) {
452*4882a593Smuzhiyun if (pos->al.offset == offset)
453*4882a593Smuzhiyun return pos;
454*4882a593Smuzhiyun if (!annotation_line__filter(&pos->al, notes))
455*4882a593Smuzhiyun ++*idx;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun return NULL;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
annotate_browser__jump(struct annotate_browser * browser,struct evsel * evsel,struct hist_browser_timer * hbt)461*4882a593Smuzhiyun static bool annotate_browser__jump(struct annotate_browser *browser,
462*4882a593Smuzhiyun struct evsel *evsel,
463*4882a593Smuzhiyun struct hist_browser_timer *hbt)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun struct disasm_line *dl = disasm_line(browser->selection);
466*4882a593Smuzhiyun u64 offset;
467*4882a593Smuzhiyun s64 idx;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun if (!ins__is_jump(&dl->ins))
470*4882a593Smuzhiyun return false;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (dl->ops.target.outside) {
473*4882a593Smuzhiyun annotate_browser__callq(browser, evsel, hbt);
474*4882a593Smuzhiyun return true;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun offset = dl->ops.target.offset;
478*4882a593Smuzhiyun dl = annotate_browser__find_offset(browser, offset, &idx);
479*4882a593Smuzhiyun if (dl == NULL) {
480*4882a593Smuzhiyun ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
481*4882a593Smuzhiyun return true;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun annotate_browser__set_top(browser, &dl->al, idx);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun return true;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun static
annotate_browser__find_string(struct annotate_browser * browser,char * s,s64 * idx)490*4882a593Smuzhiyun struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
491*4882a593Smuzhiyun char *s, s64 *idx)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun struct annotation *notes = browser__annotation(&browser->b);
494*4882a593Smuzhiyun struct annotation_line *al = browser->selection;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun *idx = browser->b.index;
497*4882a593Smuzhiyun list_for_each_entry_continue(al, ¬es->src->source, node) {
498*4882a593Smuzhiyun if (annotation_line__filter(al, notes))
499*4882a593Smuzhiyun continue;
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun ++*idx;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun if (al->line && strstr(al->line, s) != NULL)
504*4882a593Smuzhiyun return al;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun return NULL;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
__annotate_browser__search(struct annotate_browser * browser)510*4882a593Smuzhiyun static bool __annotate_browser__search(struct annotate_browser *browser)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun struct annotation_line *al;
513*4882a593Smuzhiyun s64 idx;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun al = annotate_browser__find_string(browser, browser->search_bf, &idx);
516*4882a593Smuzhiyun if (al == NULL) {
517*4882a593Smuzhiyun ui_helpline__puts("String not found!");
518*4882a593Smuzhiyun return false;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun annotate_browser__set_top(browser, al, idx);
522*4882a593Smuzhiyun browser->searching_backwards = false;
523*4882a593Smuzhiyun return true;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun static
annotate_browser__find_string_reverse(struct annotate_browser * browser,char * s,s64 * idx)527*4882a593Smuzhiyun struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
528*4882a593Smuzhiyun char *s, s64 *idx)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun struct annotation *notes = browser__annotation(&browser->b);
531*4882a593Smuzhiyun struct annotation_line *al = browser->selection;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun *idx = browser->b.index;
534*4882a593Smuzhiyun list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
535*4882a593Smuzhiyun if (annotation_line__filter(al, notes))
536*4882a593Smuzhiyun continue;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun --*idx;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun if (al->line && strstr(al->line, s) != NULL)
541*4882a593Smuzhiyun return al;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun return NULL;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
__annotate_browser__search_reverse(struct annotate_browser * browser)547*4882a593Smuzhiyun static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun struct annotation_line *al;
550*4882a593Smuzhiyun s64 idx;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
553*4882a593Smuzhiyun if (al == NULL) {
554*4882a593Smuzhiyun ui_helpline__puts("String not found!");
555*4882a593Smuzhiyun return false;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun annotate_browser__set_top(browser, al, idx);
559*4882a593Smuzhiyun browser->searching_backwards = true;
560*4882a593Smuzhiyun return true;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
annotate_browser__search_window(struct annotate_browser * browser,int delay_secs)563*4882a593Smuzhiyun static bool annotate_browser__search_window(struct annotate_browser *browser,
564*4882a593Smuzhiyun int delay_secs)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun if (ui_browser__input_window("Search", "String: ", browser->search_bf,
567*4882a593Smuzhiyun "ENTER: OK, ESC: Cancel",
568*4882a593Smuzhiyun delay_secs * 2) != K_ENTER ||
569*4882a593Smuzhiyun !*browser->search_bf)
570*4882a593Smuzhiyun return false;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun return true;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
annotate_browser__search(struct annotate_browser * browser,int delay_secs)575*4882a593Smuzhiyun static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun if (annotate_browser__search_window(browser, delay_secs))
578*4882a593Smuzhiyun return __annotate_browser__search(browser);
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun return false;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
annotate_browser__continue_search(struct annotate_browser * browser,int delay_secs)583*4882a593Smuzhiyun static bool annotate_browser__continue_search(struct annotate_browser *browser,
584*4882a593Smuzhiyun int delay_secs)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun if (!*browser->search_bf)
587*4882a593Smuzhiyun return annotate_browser__search(browser, delay_secs);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun return __annotate_browser__search(browser);
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun
annotate_browser__search_reverse(struct annotate_browser * browser,int delay_secs)592*4882a593Smuzhiyun static bool annotate_browser__search_reverse(struct annotate_browser *browser,
593*4882a593Smuzhiyun int delay_secs)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun if (annotate_browser__search_window(browser, delay_secs))
596*4882a593Smuzhiyun return __annotate_browser__search_reverse(browser);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun return false;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun static
annotate_browser__continue_search_reverse(struct annotate_browser * browser,int delay_secs)602*4882a593Smuzhiyun bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
603*4882a593Smuzhiyun int delay_secs)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun if (!*browser->search_bf)
606*4882a593Smuzhiyun return annotate_browser__search_reverse(browser, delay_secs);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun return __annotate_browser__search_reverse(browser);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
annotate_browser__show(struct ui_browser * browser,char * title,const char * help)611*4882a593Smuzhiyun static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
614*4882a593Smuzhiyun struct map_symbol *ms = browser->priv;
615*4882a593Smuzhiyun struct symbol *sym = ms->sym;
616*4882a593Smuzhiyun char symbol_dso[SYM_TITLE_MAX_SIZE];
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun if (ui_browser__show(browser, title, help) < 0)
619*4882a593Smuzhiyun return -1;
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun ui_browser__gotorc_title(browser, 0, 0);
624*4882a593Smuzhiyun ui_browser__set_color(browser, HE_COLORSET_ROOT);
625*4882a593Smuzhiyun ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
626*4882a593Smuzhiyun return 0;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun static void
switch_percent_type(struct annotation_options * opts,bool base)630*4882a593Smuzhiyun switch_percent_type(struct annotation_options *opts, bool base)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun switch (opts->percent_type) {
633*4882a593Smuzhiyun case PERCENT_HITS_LOCAL:
634*4882a593Smuzhiyun if (base)
635*4882a593Smuzhiyun opts->percent_type = PERCENT_PERIOD_LOCAL;
636*4882a593Smuzhiyun else
637*4882a593Smuzhiyun opts->percent_type = PERCENT_HITS_GLOBAL;
638*4882a593Smuzhiyun break;
639*4882a593Smuzhiyun case PERCENT_HITS_GLOBAL:
640*4882a593Smuzhiyun if (base)
641*4882a593Smuzhiyun opts->percent_type = PERCENT_PERIOD_GLOBAL;
642*4882a593Smuzhiyun else
643*4882a593Smuzhiyun opts->percent_type = PERCENT_HITS_LOCAL;
644*4882a593Smuzhiyun break;
645*4882a593Smuzhiyun case PERCENT_PERIOD_LOCAL:
646*4882a593Smuzhiyun if (base)
647*4882a593Smuzhiyun opts->percent_type = PERCENT_HITS_LOCAL;
648*4882a593Smuzhiyun else
649*4882a593Smuzhiyun opts->percent_type = PERCENT_PERIOD_GLOBAL;
650*4882a593Smuzhiyun break;
651*4882a593Smuzhiyun case PERCENT_PERIOD_GLOBAL:
652*4882a593Smuzhiyun if (base)
653*4882a593Smuzhiyun opts->percent_type = PERCENT_HITS_GLOBAL;
654*4882a593Smuzhiyun else
655*4882a593Smuzhiyun opts->percent_type = PERCENT_PERIOD_LOCAL;
656*4882a593Smuzhiyun break;
657*4882a593Smuzhiyun default:
658*4882a593Smuzhiyun WARN_ON(1);
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
annotate_browser__run(struct annotate_browser * browser,struct evsel * evsel,struct hist_browser_timer * hbt)662*4882a593Smuzhiyun static int annotate_browser__run(struct annotate_browser *browser,
663*4882a593Smuzhiyun struct evsel *evsel,
664*4882a593Smuzhiyun struct hist_browser_timer *hbt)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun struct rb_node *nd = NULL;
667*4882a593Smuzhiyun struct hists *hists = evsel__hists(evsel);
668*4882a593Smuzhiyun struct map_symbol *ms = browser->b.priv;
669*4882a593Smuzhiyun struct symbol *sym = ms->sym;
670*4882a593Smuzhiyun struct annotation *notes = symbol__annotation(ms->sym);
671*4882a593Smuzhiyun const char *help = "Press 'h' for help on key bindings";
672*4882a593Smuzhiyun int delay_secs = hbt ? hbt->refresh : 0;
673*4882a593Smuzhiyun char title[256];
674*4882a593Smuzhiyun int key;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun hists__scnprintf_title(hists, title, sizeof(title));
677*4882a593Smuzhiyun if (annotate_browser__show(&browser->b, title, help) < 0)
678*4882a593Smuzhiyun return -1;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun annotate_browser__calc_percent(browser, evsel);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun if (browser->curr_hot) {
683*4882a593Smuzhiyun annotate_browser__set_rb_top(browser, browser->curr_hot);
684*4882a593Smuzhiyun browser->b.navkeypressed = false;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun nd = browser->curr_hot;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun while (1) {
690*4882a593Smuzhiyun key = ui_browser__run(&browser->b, delay_secs);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun if (delay_secs != 0) {
693*4882a593Smuzhiyun annotate_browser__calc_percent(browser, evsel);
694*4882a593Smuzhiyun /*
695*4882a593Smuzhiyun * Current line focus got out of the list of most active
696*4882a593Smuzhiyun * lines, NULL it so that if TAB|UNTAB is pressed, we
697*4882a593Smuzhiyun * move to curr_hot (current hottest line).
698*4882a593Smuzhiyun */
699*4882a593Smuzhiyun if (nd != NULL && RB_EMPTY_NODE(nd))
700*4882a593Smuzhiyun nd = NULL;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun switch (key) {
704*4882a593Smuzhiyun case K_TIMER:
705*4882a593Smuzhiyun if (hbt)
706*4882a593Smuzhiyun hbt->timer(hbt->arg);
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun if (delay_secs != 0) {
709*4882a593Smuzhiyun symbol__annotate_decay_histogram(sym, evsel->idx);
710*4882a593Smuzhiyun hists__scnprintf_title(hists, title, sizeof(title));
711*4882a593Smuzhiyun annotate_browser__show(&browser->b, title, help);
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun continue;
714*4882a593Smuzhiyun case K_TAB:
715*4882a593Smuzhiyun if (nd != NULL) {
716*4882a593Smuzhiyun nd = rb_prev(nd);
717*4882a593Smuzhiyun if (nd == NULL)
718*4882a593Smuzhiyun nd = rb_last(&browser->entries);
719*4882a593Smuzhiyun } else
720*4882a593Smuzhiyun nd = browser->curr_hot;
721*4882a593Smuzhiyun break;
722*4882a593Smuzhiyun case K_UNTAB:
723*4882a593Smuzhiyun if (nd != NULL) {
724*4882a593Smuzhiyun nd = rb_next(nd);
725*4882a593Smuzhiyun if (nd == NULL)
726*4882a593Smuzhiyun nd = rb_first(&browser->entries);
727*4882a593Smuzhiyun } else
728*4882a593Smuzhiyun nd = browser->curr_hot;
729*4882a593Smuzhiyun break;
730*4882a593Smuzhiyun case K_F1:
731*4882a593Smuzhiyun case 'h':
732*4882a593Smuzhiyun ui_browser__help_window(&browser->b,
733*4882a593Smuzhiyun "UP/DOWN/PGUP\n"
734*4882a593Smuzhiyun "PGDN/SPACE Navigate\n"
735*4882a593Smuzhiyun "q/ESC/CTRL+C Exit\n\n"
736*4882a593Smuzhiyun "ENTER Go to target\n"
737*4882a593Smuzhiyun "ESC Exit\n"
738*4882a593Smuzhiyun "H Go to hottest instruction\n"
739*4882a593Smuzhiyun "TAB/shift+TAB Cycle thru hottest instructions\n"
740*4882a593Smuzhiyun "j Toggle showing jump to target arrows\n"
741*4882a593Smuzhiyun "J Toggle showing number of jump sources on targets\n"
742*4882a593Smuzhiyun "n Search next string\n"
743*4882a593Smuzhiyun "o Toggle disassembler output/simplified view\n"
744*4882a593Smuzhiyun "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
745*4882a593Smuzhiyun "s Toggle source code view\n"
746*4882a593Smuzhiyun "t Circulate percent, total period, samples view\n"
747*4882a593Smuzhiyun "c Show min/max cycle\n"
748*4882a593Smuzhiyun "/ Search string\n"
749*4882a593Smuzhiyun "k Toggle line numbers\n"
750*4882a593Smuzhiyun "P Print to [symbol_name].annotation file.\n"
751*4882a593Smuzhiyun "r Run available scripts\n"
752*4882a593Smuzhiyun "p Toggle percent type [local/global]\n"
753*4882a593Smuzhiyun "b Toggle percent base [period/hits]\n"
754*4882a593Smuzhiyun "? Search string backwards\n");
755*4882a593Smuzhiyun continue;
756*4882a593Smuzhiyun case 'r':
757*4882a593Smuzhiyun script_browse(NULL, NULL);
758*4882a593Smuzhiyun annotate_browser__show(&browser->b, title, help);
759*4882a593Smuzhiyun continue;
760*4882a593Smuzhiyun case 'k':
761*4882a593Smuzhiyun notes->options->show_linenr = !notes->options->show_linenr;
762*4882a593Smuzhiyun break;
763*4882a593Smuzhiyun case 'H':
764*4882a593Smuzhiyun nd = browser->curr_hot;
765*4882a593Smuzhiyun break;
766*4882a593Smuzhiyun case 's':
767*4882a593Smuzhiyun if (annotate_browser__toggle_source(browser))
768*4882a593Smuzhiyun ui_helpline__puts(help);
769*4882a593Smuzhiyun continue;
770*4882a593Smuzhiyun case 'o':
771*4882a593Smuzhiyun notes->options->use_offset = !notes->options->use_offset;
772*4882a593Smuzhiyun annotation__update_column_widths(notes);
773*4882a593Smuzhiyun continue;
774*4882a593Smuzhiyun case 'O':
775*4882a593Smuzhiyun if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
776*4882a593Smuzhiyun notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
777*4882a593Smuzhiyun continue;
778*4882a593Smuzhiyun case 'j':
779*4882a593Smuzhiyun notes->options->jump_arrows = !notes->options->jump_arrows;
780*4882a593Smuzhiyun continue;
781*4882a593Smuzhiyun case 'J':
782*4882a593Smuzhiyun notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
783*4882a593Smuzhiyun annotation__update_column_widths(notes);
784*4882a593Smuzhiyun continue;
785*4882a593Smuzhiyun case '/':
786*4882a593Smuzhiyun if (annotate_browser__search(browser, delay_secs)) {
787*4882a593Smuzhiyun show_help:
788*4882a593Smuzhiyun ui_helpline__puts(help);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun continue;
791*4882a593Smuzhiyun case 'n':
792*4882a593Smuzhiyun if (browser->searching_backwards ?
793*4882a593Smuzhiyun annotate_browser__continue_search_reverse(browser, delay_secs) :
794*4882a593Smuzhiyun annotate_browser__continue_search(browser, delay_secs))
795*4882a593Smuzhiyun goto show_help;
796*4882a593Smuzhiyun continue;
797*4882a593Smuzhiyun case '?':
798*4882a593Smuzhiyun if (annotate_browser__search_reverse(browser, delay_secs))
799*4882a593Smuzhiyun goto show_help;
800*4882a593Smuzhiyun continue;
801*4882a593Smuzhiyun case 'D': {
802*4882a593Smuzhiyun static int seq;
803*4882a593Smuzhiyun ui_helpline__pop();
804*4882a593Smuzhiyun ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
805*4882a593Smuzhiyun seq++, browser->b.nr_entries,
806*4882a593Smuzhiyun browser->b.height,
807*4882a593Smuzhiyun browser->b.index,
808*4882a593Smuzhiyun browser->b.top_idx,
809*4882a593Smuzhiyun notes->nr_asm_entries);
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun continue;
812*4882a593Smuzhiyun case K_ENTER:
813*4882a593Smuzhiyun case K_RIGHT:
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun struct disasm_line *dl = disasm_line(browser->selection);
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun if (browser->selection == NULL)
818*4882a593Smuzhiyun ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
819*4882a593Smuzhiyun else if (browser->selection->offset == -1)
820*4882a593Smuzhiyun ui_helpline__puts("Actions are only available for assembly lines.");
821*4882a593Smuzhiyun else if (!dl->ins.ops)
822*4882a593Smuzhiyun goto show_sup_ins;
823*4882a593Smuzhiyun else if (ins__is_ret(&dl->ins))
824*4882a593Smuzhiyun goto out;
825*4882a593Smuzhiyun else if (!(annotate_browser__jump(browser, evsel, hbt) ||
826*4882a593Smuzhiyun annotate_browser__callq(browser, evsel, hbt))) {
827*4882a593Smuzhiyun show_sup_ins:
828*4882a593Smuzhiyun ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun continue;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun case 'P':
833*4882a593Smuzhiyun map_symbol__annotation_dump(ms, evsel, browser->opts);
834*4882a593Smuzhiyun continue;
835*4882a593Smuzhiyun case 't':
836*4882a593Smuzhiyun if (symbol_conf.show_total_period) {
837*4882a593Smuzhiyun symbol_conf.show_total_period = false;
838*4882a593Smuzhiyun symbol_conf.show_nr_samples = true;
839*4882a593Smuzhiyun } else if (symbol_conf.show_nr_samples)
840*4882a593Smuzhiyun symbol_conf.show_nr_samples = false;
841*4882a593Smuzhiyun else
842*4882a593Smuzhiyun symbol_conf.show_total_period = true;
843*4882a593Smuzhiyun annotation__update_column_widths(notes);
844*4882a593Smuzhiyun continue;
845*4882a593Smuzhiyun case 'c':
846*4882a593Smuzhiyun if (notes->options->show_minmax_cycle)
847*4882a593Smuzhiyun notes->options->show_minmax_cycle = false;
848*4882a593Smuzhiyun else
849*4882a593Smuzhiyun notes->options->show_minmax_cycle = true;
850*4882a593Smuzhiyun annotation__update_column_widths(notes);
851*4882a593Smuzhiyun continue;
852*4882a593Smuzhiyun case 'p':
853*4882a593Smuzhiyun case 'b':
854*4882a593Smuzhiyun switch_percent_type(browser->opts, key == 'b');
855*4882a593Smuzhiyun hists__scnprintf_title(hists, title, sizeof(title));
856*4882a593Smuzhiyun annotate_browser__show(&browser->b, title, help);
857*4882a593Smuzhiyun continue;
858*4882a593Smuzhiyun case K_LEFT:
859*4882a593Smuzhiyun case K_ESC:
860*4882a593Smuzhiyun case 'q':
861*4882a593Smuzhiyun case CTRL('c'):
862*4882a593Smuzhiyun goto out;
863*4882a593Smuzhiyun default:
864*4882a593Smuzhiyun continue;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun if (nd != NULL)
868*4882a593Smuzhiyun annotate_browser__set_rb_top(browser, nd);
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun out:
871*4882a593Smuzhiyun ui_browser__hide(&browser->b);
872*4882a593Smuzhiyun return key;
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun
map_symbol__tui_annotate(struct map_symbol * ms,struct evsel * evsel,struct hist_browser_timer * hbt,struct annotation_options * opts)875*4882a593Smuzhiyun int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
876*4882a593Smuzhiyun struct hist_browser_timer *hbt,
877*4882a593Smuzhiyun struct annotation_options *opts)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun return symbol__tui_annotate(ms, evsel, hbt, opts);
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
hist_entry__tui_annotate(struct hist_entry * he,struct evsel * evsel,struct hist_browser_timer * hbt,struct annotation_options * opts)882*4882a593Smuzhiyun int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
883*4882a593Smuzhiyun struct hist_browser_timer *hbt,
884*4882a593Smuzhiyun struct annotation_options *opts)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun /* reset abort key so that it can get Ctrl-C as a key */
887*4882a593Smuzhiyun SLang_reset_tty();
888*4882a593Smuzhiyun SLang_init_tty(0, 0, 0);
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun
symbol__tui_annotate(struct map_symbol * ms,struct evsel * evsel,struct hist_browser_timer * hbt,struct annotation_options * opts)893*4882a593Smuzhiyun int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
894*4882a593Smuzhiyun struct hist_browser_timer *hbt,
895*4882a593Smuzhiyun struct annotation_options *opts)
896*4882a593Smuzhiyun {
897*4882a593Smuzhiyun struct symbol *sym = ms->sym;
898*4882a593Smuzhiyun struct annotation *notes = symbol__annotation(sym);
899*4882a593Smuzhiyun struct annotate_browser browser = {
900*4882a593Smuzhiyun .b = {
901*4882a593Smuzhiyun .refresh = annotate_browser__refresh,
902*4882a593Smuzhiyun .seek = ui_browser__list_head_seek,
903*4882a593Smuzhiyun .write = annotate_browser__write,
904*4882a593Smuzhiyun .filter = disasm_line__filter,
905*4882a593Smuzhiyun .extra_title_lines = 1, /* for hists__scnprintf_title() */
906*4882a593Smuzhiyun .priv = ms,
907*4882a593Smuzhiyun .use_navkeypressed = true,
908*4882a593Smuzhiyun },
909*4882a593Smuzhiyun .opts = opts,
910*4882a593Smuzhiyun };
911*4882a593Smuzhiyun int ret = -1, err;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun if (sym == NULL)
914*4882a593Smuzhiyun return -1;
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun if (ms->map->dso->annotate_warned)
917*4882a593Smuzhiyun return -1;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun err = symbol__annotate2(ms, evsel, opts, &browser.arch);
920*4882a593Smuzhiyun if (err) {
921*4882a593Smuzhiyun char msg[BUFSIZ];
922*4882a593Smuzhiyun symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
923*4882a593Smuzhiyun ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
924*4882a593Smuzhiyun goto out_free_offsets;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun ui_helpline__push("Press ESC to exit");
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun browser.b.width = notes->max_line_len;
930*4882a593Smuzhiyun browser.b.nr_entries = notes->nr_entries;
931*4882a593Smuzhiyun browser.b.entries = ¬es->src->source,
932*4882a593Smuzhiyun browser.b.width += 18; /* Percentage */
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun if (notes->options->hide_src_code)
935*4882a593Smuzhiyun ui_browser__init_asm_mode(&browser.b);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun ret = annotate_browser__run(&browser, evsel, hbt);
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun annotated_source__purge(notes->src);
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun out_free_offsets:
942*4882a593Smuzhiyun zfree(¬es->offsets);
943*4882a593Smuzhiyun return ret;
944*4882a593Smuzhiyun }
945