root/tools/perf/ui/browsers/annotate.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. browser__annotation
  2. disasm_line__filter
  3. ui_browser__jumps_percent_color
  4. ui_browser__set_jumps_percent_color
  5. annotate_browser__set_color
  6. annotate_browser__write_graph
  7. annotate_browser__set_percent_color
  8. annotate_browser__printf
  9. annotate_browser__write
  10. is_fused
  11. annotate_browser__draw_current_jump
  12. annotate_browser__refresh
  13. disasm__cmp
  14. disasm_rb_tree__insert
  15. annotate_browser__set_top
  16. annotate_browser__set_rb_top
  17. annotate_browser__calc_percent
  18. annotate_browser__toggle_source
  19. ui_browser__init_asm_mode
  20. sym_title
  21. annotate_browser__callq
  22. annotate_browser__find_offset
  23. annotate_browser__jump
  24. annotate_browser__find_string
  25. __annotate_browser__search
  26. annotate_browser__find_string_reverse
  27. __annotate_browser__search_reverse
  28. annotate_browser__search_window
  29. annotate_browser__search
  30. annotate_browser__continue_search
  31. annotate_browser__search_reverse
  32. annotate_browser__continue_search_reverse
  33. annotate_browser__show
  34. switch_percent_type
  35. annotate_browser__run
  36. map_symbol__tui_annotate
  37. hist_entry__tui_annotate
  38. symbol__tui_annotate

   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;
 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         pthread_mutex_unlock(&notes->lock);
 434         symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
 435         sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
 436         ui_browser__show_title(&browser->b, title);
 437         return true;
 438 }
 439 
 440 static
 441 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
 442                                           s64 offset, s64 *idx)
 443 {
 444         struct annotation *notes = browser__annotation(&browser->b);
 445         struct disasm_line *pos;
 446 
 447         *idx = 0;
 448         list_for_each_entry(pos, &notes->src->source, al.node) {
 449                 if (pos->al.offset == offset)
 450                         return pos;
 451                 if (!annotation_line__filter(&pos->al, notes))
 452                         ++*idx;
 453         }
 454 
 455         return NULL;
 456 }
 457 
 458 static bool annotate_browser__jump(struct annotate_browser *browser,
 459                                    struct evsel *evsel,
 460                                    struct hist_browser_timer *hbt)
 461 {
 462         struct disasm_line *dl = disasm_line(browser->selection);
 463         u64 offset;
 464         s64 idx;
 465 
 466         if (!ins__is_jump(&dl->ins))
 467                 return false;
 468 
 469         if (dl->ops.target.outside) {
 470                 annotate_browser__callq(browser, evsel, hbt);
 471                 return true;
 472         }
 473 
 474         offset = dl->ops.target.offset;
 475         dl = annotate_browser__find_offset(browser, offset, &idx);
 476         if (dl == NULL) {
 477                 ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
 478                 return true;
 479         }
 480 
 481         annotate_browser__set_top(browser, &dl->al, idx);
 482 
 483         return true;
 484 }
 485 
 486 static
 487 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
 488                                           char *s, s64 *idx)
 489 {
 490         struct annotation *notes = browser__annotation(&browser->b);
 491         struct annotation_line *al = browser->selection;
 492 
 493         *idx = browser->b.index;
 494         list_for_each_entry_continue(al, &notes->src->source, node) {
 495                 if (annotation_line__filter(al, notes))
 496                         continue;
 497 
 498                 ++*idx;
 499 
 500                 if (al->line && strstr(al->line, s) != NULL)
 501                         return al;
 502         }
 503 
 504         return NULL;
 505 }
 506 
 507 static bool __annotate_browser__search(struct annotate_browser *browser)
 508 {
 509         struct annotation_line *al;
 510         s64 idx;
 511 
 512         al = annotate_browser__find_string(browser, browser->search_bf, &idx);
 513         if (al == NULL) {
 514                 ui_helpline__puts("String not found!");
 515                 return false;
 516         }
 517 
 518         annotate_browser__set_top(browser, al, idx);
 519         browser->searching_backwards = false;
 520         return true;
 521 }
 522 
 523 static
 524 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
 525                                                   char *s, s64 *idx)
 526 {
 527         struct annotation *notes = browser__annotation(&browser->b);
 528         struct annotation_line *al = browser->selection;
 529 
 530         *idx = browser->b.index;
 531         list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
 532                 if (annotation_line__filter(al, notes))
 533                         continue;
 534 
 535                 --*idx;
 536 
 537                 if (al->line && strstr(al->line, s) != NULL)
 538                         return al;
 539         }
 540 
 541         return NULL;
 542 }
 543 
 544 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
 545 {
 546         struct annotation_line *al;
 547         s64 idx;
 548 
 549         al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
 550         if (al == NULL) {
 551                 ui_helpline__puts("String not found!");
 552                 return false;
 553         }
 554 
 555         annotate_browser__set_top(browser, al, idx);
 556         browser->searching_backwards = true;
 557         return true;
 558 }
 559 
 560 static bool annotate_browser__search_window(struct annotate_browser *browser,
 561                                             int delay_secs)
 562 {
 563         if (ui_browser__input_window("Search", "String: ", browser->search_bf,
 564                                      "ENTER: OK, ESC: Cancel",
 565                                      delay_secs * 2) != K_ENTER ||
 566             !*browser->search_bf)
 567                 return false;
 568 
 569         return true;
 570 }
 571 
 572 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
 573 {
 574         if (annotate_browser__search_window(browser, delay_secs))
 575                 return __annotate_browser__search(browser);
 576 
 577         return false;
 578 }
 579 
 580 static bool annotate_browser__continue_search(struct annotate_browser *browser,
 581                                               int delay_secs)
 582 {
 583         if (!*browser->search_bf)
 584                 return annotate_browser__search(browser, delay_secs);
 585 
 586         return __annotate_browser__search(browser);
 587 }
 588 
 589 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
 590                                            int delay_secs)
 591 {
 592         if (annotate_browser__search_window(browser, delay_secs))
 593                 return __annotate_browser__search_reverse(browser);
 594 
 595         return false;
 596 }
 597 
 598 static
 599 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
 600                                                int delay_secs)
 601 {
 602         if (!*browser->search_bf)
 603                 return annotate_browser__search_reverse(browser, delay_secs);
 604 
 605         return __annotate_browser__search_reverse(browser);
 606 }
 607 
 608 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
 609 {
 610         struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
 611         struct map_symbol *ms = browser->priv;
 612         struct symbol *sym = ms->sym;
 613         char symbol_dso[SYM_TITLE_MAX_SIZE];
 614 
 615         if (ui_browser__show(browser, title, help) < 0)
 616                 return -1;
 617 
 618         sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
 619 
 620         ui_browser__gotorc_title(browser, 0, 0);
 621         ui_browser__set_color(browser, HE_COLORSET_ROOT);
 622         ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
 623         return 0;
 624 }
 625 
 626 static void
 627 switch_percent_type(struct annotation_options *opts, bool base)
 628 {
 629         switch (opts->percent_type) {
 630         case PERCENT_HITS_LOCAL:
 631                 if (base)
 632                         opts->percent_type = PERCENT_PERIOD_LOCAL;
 633                 else
 634                         opts->percent_type = PERCENT_HITS_GLOBAL;
 635                 break;
 636         case PERCENT_HITS_GLOBAL:
 637                 if (base)
 638                         opts->percent_type = PERCENT_PERIOD_GLOBAL;
 639                 else
 640                         opts->percent_type = PERCENT_HITS_LOCAL;
 641                 break;
 642         case PERCENT_PERIOD_LOCAL:
 643                 if (base)
 644                         opts->percent_type = PERCENT_HITS_LOCAL;
 645                 else
 646                         opts->percent_type = PERCENT_PERIOD_GLOBAL;
 647                 break;
 648         case PERCENT_PERIOD_GLOBAL:
 649                 if (base)
 650                         opts->percent_type = PERCENT_HITS_GLOBAL;
 651                 else
 652                         opts->percent_type = PERCENT_PERIOD_LOCAL;
 653                 break;
 654         default:
 655                 WARN_ON(1);
 656         }
 657 }
 658 
 659 static int annotate_browser__run(struct annotate_browser *browser,
 660                                  struct evsel *evsel,
 661                                  struct hist_browser_timer *hbt)
 662 {
 663         struct rb_node *nd = NULL;
 664         struct hists *hists = evsel__hists(evsel);
 665         struct map_symbol *ms = browser->b.priv;
 666         struct symbol *sym = ms->sym;
 667         struct annotation *notes = symbol__annotation(ms->sym);
 668         const char *help = "Press 'h' for help on key bindings";
 669         int delay_secs = hbt ? hbt->refresh : 0;
 670         char title[256];
 671         int key;
 672 
 673         hists__scnprintf_title(hists, title, sizeof(title));
 674         if (annotate_browser__show(&browser->b, title, help) < 0)
 675                 return -1;
 676 
 677         annotate_browser__calc_percent(browser, evsel);
 678 
 679         if (browser->curr_hot) {
 680                 annotate_browser__set_rb_top(browser, browser->curr_hot);
 681                 browser->b.navkeypressed = false;
 682         }
 683 
 684         nd = browser->curr_hot;
 685 
 686         while (1) {
 687                 key = ui_browser__run(&browser->b, delay_secs);
 688 
 689                 if (delay_secs != 0) {
 690                         annotate_browser__calc_percent(browser, evsel);
 691                         /*
 692                          * Current line focus got out of the list of most active
 693                          * lines, NULL it so that if TAB|UNTAB is pressed, we
 694                          * move to curr_hot (current hottest line).
 695                          */
 696                         if (nd != NULL && RB_EMPTY_NODE(nd))
 697                                 nd = NULL;
 698                 }
 699 
 700                 switch (key) {
 701                 case K_TIMER:
 702                         if (hbt)
 703                                 hbt->timer(hbt->arg);
 704 
 705                         if (delay_secs != 0) {
 706                                 symbol__annotate_decay_histogram(sym, evsel->idx);
 707                                 hists__scnprintf_title(hists, title, sizeof(title));
 708                                 annotate_browser__show(&browser->b, title, help);
 709                         }
 710                         continue;
 711                 case K_TAB:
 712                         if (nd != NULL) {
 713                                 nd = rb_prev(nd);
 714                                 if (nd == NULL)
 715                                         nd = rb_last(&browser->entries);
 716                         } else
 717                                 nd = browser->curr_hot;
 718                         break;
 719                 case K_UNTAB:
 720                         if (nd != NULL) {
 721                                 nd = rb_next(nd);
 722                                 if (nd == NULL)
 723                                         nd = rb_first(&browser->entries);
 724                         } else
 725                                 nd = browser->curr_hot;
 726                         break;
 727                 case K_F1:
 728                 case 'h':
 729                         ui_browser__help_window(&browser->b,
 730                 "UP/DOWN/PGUP\n"
 731                 "PGDN/SPACE    Navigate\n"
 732                 "q/ESC/CTRL+C  Exit\n\n"
 733                 "ENTER         Go to target\n"
 734                 "ESC           Exit\n"
 735                 "H             Go to hottest instruction\n"
 736                 "TAB/shift+TAB Cycle thru hottest instructions\n"
 737                 "j             Toggle showing jump to target arrows\n"
 738                 "J             Toggle showing number of jump sources on targets\n"
 739                 "n             Search next string\n"
 740                 "o             Toggle disassembler output/simplified view\n"
 741                 "O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
 742                 "s             Toggle source code view\n"
 743                 "t             Circulate percent, total period, samples view\n"
 744                 "c             Show min/max cycle\n"
 745                 "/             Search string\n"
 746                 "k             Toggle line numbers\n"
 747                 "P             Print to [symbol_name].annotation file.\n"
 748                 "r             Run available scripts\n"
 749                 "p             Toggle percent type [local/global]\n"
 750                 "b             Toggle percent base [period/hits]\n"
 751                 "?             Search string backwards\n");
 752                         continue;
 753                 case 'r':
 754                         {
 755                                 script_browse(NULL, NULL);
 756                                 continue;
 757                         }
 758                 case 'k':
 759                         notes->options->show_linenr = !notes->options->show_linenr;
 760                         break;
 761                 case 'H':
 762                         nd = browser->curr_hot;
 763                         break;
 764                 case 's':
 765                         if (annotate_browser__toggle_source(browser))
 766                                 ui_helpline__puts(help);
 767                         continue;
 768                 case 'o':
 769                         notes->options->use_offset = !notes->options->use_offset;
 770                         annotation__update_column_widths(notes);
 771                         continue;
 772                 case 'O':
 773                         if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
 774                                 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
 775                         continue;
 776                 case 'j':
 777                         notes->options->jump_arrows = !notes->options->jump_arrows;
 778                         continue;
 779                 case 'J':
 780                         notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
 781                         annotation__update_column_widths(notes);
 782                         continue;
 783                 case '/':
 784                         if (annotate_browser__search(browser, delay_secs)) {
 785 show_help:
 786                                 ui_helpline__puts(help);
 787                         }
 788                         continue;
 789                 case 'n':
 790                         if (browser->searching_backwards ?
 791                             annotate_browser__continue_search_reverse(browser, delay_secs) :
 792                             annotate_browser__continue_search(browser, delay_secs))
 793                                 goto show_help;
 794                         continue;
 795                 case '?':
 796                         if (annotate_browser__search_reverse(browser, delay_secs))
 797                                 goto show_help;
 798                         continue;
 799                 case 'D': {
 800                         static int seq;
 801                         ui_helpline__pop();
 802                         ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
 803                                            seq++, browser->b.nr_entries,
 804                                            browser->b.height,
 805                                            browser->b.index,
 806                                            browser->b.top_idx,
 807                                            notes->nr_asm_entries);
 808                 }
 809                         continue;
 810                 case K_ENTER:
 811                 case K_RIGHT:
 812                 {
 813                         struct disasm_line *dl = disasm_line(browser->selection);
 814 
 815                         if (browser->selection == NULL)
 816                                 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
 817                         else if (browser->selection->offset == -1)
 818                                 ui_helpline__puts("Actions are only available for assembly lines.");
 819                         else if (!dl->ins.ops)
 820                                 goto show_sup_ins;
 821                         else if (ins__is_ret(&dl->ins))
 822                                 goto out;
 823                         else if (!(annotate_browser__jump(browser, evsel, hbt) ||
 824                                      annotate_browser__callq(browser, evsel, hbt))) {
 825 show_sup_ins:
 826                                 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
 827                         }
 828                         continue;
 829                 }
 830                 case 'P':
 831                         map_symbol__annotation_dump(ms, evsel, browser->opts);
 832                         continue;
 833                 case 't':
 834                         if (notes->options->show_total_period) {
 835                                 notes->options->show_total_period = false;
 836                                 notes->options->show_nr_samples = true;
 837                         } else if (notes->options->show_nr_samples)
 838                                 notes->options->show_nr_samples = false;
 839                         else
 840                                 notes->options->show_total_period = true;
 841                         annotation__update_column_widths(notes);
 842                         continue;
 843                 case 'c':
 844                         if (notes->options->show_minmax_cycle)
 845                                 notes->options->show_minmax_cycle = false;
 846                         else
 847                                 notes->options->show_minmax_cycle = true;
 848                         annotation__update_column_widths(notes);
 849                         continue;
 850                 case 'p':
 851                 case 'b':
 852                         switch_percent_type(browser->opts, key == 'b');
 853                         hists__scnprintf_title(hists, title, sizeof(title));
 854                         annotate_browser__show(&browser->b, title, help);
 855                         continue;
 856                 case K_LEFT:
 857                 case K_ESC:
 858                 case 'q':
 859                 case CTRL('c'):
 860                         goto out;
 861                 default:
 862                         continue;
 863                 }
 864 
 865                 if (nd != NULL)
 866                         annotate_browser__set_rb_top(browser, nd);
 867         }
 868 out:
 869         ui_browser__hide(&browser->b);
 870         return key;
 871 }
 872 
 873 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
 874                              struct hist_browser_timer *hbt,
 875                              struct annotation_options *opts)
 876 {
 877         return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts);
 878 }
 879 
 880 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
 881                              struct hist_browser_timer *hbt,
 882                              struct annotation_options *opts)
 883 {
 884         /* reset abort key so that it can get Ctrl-C as a key */
 885         SLang_reset_tty();
 886         SLang_init_tty(0, 0, 0);
 887 
 888         return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
 889 }
 890 
 891 int symbol__tui_annotate(struct symbol *sym, struct map *map,
 892                          struct evsel *evsel,
 893                          struct hist_browser_timer *hbt,
 894                          struct annotation_options *opts)
 895 {
 896         struct annotation *notes = symbol__annotation(sym);
 897         struct map_symbol ms = {
 898                 .map = map,
 899                 .sym = sym,
 900         };
 901         struct annotate_browser browser = {
 902                 .b = {
 903                         .refresh = annotate_browser__refresh,
 904                         .seek    = ui_browser__list_head_seek,
 905                         .write   = annotate_browser__write,
 906                         .filter  = disasm_line__filter,
 907                         .extra_title_lines = 1, /* for hists__scnprintf_title() */
 908                         .priv    = &ms,
 909                         .use_navkeypressed = true,
 910                 },
 911                 .opts = opts,
 912         };
 913         int ret = -1, err;
 914 
 915         if (sym == NULL)
 916                 return -1;
 917 
 918         if (map->dso->annotate_warned)
 919                 return -1;
 920 
 921         err = symbol__annotate2(sym, map, evsel, opts, &browser.arch);
 922         if (err) {
 923                 char msg[BUFSIZ];
 924                 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
 925                 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
 926                 goto out_free_offsets;
 927         }
 928 
 929         ui_helpline__push("Press ESC to exit");
 930 
 931         browser.b.width = notes->max_line_len;
 932         browser.b.nr_entries = notes->nr_entries;
 933         browser.b.entries = &notes->src->source,
 934         browser.b.width += 18; /* Percentage */
 935 
 936         if (notes->options->hide_src_code)
 937                 ui_browser__init_asm_mode(&browser.b);
 938 
 939         ret = annotate_browser__run(&browser, evsel, hbt);
 940 
 941         annotated_source__purge(notes->src);
 942 
 943 out_free_offsets:
 944         zfree(&notes->offsets);
 945         return ret;
 946 }

/* [<][>][^][v][top][bottom][index][help] */