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