Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include "../browser.h"
0003 #include "../helpline.h"
0004 #include "../ui.h"
0005 #include "../../util/annotate.h"
0006 #include "../../util/debug.h"
0007 #include "../../util/dso.h"
0008 #include "../../util/hist.h"
0009 #include "../../util/sort.h"
0010 #include "../../util/map.h"
0011 #include "../../util/symbol.h"
0012 #include "../../util/evsel.h"
0013 #include "../../util/evlist.h"
0014 #include <inttypes.h>
0015 #include <pthread.h>
0016 #include <linux/kernel.h>
0017 #include <linux/string.h>
0018 #include <linux/zalloc.h>
0019 #include <sys/ttydefaults.h>
0020 #include <asm/bug.h>
0021 
0022 struct disasm_line_samples {
0023     double            percent;
0024     struct sym_hist_entry he;
0025 };
0026 
0027 struct arch;
0028 
0029 struct annotate_browser {
0030     struct ui_browser       b;
0031     struct rb_root          entries;
0032     struct rb_node         *curr_hot;
0033     struct annotation_line     *selection;
0034     struct arch        *arch;
0035     struct annotation_options  *opts;
0036     bool                searching_backwards;
0037     char                search_bf[128];
0038 };
0039 
0040 static inline struct annotation *browser__annotation(struct ui_browser *browser)
0041 {
0042     struct map_symbol *ms = browser->priv;
0043     return symbol__annotation(ms->sym);
0044 }
0045 
0046 static bool disasm_line__filter(struct ui_browser *browser, void *entry)
0047 {
0048     struct annotation *notes = browser__annotation(browser);
0049     struct annotation_line *al = list_entry(entry, struct annotation_line, node);
0050     return annotation_line__filter(al, notes);
0051 }
0052 
0053 static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
0054 {
0055     struct annotation *notes = browser__annotation(browser);
0056 
0057     if (current && (!browser->use_navkeypressed || browser->navkeypressed))
0058         return HE_COLORSET_SELECTED;
0059     if (nr == notes->max_jump_sources)
0060         return HE_COLORSET_TOP;
0061     if (nr > 1)
0062         return HE_COLORSET_MEDIUM;
0063     return HE_COLORSET_NORMAL;
0064 }
0065 
0066 static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
0067 {
0068      int color = ui_browser__jumps_percent_color(browser, nr, current);
0069      return ui_browser__set_color(browser, color);
0070 }
0071 
0072 static int annotate_browser__set_color(void *browser, int color)
0073 {
0074     return ui_browser__set_color(browser, color);
0075 }
0076 
0077 static void annotate_browser__write_graph(void *browser, int graph)
0078 {
0079     ui_browser__write_graph(browser, graph);
0080 }
0081 
0082 static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
0083 {
0084     ui_browser__set_percent_color(browser, percent, current);
0085 }
0086 
0087 static void annotate_browser__printf(void *browser, const char *fmt, ...)
0088 {
0089     va_list args;
0090 
0091     va_start(args, fmt);
0092     ui_browser__vprintf(browser, fmt, args);
0093     va_end(args);
0094 }
0095 
0096 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
0097 {
0098     struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
0099     struct annotation *notes = browser__annotation(browser);
0100     struct annotation_line *al = list_entry(entry, struct annotation_line, node);
0101     const bool is_current_entry = ui_browser__is_current_entry(browser, row);
0102     struct annotation_write_ops ops = {
0103         .first_line      = row == 0,
0104         .current_entry       = is_current_entry,
0105         .change_color        = (!notes->options->hide_src_code &&
0106                         (!is_current_entry ||
0107                          (browser->use_navkeypressed &&
0108                           !browser->navkeypressed))),
0109         .width           = browser->width,
0110         .obj             = browser,
0111         .set_color       = annotate_browser__set_color,
0112         .set_percent_color   = annotate_browser__set_percent_color,
0113         .set_jumps_percent_color = ui_browser__set_jumps_percent_color,
0114         .printf          = annotate_browser__printf,
0115         .write_graph         = annotate_browser__write_graph,
0116     };
0117 
0118     /* The scroll bar isn't being used */
0119     if (!browser->navkeypressed)
0120         ops.width += 1;
0121 
0122     annotation_line__write(al, notes, &ops, ab->opts);
0123 
0124     if (ops.current_entry)
0125         ab->selection = al;
0126 }
0127 
0128 static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
0129 {
0130     struct disasm_line *pos = list_prev_entry(cursor, al.node);
0131     const char *name;
0132     int diff = 1;
0133 
0134     while (pos && pos->al.offset == -1) {
0135         pos = list_prev_entry(pos, al.node);
0136         if (!ab->opts->hide_src_code)
0137             diff++;
0138     }
0139 
0140     if (!pos)
0141         return 0;
0142 
0143     if (ins__is_lock(&pos->ins))
0144         name = pos->ops.locked.ins.name;
0145     else
0146         name = pos->ins.name;
0147 
0148     if (!name || !cursor->ins.name)
0149         return 0;
0150 
0151     if (ins__is_fused(ab->arch, name, cursor->ins.name))
0152         return diff;
0153     return 0;
0154 }
0155 
0156 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
0157 {
0158     struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
0159     struct disasm_line *cursor = disasm_line(ab->selection);
0160     struct annotation_line *target;
0161     unsigned int from, to;
0162     struct map_symbol *ms = ab->b.priv;
0163     struct symbol *sym = ms->sym;
0164     struct annotation *notes = symbol__annotation(sym);
0165     u8 pcnt_width = annotation__pcnt_width(notes);
0166     int width;
0167     int diff = 0;
0168 
0169     /* PLT symbols contain external offsets */
0170     if (strstr(sym->name, "@plt"))
0171         return;
0172 
0173     if (!disasm_line__is_valid_local_jump(cursor, sym))
0174         return;
0175 
0176     /*
0177      * This first was seen with a gcc function, _cpp_lex_token, that
0178      * has the usual jumps:
0179      *
0180      *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
0181      *
0182      * I.e. jumps to a label inside that function (_cpp_lex_token), and
0183      * those works, but also this kind:
0184      *
0185      *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
0186      *
0187      *  I.e. jumps to another function, outside _cpp_lex_token, which
0188      *  are not being correctly handled generating as a side effect references
0189      *  to ab->offset[] entries that are set to NULL, so to make this code
0190      *  more robust, check that here.
0191      *
0192      *  A proper fix for will be put in place, looking at the function
0193      *  name right after the '<' token and probably treating this like a
0194      *  'call' instruction.
0195      */
0196     target = notes->offsets[cursor->ops.target.offset];
0197     if (target == NULL) {
0198         ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
0199                     cursor->ops.target.offset);
0200         return;
0201     }
0202 
0203     if (notes->options->hide_src_code) {
0204         from = cursor->al.idx_asm;
0205         to = target->idx_asm;
0206     } else {
0207         from = (u64)cursor->al.idx;
0208         to = (u64)target->idx;
0209     }
0210 
0211     width = annotation__cycles_width(notes);
0212 
0213     ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
0214     __ui_browser__line_arrow(browser,
0215                  pcnt_width + 2 + notes->widths.addr + width,
0216                  from, to);
0217 
0218     diff = is_fused(ab, cursor);
0219     if (diff > 0) {
0220         ui_browser__mark_fused(browser,
0221                        pcnt_width + 3 + notes->widths.addr + width,
0222                        from - diff, diff, to > from);
0223     }
0224 }
0225 
0226 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
0227 {
0228     struct annotation *notes = browser__annotation(browser);
0229     int ret = ui_browser__list_head_refresh(browser);
0230     int pcnt_width = annotation__pcnt_width(notes);
0231 
0232     if (notes->options->jump_arrows)
0233         annotate_browser__draw_current_jump(browser);
0234 
0235     ui_browser__set_color(browser, HE_COLORSET_NORMAL);
0236     __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
0237     return ret;
0238 }
0239 
0240 static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
0241                           int percent_type)
0242 {
0243     int i;
0244 
0245     for (i = 0; i < a->data_nr; i++) {
0246         if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
0247             continue;
0248         return a->data[i].percent[percent_type] -
0249                b->data[i].percent[percent_type];
0250     }
0251     return 0;
0252 }
0253 
0254 static void disasm_rb_tree__insert(struct annotate_browser *browser,
0255                 struct annotation_line *al)
0256 {
0257     struct rb_root *root = &browser->entries;
0258     struct rb_node **p = &root->rb_node;
0259     struct rb_node *parent = NULL;
0260     struct annotation_line *l;
0261 
0262     while (*p != NULL) {
0263         parent = *p;
0264         l = rb_entry(parent, struct annotation_line, rb_node);
0265 
0266         if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
0267             p = &(*p)->rb_left;
0268         else
0269             p = &(*p)->rb_right;
0270     }
0271     rb_link_node(&al->rb_node, parent, p);
0272     rb_insert_color(&al->rb_node, root);
0273 }
0274 
0275 static void annotate_browser__set_top(struct annotate_browser *browser,
0276                       struct annotation_line *pos, u32 idx)
0277 {
0278     struct annotation *notes = browser__annotation(&browser->b);
0279     unsigned back;
0280 
0281     ui_browser__refresh_dimensions(&browser->b);
0282     back = browser->b.height / 2;
0283     browser->b.top_idx = browser->b.index = idx;
0284 
0285     while (browser->b.top_idx != 0 && back != 0) {
0286         pos = list_entry(pos->node.prev, struct annotation_line, node);
0287 
0288         if (annotation_line__filter(pos, notes))
0289             continue;
0290 
0291         --browser->b.top_idx;
0292         --back;
0293     }
0294 
0295     browser->b.top = pos;
0296     browser->b.navkeypressed = true;
0297 }
0298 
0299 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
0300                      struct rb_node *nd)
0301 {
0302     struct annotation *notes = browser__annotation(&browser->b);
0303     struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
0304     u32 idx = pos->idx;
0305 
0306     if (notes->options->hide_src_code)
0307         idx = pos->idx_asm;
0308     annotate_browser__set_top(browser, pos, idx);
0309     browser->curr_hot = nd;
0310 }
0311 
0312 static void annotate_browser__calc_percent(struct annotate_browser *browser,
0313                        struct evsel *evsel)
0314 {
0315     struct map_symbol *ms = browser->b.priv;
0316     struct symbol *sym = ms->sym;
0317     struct annotation *notes = symbol__annotation(sym);
0318     struct disasm_line *pos;
0319 
0320     browser->entries = RB_ROOT;
0321 
0322     pthread_mutex_lock(&notes->lock);
0323 
0324     symbol__calc_percent(sym, evsel);
0325 
0326     list_for_each_entry(pos, &notes->src->source, al.node) {
0327         double max_percent = 0.0;
0328         int i;
0329 
0330         if (pos->al.offset == -1) {
0331             RB_CLEAR_NODE(&pos->al.rb_node);
0332             continue;
0333         }
0334 
0335         for (i = 0; i < pos->al.data_nr; i++) {
0336             double percent;
0337 
0338             percent = annotation_data__percent(&pos->al.data[i],
0339                                browser->opts->percent_type);
0340 
0341             if (max_percent < percent)
0342                 max_percent = percent;
0343         }
0344 
0345         if (max_percent < 0.01 && pos->al.ipc == 0) {
0346             RB_CLEAR_NODE(&pos->al.rb_node);
0347             continue;
0348         }
0349         disasm_rb_tree__insert(browser, &pos->al);
0350     }
0351     pthread_mutex_unlock(&notes->lock);
0352 
0353     browser->curr_hot = rb_last(&browser->entries);
0354 }
0355 
0356 static struct annotation_line *annotate_browser__find_next_asm_line(
0357                     struct annotate_browser *browser,
0358                     struct annotation_line *al)
0359 {
0360     struct annotation_line *it = al;
0361 
0362     /* find next asm line */
0363     list_for_each_entry_continue(it, browser->b.entries, node) {
0364         if (it->idx_asm >= 0)
0365             return it;
0366     }
0367 
0368     /* no asm line found forwards, try backwards */
0369     it = al;
0370     list_for_each_entry_continue_reverse(it, browser->b.entries, node) {
0371         if (it->idx_asm >= 0)
0372             return it;
0373     }
0374 
0375     /* There are no asm lines */
0376     return NULL;
0377 }
0378 
0379 static bool annotate_browser__toggle_source(struct annotate_browser *browser)
0380 {
0381     struct annotation *notes = browser__annotation(&browser->b);
0382     struct annotation_line *al;
0383     off_t offset = browser->b.index - browser->b.top_idx;
0384 
0385     browser->b.seek(&browser->b, offset, SEEK_CUR);
0386     al = list_entry(browser->b.top, struct annotation_line, node);
0387 
0388     if (notes->options->hide_src_code) {
0389         if (al->idx_asm < offset)
0390             offset = al->idx;
0391 
0392         browser->b.nr_entries = notes->nr_entries;
0393         notes->options->hide_src_code = false;
0394         browser->b.seek(&browser->b, -offset, SEEK_CUR);
0395         browser->b.top_idx = al->idx - offset;
0396         browser->b.index = al->idx;
0397     } else {
0398         if (al->idx_asm < 0) {
0399             /* move cursor to next asm line */
0400             al = annotate_browser__find_next_asm_line(browser, al);
0401             if (!al) {
0402                 browser->b.seek(&browser->b, -offset, SEEK_CUR);
0403                 return false;
0404             }
0405         }
0406 
0407         if (al->idx_asm < offset)
0408             offset = al->idx_asm;
0409 
0410         browser->b.nr_entries = notes->nr_asm_entries;
0411         notes->options->hide_src_code = true;
0412         browser->b.seek(&browser->b, -offset, SEEK_CUR);
0413         browser->b.top_idx = al->idx_asm - offset;
0414         browser->b.index = al->idx_asm;
0415     }
0416 
0417     return true;
0418 }
0419 
0420 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
0421 
0422 static void annotate_browser__show_full_location(struct ui_browser *browser)
0423 {
0424     struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
0425     struct disasm_line *cursor = disasm_line(ab->selection);
0426     struct annotation_line *al = &cursor->al;
0427 
0428     if (al->offset != -1)
0429         ui_helpline__puts("Only available for source code lines.");
0430     else if (al->fileloc == NULL)
0431         ui_helpline__puts("No source file location.");
0432     else {
0433         char help_line[SYM_TITLE_MAX_SIZE];
0434         sprintf (help_line, "Source file location: %s", al->fileloc);
0435         ui_helpline__puts(help_line);
0436     }
0437 }
0438 
0439 static void ui_browser__init_asm_mode(struct ui_browser *browser)
0440 {
0441     struct annotation *notes = browser__annotation(browser);
0442     ui_browser__reset_index(browser);
0443     browser->nr_entries = notes->nr_asm_entries;
0444 }
0445 
0446 static int sym_title(struct symbol *sym, struct map *map, char *title,
0447              size_t sz, int percent_type)
0448 {
0449     return snprintf(title, sz, "%s  %s [Percent: %s]", sym->name, map->dso->long_name,
0450             percent_type_str(percent_type));
0451 }
0452 
0453 /*
0454  * This can be called from external jumps, i.e. jumps from one function
0455  * to another, like from the kernel's entry_SYSCALL_64 function to the
0456  * swapgs_restore_regs_and_return_to_usermode() function.
0457  *
0458  * So all we check here is that dl->ops.target.sym is set, if it is, just
0459  * go to that function and when exiting from its disassembly, come back
0460  * to the calling function.
0461  */
0462 static bool annotate_browser__callq(struct annotate_browser *browser,
0463                     struct evsel *evsel,
0464                     struct hist_browser_timer *hbt)
0465 {
0466     struct map_symbol *ms = browser->b.priv, target_ms;
0467     struct disasm_line *dl = disasm_line(browser->selection);
0468     struct annotation *notes;
0469     char title[SYM_TITLE_MAX_SIZE];
0470 
0471     if (!dl->ops.target.sym) {
0472         ui_helpline__puts("The called function was not found.");
0473         return true;
0474     }
0475 
0476     notes = symbol__annotation(dl->ops.target.sym);
0477     pthread_mutex_lock(&notes->lock);
0478 
0479     if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
0480         pthread_mutex_unlock(&notes->lock);
0481         ui__warning("Not enough memory for annotating '%s' symbol!\n",
0482                 dl->ops.target.sym->name);
0483         return true;
0484     }
0485 
0486     target_ms.maps = ms->maps;
0487     target_ms.map = ms->map;
0488     target_ms.sym = dl->ops.target.sym;
0489     pthread_mutex_unlock(&notes->lock);
0490     symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);
0491     sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
0492     ui_browser__show_title(&browser->b, title);
0493     return true;
0494 }
0495 
0496 static
0497 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
0498                       s64 offset, s64 *idx)
0499 {
0500     struct annotation *notes = browser__annotation(&browser->b);
0501     struct disasm_line *pos;
0502 
0503     *idx = 0;
0504     list_for_each_entry(pos, &notes->src->source, al.node) {
0505         if (pos->al.offset == offset)
0506             return pos;
0507         if (!annotation_line__filter(&pos->al, notes))
0508             ++*idx;
0509     }
0510 
0511     return NULL;
0512 }
0513 
0514 static bool annotate_browser__jump(struct annotate_browser *browser,
0515                    struct evsel *evsel,
0516                    struct hist_browser_timer *hbt)
0517 {
0518     struct disasm_line *dl = disasm_line(browser->selection);
0519     u64 offset;
0520     s64 idx;
0521 
0522     if (!ins__is_jump(&dl->ins))
0523         return false;
0524 
0525     if (dl->ops.target.outside) {
0526         annotate_browser__callq(browser, evsel, hbt);
0527         return true;
0528     }
0529 
0530     offset = dl->ops.target.offset;
0531     dl = annotate_browser__find_offset(browser, offset, &idx);
0532     if (dl == NULL) {
0533         ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
0534         return true;
0535     }
0536 
0537     annotate_browser__set_top(browser, &dl->al, idx);
0538 
0539     return true;
0540 }
0541 
0542 static
0543 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
0544                       char *s, s64 *idx)
0545 {
0546     struct annotation *notes = browser__annotation(&browser->b);
0547     struct annotation_line *al = browser->selection;
0548 
0549     *idx = browser->b.index;
0550     list_for_each_entry_continue(al, &notes->src->source, node) {
0551         if (annotation_line__filter(al, notes))
0552             continue;
0553 
0554         ++*idx;
0555 
0556         if (al->line && strstr(al->line, s) != NULL)
0557             return al;
0558     }
0559 
0560     return NULL;
0561 }
0562 
0563 static bool __annotate_browser__search(struct annotate_browser *browser)
0564 {
0565     struct annotation_line *al;
0566     s64 idx;
0567 
0568     al = annotate_browser__find_string(browser, browser->search_bf, &idx);
0569     if (al == NULL) {
0570         ui_helpline__puts("String not found!");
0571         return false;
0572     }
0573 
0574     annotate_browser__set_top(browser, al, idx);
0575     browser->searching_backwards = false;
0576     return true;
0577 }
0578 
0579 static
0580 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
0581                           char *s, s64 *idx)
0582 {
0583     struct annotation *notes = browser__annotation(&browser->b);
0584     struct annotation_line *al = browser->selection;
0585 
0586     *idx = browser->b.index;
0587     list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
0588         if (annotation_line__filter(al, notes))
0589             continue;
0590 
0591         --*idx;
0592 
0593         if (al->line && strstr(al->line, s) != NULL)
0594             return al;
0595     }
0596 
0597     return NULL;
0598 }
0599 
0600 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
0601 {
0602     struct annotation_line *al;
0603     s64 idx;
0604 
0605     al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
0606     if (al == NULL) {
0607         ui_helpline__puts("String not found!");
0608         return false;
0609     }
0610 
0611     annotate_browser__set_top(browser, al, idx);
0612     browser->searching_backwards = true;
0613     return true;
0614 }
0615 
0616 static bool annotate_browser__search_window(struct annotate_browser *browser,
0617                         int delay_secs)
0618 {
0619     if (ui_browser__input_window("Search", "String: ", browser->search_bf,
0620                      "ENTER: OK, ESC: Cancel",
0621                      delay_secs * 2) != K_ENTER ||
0622         !*browser->search_bf)
0623         return false;
0624 
0625     return true;
0626 }
0627 
0628 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
0629 {
0630     if (annotate_browser__search_window(browser, delay_secs))
0631         return __annotate_browser__search(browser);
0632 
0633     return false;
0634 }
0635 
0636 static bool annotate_browser__continue_search(struct annotate_browser *browser,
0637                           int delay_secs)
0638 {
0639     if (!*browser->search_bf)
0640         return annotate_browser__search(browser, delay_secs);
0641 
0642     return __annotate_browser__search(browser);
0643 }
0644 
0645 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
0646                        int delay_secs)
0647 {
0648     if (annotate_browser__search_window(browser, delay_secs))
0649         return __annotate_browser__search_reverse(browser);
0650 
0651     return false;
0652 }
0653 
0654 static
0655 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
0656                            int delay_secs)
0657 {
0658     if (!*browser->search_bf)
0659         return annotate_browser__search_reverse(browser, delay_secs);
0660 
0661     return __annotate_browser__search_reverse(browser);
0662 }
0663 
0664 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
0665 {
0666     struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
0667     struct map_symbol *ms = browser->priv;
0668     struct symbol *sym = ms->sym;
0669     char symbol_dso[SYM_TITLE_MAX_SIZE];
0670 
0671     if (ui_browser__show(browser, title, help) < 0)
0672         return -1;
0673 
0674     sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
0675 
0676     ui_browser__gotorc_title(browser, 0, 0);
0677     ui_browser__set_color(browser, HE_COLORSET_ROOT);
0678     ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
0679     return 0;
0680 }
0681 
0682 static void
0683 switch_percent_type(struct annotation_options *opts, bool base)
0684 {
0685     switch (opts->percent_type) {
0686     case PERCENT_HITS_LOCAL:
0687         if (base)
0688             opts->percent_type = PERCENT_PERIOD_LOCAL;
0689         else
0690             opts->percent_type = PERCENT_HITS_GLOBAL;
0691         break;
0692     case PERCENT_HITS_GLOBAL:
0693         if (base)
0694             opts->percent_type = PERCENT_PERIOD_GLOBAL;
0695         else
0696             opts->percent_type = PERCENT_HITS_LOCAL;
0697         break;
0698     case PERCENT_PERIOD_LOCAL:
0699         if (base)
0700             opts->percent_type = PERCENT_HITS_LOCAL;
0701         else
0702             opts->percent_type = PERCENT_PERIOD_GLOBAL;
0703         break;
0704     case PERCENT_PERIOD_GLOBAL:
0705         if (base)
0706             opts->percent_type = PERCENT_HITS_GLOBAL;
0707         else
0708             opts->percent_type = PERCENT_PERIOD_LOCAL;
0709         break;
0710     default:
0711         WARN_ON(1);
0712     }
0713 }
0714 
0715 static int annotate_browser__run(struct annotate_browser *browser,
0716                  struct evsel *evsel,
0717                  struct hist_browser_timer *hbt)
0718 {
0719     struct rb_node *nd = NULL;
0720     struct hists *hists = evsel__hists(evsel);
0721     struct map_symbol *ms = browser->b.priv;
0722     struct symbol *sym = ms->sym;
0723     struct annotation *notes = symbol__annotation(ms->sym);
0724     const char *help = "Press 'h' for help on key bindings";
0725     int delay_secs = hbt ? hbt->refresh : 0;
0726     char title[256];
0727     int key;
0728 
0729     hists__scnprintf_title(hists, title, sizeof(title));
0730     if (annotate_browser__show(&browser->b, title, help) < 0)
0731         return -1;
0732 
0733     annotate_browser__calc_percent(browser, evsel);
0734 
0735     if (browser->curr_hot) {
0736         annotate_browser__set_rb_top(browser, browser->curr_hot);
0737         browser->b.navkeypressed = false;
0738     }
0739 
0740     nd = browser->curr_hot;
0741 
0742     while (1) {
0743         key = ui_browser__run(&browser->b, delay_secs);
0744 
0745         if (delay_secs != 0) {
0746             annotate_browser__calc_percent(browser, evsel);
0747             /*
0748              * Current line focus got out of the list of most active
0749              * lines, NULL it so that if TAB|UNTAB is pressed, we
0750              * move to curr_hot (current hottest line).
0751              */
0752             if (nd != NULL && RB_EMPTY_NODE(nd))
0753                 nd = NULL;
0754         }
0755 
0756         switch (key) {
0757         case K_TIMER:
0758             if (hbt)
0759                 hbt->timer(hbt->arg);
0760 
0761             if (delay_secs != 0) {
0762                 symbol__annotate_decay_histogram(sym, evsel->core.idx);
0763                 hists__scnprintf_title(hists, title, sizeof(title));
0764                 annotate_browser__show(&browser->b, title, help);
0765             }
0766             continue;
0767         case K_TAB:
0768             if (nd != NULL) {
0769                 nd = rb_prev(nd);
0770                 if (nd == NULL)
0771                     nd = rb_last(&browser->entries);
0772             } else
0773                 nd = browser->curr_hot;
0774             break;
0775         case K_UNTAB:
0776             if (nd != NULL) {
0777                 nd = rb_next(nd);
0778                 if (nd == NULL)
0779                     nd = rb_first(&browser->entries);
0780             } else
0781                 nd = browser->curr_hot;
0782             break;
0783         case K_F1:
0784         case 'h':
0785             ui_browser__help_window(&browser->b,
0786         "UP/DOWN/PGUP\n"
0787         "PGDN/SPACE    Navigate\n"
0788         "q/ESC/CTRL+C  Exit\n\n"
0789         "ENTER         Go to target\n"
0790         "ESC           Exit\n"
0791         "H             Go to hottest instruction\n"
0792         "TAB/shift+TAB Cycle thru hottest instructions\n"
0793         "j             Toggle showing jump to target arrows\n"
0794         "J             Toggle showing number of jump sources on targets\n"
0795         "n             Search next string\n"
0796         "o             Toggle disassembler output/simplified view\n"
0797         "O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
0798         "s             Toggle source code view\n"
0799         "t             Circulate percent, total period, samples view\n"
0800         "c             Show min/max cycle\n"
0801         "/             Search string\n"
0802         "k             Toggle line numbers\n"
0803         "l             Show full source file location\n"
0804         "P             Print to [symbol_name].annotation file.\n"
0805         "r             Run available scripts\n"
0806         "p             Toggle percent type [local/global]\n"
0807         "b             Toggle percent base [period/hits]\n"
0808         "?             Search string backwards\n");
0809             continue;
0810         case 'r':
0811             script_browse(NULL, NULL);
0812             annotate_browser__show(&browser->b, title, help);
0813             continue;
0814         case 'k':
0815             notes->options->show_linenr = !notes->options->show_linenr;
0816             continue;
0817         case 'l':
0818             annotate_browser__show_full_location (&browser->b);
0819             continue;
0820         case 'H':
0821             nd = browser->curr_hot;
0822             break;
0823         case 's':
0824             if (annotate_browser__toggle_source(browser))
0825                 ui_helpline__puts(help);
0826             continue;
0827         case 'o':
0828             notes->options->use_offset = !notes->options->use_offset;
0829             annotation__update_column_widths(notes);
0830             continue;
0831         case 'O':
0832             if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
0833                 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
0834             continue;
0835         case 'j':
0836             notes->options->jump_arrows = !notes->options->jump_arrows;
0837             continue;
0838         case 'J':
0839             notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
0840             annotation__update_column_widths(notes);
0841             continue;
0842         case '/':
0843             if (annotate_browser__search(browser, delay_secs)) {
0844 show_help:
0845                 ui_helpline__puts(help);
0846             }
0847             continue;
0848         case 'n':
0849             if (browser->searching_backwards ?
0850                 annotate_browser__continue_search_reverse(browser, delay_secs) :
0851                 annotate_browser__continue_search(browser, delay_secs))
0852                 goto show_help;
0853             continue;
0854         case '?':
0855             if (annotate_browser__search_reverse(browser, delay_secs))
0856                 goto show_help;
0857             continue;
0858         case 'D': {
0859             static int seq;
0860             ui_helpline__pop();
0861             ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
0862                        seq++, browser->b.nr_entries,
0863                        browser->b.height,
0864                        browser->b.index,
0865                        browser->b.top_idx,
0866                        notes->nr_asm_entries);
0867         }
0868             continue;
0869         case K_ENTER:
0870         case K_RIGHT:
0871         {
0872             struct disasm_line *dl = disasm_line(browser->selection);
0873 
0874             if (browser->selection == NULL)
0875                 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
0876             else if (browser->selection->offset == -1)
0877                 ui_helpline__puts("Actions are only available for assembly lines.");
0878             else if (!dl->ins.ops)
0879                 goto show_sup_ins;
0880             else if (ins__is_ret(&dl->ins))
0881                 goto out;
0882             else if (!(annotate_browser__jump(browser, evsel, hbt) ||
0883                      annotate_browser__callq(browser, evsel, hbt))) {
0884 show_sup_ins:
0885                 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
0886             }
0887             continue;
0888         }
0889         case 'P':
0890             map_symbol__annotation_dump(ms, evsel, browser->opts);
0891             continue;
0892         case 't':
0893             if (symbol_conf.show_total_period) {
0894                 symbol_conf.show_total_period = false;
0895                 symbol_conf.show_nr_samples = true;
0896             } else if (symbol_conf.show_nr_samples)
0897                 symbol_conf.show_nr_samples = false;
0898             else
0899                 symbol_conf.show_total_period = true;
0900             annotation__update_column_widths(notes);
0901             continue;
0902         case 'c':
0903             if (notes->options->show_minmax_cycle)
0904                 notes->options->show_minmax_cycle = false;
0905             else
0906                 notes->options->show_minmax_cycle = true;
0907             annotation__update_column_widths(notes);
0908             continue;
0909         case 'p':
0910         case 'b':
0911             switch_percent_type(browser->opts, key == 'b');
0912             hists__scnprintf_title(hists, title, sizeof(title));
0913             annotate_browser__show(&browser->b, title, help);
0914             continue;
0915         case K_LEFT:
0916         case K_ESC:
0917         case 'q':
0918         case CTRL('c'):
0919             goto out;
0920         default:
0921             continue;
0922         }
0923 
0924         if (nd != NULL)
0925             annotate_browser__set_rb_top(browser, nd);
0926     }
0927 out:
0928     ui_browser__hide(&browser->b);
0929     return key;
0930 }
0931 
0932 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
0933                  struct hist_browser_timer *hbt,
0934                  struct annotation_options *opts)
0935 {
0936     return symbol__tui_annotate(ms, evsel, hbt, opts);
0937 }
0938 
0939 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
0940                  struct hist_browser_timer *hbt,
0941                  struct annotation_options *opts)
0942 {
0943     /* reset abort key so that it can get Ctrl-C as a key */
0944     SLang_reset_tty();
0945     SLang_init_tty(0, 0, 0);
0946 
0947     return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
0948 }
0949 
0950 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
0951              struct hist_browser_timer *hbt,
0952              struct annotation_options *opts)
0953 {
0954     struct symbol *sym = ms->sym;
0955     struct annotation *notes = symbol__annotation(sym);
0956     struct annotate_browser browser = {
0957         .b = {
0958             .refresh = annotate_browser__refresh,
0959             .seek    = ui_browser__list_head_seek,
0960             .write   = annotate_browser__write,
0961             .filter  = disasm_line__filter,
0962             .extra_title_lines = 1, /* for hists__scnprintf_title() */
0963             .priv    = ms,
0964             .use_navkeypressed = true,
0965         },
0966         .opts = opts,
0967     };
0968     int ret = -1, err;
0969     int not_annotated = list_empty(&notes->src->source);
0970 
0971     if (sym == NULL)
0972         return -1;
0973 
0974     if (ms->map->dso->annotate_warned)
0975         return -1;
0976 
0977     if (not_annotated) {
0978         err = symbol__annotate2(ms, evsel, opts, &browser.arch);
0979         if (err) {
0980             char msg[BUFSIZ];
0981             ms->map->dso->annotate_warned = true;
0982             symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
0983             ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
0984             goto out_free_offsets;
0985         }
0986     }
0987 
0988     ui_helpline__push("Press ESC to exit");
0989 
0990     browser.b.width = notes->max_line_len;
0991     browser.b.nr_entries = notes->nr_entries;
0992     browser.b.entries = &notes->src->source,
0993     browser.b.width += 18; /* Percentage */
0994 
0995     if (notes->options->hide_src_code)
0996         ui_browser__init_asm_mode(&browser.b);
0997 
0998     ret = annotate_browser__run(&browser, evsel, hbt);
0999 
1000     if(not_annotated)
1001         annotated_source__purge(notes->src);
1002 
1003 out_free_offsets:
1004     if(not_annotated)
1005         zfree(&notes->offsets);
1006     return ret;
1007 }