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