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

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

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