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; 30aca7a94dSNamhyung Kim bool searching_backwards; 31aca7a94dSNamhyung Kim char search_bf[128]; 32aca7a94dSNamhyung Kim }; 33aca7a94dSNamhyung Kim 3495aa89d9SArnaldo Carvalho de Melo static inline struct annotation *browser__annotation(struct ui_browser *browser) 3595aa89d9SArnaldo Carvalho de Melo { 3695aa89d9SArnaldo Carvalho de Melo struct map_symbol *ms = browser->priv; 3795aa89d9SArnaldo Carvalho de Melo return symbol__annotation(ms->sym); 3895aa89d9SArnaldo Carvalho de Melo } 3995aa89d9SArnaldo Carvalho de Melo 402fa21d69SNamhyung Kim static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, void *entry) 41aca7a94dSNamhyung Kim { 42d5490b96SJiri Olsa struct annotation_line *al = list_entry(entry, struct annotation_line, node); 432fa21d69SNamhyung Kim return annotation_line__filter(al); 44aca7a94dSNamhyung Kim } 45aca7a94dSNamhyung Kim 4627feb761SArnaldo Carvalho de Melo static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current) 472402e4a9SArnaldo Carvalho de Melo { 4827feb761SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 49bc1c0f3dSArnaldo Carvalho de Melo 5027feb761SArnaldo Carvalho de Melo if (current && (!browser->use_navkeypressed || browser->navkeypressed)) 512402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_SELECTED; 52bc1c0f3dSArnaldo Carvalho de Melo if (nr == notes->max_jump_sources) 532402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_TOP; 542402e4a9SArnaldo Carvalho de Melo if (nr > 1) 552402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_MEDIUM; 562402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_NORMAL; 572402e4a9SArnaldo Carvalho de Melo } 582402e4a9SArnaldo Carvalho de Melo 59a1e9b74cSArnaldo Carvalho de Melo static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current) 602402e4a9SArnaldo Carvalho de Melo { 6127feb761SArnaldo Carvalho de Melo int color = ui_browser__jumps_percent_color(browser, nr, current); 6227feb761SArnaldo Carvalho de Melo return ui_browser__set_color(browser, color); 632402e4a9SArnaldo Carvalho de Melo } 642402e4a9SArnaldo Carvalho de Melo 65a1e9b74cSArnaldo Carvalho de Melo static int annotate_browser__set_color(void *browser, int color) 66aca7a94dSNamhyung Kim { 67a1e9b74cSArnaldo Carvalho de Melo return ui_browser__set_color(browser, color); 684ea08b52SArnaldo Carvalho de Melo } 694ea08b52SArnaldo Carvalho de Melo 70a1e9b74cSArnaldo Carvalho de Melo static void annotate_browser__write_graph(void *browser, int graph) 71a1e9b74cSArnaldo Carvalho de Melo { 72a1e9b74cSArnaldo Carvalho de Melo ui_browser__write_graph(browser, graph); 73a5433b3eSJiri Olsa } 74a5433b3eSJiri Olsa 752ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__set_percent_color(void *browser, double percent, bool current) 762ba5eca1SArnaldo Carvalho de Melo { 772ba5eca1SArnaldo Carvalho de Melo ui_browser__set_percent_color(browser, percent, current); 782ba5eca1SArnaldo Carvalho de Melo } 792ba5eca1SArnaldo Carvalho de Melo 802ba5eca1SArnaldo Carvalho de Melo static void annotate_browser__printf(void *browser, const char *fmt, ...) 812ba5eca1SArnaldo Carvalho de Melo { 822ba5eca1SArnaldo Carvalho de Melo va_list args; 832ba5eca1SArnaldo Carvalho de Melo 842ba5eca1SArnaldo Carvalho de Melo va_start(args, fmt); 852ba5eca1SArnaldo Carvalho de Melo ui_browser__vprintf(browser, fmt, args); 862ba5eca1SArnaldo Carvalho de Melo va_end(args); 872ba5eca1SArnaldo Carvalho de Melo } 882ba5eca1SArnaldo Carvalho de Melo 89a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 90a5433b3eSJiri Olsa { 91a5433b3eSJiri Olsa struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 9295aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 93a5433b3eSJiri Olsa struct annotation_line *al = list_entry(entry, struct annotation_line, node); 94da201963SArnaldo Carvalho de Melo const bool is_current_entry = ui_browser__is_current_entry(browser, row); 95c298304bSArnaldo Carvalho de Melo struct annotation_write_ops ops = { 96c298304bSArnaldo Carvalho de Melo .first_line = row == 0, 97da201963SArnaldo Carvalho de Melo .current_entry = is_current_entry, 9822197fb2SNamhyung Kim .change_color = (!annotate_opts.hide_src_code && 99da201963SArnaldo Carvalho de Melo (!is_current_entry || 100c298304bSArnaldo Carvalho de Melo (browser->use_navkeypressed && 101c298304bSArnaldo Carvalho de Melo !browser->navkeypressed))), 102c298304bSArnaldo Carvalho de Melo .width = browser->width, 103c298304bSArnaldo Carvalho de Melo .obj = browser, 104c298304bSArnaldo Carvalho de Melo .set_color = annotate_browser__set_color, 105c298304bSArnaldo Carvalho de Melo .set_percent_color = annotate_browser__set_percent_color, 106c298304bSArnaldo Carvalho de Melo .set_jumps_percent_color = ui_browser__set_jumps_percent_color, 107c298304bSArnaldo Carvalho de Melo .printf = annotate_browser__printf, 108c298304bSArnaldo Carvalho de Melo .write_graph = annotate_browser__write_graph, 109c298304bSArnaldo Carvalho de Melo }; 110a5433b3eSJiri Olsa 111a5433b3eSJiri Olsa /* The scroll bar isn't being used */ 112a5433b3eSJiri Olsa if (!browser->navkeypressed) 113c298304bSArnaldo Carvalho de Melo ops.width += 1; 114a5433b3eSJiri Olsa 11541fd3cacSNamhyung Kim annotation_line__write(al, notes, &ops); 116aca7a94dSNamhyung Kim 117c298304bSArnaldo Carvalho de Melo if (ops.current_entry) 118a5433b3eSJiri Olsa ab->selection = al; 119aca7a94dSNamhyung Kim } 120aca7a94dSNamhyung Kim 1217efbcc8cSRavi Bangoria static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor) 1227e63a13aSJin Yao { 123a17c4ca0SJiri Olsa struct disasm_line *pos = list_prev_entry(cursor, al.node); 1247e63a13aSJin Yao const char *name; 1257efbcc8cSRavi Bangoria int diff = 1; 1267efbcc8cSRavi Bangoria 1277efbcc8cSRavi Bangoria while (pos && pos->al.offset == -1) { 1287efbcc8cSRavi Bangoria pos = list_prev_entry(pos, al.node); 12922197fb2SNamhyung Kim if (!annotate_opts.hide_src_code) 1307efbcc8cSRavi Bangoria diff++; 1317efbcc8cSRavi Bangoria } 1327e63a13aSJin Yao 1337e63a13aSJin Yao if (!pos) 1347efbcc8cSRavi Bangoria return 0; 1357e63a13aSJin Yao 1367e63a13aSJin Yao if (ins__is_lock(&pos->ins)) 1377e63a13aSJin Yao name = pos->ops.locked.ins.name; 1387e63a13aSJin Yao else 1397e63a13aSJin Yao name = pos->ins.name; 1407e63a13aSJin Yao 1417e63a13aSJin Yao if (!name || !cursor->ins.name) 1427efbcc8cSRavi Bangoria return 0; 1437e63a13aSJin Yao 1447efbcc8cSRavi Bangoria if (ins__is_fused(ab->arch, name, cursor->ins.name)) 1457efbcc8cSRavi Bangoria return diff; 1467efbcc8cSRavi Bangoria return 0; 1477e63a13aSJin Yao } 1487e63a13aSJin Yao 1499d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser) 150a3f895beSArnaldo Carvalho de Melo { 151a3f895beSArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 1527bcbcd58SJiri Olsa struct disasm_line *cursor = disasm_line(ab->selection); 153a5ef2702SJiri Olsa struct annotation_line *target; 15483b1f2aaSArnaldo Carvalho de Melo unsigned int from, to; 15532ae1efdSNamhyung Kim struct map_symbol *ms = ab->b.priv; 15632ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 1570e83a7e9SArnaldo Carvalho de Melo struct annotation *notes = symbol__annotation(sym); 1586af612d2SArnaldo Carvalho de Melo u8 pcnt_width = annotation__pcnt_width(notes); 15900ea0eb2SArnaldo Carvalho de Melo int width; 1607efbcc8cSRavi Bangoria int diff = 0; 16132ae1efdSNamhyung Kim 16232ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 16332ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 16432ae1efdSNamhyung Kim return; 165a3f895beSArnaldo Carvalho de Melo 1662eff0611SArnaldo Carvalho de Melo if (!disasm_line__is_valid_local_jump(cursor, sym)) 167a3f895beSArnaldo Carvalho de Melo return; 168a3f895beSArnaldo Carvalho de Melo 1699c04409dSArnaldo Carvalho de Melo /* 1709c04409dSArnaldo Carvalho de Melo * This first was seen with a gcc function, _cpp_lex_token, that 1719c04409dSArnaldo Carvalho de Melo * has the usual jumps: 1729c04409dSArnaldo Carvalho de Melo * 1739c04409dSArnaldo Carvalho de Melo * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92> 1749c04409dSArnaldo Carvalho de Melo * 1759c04409dSArnaldo Carvalho de Melo * I.e. jumps to a label inside that function (_cpp_lex_token), and 1769c04409dSArnaldo Carvalho de Melo * those works, but also this kind: 1779c04409dSArnaldo Carvalho de Melo * 1789c04409dSArnaldo Carvalho de Melo * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72> 1799c04409dSArnaldo Carvalho de Melo * 1809c04409dSArnaldo Carvalho de Melo * I.e. jumps to another function, outside _cpp_lex_token, which 1819c04409dSArnaldo Carvalho de Melo * are not being correctly handled generating as a side effect references 1829c04409dSArnaldo Carvalho de Melo * to ab->offset[] entries that are set to NULL, so to make this code 1839c04409dSArnaldo Carvalho de Melo * more robust, check that here. 1849c04409dSArnaldo Carvalho de Melo * 1859c04409dSArnaldo Carvalho de Melo * A proper fix for will be put in place, looking at the function 1869c04409dSArnaldo Carvalho de Melo * name right after the '<' token and probably treating this like a 1879c04409dSArnaldo Carvalho de Melo * 'call' instruction. 1889c04409dSArnaldo Carvalho de Melo */ 189b753d48fSNamhyung Kim target = notes->src->offsets[cursor->ops.target.offset]; 1909c04409dSArnaldo Carvalho de Melo if (target == NULL) { 1919d6bb41dSArnaldo Carvalho de Melo ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n", 1929c04409dSArnaldo Carvalho de Melo cursor->ops.target.offset); 1939c04409dSArnaldo Carvalho de Melo return; 1949c04409dSArnaldo Carvalho de Melo } 1959d1ef56dSArnaldo Carvalho de Melo 19622197fb2SNamhyung Kim if (annotate_opts.hide_src_code) { 1974850c92eSArnaldo Carvalho de Melo from = cursor->al.idx_asm; 1984850c92eSArnaldo Carvalho de Melo to = target->idx_asm; 199a3f895beSArnaldo Carvalho de Melo } else { 2004850c92eSArnaldo Carvalho de Melo from = (u64)cursor->al.idx; 2014850c92eSArnaldo Carvalho de Melo to = (u64)target->idx; 202a3f895beSArnaldo Carvalho de Melo } 203a3f895beSArnaldo Carvalho de Melo 2040e83a7e9SArnaldo Carvalho de Melo width = annotation__cycles_width(notes); 205b40982e8SJin Yao 20678ce08dfSTaeung Song ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 207b40982e8SJin Yao __ui_browser__line_arrow(browser, 2089761e86eSArnaldo Carvalho de Melo pcnt_width + 2 + notes->widths.addr + width, 209c7e7b610SNamhyung Kim from, to); 2107e63a13aSJin Yao 2117efbcc8cSRavi Bangoria diff = is_fused(ab, cursor); 2127efbcc8cSRavi Bangoria if (diff > 0) { 2137e63a13aSJin Yao ui_browser__mark_fused(browser, 2149761e86eSArnaldo Carvalho de Melo pcnt_width + 3 + notes->widths.addr + width, 2157efbcc8cSRavi Bangoria from - diff, diff, to > from); 2167e63a13aSJin Yao } 217a3f895beSArnaldo Carvalho de Melo } 218a3f895beSArnaldo Carvalho de Melo 219a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser) 220a3f895beSArnaldo Carvalho de Melo { 22195aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 222a3f895beSArnaldo Carvalho de Melo int ret = ui_browser__list_head_refresh(browser); 2236af612d2SArnaldo Carvalho de Melo int pcnt_width = annotation__pcnt_width(notes); 224a3f895beSArnaldo Carvalho de Melo 22522197fb2SNamhyung Kim if (annotate_opts.jump_arrows) 2269d1ef56dSArnaldo Carvalho de Melo annotate_browser__draw_current_jump(browser); 227a3f895beSArnaldo Carvalho de Melo 22883b1f2aaSArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_NORMAL); 229e726c851SArnaldo Carvalho de Melo __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1); 230a3f895beSArnaldo Carvalho de Melo return ret; 231a3f895beSArnaldo Carvalho de Melo } 232a3f895beSArnaldo Carvalho de Melo 233da06d568SHe Kuang static double disasm__cmp(struct annotation_line *a, struct annotation_line *b, 234da06d568SHe Kuang int percent_type) 235c7e7b610SNamhyung Kim { 236c7e7b610SNamhyung Kim int i; 237c7e7b610SNamhyung Kim 238c2f938baSJiri Olsa for (i = 0; i < a->data_nr; i++) { 239da06d568SHe Kuang if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type]) 240c7e7b610SNamhyung Kim continue; 241da06d568SHe Kuang return a->data[i].percent[percent_type] - 242da06d568SHe Kuang b->data[i].percent[percent_type]; 243c7e7b610SNamhyung Kim } 244c7e7b610SNamhyung Kim return 0; 245c7e7b610SNamhyung Kim } 246c7e7b610SNamhyung Kim 247da06d568SHe Kuang static void disasm_rb_tree__insert(struct annotate_browser *browser, 248da06d568SHe Kuang struct annotation_line *al) 249aca7a94dSNamhyung Kim { 250da06d568SHe Kuang struct rb_root *root = &browser->entries; 25129ed6e76SArnaldo Carvalho de Melo struct rb_node **p = &root->rb_node; 252aca7a94dSNamhyung Kim struct rb_node *parent = NULL; 2533ab6db8dSJiri Olsa struct annotation_line *l; 254aca7a94dSNamhyung Kim 255aca7a94dSNamhyung Kim while (*p != NULL) { 256aca7a94dSNamhyung Kim parent = *p; 2573ab6db8dSJiri Olsa l = rb_entry(parent, struct annotation_line, rb_node); 258c7e7b610SNamhyung Kim 25922197fb2SNamhyung Kim if (disasm__cmp(al, l, annotate_opts.percent_type) < 0) 260aca7a94dSNamhyung Kim p = &(*p)->rb_left; 261aca7a94dSNamhyung Kim else 262aca7a94dSNamhyung Kim p = &(*p)->rb_right; 263aca7a94dSNamhyung Kim } 2643ab6db8dSJiri Olsa rb_link_node(&al->rb_node, parent, p); 2653ab6db8dSJiri Olsa rb_insert_color(&al->rb_node, root); 266aca7a94dSNamhyung Kim } 267aca7a94dSNamhyung Kim 26805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser, 269ec03a77dSJiri Olsa struct annotation_line *pos, u32 idx) 270aca7a94dSNamhyung Kim { 271aca7a94dSNamhyung Kim unsigned back; 272aca7a94dSNamhyung Kim 27305e8b080SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(&browser->b); 27405e8b080SArnaldo Carvalho de Melo back = browser->b.height / 2; 27505e8b080SArnaldo Carvalho de Melo browser->b.top_idx = browser->b.index = idx; 276aca7a94dSNamhyung Kim 27705e8b080SArnaldo Carvalho de Melo while (browser->b.top_idx != 0 && back != 0) { 278ec03a77dSJiri Olsa pos = list_entry(pos->node.prev, struct annotation_line, node); 279aca7a94dSNamhyung Kim 2802fa21d69SNamhyung Kim if (annotation_line__filter(pos)) 281aca7a94dSNamhyung Kim continue; 282aca7a94dSNamhyung Kim 28305e8b080SArnaldo Carvalho de Melo --browser->b.top_idx; 284aca7a94dSNamhyung Kim --back; 285aca7a94dSNamhyung Kim } 286aca7a94dSNamhyung Kim 287ec03a77dSJiri Olsa browser->b.top = pos; 28805e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = true; 289aca7a94dSNamhyung Kim } 290aca7a94dSNamhyung Kim 291aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser, 292aca7a94dSNamhyung Kim struct rb_node *nd) 293aca7a94dSNamhyung Kim { 2944850c92eSArnaldo Carvalho de Melo struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node); 2954850c92eSArnaldo Carvalho de Melo u32 idx = pos->idx; 296aca7a94dSNamhyung Kim 29722197fb2SNamhyung Kim if (annotate_opts.hide_src_code) 2984850c92eSArnaldo Carvalho de Melo idx = pos->idx_asm; 299a44b45f2SArnaldo Carvalho de Melo annotate_browser__set_top(browser, pos, idx); 300aca7a94dSNamhyung Kim browser->curr_hot = nd; 301aca7a94dSNamhyung Kim } 302aca7a94dSNamhyung Kim 303aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser, 30432dcd021SJiri Olsa struct evsel *evsel) 305aca7a94dSNamhyung Kim { 306aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 307aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 308aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 309c4c72436SJiri Olsa struct disasm_line *pos; 310aca7a94dSNamhyung Kim 311aca7a94dSNamhyung Kim browser->entries = RB_ROOT; 312aca7a94dSNamhyung Kim 3132e9f9d4aSIan Rogers annotation__lock(notes); 314aca7a94dSNamhyung Kim 315e425da6cSJiri Olsa symbol__calc_percent(sym, evsel); 316e425da6cSJiri Olsa 317a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 318c7e7b610SNamhyung Kim double max_percent = 0.0; 319c7e7b610SNamhyung Kim int i; 320e64aa75bSNamhyung Kim 321d5490b96SJiri Olsa if (pos->al.offset == -1) { 3225b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 323e64aa75bSNamhyung Kim continue; 324e64aa75bSNamhyung Kim } 325e64aa75bSNamhyung Kim 326c2f938baSJiri Olsa for (i = 0; i < pos->al.data_nr; i++) { 3276d9f0c2dSJiri Olsa double percent; 3280c4a5bceSMartin Liška 3296d9f0c2dSJiri Olsa percent = annotation_data__percent(&pos->al.data[i], 33022197fb2SNamhyung Kim annotate_opts.percent_type); 3316d9f0c2dSJiri Olsa 3326d9f0c2dSJiri Olsa if (max_percent < percent) 3336d9f0c2dSJiri Olsa max_percent = percent; 334c7e7b610SNamhyung Kim } 335c7e7b610SNamhyung Kim 336de2c7eb5SNamhyung Kim if (max_percent < 0.01 && (!pos->al.cycles || pos->al.cycles->ipc == 0)) { 3375b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 338aca7a94dSNamhyung Kim continue; 339aca7a94dSNamhyung Kim } 340da06d568SHe Kuang disasm_rb_tree__insert(browser, &pos->al); 341aca7a94dSNamhyung Kim } 3422e9f9d4aSIan Rogers annotation__unlock(notes); 343aca7a94dSNamhyung Kim 344aca7a94dSNamhyung Kim browser->curr_hot = rb_last(&browser->entries); 345aca7a94dSNamhyung Kim } 346aca7a94dSNamhyung Kim 3476de249d6SRiccardo Mancini static struct annotation_line *annotate_browser__find_next_asm_line( 3486de249d6SRiccardo Mancini struct annotate_browser *browser, 3496de249d6SRiccardo Mancini struct annotation_line *al) 3506de249d6SRiccardo Mancini { 3516de249d6SRiccardo Mancini struct annotation_line *it = al; 3526de249d6SRiccardo Mancini 3536de249d6SRiccardo Mancini /* find next asm line */ 3545a4451e4SRiccardo Mancini list_for_each_entry_continue(it, browser->b.entries, node) { 3556de249d6SRiccardo Mancini if (it->idx_asm >= 0) 3566de249d6SRiccardo Mancini return it; 3576de249d6SRiccardo Mancini } 3586de249d6SRiccardo Mancini 3596de249d6SRiccardo Mancini /* no asm line found forwards, try backwards */ 3606de249d6SRiccardo Mancini it = al; 3615a4451e4SRiccardo Mancini list_for_each_entry_continue_reverse(it, browser->b.entries, node) { 3626de249d6SRiccardo Mancini if (it->idx_asm >= 0) 3636de249d6SRiccardo Mancini return it; 3646de249d6SRiccardo Mancini } 3656de249d6SRiccardo Mancini 3666de249d6SRiccardo Mancini /* There are no asm lines */ 3676de249d6SRiccardo Mancini return NULL; 3686de249d6SRiccardo Mancini } 3696de249d6SRiccardo Mancini 370aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser) 371aca7a94dSNamhyung Kim { 37295aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 373ec03a77dSJiri Olsa struct annotation_line *al; 374aca7a94dSNamhyung Kim off_t offset = browser->b.index - browser->b.top_idx; 375aca7a94dSNamhyung Kim 376aca7a94dSNamhyung Kim browser->b.seek(&browser->b, offset, SEEK_CUR); 377ec03a77dSJiri Olsa al = list_entry(browser->b.top, struct annotation_line, node); 378aca7a94dSNamhyung Kim 37922197fb2SNamhyung Kim if (annotate_opts.hide_src_code) { 3804850c92eSArnaldo Carvalho de Melo if (al->idx_asm < offset) 3814850c92eSArnaldo Carvalho de Melo offset = al->idx; 382aca7a94dSNamhyung Kim 3830aae4c99SNamhyung Kim browser->b.nr_entries = notes->src->nr_entries; 38422197fb2SNamhyung Kim annotate_opts.hide_src_code = false; 385aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 3864850c92eSArnaldo Carvalho de Melo browser->b.top_idx = al->idx - offset; 3874850c92eSArnaldo Carvalho de Melo browser->b.index = al->idx; 388aca7a94dSNamhyung Kim } else { 3894850c92eSArnaldo Carvalho de Melo if (al->idx_asm < 0) { 3906de249d6SRiccardo Mancini /* move cursor to next asm line */ 3916de249d6SRiccardo Mancini al = annotate_browser__find_next_asm_line(browser, al); 3926de249d6SRiccardo Mancini if (!al) { 393aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 394aca7a94dSNamhyung Kim return false; 395aca7a94dSNamhyung Kim } 3966de249d6SRiccardo Mancini } 397aca7a94dSNamhyung Kim 3984850c92eSArnaldo Carvalho de Melo if (al->idx_asm < offset) 3994850c92eSArnaldo Carvalho de Melo offset = al->idx_asm; 400aca7a94dSNamhyung Kim 4010aae4c99SNamhyung Kim browser->b.nr_entries = notes->src->nr_asm_entries; 40222197fb2SNamhyung Kim annotate_opts.hide_src_code = true; 403aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 4044850c92eSArnaldo Carvalho de Melo browser->b.top_idx = al->idx_asm - offset; 4054850c92eSArnaldo Carvalho de Melo browser->b.index = al->idx_asm; 406aca7a94dSNamhyung Kim } 407aca7a94dSNamhyung Kim 408aca7a94dSNamhyung Kim return true; 409aca7a94dSNamhyung Kim } 410aca7a94dSNamhyung Kim 4112777b81bSMartin Liska #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 4122777b81bSMartin Liska 4132777b81bSMartin Liska static void annotate_browser__show_full_location(struct ui_browser *browser) 4142777b81bSMartin Liska { 4152777b81bSMartin Liska struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 4162777b81bSMartin Liska struct disasm_line *cursor = disasm_line(ab->selection); 4172777b81bSMartin Liska struct annotation_line *al = &cursor->al; 4182777b81bSMartin Liska 4192777b81bSMartin Liska if (al->offset != -1) 4202777b81bSMartin Liska ui_helpline__puts("Only available for source code lines."); 4212777b81bSMartin Liska else if (al->fileloc == NULL) 4222777b81bSMartin Liska ui_helpline__puts("No source file location."); 4232777b81bSMartin Liska else { 4242777b81bSMartin Liska char help_line[SYM_TITLE_MAX_SIZE]; 4252777b81bSMartin Liska sprintf (help_line, "Source file location: %s", al->fileloc); 4262777b81bSMartin Liska ui_helpline__puts(help_line); 4272777b81bSMartin Liska } 4282777b81bSMartin Liska } 4292777b81bSMartin Liska 4301cf5f98aSArnaldo Carvalho de Melo static void ui_browser__init_asm_mode(struct ui_browser *browser) 431e9823b21SArnaldo Carvalho de Melo { 4321cf5f98aSArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(browser); 4331cf5f98aSArnaldo Carvalho de Melo ui_browser__reset_index(browser); 4340aae4c99SNamhyung Kim browser->nr_entries = notes->src->nr_asm_entries; 435e9823b21SArnaldo Carvalho de Melo } 436e9823b21SArnaldo Carvalho de Melo 43734f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title, 4383e0d7953SJiri Olsa size_t sz, int percent_type) 43934f77abcSAdrian Hunter { 44063df0e4bSIan Rogers return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, 44163df0e4bSIan Rogers map__dso(map)->long_name, 4423e0d7953SJiri Olsa percent_type_str(percent_type)); 44334f77abcSAdrian Hunter } 44434f77abcSAdrian Hunter 445e4cc91b8SArnaldo Carvalho de Melo /* 4464d39c89fSIngo Molnar * This can be called from external jumps, i.e. jumps from one function 447e4cc91b8SArnaldo Carvalho de Melo * to another, like from the kernel's entry_SYSCALL_64 function to the 448e4cc91b8SArnaldo Carvalho de Melo * swapgs_restore_regs_and_return_to_usermode() function. 449e4cc91b8SArnaldo Carvalho de Melo * 450e4cc91b8SArnaldo Carvalho de Melo * So all we check here is that dl->ops.target.sym is set, if it is, just 451e4cc91b8SArnaldo Carvalho de Melo * go to that function and when exiting from its disassembly, come back 452e4cc91b8SArnaldo Carvalho de Melo * to the calling function. 453e4cc91b8SArnaldo Carvalho de Melo */ 454db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser, 45532dcd021SJiri Olsa struct evsel *evsel, 4569783adf7SNamhyung Kim struct hist_browser_timer *hbt) 457aca7a94dSNamhyung Kim { 45829754894SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv, target_ms; 4597bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 460aca7a94dSNamhyung Kim struct annotation *notes; 46134f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 462aca7a94dSNamhyung Kim 463696703afSArnaldo Carvalho de Melo if (!dl->ops.target.sym) { 464aca7a94dSNamhyung Kim ui_helpline__puts("The called function was not found."); 465aca7a94dSNamhyung Kim return true; 466aca7a94dSNamhyung Kim } 467aca7a94dSNamhyung Kim 468696703afSArnaldo Carvalho de Melo notes = symbol__annotation(dl->ops.target.sym); 4692e9f9d4aSIan Rogers annotation__lock(notes); 470aca7a94dSNamhyung Kim 4716484d2f9SJiri Olsa if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) { 4722e9f9d4aSIan Rogers annotation__unlock(notes); 473aca7a94dSNamhyung Kim ui__warning("Not enough memory for annotating '%s' symbol!\n", 474696703afSArnaldo Carvalho de Melo dl->ops.target.sym->name); 475aca7a94dSNamhyung Kim return true; 476aca7a94dSNamhyung Kim } 477aca7a94dSNamhyung Kim 478f2eaea09SArnaldo Carvalho de Melo target_ms.maps = ms->maps; 47929754894SArnaldo Carvalho de Melo target_ms.map = ms->map; 48029754894SArnaldo Carvalho de Melo target_ms.sym = dl->ops.target.sym; 4812e9f9d4aSIan Rogers annotation__unlock(notes); 48222197fb2SNamhyung Kim symbol__tui_annotate(&target_ms, evsel, hbt); 48322197fb2SNamhyung Kim sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_type); 48434f77abcSAdrian Hunter ui_browser__show_title(&browser->b, title); 485aca7a94dSNamhyung Kim return true; 486aca7a94dSNamhyung Kim } 487aca7a94dSNamhyung Kim 48829ed6e76SArnaldo Carvalho de Melo static 48929ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 490aca7a94dSNamhyung Kim s64 offset, s64 *idx) 491aca7a94dSNamhyung Kim { 49295aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 49329ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 494aca7a94dSNamhyung Kim 495aca7a94dSNamhyung Kim *idx = 0; 496a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 497d5490b96SJiri Olsa if (pos->al.offset == offset) 498aca7a94dSNamhyung Kim return pos; 4992fa21d69SNamhyung Kim if (!annotation_line__filter(&pos->al)) 500aca7a94dSNamhyung Kim ++*idx; 501aca7a94dSNamhyung Kim } 502aca7a94dSNamhyung Kim 503aca7a94dSNamhyung Kim return NULL; 504aca7a94dSNamhyung Kim } 505aca7a94dSNamhyung Kim 506e4cc91b8SArnaldo Carvalho de Melo static bool annotate_browser__jump(struct annotate_browser *browser, 50732dcd021SJiri Olsa struct evsel *evsel, 508e4cc91b8SArnaldo Carvalho de Melo struct hist_browser_timer *hbt) 509aca7a94dSNamhyung Kim { 5107bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 5115252b1aeSArnaldo Carvalho de Melo u64 offset; 5124f9d0325SArnaldo Carvalho de Melo s64 idx; 513aca7a94dSNamhyung Kim 51475b49202SArnaldo Carvalho de Melo if (!ins__is_jump(&dl->ins)) 515aca7a94dSNamhyung Kim return false; 516aca7a94dSNamhyung Kim 517e4cc91b8SArnaldo Carvalho de Melo if (dl->ops.target.outside) { 518e4cc91b8SArnaldo Carvalho de Melo annotate_browser__callq(browser, evsel, hbt); 519e4cc91b8SArnaldo Carvalho de Melo return true; 520e4cc91b8SArnaldo Carvalho de Melo } 521e4cc91b8SArnaldo Carvalho de Melo 5225252b1aeSArnaldo Carvalho de Melo offset = dl->ops.target.offset; 5235252b1aeSArnaldo Carvalho de Melo dl = annotate_browser__find_offset(browser, offset, &idx); 52429ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 5255252b1aeSArnaldo Carvalho de Melo ui_helpline__printf("Invalid jump offset: %" PRIx64, offset); 526aca7a94dSNamhyung Kim return true; 527aca7a94dSNamhyung Kim } 528aca7a94dSNamhyung Kim 529ec03a77dSJiri Olsa annotate_browser__set_top(browser, &dl->al, idx); 530aca7a94dSNamhyung Kim 531aca7a94dSNamhyung Kim return true; 532aca7a94dSNamhyung Kim } 533aca7a94dSNamhyung Kim 53429ed6e76SArnaldo Carvalho de Melo static 5359213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser, 536aca7a94dSNamhyung Kim char *s, s64 *idx) 537aca7a94dSNamhyung Kim { 53895aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 5399213afbdSJiri Olsa struct annotation_line *al = browser->selection; 540aca7a94dSNamhyung Kim 541aca7a94dSNamhyung Kim *idx = browser->b.index; 5429213afbdSJiri Olsa list_for_each_entry_continue(al, ¬es->src->source, node) { 5432fa21d69SNamhyung Kim if (annotation_line__filter(al)) 544aca7a94dSNamhyung Kim continue; 545aca7a94dSNamhyung Kim 546aca7a94dSNamhyung Kim ++*idx; 547aca7a94dSNamhyung Kim 5489213afbdSJiri Olsa if (al->line && strstr(al->line, s) != NULL) 5499213afbdSJiri Olsa return al; 550aca7a94dSNamhyung Kim } 551aca7a94dSNamhyung Kim 552aca7a94dSNamhyung Kim return NULL; 553aca7a94dSNamhyung Kim } 554aca7a94dSNamhyung Kim 555aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser) 556aca7a94dSNamhyung Kim { 5579213afbdSJiri Olsa struct annotation_line *al; 558aca7a94dSNamhyung Kim s64 idx; 559aca7a94dSNamhyung Kim 5609213afbdSJiri Olsa al = annotate_browser__find_string(browser, browser->search_bf, &idx); 5619213afbdSJiri Olsa if (al == NULL) { 562aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 563aca7a94dSNamhyung Kim return false; 564aca7a94dSNamhyung Kim } 565aca7a94dSNamhyung Kim 566ec03a77dSJiri Olsa annotate_browser__set_top(browser, al, idx); 567aca7a94dSNamhyung Kim browser->searching_backwards = false; 568aca7a94dSNamhyung Kim return true; 569aca7a94dSNamhyung Kim } 570aca7a94dSNamhyung Kim 57129ed6e76SArnaldo Carvalho de Melo static 5729213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 573aca7a94dSNamhyung Kim char *s, s64 *idx) 574aca7a94dSNamhyung Kim { 57595aa89d9SArnaldo Carvalho de Melo struct annotation *notes = browser__annotation(&browser->b); 5769213afbdSJiri Olsa struct annotation_line *al = browser->selection; 577aca7a94dSNamhyung Kim 578aca7a94dSNamhyung Kim *idx = browser->b.index; 5799213afbdSJiri Olsa list_for_each_entry_continue_reverse(al, ¬es->src->source, node) { 5802fa21d69SNamhyung Kim if (annotation_line__filter(al)) 581aca7a94dSNamhyung Kim continue; 582aca7a94dSNamhyung Kim 583aca7a94dSNamhyung Kim --*idx; 584aca7a94dSNamhyung Kim 5859213afbdSJiri Olsa if (al->line && strstr(al->line, s) != NULL) 5869213afbdSJiri Olsa return al; 587aca7a94dSNamhyung Kim } 588aca7a94dSNamhyung Kim 589aca7a94dSNamhyung Kim return NULL; 590aca7a94dSNamhyung Kim } 591aca7a94dSNamhyung Kim 592aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser) 593aca7a94dSNamhyung Kim { 5949213afbdSJiri Olsa struct annotation_line *al; 595aca7a94dSNamhyung Kim s64 idx; 596aca7a94dSNamhyung Kim 5979213afbdSJiri Olsa al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 5989213afbdSJiri Olsa if (al == NULL) { 599aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 600aca7a94dSNamhyung Kim return false; 601aca7a94dSNamhyung Kim } 602aca7a94dSNamhyung Kim 603ec03a77dSJiri Olsa annotate_browser__set_top(browser, al, idx); 604aca7a94dSNamhyung Kim browser->searching_backwards = true; 605aca7a94dSNamhyung Kim return true; 606aca7a94dSNamhyung Kim } 607aca7a94dSNamhyung Kim 608aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser, 609aca7a94dSNamhyung Kim int delay_secs) 610aca7a94dSNamhyung Kim { 611aca7a94dSNamhyung Kim if (ui_browser__input_window("Search", "String: ", browser->search_bf, 612aca7a94dSNamhyung Kim "ENTER: OK, ESC: Cancel", 613aca7a94dSNamhyung Kim delay_secs * 2) != K_ENTER || 614aca7a94dSNamhyung Kim !*browser->search_bf) 615aca7a94dSNamhyung Kim return false; 616aca7a94dSNamhyung Kim 617aca7a94dSNamhyung Kim return true; 618aca7a94dSNamhyung Kim } 619aca7a94dSNamhyung Kim 620aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) 621aca7a94dSNamhyung Kim { 622aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 623aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 624aca7a94dSNamhyung Kim 625aca7a94dSNamhyung Kim return false; 626aca7a94dSNamhyung Kim } 627aca7a94dSNamhyung Kim 628aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser, 629aca7a94dSNamhyung Kim int delay_secs) 630aca7a94dSNamhyung Kim { 631aca7a94dSNamhyung Kim if (!*browser->search_bf) 632aca7a94dSNamhyung Kim return annotate_browser__search(browser, delay_secs); 633aca7a94dSNamhyung Kim 634aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 635aca7a94dSNamhyung Kim } 636aca7a94dSNamhyung Kim 637aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser, 638aca7a94dSNamhyung Kim int delay_secs) 639aca7a94dSNamhyung Kim { 640aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 641aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 642aca7a94dSNamhyung Kim 643aca7a94dSNamhyung Kim return false; 644aca7a94dSNamhyung Kim } 645aca7a94dSNamhyung Kim 646aca7a94dSNamhyung Kim static 647aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, 648aca7a94dSNamhyung Kim int delay_secs) 649aca7a94dSNamhyung Kim { 650aca7a94dSNamhyung Kim if (!*browser->search_bf) 651aca7a94dSNamhyung Kim return annotate_browser__search_reverse(browser, delay_secs); 652aca7a94dSNamhyung Kim 653aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 654aca7a94dSNamhyung Kim } 655aca7a94dSNamhyung Kim 6566920e285SArnaldo Carvalho de Melo static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) 6576920e285SArnaldo Carvalho de Melo { 6586920e285SArnaldo Carvalho de Melo struct map_symbol *ms = browser->priv; 6596920e285SArnaldo Carvalho de Melo struct symbol *sym = ms->sym; 6606920e285SArnaldo Carvalho de Melo char symbol_dso[SYM_TITLE_MAX_SIZE]; 6616920e285SArnaldo Carvalho de Melo 6626920e285SArnaldo Carvalho de Melo if (ui_browser__show(browser, title, help) < 0) 6636920e285SArnaldo Carvalho de Melo return -1; 6646920e285SArnaldo Carvalho de Melo 66522197fb2SNamhyung Kim sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), annotate_opts.percent_type); 6666920e285SArnaldo Carvalho de Melo 6676920e285SArnaldo Carvalho de Melo ui_browser__gotorc_title(browser, 0, 0); 6686920e285SArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_ROOT); 6696920e285SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); 6706920e285SArnaldo Carvalho de Melo return 0; 6716920e285SArnaldo Carvalho de Melo } 6726920e285SArnaldo Carvalho de Melo 6733e0d7953SJiri Olsa static void 6743e0d7953SJiri Olsa switch_percent_type(struct annotation_options *opts, bool base) 6753e0d7953SJiri Olsa { 6763e0d7953SJiri Olsa switch (opts->percent_type) { 6773e0d7953SJiri Olsa case PERCENT_HITS_LOCAL: 6783e0d7953SJiri Olsa if (base) 6793e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_LOCAL; 6803e0d7953SJiri Olsa else 6813e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_GLOBAL; 6823e0d7953SJiri Olsa break; 6833e0d7953SJiri Olsa case PERCENT_HITS_GLOBAL: 6843e0d7953SJiri Olsa if (base) 6853e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_GLOBAL; 6863e0d7953SJiri Olsa else 6873e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_LOCAL; 6883e0d7953SJiri Olsa break; 6893e0d7953SJiri Olsa case PERCENT_PERIOD_LOCAL: 6903e0d7953SJiri Olsa if (base) 6913e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_LOCAL; 6923e0d7953SJiri Olsa else 6933e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_GLOBAL; 6943e0d7953SJiri Olsa break; 6953e0d7953SJiri Olsa case PERCENT_PERIOD_GLOBAL: 6963e0d7953SJiri Olsa if (base) 6973e0d7953SJiri Olsa opts->percent_type = PERCENT_HITS_GLOBAL; 6983e0d7953SJiri Olsa else 6993e0d7953SJiri Olsa opts->percent_type = PERCENT_PERIOD_LOCAL; 7003e0d7953SJiri Olsa break; 7013e0d7953SJiri Olsa default: 7023e0d7953SJiri Olsa WARN_ON(1); 7033e0d7953SJiri Olsa } 7043e0d7953SJiri Olsa } 7053e0d7953SJiri Olsa 706db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser, 70732dcd021SJiri Olsa struct evsel *evsel, 7089783adf7SNamhyung Kim struct hist_browser_timer *hbt) 709aca7a94dSNamhyung Kim { 710aca7a94dSNamhyung Kim struct rb_node *nd = NULL; 7116920e285SArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 71205e8b080SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv; 713aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 71416932d77SArnaldo Carvalho de Melo struct annotation *notes = symbol__annotation(ms->sym); 71554e7a4e8SArnaldo Carvalho de Melo const char *help = "Press 'h' for help on key bindings"; 7169783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 7176920e285SArnaldo Carvalho de Melo char title[256]; 718aca7a94dSNamhyung Kim int key; 719aca7a94dSNamhyung Kim 7200683d13cSJiri Olsa hists__scnprintf_title(hists, title, sizeof(title)); 7216920e285SArnaldo Carvalho de Melo if (annotate_browser__show(&browser->b, title, help) < 0) 722aca7a94dSNamhyung Kim return -1; 723aca7a94dSNamhyung Kim 724db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 725aca7a94dSNamhyung Kim 72605e8b080SArnaldo Carvalho de Melo if (browser->curr_hot) { 72705e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, browser->curr_hot); 72805e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = false; 729aca7a94dSNamhyung Kim } 730aca7a94dSNamhyung Kim 73105e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 732aca7a94dSNamhyung Kim 733aca7a94dSNamhyung Kim while (1) { 73405e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 735aca7a94dSNamhyung Kim 736aca7a94dSNamhyung Kim if (delay_secs != 0) { 737db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 738aca7a94dSNamhyung Kim /* 739aca7a94dSNamhyung Kim * Current line focus got out of the list of most active 740aca7a94dSNamhyung Kim * lines, NULL it so that if TAB|UNTAB is pressed, we 741aca7a94dSNamhyung Kim * move to curr_hot (current hottest line). 742aca7a94dSNamhyung Kim */ 743aca7a94dSNamhyung Kim if (nd != NULL && RB_EMPTY_NODE(nd)) 744aca7a94dSNamhyung Kim nd = NULL; 745aca7a94dSNamhyung Kim } 746aca7a94dSNamhyung Kim 747aca7a94dSNamhyung Kim switch (key) { 748aca7a94dSNamhyung Kim case K_TIMER: 7499783adf7SNamhyung Kim if (hbt) 7509783adf7SNamhyung Kim hbt->timer(hbt->arg); 751aca7a94dSNamhyung Kim 7526920e285SArnaldo Carvalho de Melo if (delay_secs != 0) { 75338fe0e01SJiri Olsa symbol__annotate_decay_histogram(sym, evsel->core.idx); 7546920e285SArnaldo Carvalho de Melo hists__scnprintf_title(hists, title, sizeof(title)); 7556920e285SArnaldo Carvalho de Melo annotate_browser__show(&browser->b, title, help); 7566920e285SArnaldo Carvalho de Melo } 757aca7a94dSNamhyung Kim continue; 758aca7a94dSNamhyung Kim case K_TAB: 759aca7a94dSNamhyung Kim if (nd != NULL) { 760aca7a94dSNamhyung Kim nd = rb_prev(nd); 761aca7a94dSNamhyung Kim if (nd == NULL) 76205e8b080SArnaldo Carvalho de Melo nd = rb_last(&browser->entries); 763aca7a94dSNamhyung Kim } else 76405e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 765aca7a94dSNamhyung Kim break; 766aca7a94dSNamhyung Kim case K_UNTAB: 767d4913cbdSMarkus Trippelsdorf if (nd != NULL) { 768aca7a94dSNamhyung Kim nd = rb_next(nd); 769aca7a94dSNamhyung Kim if (nd == NULL) 77005e8b080SArnaldo Carvalho de Melo nd = rb_first(&browser->entries); 771d4913cbdSMarkus Trippelsdorf } else 77205e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 773aca7a94dSNamhyung Kim break; 77454e7a4e8SArnaldo Carvalho de Melo case K_F1: 775aca7a94dSNamhyung Kim case 'h': 77605e8b080SArnaldo Carvalho de Melo ui_browser__help_window(&browser->b, 77754e7a4e8SArnaldo Carvalho de Melo "UP/DOWN/PGUP\n" 77854e7a4e8SArnaldo Carvalho de Melo "PGDN/SPACE Navigate\n" 7796d491b37SNamhyung Kim "</> Move to prev/next symbol\n" 78054e7a4e8SArnaldo Carvalho de Melo "q/ESC/CTRL+C Exit\n\n" 7817727a925SArnaldo Carvalho de Melo "ENTER Go to target\n" 782eba9fac0SArnaldo Carvalho de Melo "H Go to hottest instruction\n" 783eba9fac0SArnaldo Carvalho de Melo "TAB/shift+TAB Cycle thru hottest instructions\n" 78454e7a4e8SArnaldo Carvalho de Melo "j Toggle showing jump to target arrows\n" 78554e7a4e8SArnaldo Carvalho de Melo "J Toggle showing number of jump sources on targets\n" 78654e7a4e8SArnaldo Carvalho de Melo "n Search next string\n" 78754e7a4e8SArnaldo Carvalho de Melo "o Toggle disassembler output/simplified view\n" 78851f39603SArnaldo Carvalho de Melo "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n" 78954e7a4e8SArnaldo Carvalho de Melo "s Toggle source code view\n" 7903a555c77STaeung Song "t Circulate percent, total period, samples view\n" 7913e71fc03SJin Yao "c Show min/max cycle\n" 79254e7a4e8SArnaldo Carvalho de Melo "/ Search string\n" 793e592488cSAndi Kleen "k Toggle line numbers\n" 7942777b81bSMartin Liska "l Show full source file location\n" 795d9bd7665SArnaldo Carvalho de Melo "P Print to [symbol_name].annotation file.\n" 79679ee47faSFeng Tang "r Run available scripts\n" 7973e0d7953SJiri Olsa "p Toggle percent type [local/global]\n" 7983e0d7953SJiri Olsa "b Toggle percent base [period/hits]\n" 7997d18a824SNamhyung Kim "? Search string backwards\n" 8007d18a824SNamhyung Kim "f Toggle showing offsets to full address\n"); 80154e7a4e8SArnaldo Carvalho de Melo continue; 80279ee47faSFeng Tang case 'r': 8036f3da20eSAndi Kleen script_browse(NULL, NULL); 80454cf752cSRavi Bangoria annotate_browser__show(&browser->b, title, help); 80579ee47faSFeng Tang continue; 806e592488cSAndi Kleen case 'k': 80722197fb2SNamhyung Kim annotate_opts.show_linenr = !annotate_opts.show_linenr; 8084fd00847SMartin Liška continue; 8092777b81bSMartin Liska case 'l': 8102777b81bSMartin Liska annotate_browser__show_full_location (&browser->b); 8112777b81bSMartin Liska continue; 81254e7a4e8SArnaldo Carvalho de Melo case 'H': 81305e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 814aca7a94dSNamhyung Kim break; 815aca7a94dSNamhyung Kim case 's': 81605e8b080SArnaldo Carvalho de Melo if (annotate_browser__toggle_source(browser)) 817aca7a94dSNamhyung Kim ui_helpline__puts(help); 818aca7a94dSNamhyung Kim continue; 819aca7a94dSNamhyung Kim case 'o': 82022197fb2SNamhyung Kim annotate_opts.use_offset = !annotate_opts.use_offset; 8219761e86eSArnaldo Carvalho de Melo annotation__update_column_widths(notes); 822aca7a94dSNamhyung Kim continue; 82351f39603SArnaldo Carvalho de Melo case 'O': 82422197fb2SNamhyung Kim if (++annotate_opts.offset_level > ANNOTATION__MAX_OFFSET_LEVEL) 82522197fb2SNamhyung Kim annotate_opts.offset_level = ANNOTATION__MIN_OFFSET_LEVEL; 82651f39603SArnaldo Carvalho de Melo continue; 8279d1ef56dSArnaldo Carvalho de Melo case 'j': 82822197fb2SNamhyung Kim annotate_opts.jump_arrows = !annotate_opts.jump_arrows; 8299d1ef56dSArnaldo Carvalho de Melo continue; 8302402e4a9SArnaldo Carvalho de Melo case 'J': 83122197fb2SNamhyung Kim annotate_opts.show_nr_jumps = !annotate_opts.show_nr_jumps; 8329761e86eSArnaldo Carvalho de Melo annotation__update_column_widths(notes); 833e9823b21SArnaldo Carvalho de Melo continue; 834aca7a94dSNamhyung Kim case '/': 83505e8b080SArnaldo Carvalho de Melo if (annotate_browser__search(browser, delay_secs)) { 836aca7a94dSNamhyung Kim show_help: 837aca7a94dSNamhyung Kim ui_helpline__puts(help); 838aca7a94dSNamhyung Kim } 839aca7a94dSNamhyung Kim continue; 840aca7a94dSNamhyung Kim case 'n': 84105e8b080SArnaldo Carvalho de Melo if (browser->searching_backwards ? 84205e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search_reverse(browser, delay_secs) : 84305e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search(browser, delay_secs)) 844aca7a94dSNamhyung Kim goto show_help; 845aca7a94dSNamhyung Kim continue; 846aca7a94dSNamhyung Kim case '?': 84705e8b080SArnaldo Carvalho de Melo if (annotate_browser__search_reverse(browser, delay_secs)) 848aca7a94dSNamhyung Kim goto show_help; 849aca7a94dSNamhyung Kim continue; 850e9823b21SArnaldo Carvalho de Melo case 'D': { 851e9823b21SArnaldo Carvalho de Melo static int seq; 852e9823b21SArnaldo Carvalho de Melo ui_helpline__pop(); 853e9823b21SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d", 85405e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 85505e8b080SArnaldo Carvalho de Melo browser->b.height, 85605e8b080SArnaldo Carvalho de Melo browser->b.index, 85705e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 8580aae4c99SNamhyung Kim notes->src->nr_asm_entries); 859e9823b21SArnaldo Carvalho de Melo } 860e9823b21SArnaldo Carvalho de Melo continue; 861aca7a94dSNamhyung Kim case K_ENTER: 862aca7a94dSNamhyung Kim case K_RIGHT: 8637bcbcd58SJiri Olsa { 8647bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 8657bcbcd58SJiri Olsa 86605e8b080SArnaldo Carvalho de Melo if (browser->selection == NULL) 867aca7a94dSNamhyung Kim ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 8687bcbcd58SJiri Olsa else if (browser->selection->offset == -1) 869aca7a94dSNamhyung Kim ui_helpline__puts("Actions are only available for assembly lines."); 8707bcbcd58SJiri Olsa else if (!dl->ins.ops) 871c4cceae3SArnaldo Carvalho de Melo goto show_sup_ins; 8727bcbcd58SJiri Olsa else if (ins__is_ret(&dl->ins)) 873c4cceae3SArnaldo Carvalho de Melo goto out; 874e4cc91b8SArnaldo Carvalho de Melo else if (!(annotate_browser__jump(browser, evsel, hbt) || 875db8fd07aSNamhyung Kim annotate_browser__callq(browser, evsel, hbt))) { 876c4cceae3SArnaldo Carvalho de Melo show_sup_ins: 8776ef94929SNaveen N. Rao ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 878c4cceae3SArnaldo Carvalho de Melo } 879aca7a94dSNamhyung Kim continue; 8807bcbcd58SJiri Olsa } 881d9bd7665SArnaldo Carvalho de Melo case 'P': 88241fd3cacSNamhyung Kim map_symbol__annotation_dump(ms, evsel); 883d9bd7665SArnaldo Carvalho de Melo continue; 8840c4a5bceSMartin Liška case 't': 88568aac855SRavi Bangoria if (symbol_conf.show_total_period) { 88668aac855SRavi Bangoria symbol_conf.show_total_period = false; 88746ccb442SRavi Bangoria symbol_conf.show_nr_samples = true; 88846ccb442SRavi Bangoria } else if (symbol_conf.show_nr_samples) 88946ccb442SRavi Bangoria symbol_conf.show_nr_samples = false; 8903a555c77STaeung Song else 89168aac855SRavi Bangoria symbol_conf.show_total_period = true; 8929761e86eSArnaldo Carvalho de Melo annotation__update_column_widths(notes); 8930c4a5bceSMartin Liška continue; 8943e71fc03SJin Yao case 'c': 89522197fb2SNamhyung Kim if (annotate_opts.show_minmax_cycle) 89622197fb2SNamhyung Kim annotate_opts.show_minmax_cycle = false; 8973e71fc03SJin Yao else 89822197fb2SNamhyung Kim annotate_opts.show_minmax_cycle = true; 8993e71fc03SJin Yao annotation__update_column_widths(notes); 9003e71fc03SJin Yao continue; 9013e0d7953SJiri Olsa case 'p': 9023e0d7953SJiri Olsa case 'b': 90322197fb2SNamhyung Kim switch_percent_type(&annotate_opts, key == 'b'); 9043e0d7953SJiri Olsa hists__scnprintf_title(hists, title, sizeof(title)); 9053e0d7953SJiri Olsa annotate_browser__show(&browser->b, title, help); 9063e0d7953SJiri Olsa continue; 9077d18a824SNamhyung Kim case 'f': 9087d18a824SNamhyung Kim annotation__toggle_full_addr(notes, ms); 9097d18a824SNamhyung Kim continue; 910aca7a94dSNamhyung Kim case K_LEFT: 9116d491b37SNamhyung Kim case '<': 9126d491b37SNamhyung Kim case '>': 913aca7a94dSNamhyung Kim case K_ESC: 914aca7a94dSNamhyung Kim case 'q': 915aca7a94dSNamhyung Kim case CTRL('c'): 916aca7a94dSNamhyung Kim goto out; 917aca7a94dSNamhyung Kim default: 918aca7a94dSNamhyung Kim continue; 919aca7a94dSNamhyung Kim } 920aca7a94dSNamhyung Kim 921aca7a94dSNamhyung Kim if (nd != NULL) 92205e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, nd); 923aca7a94dSNamhyung Kim } 924aca7a94dSNamhyung Kim out: 92505e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 926aca7a94dSNamhyung Kim return key; 927aca7a94dSNamhyung Kim } 928aca7a94dSNamhyung Kim 92932dcd021SJiri Olsa int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, 93022197fb2SNamhyung Kim struct hist_browser_timer *hbt) 931d5dbc518SArnaldo Carvalho de Melo { 93222197fb2SNamhyung Kim return symbol__tui_annotate(ms, evsel, hbt); 933d5dbc518SArnaldo Carvalho de Melo } 934d5dbc518SArnaldo Carvalho de Melo 93532dcd021SJiri Olsa int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, 93622197fb2SNamhyung Kim struct hist_browser_timer *hbt) 937aca7a94dSNamhyung Kim { 938ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 939ed426915SNamhyung Kim SLang_reset_tty(); 940ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 9416af6d224SAhelenia Ziemiańska SLtty_set_suspend_state(true); 942ed426915SNamhyung Kim 94322197fb2SNamhyung Kim return map_symbol__tui_annotate(&he->ms, evsel, hbt); 944aca7a94dSNamhyung Kim } 945aca7a94dSNamhyung Kim 94629754894SArnaldo Carvalho de Melo int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, 94722197fb2SNamhyung Kim struct hist_browser_timer *hbt) 948aca7a94dSNamhyung Kim { 94929754894SArnaldo Carvalho de Melo struct symbol *sym = ms->sym; 9509d6bb41dSArnaldo Carvalho de Melo struct annotation *notes = symbol__annotation(sym); 951aca7a94dSNamhyung Kim struct annotate_browser browser = { 952aca7a94dSNamhyung Kim .b = { 953a3f895beSArnaldo Carvalho de Melo .refresh = annotate_browser__refresh, 954aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 955aca7a94dSNamhyung Kim .write = annotate_browser__write, 95629ed6e76SArnaldo Carvalho de Melo .filter = disasm_line__filter, 9576920e285SArnaldo Carvalho de Melo .extra_title_lines = 1, /* for hists__scnprintf_title() */ 95829754894SArnaldo Carvalho de Melo .priv = ms, 959aca7a94dSNamhyung Kim .use_navkeypressed = true, 960aca7a94dSNamhyung Kim }, 961aca7a94dSNamhyung Kim }; 96263df0e4bSIan Rogers struct dso *dso; 963ee51d851SArnaldo Carvalho de Melo int ret = -1, err; 964d5962fb7SDario Petrillo int not_annotated = list_empty(¬es->src->source); 965aca7a94dSNamhyung Kim 966aca7a94dSNamhyung Kim if (sym == NULL) 967aca7a94dSNamhyung Kim return -1; 968aca7a94dSNamhyung Kim 96963df0e4bSIan Rogers dso = map__dso(ms->map); 97063df0e4bSIan Rogers if (dso->annotate_warned) 971aca7a94dSNamhyung Kim return -1; 972aca7a94dSNamhyung Kim 973*2b8dbf69SNamhyung Kim if (not_annotated || !sym->annotate2) { 97441fd3cacSNamhyung Kim err = symbol__annotate2(ms, evsel, &browser.arch); 975ee51d851SArnaldo Carvalho de Melo if (err) { 976ee51d851SArnaldo Carvalho de Melo char msg[BUFSIZ]; 97763df0e4bSIan Rogers dso->annotate_warned = true; 97829754894SArnaldo Carvalho de Melo symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); 979ee51d851SArnaldo Carvalho de Melo ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 980b793a401SArnaldo Carvalho de Melo goto out_free_offsets; 981aca7a94dSNamhyung Kim } 982d5962fb7SDario Petrillo } 983aca7a94dSNamhyung Kim 9847727a925SArnaldo Carvalho de Melo ui_helpline__push("Press ESC to exit"); 985aca7a94dSNamhyung Kim 9860aae4c99SNamhyung Kim browser.b.width = notes->src->max_line_len; 9870aae4c99SNamhyung Kim browser.b.nr_entries = notes->src->nr_entries; 988aca7a94dSNamhyung Kim browser.b.entries = ¬es->src->source, 989aca7a94dSNamhyung Kim browser.b.width += 18; /* Percentage */ 990e9823b21SArnaldo Carvalho de Melo 99122197fb2SNamhyung Kim if (annotate_opts.hide_src_code) 9921cf5f98aSArnaldo Carvalho de Melo ui_browser__init_asm_mode(&browser.b); 993e9823b21SArnaldo Carvalho de Melo 994db8fd07aSNamhyung Kim ret = annotate_browser__run(&browser, evsel, hbt); 995f8eb37bdSJiri Olsa 996d5962fb7SDario Petrillo if(not_annotated) 997f8eb37bdSJiri Olsa annotated_source__purge(notes->src); 998b793a401SArnaldo Carvalho de Melo 999b793a401SArnaldo Carvalho de Melo out_free_offsets: 1000d5962fb7SDario Petrillo if(not_annotated) 1001b753d48fSNamhyung Kim zfree(¬es->src->offsets); 1002aca7a94dSNamhyung Kim return ret; 1003aca7a94dSNamhyung Kim } 1004