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