1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2aca7a94dSNamhyung Kim #include "../browser.h" 3aca7a94dSNamhyung Kim #include "../helpline.h" 4aca7a94dSNamhyung Kim #include "../ui.h" 5aca7a94dSNamhyung Kim #include "../../util/annotate.h" 6b4209025SArnaldo Carvalho de Melo #include "../../util/debug.h" 74a3cec84SArnaldo Carvalho de Melo #include "../../util/dso.h" 8aca7a94dSNamhyung Kim #include "../../util/hist.h" 9aca7a94dSNamhyung Kim #include "../../util/sort.h" 101101f69aSArnaldo Carvalho de Melo #include "../../util/map.h" 1182aff6ccSIan Rogers #include "../../util/mutex.h" 12aca7a94dSNamhyung Kim #include "../../util/symbol.h" 13db8fd07aSNamhyung Kim #include "../../util/evsel.h" 1469fb09f6SJin Yao #include "../../util/evlist.h" 15fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 16877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 178e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h> 187f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 19b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h> 203e0d7953SJiri Olsa #include <asm/bug.h> 21aca7a94dSNamhyung Kim 22dcaa3948SJin Yao struct arch; 23dcaa3948SJin Yao 24aca7a94dSNamhyung Kim struct annotate_browser { 25aca7a94dSNamhyung Kim struct ui_browser b; 26aca7a94dSNamhyung Kim struct rb_root entries; 27aca7a94dSNamhyung Kim struct rb_node *curr_hot; 287bcbcd58SJiri Olsa struct annotation_line *selection; 29dcaa3948SJin Yao struct arch *arch; 30cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *opts; 31aca7a94dSNamhyung Kim bool searching_backwards; 32aca7a94dSNamhyung Kim char search_bf[128]; 33aca7a94dSNamhyung Kim }; 34aca7a94dSNamhyung Kim 3595aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser) 3695aa89d9SArnaldo Carvalho de Melo { 3795aa89d9SArnaldo Carvalho de Melo struct map_symbol *ms = browser->priv; 3895aa89d9SArnaldo Carvalho de Melo return symbol__annotation(ms->sym); 3995aa89d9SArnaldo Carvalho de Melo } 4095aa89d9SArnaldo Carvalho de Melo 4116932d77SArnaldo Carvalho de Melo static bool disasm_line__filter(struct ui_browser *browser, void *entry) 42aca7a94dSNamhyung Kim { 4395aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 44d5490b96SJiri Olsa struct annotation_line *al = list_entry(entry, struct annotation_line, node); 459b80d1f9SArnaldo Carvalho de Melo return annotation_line__filter(al, notes); 46aca7a94dSNamhyung Kim } 47aca7a94dSNamhyung Kim 4827feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current) 492402e4a9SArnaldo Carvalho de Melo { 5027feb761SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 51bc1c0f3dSArnaldo Carvalho de Melo 5227feb761SArnaldo Carvalho de Melo if (current && (!browser->use_navkeypressed || browser->navkeypressed)) 532402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_SELECTED; 54bc1c0f3dSArnaldo Carvalho de Melo if (nr == notes->max_jump_sources) 552402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_TOP; 562402e4a9SArnaldo Carvalho de Melo if (nr > 1) 572402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_MEDIUM; 582402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_NORMAL; 592402e4a9SArnaldo Carvalho de Melo } 602402e4a9SArnaldo Carvalho de Melo 61a1e9b74cSArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current) 622402e4a9SArnaldo Carvalho de Melo { 6327feb761SArnaldo Carvalho de Melo int color = ui_browser__jumps_percent_color(browser, nr, current); 6427feb761SArnaldo Carvalho de Melo return ui_browser__set_color(browser, color); 652402e4a9SArnaldo Carvalho de Melo } 662402e4a9SArnaldo Carvalho de Melo 67a1e9b74cSArnaldo Carvalho de Melo static int annotate_browser__set_color(void *browser, int color) 68aca7a94dSNamhyung Kim { 69a1e9b74cSArnaldo Carvalho de Melo return ui_browser__set_color(browser, color); 704ea08b52SArnaldo Carvalho de Melo } 714ea08b52SArnaldo Carvalho de Melo 72a1e9b74cSArnaldo Carvalho de Melo static void annotate_browser__write_graph(void *browser, int graph) 73a1e9b74cSArnaldo Carvalho de Melo { 74a1e9b74cSArnaldo Carvalho de Melo ui_browser__write_graph(browser, graph); 75a5433b3eSJiri Olsa } 76a5433b3eSJiri Olsa 772ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__set_percent_color(void *browser, double percent, bool current) 782ba5eca1SArnaldo Carvalho de Melo { 792ba5eca1SArnaldo Carvalho de Melo ui_browser__set_percent_color(browser, percent, current); 802ba5eca1SArnaldo Carvalho de Melo } 812ba5eca1SArnaldo Carvalho de Melo 822ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__printf(void *browser, const char *fmt, ...) 832ba5eca1SArnaldo Carvalho de Melo { 842ba5eca1SArnaldo Carvalho de Melo va_list args; 852ba5eca1SArnaldo Carvalho de Melo 862ba5eca1SArnaldo Carvalho de Melo va_start(args, fmt); 872ba5eca1SArnaldo Carvalho de Melo ui_browser__vprintf(browser, fmt, args); 882ba5eca1SArnaldo Carvalho de Melo va_end(args); 892ba5eca1SArnaldo Carvalho de Melo } 902ba5eca1SArnaldo Carvalho de Melo 91a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 92a5433b3eSJiri Olsa { 93a5433b3eSJiri Olsa struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 9495aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 95a5433b3eSJiri Olsa struct annotation_line *al = list_entry(entry, struct annotation_line, node); 96da201963SArnaldo Carvalho de Melo const bool is_current_entry = ui_browser__is_current_entry(browser, row); 97c298304bSArnaldo Carvalho de Melo struct annotation_write_ops ops = { 98c298304bSArnaldo Carvalho de Melo .first_line = row == 0, 99da201963SArnaldo Carvalho de Melo .current_entry = is_current_entry, 100c298304bSArnaldo Carvalho de Melo .change_color = (!notes->options->hide_src_code && 101da201963SArnaldo Carvalho de Melo (!is_current_entry || 102c298304bSArnaldo Carvalho de Melo (browser->use_navkeypressed && 103c298304bSArnaldo Carvalho de Melo !browser->navkeypressed))), 104c298304bSArnaldo Carvalho de Melo .width = browser->width, 105c298304bSArnaldo Carvalho de Melo .obj = browser, 106c298304bSArnaldo Carvalho de Melo .set_color = annotate_browser__set_color, 107c298304bSArnaldo Carvalho de Melo .set_percent_color = annotate_browser__set_percent_color, 108c298304bSArnaldo Carvalho de Melo .set_jumps_percent_color = ui_browser__set_jumps_percent_color, 109c298304bSArnaldo Carvalho de Melo .printf = annotate_browser__printf, 110c298304bSArnaldo Carvalho de Melo .write_graph = annotate_browser__write_graph, 111c298304bSArnaldo Carvalho de Melo }; 112a5433b3eSJiri Olsa 113a5433b3eSJiri Olsa /* The scroll bar isn't being used */ 114a5433b3eSJiri Olsa if (!browser->navkeypressed) 115c298304bSArnaldo Carvalho de Melo ops.width += 1; 116a5433b3eSJiri Olsa 1174c650ddcSJiri Olsa annotation_line__write(al, notes, &ops, ab->opts); 118aca7a94dSNamhyung Kim 119c298304bSArnaldo Carvalho de Melo if (ops.current_entry) 120a5433b3eSJiri Olsa ab->selection = al; 121aca7a94dSNamhyung Kim } 122aca7a94dSNamhyung Kim 1237efbcc8cSRavi Bangoria static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor) 1247e63a13aSJin Yao { 125a17c4ca0SJiri Olsa struct disasm_line *pos = list_prev_entry(cursor, al.node); 1267e63a13aSJin Yao const char *name; 1277efbcc8cSRavi Bangoria int diff = 1; 1287efbcc8cSRavi Bangoria 1297efbcc8cSRavi Bangoria while (pos && pos->al.offset == -1) { 1307efbcc8cSRavi Bangoria pos = list_prev_entry(pos, al.node); 1317efbcc8cSRavi Bangoria if (!ab->opts->hide_src_code) 1327efbcc8cSRavi Bangoria diff++; 1337efbcc8cSRavi Bangoria } 1347e63a13aSJin Yao 1357e63a13aSJin Yao if (!pos) 1367efbcc8cSRavi Bangoria return 0; 1377e63a13aSJin Yao 1387e63a13aSJin Yao if (ins__is_lock(&pos->ins)) 1397e63a13aSJin Yao name = pos->ops.locked.ins.name; 1407e63a13aSJin Yao else 1417e63a13aSJin Yao name = pos->ins.name; 1427e63a13aSJin Yao 1437e63a13aSJin Yao if (!name || !cursor->ins.name) 1447efbcc8cSRavi Bangoria return 0; 1457e63a13aSJin Yao 1467efbcc8cSRavi Bangoria if (ins__is_fused(ab->arch, name, cursor->ins.name)) 1477efbcc8cSRavi Bangoria return diff; 1487efbcc8cSRavi Bangoria return 0; 1497e63a13aSJin Yao } 1507e63a13aSJin Yao 1519d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser) 152a3f895beSArnaldo Carvalho de Melo { 153a3f895beSArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 1547bcbcd58SJiri Olsa struct disasm_line *cursor = disasm_line(ab->selection); 155a5ef2702SJiri Olsa struct annotation_line *target; 15683b1f2aaSArnaldo Carvalho de Melo unsigned int from, to; 15732ae1efdSNamhyung Kim struct map_symbol *ms = ab->b.priv; 15832ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 1590e83a7e9SArnaldo Carvalho de Melo struct annotation *notes = symbol__annotation(sym); 1606af612d2SArnaldo Carvalho de Melo u8 pcnt_width = annotation__pcnt_width(notes); 16100ea0eb2SArnaldo Carvalho de Melo int width; 1627efbcc8cSRavi Bangoria int diff = 0; 16332ae1efdSNamhyung Kim 16432ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 16532ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 16632ae1efdSNamhyung Kim return; 167a3f895beSArnaldo Carvalho de Melo 1682eff0611SArnaldo Carvalho de Melo if (!disasm_line__is_valid_local_jump(cursor, sym)) 169a3f895beSArnaldo Carvalho de Melo return; 170a3f895beSArnaldo Carvalho de Melo 1719c04409dSArnaldo Carvalho de Melo /* 1729c04409dSArnaldo Carvalho de Melo * This first was seen with a gcc function, _cpp_lex_token, that 1739c04409dSArnaldo Carvalho de Melo * has the usual jumps: 1749c04409dSArnaldo Carvalho de Melo * 1759c04409dSArnaldo Carvalho de Melo * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92> 1769c04409dSArnaldo Carvalho de Melo * 1779c04409dSArnaldo Carvalho de Melo * I.e. jumps to a label inside that function (_cpp_lex_token), and 1789c04409dSArnaldo Carvalho de Melo * those works, but also this kind: 1799c04409dSArnaldo Carvalho de Melo * 1809c04409dSArnaldo Carvalho de Melo * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72> 1819c04409dSArnaldo Carvalho de Melo * 1829c04409dSArnaldo Carvalho de Melo * I.e. jumps to another function, outside _cpp_lex_token, which 1839c04409dSArnaldo Carvalho de Melo * are not being correctly handled generating as a side effect references 1849c04409dSArnaldo Carvalho de Melo * to ab->offset[] entries that are set to NULL, so to make this code 1859c04409dSArnaldo Carvalho de Melo * more robust, check that here. 1869c04409dSArnaldo Carvalho de Melo * 1879c04409dSArnaldo Carvalho de Melo * A proper fix for will be put in place, looking at the function 1889c04409dSArnaldo Carvalho de Melo * name right after the '<' token and probably treating this like a 1899c04409dSArnaldo Carvalho de Melo * 'call' instruction. 1909c04409dSArnaldo Carvalho de Melo */ 1919d6bb41dSArnaldo Carvalho de Melo target = notes->offsets[cursor->ops.target.offset]; 1929c04409dSArnaldo Carvalho de Melo if (target == NULL) { 1939d6bb41dSArnaldo Carvalho de Melo ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n", 1949c04409dSArnaldo Carvalho de Melo cursor->ops.target.offset); 1959c04409dSArnaldo Carvalho de Melo return; 1969c04409dSArnaldo Carvalho de Melo } 1979d1ef56dSArnaldo Carvalho de Melo 19816932d77SArnaldo Carvalho de Melo if (notes->options->hide_src_code) { 1994850c92eSArnaldo Carvalho de Melo from = cursor->al.idx_asm; 2004850c92eSArnaldo Carvalho de Melo to = target->idx_asm; 201a3f895beSArnaldo Carvalho de Melo } else { 2024850c92eSArnaldo Carvalho de Melo from = (u64)cursor->al.idx; 2034850c92eSArnaldo Carvalho de Melo to = (u64)target->idx; 204a3f895beSArnaldo Carvalho de Melo } 205a3f895beSArnaldo Carvalho de Melo 2060e83a7e9SArnaldo Carvalho de Melo width = annotation__cycles_width(notes); 207b40982e8SJin Yao 20878ce08dfSTaeung Song ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 209b40982e8SJin Yao __ui_browser__line_arrow(browser, 2109761e86eSArnaldo Carvalho de Melo pcnt_width + 2 + notes->widths.addr + width, 211c7e7b610SNamhyung Kim from, to); 2127e63a13aSJin Yao 2137efbcc8cSRavi Bangoria diff = is_fused(ab, cursor); 2147efbcc8cSRavi Bangoria if (diff > 0) { 2157e63a13aSJin Yao ui_browser__mark_fused(browser, 2169761e86eSArnaldo Carvalho de Melo pcnt_width + 3 + notes->widths.addr + width, 2177efbcc8cSRavi Bangoria from - diff, diff, to > from); 2187e63a13aSJin Yao } 219a3f895beSArnaldo Carvalho de Melo } 220a3f895beSArnaldo Carvalho de Melo 221a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser) 222a3f895beSArnaldo Carvalho de Melo { 22395aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 224a3f895beSArnaldo Carvalho de Melo int ret = ui_browser__list_head_refresh(browser); 2256af612d2SArnaldo Carvalho de Melo int pcnt_width = annotation__pcnt_width(notes); 226a3f895beSArnaldo Carvalho de Melo 22716932d77SArnaldo Carvalho de Melo if (notes->options->jump_arrows) 2289d1ef56dSArnaldo Carvalho de Melo annotate_browser__draw_current_jump(browser); 229a3f895beSArnaldo Carvalho de Melo 23083b1f2aaSArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_NORMAL); 231e726c851SArnaldo Carvalho de Melo __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1); 232a3f895beSArnaldo Carvalho de Melo return ret; 233a3f895beSArnaldo Carvalho de Melo } 234a3f895beSArnaldo Carvalho de Melo 235da06d568SHe Kuang static double disasm__cmp(struct annotation_line *a, struct annotation_line *b, 236da06d568SHe Kuang int percent_type) 237c7e7b610SNamhyung Kim { 238c7e7b610SNamhyung Kim int i; 239c7e7b610SNamhyung Kim 240c2f938baSJiri Olsa for (i = 0; i < a->data_nr; i++) { 241da06d568SHe Kuang if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type]) 242c7e7b610SNamhyung Kim continue; 243da06d568SHe Kuang return a->data[i].percent[percent_type] - 244da06d568SHe Kuang b->data[i].percent[percent_type]; 245c7e7b610SNamhyung Kim } 246c7e7b610SNamhyung Kim return 0; 247c7e7b610SNamhyung Kim } 248c7e7b610SNamhyung Kim 249da06d568SHe Kuang static void disasm_rb_tree__insert(struct annotate_browser *browser, 250da06d568SHe Kuang struct annotation_line *al) 251aca7a94dSNamhyung Kim { 252da06d568SHe Kuang struct rb_root *root = &browser->entries; 25329ed6e76SArnaldo Carvalho de Melo struct rb_node **p = &root->rb_node; 254aca7a94dSNamhyung Kim struct rb_node *parent = NULL; 2553ab6db8dSJiri Olsa struct annotation_line *l; 256aca7a94dSNamhyung Kim 257aca7a94dSNamhyung Kim while (*p != NULL) { 258aca7a94dSNamhyung Kim parent = *p; 2593ab6db8dSJiri Olsa l = rb_entry(parent, struct annotation_line, rb_node); 260c7e7b610SNamhyung Kim 261da06d568SHe Kuang if (disasm__cmp(al, l, browser->opts->percent_type) < 0) 262aca7a94dSNamhyung Kim p = &(*p)->rb_left; 263aca7a94dSNamhyung Kim else 264aca7a94dSNamhyung Kim p = &(*p)->rb_right; 265aca7a94dSNamhyung Kim } 2663ab6db8dSJiri Olsa rb_link_node(&al->rb_node, parent, p); 2673ab6db8dSJiri Olsa rb_insert_color(&al->rb_node, root); 268aca7a94dSNamhyung Kim } 269aca7a94dSNamhyung Kim 27005e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser, 271ec03a77dSJiri Olsa struct annotation_line *pos, u32 idx) 272aca7a94dSNamhyung Kim { 2739b80d1f9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 274aca7a94dSNamhyung Kim unsigned back; 275aca7a94dSNamhyung Kim 27605e8b080SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(&browser->b); 27705e8b080SArnaldo Carvalho de Melo back = browser->b.height / 2; 27805e8b080SArnaldo Carvalho de Melo browser->b.top_idx = browser->b.index = idx; 279aca7a94dSNamhyung Kim 28005e8b080SArnaldo Carvalho de Melo while (browser->b.top_idx != 0 && back != 0) { 281ec03a77dSJiri Olsa pos = list_entry(pos->node.prev, struct annotation_line, node); 282aca7a94dSNamhyung Kim 2839b80d1f9SArnaldo Carvalho de Melo if (annotation_line__filter(pos, notes)) 284aca7a94dSNamhyung Kim continue; 285aca7a94dSNamhyung Kim 28605e8b080SArnaldo Carvalho de Melo --browser->b.top_idx; 287aca7a94dSNamhyung Kim --back; 288aca7a94dSNamhyung Kim } 289aca7a94dSNamhyung Kim 290ec03a77dSJiri Olsa browser->b.top = pos; 29105e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = true; 292aca7a94dSNamhyung Kim } 293aca7a94dSNamhyung Kim 294aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser, 295aca7a94dSNamhyung Kim struct rb_node *nd) 296aca7a94dSNamhyung Kim { 29795aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 2984850c92eSArnaldo Carvalho de Melo struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node); 2994850c92eSArnaldo Carvalho de Melo u32 idx = pos->idx; 300aca7a94dSNamhyung Kim 30116932d77SArnaldo Carvalho de Melo if (notes->options->hide_src_code) 3024850c92eSArnaldo Carvalho de Melo idx = pos->idx_asm; 303a44b45f2SArnaldo Carvalho de Melo annotate_browser__set_top(browser, pos, idx); 304aca7a94dSNamhyung Kim browser->curr_hot = nd; 305aca7a94dSNamhyung Kim } 306aca7a94dSNamhyung Kim 307aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser, 30832dcd021SJiri Olsa struct evsel *evsel) 309aca7a94dSNamhyung Kim { 310aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 311aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 312aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 313c4c72436SJiri Olsa struct disasm_line *pos; 314aca7a94dSNamhyung Kim 315aca7a94dSNamhyung Kim browser->entries = RB_ROOT; 316aca7a94dSNamhyung Kim 3179b3726efSIan Rogers mutex_lock(¬es->lock); 318aca7a94dSNamhyung Kim 319e425da6cSJiri Olsa symbol__calc_percent(sym, evsel); 320e425da6cSJiri Olsa 321a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 322c7e7b610SNamhyung Kim double max_percent = 0.0; 323c7e7b610SNamhyung Kim int i; 324e64aa75bSNamhyung Kim 325d5490b96SJiri Olsa if (pos->al.offset == -1) { 3265b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 327e64aa75bSNamhyung Kim continue; 328e64aa75bSNamhyung Kim } 329e64aa75bSNamhyung Kim 330c2f938baSJiri Olsa for (i = 0; i < pos->al.data_nr; i++) { 3316d9f0c2dSJiri Olsa double percent; 3320c4a5bceSMartin Liška 3336d9f0c2dSJiri Olsa percent = annotation_data__percent(&pos->al.data[i], 334d4265b1aSJiri Olsa browser->opts->percent_type); 3356d9f0c2dSJiri Olsa 3366d9f0c2dSJiri Olsa if (max_percent < percent) 3376d9f0c2dSJiri Olsa max_percent = percent; 338c7e7b610SNamhyung Kim } 339c7e7b610SNamhyung Kim 34037236d5eSJiri Olsa if (max_percent < 0.01 && pos->al.ipc == 0) { 3415b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 342aca7a94dSNamhyung Kim continue; 343aca7a94dSNamhyung Kim } 344da06d568SHe Kuang disasm_rb_tree__insert(browser, &pos->al); 345aca7a94dSNamhyung Kim } 3469b3726efSIan Rogers mutex_unlock(¬es->lock); 347aca7a94dSNamhyung Kim 348aca7a94dSNamhyung Kim browser->curr_hot = rb_last(&browser->entries); 349aca7a94dSNamhyung Kim } 350aca7a94dSNamhyung Kim 3516de249d6SRiccardo Mancini static struct annotation_line *annotate_browser__find_next_asm_line( 3526de249d6SRiccardo Mancini struct annotate_browser *browser, 3536de249d6SRiccardo Mancini struct annotation_line *al) 3546de249d6SRiccardo Mancini { 3556de249d6SRiccardo Mancini struct annotation_line *it = al; 3566de249d6SRiccardo Mancini 3576de249d6SRiccardo Mancini /* find next asm line */ 3585a4451e4SRiccardo Mancini list_for_each_entry_continue(it, browser->b.entries, node) { 3596de249d6SRiccardo Mancini if (it->idx_asm >= 0) 3606de249d6SRiccardo Mancini return it; 3616de249d6SRiccardo Mancini } 3626de249d6SRiccardo Mancini 3636de249d6SRiccardo Mancini /* no asm line found forwards, try backwards */ 3646de249d6SRiccardo Mancini it = al; 3655a4451e4SRiccardo Mancini list_for_each_entry_continue_reverse(it, browser->b.entries, node) { 3666de249d6SRiccardo Mancini if (it->idx_asm >= 0) 3676de249d6SRiccardo Mancini return it; 3686de249d6SRiccardo Mancini } 3696de249d6SRiccardo Mancini 3706de249d6SRiccardo Mancini /* There are no asm lines */ 3716de249d6SRiccardo Mancini return NULL; 3726de249d6SRiccardo Mancini } 3736de249d6SRiccardo Mancini 374aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser) 375aca7a94dSNamhyung Kim { 37695aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 377ec03a77dSJiri Olsa struct annotation_line *al; 378aca7a94dSNamhyung Kim off_t offset = browser->b.index - browser->b.top_idx; 379aca7a94dSNamhyung Kim 380aca7a94dSNamhyung Kim browser->b.seek(&browser->b, offset, SEEK_CUR); 381ec03a77dSJiri Olsa al = list_entry(browser->b.top, struct annotation_line, node); 382aca7a94dSNamhyung Kim 38316932d77SArnaldo Carvalho de Melo if (notes->options->hide_src_code) { 3844850c92eSArnaldo Carvalho de Melo if (al->idx_asm < offset) 3854850c92eSArnaldo Carvalho de Melo offset = al->idx; 386aca7a94dSNamhyung Kim 3871cf5f98aSArnaldo Carvalho de Melo browser->b.nr_entries = notes->nr_entries; 38816932d77SArnaldo Carvalho de Melo notes->options->hide_src_code = false; 389aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 3904850c92eSArnaldo Carvalho de Melo browser->b.top_idx = al->idx - offset; 3914850c92eSArnaldo Carvalho de Melo browser->b.index = al->idx; 392aca7a94dSNamhyung Kim } else { 3934850c92eSArnaldo Carvalho de Melo if (al->idx_asm < 0) { 3946de249d6SRiccardo Mancini /* move cursor to next asm line */ 3956de249d6SRiccardo Mancini al = annotate_browser__find_next_asm_line(browser, al); 3966de249d6SRiccardo Mancini if (!al) { 397aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 398aca7a94dSNamhyung Kim return false; 399aca7a94dSNamhyung Kim } 4006de249d6SRiccardo Mancini } 401aca7a94dSNamhyung Kim 4024850c92eSArnaldo Carvalho de Melo if (al->idx_asm < offset) 4034850c92eSArnaldo Carvalho de Melo offset = al->idx_asm; 404aca7a94dSNamhyung Kim 4051cf5f98aSArnaldo Carvalho de Melo browser->b.nr_entries = notes->nr_asm_entries; 40616932d77SArnaldo Carvalho de Melo notes->options->hide_src_code = true; 407aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 4084850c92eSArnaldo Carvalho de Melo browser->b.top_idx = al->idx_asm - offset; 4094850c92eSArnaldo Carvalho de Melo browser->b.index = al->idx_asm; 410aca7a94dSNamhyung Kim } 411aca7a94dSNamhyung Kim 412aca7a94dSNamhyung Kim return true; 413aca7a94dSNamhyung Kim } 414aca7a94dSNamhyung Kim 4152777b81bSMartin Liska #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 4162777b81bSMartin Liska 4172777b81bSMartin Liska static void annotate_browser__show_full_location(struct ui_browser *browser) 4182777b81bSMartin Liska { 4192777b81bSMartin Liska struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 4202777b81bSMartin Liska struct disasm_line *cursor = disasm_line(ab->selection); 4212777b81bSMartin Liska struct annotation_line *al = &cursor->al; 4222777b81bSMartin Liska 4232777b81bSMartin Liska if (al->offset != -1) 4242777b81bSMartin Liska ui_helpline__puts("Only available for source code lines."); 4252777b81bSMartin Liska else if (al->fileloc == NULL) 4262777b81bSMartin Liska ui_helpline__puts("No source file location."); 4272777b81bSMartin Liska else { 4282777b81bSMartin Liska char help_line[SYM_TITLE_MAX_SIZE]; 4292777b81bSMartin Liska sprintf (help_line, "Source file location: %s", al->fileloc); 4302777b81bSMartin Liska ui_helpline__puts(help_line); 4312777b81bSMartin Liska } 4322777b81bSMartin Liska } 4332777b81bSMartin Liska 4341cf5f98aSArnaldo Carvalho de Melo static void ui_browser__init_asm_mode(struct ui_browser *browser) 435e9823b21SArnaldo Carvalho de Melo { 4361cf5f98aSArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 4371cf5f98aSArnaldo Carvalho de Melo ui_browser__reset_index(browser); 4381cf5f98aSArnaldo Carvalho de Melo browser->nr_entries = notes->nr_asm_entries; 439e9823b21SArnaldo Carvalho de Melo } 440e9823b21SArnaldo Carvalho de Melo 44134f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title, 4423e0d7953SJiri Olsa size_t sz, int percent_type) 44334f77abcSAdrian Hunter { 444*63df0e4bSIan Rogers return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, 445*63df0e4bSIan Rogers map__dso(map)->long_name, 4463e0d7953SJiri Olsa percent_type_str(percent_type)); 44734f77abcSAdrian Hunter } 44834f77abcSAdrian Hunter 449e4cc91b8SArnaldo Carvalho de Melo /* 4504d39c89fSIngo Molnar * This can be called from external jumps, i.e. jumps from one function 451e4cc91b8SArnaldo Carvalho de Melo * to another, like from the kernel's entry_SYSCALL_64 function to the 452e4cc91b8SArnaldo Carvalho de Melo * swapgs_restore_regs_and_return_to_usermode() function. 453e4cc91b8SArnaldo Carvalho de Melo * 454e4cc91b8SArnaldo Carvalho de Melo * So all we check here is that dl->ops.target.sym is set, if it is, just 455e4cc91b8SArnaldo Carvalho de Melo * go to that function and when exiting from its disassembly, come back 456e4cc91b8SArnaldo Carvalho de Melo * to the calling function. 457e4cc91b8SArnaldo Carvalho de Melo */ 458db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser, 45932dcd021SJiri Olsa struct evsel *evsel, 4609783adf7SNamhyung Kim struct hist_browser_timer *hbt) 461aca7a94dSNamhyung Kim { 46229754894SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv, target_ms; 4637bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 464aca7a94dSNamhyung Kim struct annotation *notes; 46534f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 466aca7a94dSNamhyung Kim 467696703afSArnaldo Carvalho de Melo if (!dl->ops.target.sym) { 468aca7a94dSNamhyung Kim ui_helpline__puts("The called function was not found."); 469aca7a94dSNamhyung Kim return true; 470aca7a94dSNamhyung Kim } 471aca7a94dSNamhyung Kim 472696703afSArnaldo Carvalho de Melo notes = symbol__annotation(dl->ops.target.sym); 4739b3726efSIan Rogers mutex_lock(¬es->lock); 474aca7a94dSNamhyung Kim 4756484d2f9SJiri Olsa if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) { 4769b3726efSIan Rogers mutex_unlock(¬es->lock); 477aca7a94dSNamhyung Kim ui__warning("Not enough memory for annotating '%s' symbol!\n", 478696703afSArnaldo Carvalho de Melo dl->ops.target.sym->name); 479aca7a94dSNamhyung Kim return true; 480aca7a94dSNamhyung Kim } 481aca7a94dSNamhyung Kim 482f2eaea09SArnaldo Carvalho de Melo target_ms.maps = ms->maps; 48329754894SArnaldo Carvalho de Melo target_ms.map = ms->map; 48429754894SArnaldo Carvalho de Melo target_ms.sym = dl->ops.target.sym; 4859b3726efSIan Rogers mutex_unlock(¬es->lock); 48629754894SArnaldo Carvalho de Melo symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts); 4873e0d7953SJiri Olsa sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type); 48834f77abcSAdrian Hunter ui_browser__show_title(&browser->b, title); 489aca7a94dSNamhyung Kim return true; 490aca7a94dSNamhyung Kim } 491aca7a94dSNamhyung Kim 49229ed6e76SArnaldo Carvalho de Melo static 49329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 494aca7a94dSNamhyung Kim s64 offset, s64 *idx) 495aca7a94dSNamhyung Kim { 49695aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 49729ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 498aca7a94dSNamhyung Kim 499aca7a94dSNamhyung Kim *idx = 0; 500a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 501d5490b96SJiri Olsa if (pos->al.offset == offset) 502aca7a94dSNamhyung Kim return pos; 5039b80d1f9SArnaldo Carvalho de Melo if (!annotation_line__filter(&pos->al, notes)) 504aca7a94dSNamhyung Kim ++*idx; 505aca7a94dSNamhyung Kim } 506aca7a94dSNamhyung Kim 507aca7a94dSNamhyung Kim return NULL; 508aca7a94dSNamhyung Kim } 509aca7a94dSNamhyung Kim 510e4cc91b8SArnaldo Carvalho de Melo static bool annotate_browser__jump(struct annotate_browser *browser, 51132dcd021SJiri Olsa struct evsel *evsel, 512e4cc91b8SArnaldo Carvalho de Melo struct hist_browser_timer *hbt) 513aca7a94dSNamhyung Kim { 5147bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 5155252b1aeSArnaldo Carvalho de Melo u64 offset; 5164f9d0325SArnaldo Carvalho de Melo s64 idx; 517aca7a94dSNamhyung Kim 51875b49202SArnaldo Carvalho de Melo if (!ins__is_jump(&dl->ins)) 519aca7a94dSNamhyung Kim return false; 520aca7a94dSNamhyung Kim 521e4cc91b8SArnaldo Carvalho de Melo if (dl->ops.target.outside) { 522e4cc91b8SArnaldo Carvalho de Melo annotate_browser__callq(browser, evsel, hbt); 523e4cc91b8SArnaldo Carvalho de Melo return true; 524e4cc91b8SArnaldo Carvalho de Melo } 525e4cc91b8SArnaldo Carvalho de Melo 5265252b1aeSArnaldo Carvalho de Melo offset = dl->ops.target.offset; 5275252b1aeSArnaldo Carvalho de Melo dl = annotate_browser__find_offset(browser, offset, &idx); 52829ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 5295252b1aeSArnaldo Carvalho de Melo ui_helpline__printf("Invalid jump offset: %" PRIx64, offset); 530aca7a94dSNamhyung Kim return true; 531aca7a94dSNamhyung Kim } 532aca7a94dSNamhyung Kim 533ec03a77dSJiri Olsa annotate_browser__set_top(browser, &dl->al, idx); 534aca7a94dSNamhyung Kim 535aca7a94dSNamhyung Kim return true; 536aca7a94dSNamhyung Kim } 537aca7a94dSNamhyung Kim 53829ed6e76SArnaldo Carvalho de Melo static 5399213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser, 540aca7a94dSNamhyung Kim char *s, s64 *idx) 541aca7a94dSNamhyung Kim { 54295aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 5439213afbdSJiri Olsa struct annotation_line *al = browser->selection; 544aca7a94dSNamhyung Kim 545aca7a94dSNamhyung Kim *idx = browser->b.index; 5469213afbdSJiri Olsa list_for_each_entry_continue(al, ¬es->src->source, node) { 5479b80d1f9SArnaldo Carvalho de Melo if (annotation_line__filter(al, notes)) 548aca7a94dSNamhyung Kim continue; 549aca7a94dSNamhyung Kim 550aca7a94dSNamhyung Kim ++*idx; 551aca7a94dSNamhyung Kim 5529213afbdSJiri Olsa if (al->line && strstr(al->line, s) != NULL) 5539213afbdSJiri Olsa return al; 554aca7a94dSNamhyung Kim } 555aca7a94dSNamhyung Kim 556aca7a94dSNamhyung Kim return NULL; 557aca7a94dSNamhyung Kim } 558aca7a94dSNamhyung Kim 559aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser) 560aca7a94dSNamhyung Kim { 5619213afbdSJiri Olsa struct annotation_line *al; 562aca7a94dSNamhyung Kim s64 idx; 563aca7a94dSNamhyung Kim 5649213afbdSJiri Olsa al = annotate_browser__find_string(browser, browser->search_bf, &idx); 5659213afbdSJiri Olsa if (al == NULL) { 566aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 567aca7a94dSNamhyung Kim return false; 568aca7a94dSNamhyung Kim } 569aca7a94dSNamhyung Kim 570ec03a77dSJiri Olsa annotate_browser__set_top(browser, al, idx); 571aca7a94dSNamhyung Kim browser->searching_backwards = false; 572aca7a94dSNamhyung Kim return true; 573aca7a94dSNamhyung Kim } 574aca7a94dSNamhyung Kim 57529ed6e76SArnaldo Carvalho de Melo static 5769213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 577aca7a94dSNamhyung Kim char *s, s64 *idx) 578aca7a94dSNamhyung Kim { 57995aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 5809213afbdSJiri Olsa struct annotation_line *al = browser->selection; 581aca7a94dSNamhyung Kim 582aca7a94dSNamhyung Kim *idx = browser->b.index; 5839213afbdSJiri Olsa list_for_each_entry_continue_reverse(al, ¬es->src->source, node) { 5849b80d1f9SArnaldo Carvalho de Melo if (annotation_line__filter(al, notes)) 585aca7a94dSNamhyung Kim continue; 586aca7a94dSNamhyung Kim 587aca7a94dSNamhyung Kim --*idx; 588aca7a94dSNamhyung Kim 5899213afbdSJiri Olsa if (al->line && strstr(al->line, s) != NULL) 5909213afbdSJiri Olsa return al; 591aca7a94dSNamhyung Kim } 592aca7a94dSNamhyung Kim 593aca7a94dSNamhyung Kim return NULL; 594aca7a94dSNamhyung Kim } 595aca7a94dSNamhyung Kim 596aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser) 597aca7a94dSNamhyung Kim { 5989213afbdSJiri Olsa struct annotation_line *al; 599aca7a94dSNamhyung Kim s64 idx; 600aca7a94dSNamhyung Kim 6019213afbdSJiri Olsa al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 6029213afbdSJiri Olsa if (al == NULL) { 603aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 604aca7a94dSNamhyung Kim return false; 605aca7a94dSNamhyung Kim } 606aca7a94dSNamhyung Kim 607ec03a77dSJiri Olsa annotate_browser__set_top(browser, al, idx); 608aca7a94dSNamhyung Kim browser->searching_backwards = true; 609aca7a94dSNamhyung Kim return true; 610aca7a94dSNamhyung Kim } 611aca7a94dSNamhyung Kim 612aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser, 613aca7a94dSNamhyung Kim int delay_secs) 614aca7a94dSNamhyung Kim { 615aca7a94dSNamhyung Kim if (ui_browser__input_window("Search", "String: ", browser->search_bf, 616aca7a94dSNamhyung Kim "ENTER: OK, ESC: Cancel", 617aca7a94dSNamhyung Kim delay_secs * 2) != K_ENTER || 618aca7a94dSNamhyung Kim !*browser->search_bf) 619aca7a94dSNamhyung Kim return false; 620aca7a94dSNamhyung Kim 621aca7a94dSNamhyung Kim return true; 622aca7a94dSNamhyung Kim } 623aca7a94dSNamhyung Kim 624aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) 625aca7a94dSNamhyung Kim { 626aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 627aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 628aca7a94dSNamhyung Kim 629aca7a94dSNamhyung Kim return false; 630aca7a94dSNamhyung Kim } 631aca7a94dSNamhyung Kim 632aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser, 633aca7a94dSNamhyung Kim int delay_secs) 634aca7a94dSNamhyung Kim { 635aca7a94dSNamhyung Kim if (!*browser->search_bf) 636aca7a94dSNamhyung Kim return annotate_browser__search(browser, delay_secs); 637aca7a94dSNamhyung Kim 638aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 639aca7a94dSNamhyung Kim } 640aca7a94dSNamhyung Kim 641aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser, 642aca7a94dSNamhyung Kim int delay_secs) 643aca7a94dSNamhyung Kim { 644aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 645aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 646aca7a94dSNamhyung Kim 647aca7a94dSNamhyung Kim return false; 648aca7a94dSNamhyung Kim } 649aca7a94dSNamhyung Kim 650aca7a94dSNamhyung Kim static 651aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, 652aca7a94dSNamhyung Kim int delay_secs) 653aca7a94dSNamhyung Kim { 654aca7a94dSNamhyung Kim if (!*browser->search_bf) 655aca7a94dSNamhyung Kim return annotate_browser__search_reverse(browser, delay_secs); 656aca7a94dSNamhyung Kim 657aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 658aca7a94dSNamhyung Kim } 659aca7a94dSNamhyung Kim 6606920e285SArnaldo Carvalho de Melo static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) 6616920e285SArnaldo Carvalho de Melo { 6623e0d7953SJiri Olsa struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 6636920e285SArnaldo Carvalho de Melo struct map_symbol *ms = browser->priv; 6646920e285SArnaldo Carvalho de Melo struct symbol *sym = ms->sym; 6656920e285SArnaldo Carvalho de Melo char symbol_dso[SYM_TITLE_MAX_SIZE]; 6666920e285SArnaldo Carvalho de Melo 6676920e285SArnaldo Carvalho de Melo if (ui_browser__show(browser, title, help) < 0) 6686920e285SArnaldo Carvalho de Melo return -1; 6696920e285SArnaldo Carvalho de Melo 6703e0d7953SJiri Olsa sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type); 6716920e285SArnaldo Carvalho de Melo 6726920e285SArnaldo Carvalho de Melo ui_browser__gotorc_title(browser, 0, 0); 6736920e285SArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_ROOT); 6746920e285SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); 6756920e285SArnaldo Carvalho de Melo return 0; 6766920e285SArnaldo Carvalho de Melo } 6776920e285SArnaldo Carvalho de Melo 6783e0d7953SJiri Olsa static void 6793e0d7953SJiri Olsa switch_percent_type(struct annotation_options *opts, bool base) 6803e0d7953SJiri Olsa { 6813e0d7953SJiri Olsa switch (opts->percent_type) { 6823e0d7953SJiri Olsa case PERCENT_HITS_LOCAL: 6833e0d7953SJiri Olsa if (base) 6843e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_LOCAL; 6853e0d7953SJiri Olsa else 6863e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_GLOBAL; 6873e0d7953SJiri Olsa break; 6883e0d7953SJiri Olsa case PERCENT_HITS_GLOBAL: 6893e0d7953SJiri Olsa if (base) 6903e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_GLOBAL; 6913e0d7953SJiri Olsa else 6923e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_LOCAL; 6933e0d7953SJiri Olsa break; 6943e0d7953SJiri Olsa case PERCENT_PERIOD_LOCAL: 6953e0d7953SJiri Olsa if (base) 6963e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_LOCAL; 6973e0d7953SJiri Olsa else 6983e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_GLOBAL; 6993e0d7953SJiri Olsa break; 7003e0d7953SJiri Olsa case PERCENT_PERIOD_GLOBAL: 7013e0d7953SJiri Olsa if (base) 7023e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_GLOBAL; 7033e0d7953SJiri Olsa else 7043e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_LOCAL; 7053e0d7953SJiri Olsa break; 7063e0d7953SJiri Olsa default: 7073e0d7953SJiri Olsa WARN_ON(1); 7083e0d7953SJiri Olsa } 7093e0d7953SJiri Olsa } 7103e0d7953SJiri Olsa 711db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser, 71232dcd021SJiri Olsa struct evsel *evsel, 7139783adf7SNamhyung Kim struct hist_browser_timer *hbt) 714aca7a94dSNamhyung Kim { 715aca7a94dSNamhyung Kim struct rb_node *nd = NULL; 7166920e285SArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 71705e8b080SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv; 718aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 71916932d77SArnaldo Carvalho de Melo struct annotation *notes = symbol__annotation(ms->sym); 72054e7a4e8SArnaldo Carvalho de Melo const char *help = "Press 'h' for help on key bindings"; 7219783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 7226920e285SArnaldo Carvalho de Melo char title[256]; 723aca7a94dSNamhyung Kim int key; 724aca7a94dSNamhyung Kim 7250683d13cSJiri Olsa hists__scnprintf_title(hists, title, sizeof(title)); 7266920e285SArnaldo Carvalho de Melo if (annotate_browser__show(&browser->b, title, help) < 0) 727aca7a94dSNamhyung Kim return -1; 728aca7a94dSNamhyung Kim 729db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 730aca7a94dSNamhyung Kim 73105e8b080SArnaldo Carvalho de Melo if (browser->curr_hot) { 73205e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, browser->curr_hot); 73305e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = false; 734aca7a94dSNamhyung Kim } 735aca7a94dSNamhyung Kim 73605e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 737aca7a94dSNamhyung Kim 738aca7a94dSNamhyung Kim while (1) { 73905e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 740aca7a94dSNamhyung Kim 741aca7a94dSNamhyung Kim if (delay_secs != 0) { 742db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 743aca7a94dSNamhyung Kim /* 744aca7a94dSNamhyung Kim * Current line focus got out of the list of most active 745aca7a94dSNamhyung Kim * lines, NULL it so that if TAB|UNTAB is pressed, we 746aca7a94dSNamhyung Kim * move to curr_hot (current hottest line). 747aca7a94dSNamhyung Kim */ 748aca7a94dSNamhyung Kim if (nd != NULL && RB_EMPTY_NODE(nd)) 749aca7a94dSNamhyung Kim nd = NULL; 750aca7a94dSNamhyung Kim } 751aca7a94dSNamhyung Kim 752aca7a94dSNamhyung Kim switch (key) { 753aca7a94dSNamhyung Kim case K_TIMER: 7549783adf7SNamhyung Kim if (hbt) 7559783adf7SNamhyung Kim hbt->timer(hbt->arg); 756aca7a94dSNamhyung Kim 7576920e285SArnaldo Carvalho de Melo if (delay_secs != 0) { 75838fe0e01SJiri Olsa symbol__annotate_decay_histogram(sym, evsel->core.idx); 7596920e285SArnaldo Carvalho de Melo hists__scnprintf_title(hists, title, sizeof(title)); 7606920e285SArnaldo Carvalho de Melo annotate_browser__show(&browser->b, title, help); 7616920e285SArnaldo Carvalho de Melo } 762aca7a94dSNamhyung Kim continue; 763aca7a94dSNamhyung Kim case K_TAB: 764aca7a94dSNamhyung Kim if (nd != NULL) { 765aca7a94dSNamhyung Kim nd = rb_prev(nd); 766aca7a94dSNamhyung Kim if (nd == NULL) 76705e8b080SArnaldo Carvalho de Melo nd = rb_last(&browser->entries); 768aca7a94dSNamhyung Kim } else 76905e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 770aca7a94dSNamhyung Kim break; 771aca7a94dSNamhyung Kim case K_UNTAB: 772d4913cbdSMarkus Trippelsdorf if (nd != NULL) { 773aca7a94dSNamhyung Kim nd = rb_next(nd); 774aca7a94dSNamhyung Kim if (nd == NULL) 77505e8b080SArnaldo Carvalho de Melo nd = rb_first(&browser->entries); 776d4913cbdSMarkus Trippelsdorf } else 77705e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 778aca7a94dSNamhyung Kim break; 77954e7a4e8SArnaldo Carvalho de Melo case K_F1: 780aca7a94dSNamhyung Kim case 'h': 78105e8b080SArnaldo Carvalho de Melo ui_browser__help_window(&browser->b, 78254e7a4e8SArnaldo Carvalho de Melo "UP/DOWN/PGUP\n" 78354e7a4e8SArnaldo Carvalho de Melo "PGDN/SPACE Navigate\n" 78454e7a4e8SArnaldo Carvalho de Melo "q/ESC/CTRL+C Exit\n\n" 7857727a925SArnaldo Carvalho de Melo "ENTER Go to target\n" 7867727a925SArnaldo Carvalho de Melo "ESC Exit\n" 787eba9fac0SArnaldo Carvalho de Melo "H Go to hottest instruction\n" 788eba9fac0SArnaldo Carvalho de Melo "TAB/shift+TAB Cycle thru hottest instructions\n" 78954e7a4e8SArnaldo Carvalho de Melo "j Toggle showing jump to target arrows\n" 79054e7a4e8SArnaldo Carvalho de Melo "J Toggle showing number of jump sources on targets\n" 79154e7a4e8SArnaldo Carvalho de Melo "n Search next string\n" 79254e7a4e8SArnaldo Carvalho de Melo "o Toggle disassembler output/simplified view\n" 79351f39603SArnaldo Carvalho de Melo "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n" 79454e7a4e8SArnaldo Carvalho de Melo "s Toggle source code view\n" 7953a555c77STaeung Song "t Circulate percent, total period, samples view\n" 7963e71fc03SJin Yao "c Show min/max cycle\n" 79754e7a4e8SArnaldo Carvalho de Melo "/ Search string\n" 798e592488cSAndi Kleen "k Toggle line numbers\n" 7992777b81bSMartin Liska "l Show full source file location\n" 800d9bd7665SArnaldo Carvalho de Melo "P Print to [symbol_name].annotation file.\n" 80179ee47faSFeng Tang "r Run available scripts\n" 8023e0d7953SJiri Olsa "p Toggle percent type [local/global]\n" 8033e0d7953SJiri Olsa "b Toggle percent base [period/hits]\n" 8047d18a824SNamhyung Kim "? Search string backwards\n" 8057d18a824SNamhyung Kim "f Toggle showing offsets to full address\n"); 80654e7a4e8SArnaldo Carvalho de Melo continue; 80779ee47faSFeng Tang case 'r': 8086f3da20eSAndi Kleen script_browse(NULL, NULL); 80954cf752cSRavi Bangoria annotate_browser__show(&browser->b, title, help); 81079ee47faSFeng Tang continue; 811e592488cSAndi Kleen case 'k': 81216932d77SArnaldo Carvalho de Melo notes->options->show_linenr = !notes->options->show_linenr; 8134fd00847SMartin Liška continue; 8142777b81bSMartin Liska case 'l': 8152777b81bSMartin Liska annotate_browser__show_full_location (&browser->b); 8162777b81bSMartin Liska continue; 81754e7a4e8SArnaldo Carvalho de Melo case 'H': 81805e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 819aca7a94dSNamhyung Kim break; 820aca7a94dSNamhyung Kim case 's': 82105e8b080SArnaldo Carvalho de Melo if (annotate_browser__toggle_source(browser)) 822aca7a94dSNamhyung Kim ui_helpline__puts(help); 823aca7a94dSNamhyung Kim continue; 824aca7a94dSNamhyung Kim case 'o': 82516932d77SArnaldo Carvalho de Melo notes->options->use_offset = !notes->options->use_offset; 8269761e86eSArnaldo Carvalho de Melo annotation__update_column_widths(notes); 827aca7a94dSNamhyung Kim continue; 82851f39603SArnaldo Carvalho de Melo case 'O': 82951f39603SArnaldo Carvalho de Melo if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL) 83051f39603SArnaldo Carvalho de Melo notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL; 83151f39603SArnaldo Carvalho de Melo continue; 8329d1ef56dSArnaldo Carvalho de Melo case 'j': 83316932d77SArnaldo Carvalho de Melo notes->options->jump_arrows = !notes->options->jump_arrows; 8349d1ef56dSArnaldo Carvalho de Melo continue; 8352402e4a9SArnaldo Carvalho de Melo case 'J': 83616932d77SArnaldo Carvalho de Melo notes->options->show_nr_jumps = !notes->options->show_nr_jumps; 8379761e86eSArnaldo Carvalho de Melo annotation__update_column_widths(notes); 838e9823b21SArnaldo Carvalho de Melo continue; 839aca7a94dSNamhyung Kim case '/': 84005e8b080SArnaldo Carvalho de Melo if (annotate_browser__search(browser, delay_secs)) { 841aca7a94dSNamhyung Kim show_help: 842aca7a94dSNamhyung Kim ui_helpline__puts(help); 843aca7a94dSNamhyung Kim } 844aca7a94dSNamhyung Kim continue; 845aca7a94dSNamhyung Kim case 'n': 84605e8b080SArnaldo Carvalho de Melo if (browser->searching_backwards ? 84705e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search_reverse(browser, delay_secs) : 84805e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search(browser, delay_secs)) 849aca7a94dSNamhyung Kim goto show_help; 850aca7a94dSNamhyung Kim continue; 851aca7a94dSNamhyung Kim case '?': 85205e8b080SArnaldo Carvalho de Melo if (annotate_browser__search_reverse(browser, delay_secs)) 853aca7a94dSNamhyung Kim goto show_help; 854aca7a94dSNamhyung Kim continue; 855e9823b21SArnaldo Carvalho de Melo case 'D': { 856e9823b21SArnaldo Carvalho de Melo static int seq; 857e9823b21SArnaldo Carvalho de Melo ui_helpline__pop(); 858e9823b21SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d", 85905e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 86005e8b080SArnaldo Carvalho de Melo browser->b.height, 86105e8b080SArnaldo Carvalho de Melo browser->b.index, 86205e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 8631cf5f98aSArnaldo Carvalho de Melo notes->nr_asm_entries); 864e9823b21SArnaldo Carvalho de Melo } 865e9823b21SArnaldo Carvalho de Melo continue; 866aca7a94dSNamhyung Kim case K_ENTER: 867aca7a94dSNamhyung Kim case K_RIGHT: 8687bcbcd58SJiri Olsa { 8697bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 8707bcbcd58SJiri Olsa 87105e8b080SArnaldo Carvalho de Melo if (browser->selection == NULL) 872aca7a94dSNamhyung Kim ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 8737bcbcd58SJiri Olsa else if (browser->selection->offset == -1) 874aca7a94dSNamhyung Kim ui_helpline__puts("Actions are only available for assembly lines."); 8757bcbcd58SJiri Olsa else if (!dl->ins.ops) 876c4cceae3SArnaldo Carvalho de Melo goto show_sup_ins; 8777bcbcd58SJiri Olsa else if (ins__is_ret(&dl->ins)) 878c4cceae3SArnaldo Carvalho de Melo goto out; 879e4cc91b8SArnaldo Carvalho de Melo else if (!(annotate_browser__jump(browser, evsel, hbt) || 880db8fd07aSNamhyung Kim annotate_browser__callq(browser, evsel, hbt))) { 881c4cceae3SArnaldo Carvalho de Melo show_sup_ins: 8826ef94929SNaveen N. Rao ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 883c4cceae3SArnaldo Carvalho de Melo } 884aca7a94dSNamhyung Kim continue; 8857bcbcd58SJiri Olsa } 886d9bd7665SArnaldo Carvalho de Melo case 'P': 8874c650ddcSJiri Olsa map_symbol__annotation_dump(ms, evsel, browser->opts); 888d9bd7665SArnaldo Carvalho de Melo continue; 8890c4a5bceSMartin Liška case 't': 89068aac855SRavi Bangoria if (symbol_conf.show_total_period) { 89168aac855SRavi Bangoria symbol_conf.show_total_period = false; 89246ccb442SRavi Bangoria symbol_conf.show_nr_samples = true; 89346ccb442SRavi Bangoria } else if (symbol_conf.show_nr_samples) 89446ccb442SRavi Bangoria symbol_conf.show_nr_samples = false; 8953a555c77STaeung Song else 89668aac855SRavi Bangoria symbol_conf.show_total_period = true; 8979761e86eSArnaldo Carvalho de Melo annotation__update_column_widths(notes); 8980c4a5bceSMartin Liška continue; 8993e71fc03SJin Yao case 'c': 9003e71fc03SJin Yao if (notes->options->show_minmax_cycle) 9013e71fc03SJin Yao notes->options->show_minmax_cycle = false; 9023e71fc03SJin Yao else 9033e71fc03SJin Yao notes->options->show_minmax_cycle = true; 9043e71fc03SJin Yao annotation__update_column_widths(notes); 9053e71fc03SJin Yao continue; 9063e0d7953SJiri Olsa case 'p': 9073e0d7953SJiri Olsa case 'b': 9083e0d7953SJiri Olsa switch_percent_type(browser->opts, key == 'b'); 9093e0d7953SJiri Olsa hists__scnprintf_title(hists, title, sizeof(title)); 9103e0d7953SJiri Olsa annotate_browser__show(&browser->b, title, help); 9113e0d7953SJiri Olsa continue; 9127d18a824SNamhyung Kim case 'f': 9137d18a824SNamhyung Kim annotation__toggle_full_addr(notes, ms); 9147d18a824SNamhyung Kim continue; 915aca7a94dSNamhyung Kim case K_LEFT: 916aca7a94dSNamhyung Kim case K_ESC: 917aca7a94dSNamhyung Kim case 'q': 918aca7a94dSNamhyung Kim case CTRL('c'): 919aca7a94dSNamhyung Kim goto out; 920aca7a94dSNamhyung Kim default: 921aca7a94dSNamhyung Kim continue; 922aca7a94dSNamhyung Kim } 923aca7a94dSNamhyung Kim 924aca7a94dSNamhyung Kim if (nd != NULL) 92505e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, nd); 926aca7a94dSNamhyung Kim } 927aca7a94dSNamhyung Kim out: 92805e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 929aca7a94dSNamhyung Kim return key; 930aca7a94dSNamhyung Kim } 931aca7a94dSNamhyung Kim 93232dcd021SJiri Olsa int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, 933cd0cccbaSArnaldo Carvalho de Melo struct hist_browser_timer *hbt, 934cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *opts) 935d5dbc518SArnaldo Carvalho de Melo { 93629754894SArnaldo Carvalho de Melo return symbol__tui_annotate(ms, evsel, hbt, opts); 937d5dbc518SArnaldo Carvalho de Melo } 938d5dbc518SArnaldo Carvalho de Melo 93932dcd021SJiri Olsa int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, 940cd0cccbaSArnaldo Carvalho de Melo struct hist_browser_timer *hbt, 941cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *opts) 942aca7a94dSNamhyung Kim { 943ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 944ed426915SNamhyung Kim SLang_reset_tty(); 945ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 946ed426915SNamhyung Kim 947cd0cccbaSArnaldo Carvalho de Melo return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts); 948aca7a94dSNamhyung Kim } 949aca7a94dSNamhyung Kim 95029754894SArnaldo Carvalho de Melo int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, 951cd0cccbaSArnaldo Carvalho de Melo struct hist_browser_timer *hbt, 952cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *opts) 953aca7a94dSNamhyung Kim { 95429754894SArnaldo Carvalho de Melo struct symbol *sym = ms->sym; 9559d6bb41dSArnaldo Carvalho de Melo struct annotation *notes = symbol__annotation(sym); 956aca7a94dSNamhyung Kim struct annotate_browser browser = { 957aca7a94dSNamhyung Kim .b = { 958a3f895beSArnaldo Carvalho de Melo .refresh = annotate_browser__refresh, 959aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 960aca7a94dSNamhyung Kim .write = annotate_browser__write, 96129ed6e76SArnaldo Carvalho de Melo .filter = disasm_line__filter, 9626920e285SArnaldo Carvalho de Melo .extra_title_lines = 1, /* for hists__scnprintf_title() */ 96329754894SArnaldo Carvalho de Melo .priv = ms, 964aca7a94dSNamhyung Kim .use_navkeypressed = true, 965aca7a94dSNamhyung Kim }, 966cd0cccbaSArnaldo Carvalho de Melo .opts = opts, 967aca7a94dSNamhyung Kim }; 968*63df0e4bSIan Rogers struct dso *dso; 969ee51d851SArnaldo Carvalho de Melo int ret = -1, err; 970d5962fb7SDario Petrillo int not_annotated = list_empty(¬es->src->source); 971aca7a94dSNamhyung Kim 972aca7a94dSNamhyung Kim if (sym == NULL) 973aca7a94dSNamhyung Kim return -1; 974aca7a94dSNamhyung Kim 975*63df0e4bSIan Rogers dso = map__dso(ms->map); 976*63df0e4bSIan Rogers if (dso->annotate_warned) 977aca7a94dSNamhyung Kim return -1; 978aca7a94dSNamhyung Kim 979d5962fb7SDario Petrillo if (not_annotated) { 98029754894SArnaldo Carvalho de Melo err = symbol__annotate2(ms, evsel, opts, &browser.arch); 981ee51d851SArnaldo Carvalho de Melo if (err) { 982ee51d851SArnaldo Carvalho de Melo char msg[BUFSIZ]; 983*63df0e4bSIan Rogers dso->annotate_warned = true; 98429754894SArnaldo Carvalho de Melo symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); 985ee51d851SArnaldo Carvalho de Melo ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 986b793a401SArnaldo Carvalho de Melo goto out_free_offsets; 987aca7a94dSNamhyung Kim } 988d5962fb7SDario Petrillo } 989aca7a94dSNamhyung Kim 9907727a925SArnaldo Carvalho de Melo ui_helpline__push("Press ESC to exit"); 991aca7a94dSNamhyung Kim 9925bc49f61SArnaldo Carvalho de Melo browser.b.width = notes->max_line_len; 9931cf5f98aSArnaldo Carvalho de Melo browser.b.nr_entries = notes->nr_entries; 994aca7a94dSNamhyung Kim browser.b.entries = ¬es->src->source, 995aca7a94dSNamhyung Kim browser.b.width += 18; /* Percentage */ 996e9823b21SArnaldo Carvalho de Melo 99716932d77SArnaldo Carvalho de Melo if (notes->options->hide_src_code) 9981cf5f98aSArnaldo Carvalho de Melo ui_browser__init_asm_mode(&browser.b); 999e9823b21SArnaldo Carvalho de Melo 1000db8fd07aSNamhyung Kim ret = annotate_browser__run(&browser, evsel, hbt); 1001f8eb37bdSJiri Olsa 1002d5962fb7SDario Petrillo if(not_annotated) 1003f8eb37bdSJiri Olsa annotated_source__purge(notes->src); 1004b793a401SArnaldo Carvalho de Melo 1005b793a401SArnaldo Carvalho de Melo out_free_offsets: 1006d5962fb7SDario Petrillo if(not_annotated) 10079d6bb41dSArnaldo Carvalho de Melo zfree(¬es->offsets); 1008aca7a94dSNamhyung Kim return ret; 1009aca7a94dSNamhyung Kim } 1010