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