0001
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
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
0170 if (strstr(sym->name, "@plt"))
0171 return;
0172
0173 if (!disasm_line__is_valid_local_jump(cursor, sym))
0174 return;
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
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(¬es->lock);
0323
0324 symbol__calc_percent(sym, evsel);
0325
0326 list_for_each_entry(pos, ¬es->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(¬es->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
0363 list_for_each_entry_continue(it, browser->b.entries, node) {
0364 if (it->idx_asm >= 0)
0365 return it;
0366 }
0367
0368
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
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
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
0455
0456
0457
0458
0459
0460
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(¬es->lock);
0478
0479 if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
0480 pthread_mutex_unlock(¬es->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(¬es->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, ¬es->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, ¬es->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, ¬es->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
0749
0750
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
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,
0963 .priv = ms,
0964 .use_navkeypressed = true,
0965 },
0966 .opts = opts,
0967 };
0968 int ret = -1, err;
0969 int not_annotated = list_empty(¬es->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 = ¬es->src->source,
0993 browser.b.width += 18;
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(¬es->offsets);
1006 return ret;
1007 }