~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/ui/browsers/annotate.c

Version: ~ [ linux-5.9 ] ~ [ linux-5.8.14 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.70 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.150 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.200 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.238 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.238 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp