1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2aca7a94dSNamhyung Kim #include "../../util/util.h" 3aca7a94dSNamhyung Kim #include "../browser.h" 4aca7a94dSNamhyung Kim #include "../helpline.h" 5aca7a94dSNamhyung Kim #include "../ui.h" 6aca7a94dSNamhyung Kim #include "../util.h" 7aca7a94dSNamhyung Kim #include "../../util/annotate.h" 8aca7a94dSNamhyung Kim #include "../../util/hist.h" 9aca7a94dSNamhyung Kim #include "../../util/sort.h" 10aca7a94dSNamhyung Kim #include "../../util/symbol.h" 11db8fd07aSNamhyung Kim #include "../../util/evsel.h" 1241840d21STaeung Song #include "../../util/config.h" 1369fb09f6SJin Yao #include "../../util/evlist.h" 14fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 15aca7a94dSNamhyung Kim #include <pthread.h> 16877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 178e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h> 18b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h> 19aca7a94dSNamhyung Kim 200c4a5bceSMartin Liška struct disasm_line_samples { 210c4a5bceSMartin Liška double percent; 22bb79a232SArnaldo Carvalho de Melo struct sym_hist_entry he; 230c4a5bceSMartin Liška }; 240c4a5bceSMartin Liška 25f8f4aaeaSAndi Kleen #define IPC_WIDTH 6 26f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6 27f8f4aaeaSAndi Kleen 28b793a401SArnaldo Carvalho de Melo struct browser_disasm_line { 29b793a401SArnaldo Carvalho de Melo u32 idx; 30b793a401SArnaldo Carvalho de Melo int idx_asm; 317d5b12f5SArnaldo Carvalho de Melo int jump_sources; 32b793a401SArnaldo Carvalho de Melo }; 33b793a401SArnaldo Carvalho de Melo 34e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt { 35e9823b21SArnaldo Carvalho de Melo bool hide_src_code, 36e9823b21SArnaldo Carvalho de Melo use_offset, 37e9823b21SArnaldo Carvalho de Melo jump_arrows, 38e592488cSAndi Kleen show_linenr, 390c4a5bceSMartin Liška show_nr_jumps, 409cef4b0bSTaeung Song show_nr_samples, 410c4a5bceSMartin Liška show_total_period; 42e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = { 43e9823b21SArnaldo Carvalho de Melo .use_offset = true, 44e9823b21SArnaldo Carvalho de Melo .jump_arrows = true, 45e9823b21SArnaldo Carvalho de Melo }; 46e9823b21SArnaldo Carvalho de Melo 47dcaa3948SJin Yao struct arch; 48dcaa3948SJin Yao 49aca7a94dSNamhyung Kim struct annotate_browser { 50aca7a94dSNamhyung Kim struct ui_browser b; 51aca7a94dSNamhyung Kim struct rb_root entries; 52aca7a94dSNamhyung Kim struct rb_node *curr_hot; 5329ed6e76SArnaldo Carvalho de Melo struct disasm_line *selection; 54b793a401SArnaldo Carvalho de Melo struct disasm_line **offsets; 55dcaa3948SJin Yao struct arch *arch; 56c7e7b610SNamhyung Kim int nr_events; 57aca7a94dSNamhyung Kim u64 start; 58aca7a94dSNamhyung Kim int nr_asm_entries; 59aca7a94dSNamhyung Kim int nr_entries; 602402e4a9SArnaldo Carvalho de Melo int max_jump_sources; 612402e4a9SArnaldo Carvalho de Melo int nr_jumps; 62aca7a94dSNamhyung Kim bool searching_backwards; 6330e863bbSAndi Kleen bool have_cycles; 6483b1f2aaSArnaldo Carvalho de Melo u8 addr_width; 652402e4a9SArnaldo Carvalho de Melo u8 jumps_width; 662402e4a9SArnaldo Carvalho de Melo u8 target_width; 6783b1f2aaSArnaldo Carvalho de Melo u8 min_addr_width; 6883b1f2aaSArnaldo Carvalho de Melo u8 max_addr_width; 69aca7a94dSNamhyung Kim char search_bf[128]; 70aca7a94dSNamhyung Kim }; 71aca7a94dSNamhyung Kim 72887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl) 73aca7a94dSNamhyung Kim { 743ab6db8dSJiri Olsa return (void *) dl - sizeof(struct browser_disasm_line); 75aca7a94dSNamhyung Kim } 76aca7a94dSNamhyung Kim 771d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, 781d037ca1SIrina Tirdea void *entry) 79aca7a94dSNamhyung Kim { 80e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 81d5490b96SJiri Olsa struct annotation_line *al = list_entry(entry, struct annotation_line, node); 82d5490b96SJiri Olsa 83d5490b96SJiri Olsa return al->offset == -1; 84aca7a94dSNamhyung Kim } 85aca7a94dSNamhyung Kim 86aca7a94dSNamhyung Kim return false; 87aca7a94dSNamhyung Kim } 88aca7a94dSNamhyung Kim 892402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, 902402e4a9SArnaldo Carvalho de Melo int nr, bool current) 912402e4a9SArnaldo Carvalho de Melo { 922402e4a9SArnaldo Carvalho de Melo if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) 932402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_SELECTED; 942402e4a9SArnaldo Carvalho de Melo if (nr == browser->max_jump_sources) 952402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_TOP; 962402e4a9SArnaldo Carvalho de Melo if (nr > 1) 972402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_MEDIUM; 982402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_NORMAL; 992402e4a9SArnaldo Carvalho de Melo } 1002402e4a9SArnaldo Carvalho de Melo 1012402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, 1022402e4a9SArnaldo Carvalho de Melo int nr, bool current) 1032402e4a9SArnaldo Carvalho de Melo { 1042402e4a9SArnaldo Carvalho de Melo int color = annotate_browser__jumps_percent_color(browser, nr, current); 1052402e4a9SArnaldo Carvalho de Melo return ui_browser__set_color(&browser->b, color); 1062402e4a9SArnaldo Carvalho de Melo } 1072402e4a9SArnaldo Carvalho de Melo 108f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab) 109f8f4aaeaSAndi Kleen { 1103861c4a4SArnaldo Carvalho de Melo return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events; 111bc1e5d60SArnaldo Carvalho de Melo } 112f8f4aaeaSAndi Kleen 113bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab) 114bc1e5d60SArnaldo Carvalho de Melo { 115bc1e5d60SArnaldo Carvalho de Melo return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0; 116f8f4aaeaSAndi Kleen } 117f8f4aaeaSAndi Kleen 11805e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 119aca7a94dSNamhyung Kim { 12005e8b080SArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 121a17c4ca0SJiri Olsa struct disasm_line *dl = list_entry(entry, struct disasm_line, al.node); 122b793a401SArnaldo Carvalho de Melo struct browser_disasm_line *bdl = disasm_line__browser(dl); 12305e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(browser, row); 124e9823b21SArnaldo Carvalho de Melo bool change_color = (!annotate_browser__opts.hide_src_code && 12505e8b080SArnaldo Carvalho de Melo (!current_entry || (browser->use_navkeypressed && 12605e8b080SArnaldo Carvalho de Melo !browser->navkeypressed))); 12705e8b080SArnaldo Carvalho de Melo int width = browser->width, printed; 128bc1e5d60SArnaldo Carvalho de Melo int i, pcnt_width = annotate_browser__pcnt_width(ab), 129bc1e5d60SArnaldo Carvalho de Melo cycles_width = annotate_browser__cycles_width(ab); 130c7e7b610SNamhyung Kim double percent_max = 0.0; 13183b1f2aaSArnaldo Carvalho de Melo char bf[256]; 132ec27ae18SJin Yao bool show_title = false; 133aca7a94dSNamhyung Kim 134c7e7b610SNamhyung Kim for (i = 0; i < ab->nr_events; i++) { 1353ab6db8dSJiri Olsa if (dl->al.samples[i].percent > percent_max) 1363ab6db8dSJiri Olsa percent_max = dl->al.samples[i].percent; 137c7e7b610SNamhyung Kim } 138c7e7b610SNamhyung Kim 139d5490b96SJiri Olsa if ((row == 0) && (dl->al.offset == -1 || percent_max == 0.0)) { 140ec27ae18SJin Yao if (ab->have_cycles) { 14137236d5eSJiri Olsa if (dl->al.ipc == 0.0 && dl->al.cycles == 0) 142ec27ae18SJin Yao show_title = true; 143ec27ae18SJin Yao } else 144ec27ae18SJin Yao show_title = true; 145ec27ae18SJin Yao } 146ec27ae18SJin Yao 147d5490b96SJiri Olsa if (dl->al.offset != -1 && percent_max != 0.0) { 148c7e7b610SNamhyung Kim for (i = 0; i < ab->nr_events; i++) { 1490c4a5bceSMartin Liška ui_browser__set_percent_color(browser, 1503ab6db8dSJiri Olsa dl->al.samples[i].percent, 151c7e7b610SNamhyung Kim current_entry); 152517dfdb3SArnaldo Carvalho de Melo if (annotate_browser__opts.show_total_period) { 1533861c4a4SArnaldo Carvalho de Melo ui_browser__printf(browser, "%11" PRIu64 " ", 1543ab6db8dSJiri Olsa dl->al.samples[i].he.period); 1559cef4b0bSTaeung Song } else if (annotate_browser__opts.show_nr_samples) { 1569cef4b0bSTaeung Song ui_browser__printf(browser, "%6" PRIu64 " ", 1573ab6db8dSJiri Olsa dl->al.samples[i].he.nr_samples); 158517dfdb3SArnaldo Carvalho de Melo } else { 159517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%6.2f ", 1603ab6db8dSJiri Olsa dl->al.samples[i].percent); 161517dfdb3SArnaldo Carvalho de Melo } 162c7e7b610SNamhyung Kim } 163aca7a94dSNamhyung Kim } else { 16405e8b080SArnaldo Carvalho de Melo ui_browser__set_percent_color(browser, 0, current_entry); 165ec27ae18SJin Yao 166ec27ae18SJin Yao if (!show_title) 167bc1e5d60SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", pcnt_width); 1683861c4a4SArnaldo Carvalho de Melo else { 1693861c4a4SArnaldo Carvalho de Melo ui_browser__printf(browser, "%*s", pcnt_width, 1709cef4b0bSTaeung Song annotate_browser__opts.show_total_period ? "Period" : 1719cef4b0bSTaeung Song annotate_browser__opts.show_nr_samples ? "Samples" : "Percent"); 1723861c4a4SArnaldo Carvalho de Melo } 173f8f4aaeaSAndi Kleen } 174f8f4aaeaSAndi Kleen if (ab->have_cycles) { 17537236d5eSJiri Olsa if (dl->al.ipc) 17637236d5eSJiri Olsa ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->al.ipc); 177ec27ae18SJin Yao else if (!show_title) 17826270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", IPC_WIDTH); 179ec27ae18SJin Yao else 180ec27ae18SJin Yao ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC"); 181ec27ae18SJin Yao 18237236d5eSJiri Olsa if (dl->al.cycles) 183517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%*" PRIu64 " ", 18437236d5eSJiri Olsa CYCLES_WIDTH - 1, dl->al.cycles); 185ec27ae18SJin Yao else if (!show_title) 18626270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); 187ec27ae18SJin Yao else 188ec27ae18SJin Yao ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle"); 189aca7a94dSNamhyung Kim } 190aca7a94dSNamhyung Kim 191cf2dacc5SArnaldo Carvalho de Melo SLsmg_write_char(' '); 192aca7a94dSNamhyung Kim 193aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 19405e8b080SArnaldo Carvalho de Melo if (!browser->navkeypressed) 195aca7a94dSNamhyung Kim width += 1; 196aca7a94dSNamhyung Kim 197d5490b96SJiri Olsa if (!*dl->al.line) 198bc1e5d60SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); 199d5490b96SJiri Olsa else if (dl->al.offset == -1) { 200d5490b96SJiri Olsa if (dl->al.line_nr && annotate_browser__opts.show_linenr) 201e592488cSAndi Kleen printed = scnprintf(bf, sizeof(bf), "%-*d ", 202d5490b96SJiri Olsa ab->addr_width + 1, dl->al.line_nr); 203e592488cSAndi Kleen else 20483b1f2aaSArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*s ", 20583b1f2aaSArnaldo Carvalho de Melo ab->addr_width, " "); 20626270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, printed); 207d5490b96SJiri Olsa ui_browser__write_nstring(browser, dl->al.line, width - printed - pcnt_width - cycles_width + 1); 20883b1f2aaSArnaldo Carvalho de Melo } else { 209d5490b96SJiri Olsa u64 addr = dl->al.offset; 21083b1f2aaSArnaldo Carvalho de Melo int color = -1; 211aca7a94dSNamhyung Kim 212e9823b21SArnaldo Carvalho de Melo if (!annotate_browser__opts.use_offset) 213aca7a94dSNamhyung Kim addr += ab->start; 214aca7a94dSNamhyung Kim 215e9823b21SArnaldo Carvalho de Melo if (!annotate_browser__opts.use_offset) { 216aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); 21761e04b33SArnaldo Carvalho de Melo } else { 2187d5b12f5SArnaldo Carvalho de Melo if (bdl->jump_sources) { 219e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.show_nr_jumps) { 2202402e4a9SArnaldo Carvalho de Melo int prev; 2212402e4a9SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*d ", 2222402e4a9SArnaldo Carvalho de Melo ab->jumps_width, 2232402e4a9SArnaldo Carvalho de Melo bdl->jump_sources); 2242402e4a9SArnaldo Carvalho de Melo prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources, 2252402e4a9SArnaldo Carvalho de Melo current_entry); 22626270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, printed); 22705e8b080SArnaldo Carvalho de Melo ui_browser__set_color(browser, prev); 2282402e4a9SArnaldo Carvalho de Melo } 2292402e4a9SArnaldo Carvalho de Melo 23061e04b33SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", 2312402e4a9SArnaldo Carvalho de Melo ab->target_width, addr); 23261e04b33SArnaldo Carvalho de Melo } else { 23361e04b33SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*s ", 23483b1f2aaSArnaldo Carvalho de Melo ab->addr_width, " "); 23561e04b33SArnaldo Carvalho de Melo } 23661e04b33SArnaldo Carvalho de Melo } 237b793a401SArnaldo Carvalho de Melo 238aca7a94dSNamhyung Kim if (change_color) 23905e8b080SArnaldo Carvalho de Melo color = ui_browser__set_color(browser, HE_COLORSET_ADDR); 24026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, printed); 241aca7a94dSNamhyung Kim if (change_color) 24205e8b080SArnaldo Carvalho de Melo ui_browser__set_color(browser, color); 24375b49202SArnaldo Carvalho de Melo if (dl->ins.ops && dl->ins.ops->scnprintf) { 24475b49202SArnaldo Carvalho de Melo if (ins__is_jump(&dl->ins)) { 245d5490b96SJiri Olsa bool fwd = dl->ops.target.offset > dl->al.offset; 24651a0d455SArnaldo Carvalho de Melo 24705e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : 24851a0d455SArnaldo Carvalho de Melo SLSMG_UARROW_CHAR); 24951a0d455SArnaldo Carvalho de Melo SLsmg_write_char(' '); 25075b49202SArnaldo Carvalho de Melo } else if (ins__is_call(&dl->ins)) { 25105e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); 25288298f5aSArnaldo Carvalho de Melo SLsmg_write_char(' '); 25375b49202SArnaldo Carvalho de Melo } else if (ins__is_ret(&dl->ins)) { 25405e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); 2554ea08b52SArnaldo Carvalho de Melo SLsmg_write_char(' '); 2566ef94929SNaveen N. Rao } else { 2576ef94929SNaveen N. Rao ui_browser__write_nstring(browser, " ", 2); 2584ea08b52SArnaldo Carvalho de Melo } 2596ef94929SNaveen N. Rao } else { 2606ef94929SNaveen N. Rao ui_browser__write_nstring(browser, " ", 2); 2614ea08b52SArnaldo Carvalho de Melo } 2624ea08b52SArnaldo Carvalho de Melo 263e9823b21SArnaldo Carvalho de Melo disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 264bc1e5d60SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed); 265aca7a94dSNamhyung Kim } 266aca7a94dSNamhyung Kim 267aca7a94dSNamhyung Kim if (current_entry) 26829ed6e76SArnaldo Carvalho de Melo ab->selection = dl; 269aca7a94dSNamhyung Kim } 270aca7a94dSNamhyung Kim 271865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) 272865c66c4SFrederik Deweerdt { 27375b49202SArnaldo Carvalho de Melo if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) 274865c66c4SFrederik Deweerdt || !disasm_line__has_offset(dl) 275e216874cSRavi Bangoria || dl->ops.target.offset < 0 276e216874cSRavi Bangoria || dl->ops.target.offset >= (s64)symbol__size(sym)) 277865c66c4SFrederik Deweerdt return false; 278865c66c4SFrederik Deweerdt 279865c66c4SFrederik Deweerdt return true; 280865c66c4SFrederik Deweerdt } 281865c66c4SFrederik Deweerdt 2827e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor) 2837e63a13aSJin Yao { 284a17c4ca0SJiri Olsa struct disasm_line *pos = list_prev_entry(cursor, al.node); 2857e63a13aSJin Yao const char *name; 2867e63a13aSJin Yao 2877e63a13aSJin Yao if (!pos) 2887e63a13aSJin Yao return false; 2897e63a13aSJin Yao 2907e63a13aSJin Yao if (ins__is_lock(&pos->ins)) 2917e63a13aSJin Yao name = pos->ops.locked.ins.name; 2927e63a13aSJin Yao else 2937e63a13aSJin Yao name = pos->ins.name; 2947e63a13aSJin Yao 2957e63a13aSJin Yao if (!name || !cursor->ins.name) 2967e63a13aSJin Yao return false; 2977e63a13aSJin Yao 2987e63a13aSJin Yao return ins__is_fused(ab->arch, name, cursor->ins.name); 2997e63a13aSJin Yao } 3007e63a13aSJin Yao 3019d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser) 302a3f895beSArnaldo Carvalho de Melo { 303a3f895beSArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 3049d1ef56dSArnaldo Carvalho de Melo struct disasm_line *cursor = ab->selection, *target; 3059d1ef56dSArnaldo Carvalho de Melo struct browser_disasm_line *btarget, *bcursor; 30683b1f2aaSArnaldo Carvalho de Melo unsigned int from, to; 30732ae1efdSNamhyung Kim struct map_symbol *ms = ab->b.priv; 30832ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 309f8f4aaeaSAndi Kleen u8 pcnt_width = annotate_browser__pcnt_width(ab); 31032ae1efdSNamhyung Kim 31132ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 31232ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 31332ae1efdSNamhyung Kim return; 314a3f895beSArnaldo Carvalho de Melo 315865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(cursor, sym)) 316a3f895beSArnaldo Carvalho de Melo return; 317a3f895beSArnaldo Carvalho de Melo 3189d1ef56dSArnaldo Carvalho de Melo target = ab->offsets[cursor->ops.target.offset]; 3199d1ef56dSArnaldo Carvalho de Melo if (!target) 3209d1ef56dSArnaldo Carvalho de Melo return; 3219d1ef56dSArnaldo Carvalho de Melo 3229d1ef56dSArnaldo Carvalho de Melo bcursor = disasm_line__browser(cursor); 3239d1ef56dSArnaldo Carvalho de Melo btarget = disasm_line__browser(target); 3249d1ef56dSArnaldo Carvalho de Melo 325e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 3269d1ef56dSArnaldo Carvalho de Melo from = bcursor->idx_asm; 327a3f895beSArnaldo Carvalho de Melo to = btarget->idx_asm; 328a3f895beSArnaldo Carvalho de Melo } else { 3299d1ef56dSArnaldo Carvalho de Melo from = (u64)bcursor->idx; 330a3f895beSArnaldo Carvalho de Melo to = (u64)btarget->idx; 331a3f895beSArnaldo Carvalho de Melo } 332a3f895beSArnaldo Carvalho de Melo 33378ce08dfSTaeung Song ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 334c7e7b610SNamhyung Kim __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 335c7e7b610SNamhyung Kim from, to); 3367e63a13aSJin Yao 3377e63a13aSJin Yao if (is_fused(ab, cursor)) { 3387e63a13aSJin Yao ui_browser__mark_fused(browser, 3397e63a13aSJin Yao pcnt_width + 3 + ab->addr_width, 3407e63a13aSJin Yao from - 1, 3417e63a13aSJin Yao to > from ? true : false); 3427e63a13aSJin Yao } 343a3f895beSArnaldo Carvalho de Melo } 344a3f895beSArnaldo Carvalho de Melo 345a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser) 346a3f895beSArnaldo Carvalho de Melo { 347c7e7b610SNamhyung Kim struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 348a3f895beSArnaldo Carvalho de Melo int ret = ui_browser__list_head_refresh(browser); 349f8f4aaeaSAndi Kleen int pcnt_width = annotate_browser__pcnt_width(ab); 350a3f895beSArnaldo Carvalho de Melo 351e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.jump_arrows) 3529d1ef56dSArnaldo Carvalho de Melo annotate_browser__draw_current_jump(browser); 353a3f895beSArnaldo Carvalho de Melo 35483b1f2aaSArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_NORMAL); 355c7e7b610SNamhyung Kim __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); 356a3f895beSArnaldo Carvalho de Melo return ret; 357a3f895beSArnaldo Carvalho de Melo } 358a3f895beSArnaldo Carvalho de Melo 359*b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b) 360c7e7b610SNamhyung Kim { 361c7e7b610SNamhyung Kim int i; 362c7e7b610SNamhyung Kim 363*b15636c6SJiri Olsa for (i = 0; i < a->samples_nr; i++) { 3640c4a5bceSMartin Liška if (a->samples[i].percent == b->samples[i].percent) 365c7e7b610SNamhyung Kim continue; 3660c4a5bceSMartin Liška return a->samples[i].percent < b->samples[i].percent; 367c7e7b610SNamhyung Kim } 368c7e7b610SNamhyung Kim return 0; 369c7e7b610SNamhyung Kim } 370c7e7b610SNamhyung Kim 371*b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al) 372aca7a94dSNamhyung Kim { 37329ed6e76SArnaldo Carvalho de Melo struct rb_node **p = &root->rb_node; 374aca7a94dSNamhyung Kim struct rb_node *parent = NULL; 3753ab6db8dSJiri Olsa struct annotation_line *l; 376aca7a94dSNamhyung Kim 377aca7a94dSNamhyung Kim while (*p != NULL) { 378aca7a94dSNamhyung Kim parent = *p; 3793ab6db8dSJiri Olsa l = rb_entry(parent, struct annotation_line, rb_node); 380c7e7b610SNamhyung Kim 381*b15636c6SJiri Olsa if (disasm__cmp(al, l)) 382aca7a94dSNamhyung Kim p = &(*p)->rb_left; 383aca7a94dSNamhyung Kim else 384aca7a94dSNamhyung Kim p = &(*p)->rb_right; 385aca7a94dSNamhyung Kim } 3863ab6db8dSJiri Olsa rb_link_node(&al->rb_node, parent, p); 3873ab6db8dSJiri Olsa rb_insert_color(&al->rb_node, root); 388aca7a94dSNamhyung Kim } 389aca7a94dSNamhyung Kim 39005e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser, 39129ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos, u32 idx) 392aca7a94dSNamhyung Kim { 393aca7a94dSNamhyung Kim unsigned back; 394aca7a94dSNamhyung Kim 39505e8b080SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(&browser->b); 39605e8b080SArnaldo Carvalho de Melo back = browser->b.height / 2; 39705e8b080SArnaldo Carvalho de Melo browser->b.top_idx = browser->b.index = idx; 398aca7a94dSNamhyung Kim 39905e8b080SArnaldo Carvalho de Melo while (browser->b.top_idx != 0 && back != 0) { 400a17c4ca0SJiri Olsa pos = list_entry(pos->al.node.prev, struct disasm_line, al.node); 401aca7a94dSNamhyung Kim 402a17c4ca0SJiri Olsa if (disasm_line__filter(&browser->b, &pos->al.node)) 403aca7a94dSNamhyung Kim continue; 404aca7a94dSNamhyung Kim 40505e8b080SArnaldo Carvalho de Melo --browser->b.top_idx; 406aca7a94dSNamhyung Kim --back; 407aca7a94dSNamhyung Kim } 408aca7a94dSNamhyung Kim 409a17c4ca0SJiri Olsa browser->b.top = &pos->al; 41005e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = true; 411aca7a94dSNamhyung Kim } 412aca7a94dSNamhyung Kim 413aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser, 414aca7a94dSNamhyung Kim struct rb_node *nd) 415aca7a94dSNamhyung Kim { 416887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos; 41729ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 418a44b45f2SArnaldo Carvalho de Melo u32 idx; 419aca7a94dSNamhyung Kim 4205b12adc8SJiri Olsa pos = rb_entry(nd, struct disasm_line, al.rb_node); 4215b12adc8SJiri Olsa bpos = disasm_line__browser(pos); 4225b12adc8SJiri Olsa 423a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx; 424e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 425a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx_asm; 426a44b45f2SArnaldo Carvalho de Melo annotate_browser__set_top(browser, pos, idx); 427aca7a94dSNamhyung Kim browser->curr_hot = nd; 428aca7a94dSNamhyung Kim } 429aca7a94dSNamhyung Kim 430aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser, 431db8fd07aSNamhyung Kim struct perf_evsel *evsel) 432aca7a94dSNamhyung Kim { 433aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 434aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 435aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 436c4c72436SJiri Olsa struct disasm_line *pos; 437aca7a94dSNamhyung Kim 438aca7a94dSNamhyung Kim browser->entries = RB_ROOT; 439aca7a94dSNamhyung Kim 440aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 441aca7a94dSNamhyung Kim 442e425da6cSJiri Olsa symbol__calc_percent(sym, evsel); 443e425da6cSJiri Olsa 444a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 445c7e7b610SNamhyung Kim double max_percent = 0.0; 446c7e7b610SNamhyung Kim int i; 447e64aa75bSNamhyung Kim 448d5490b96SJiri Olsa if (pos->al.offset == -1) { 4495b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 450e64aa75bSNamhyung Kim continue; 451e64aa75bSNamhyung Kim } 452e64aa75bSNamhyung Kim 453*b15636c6SJiri Olsa for (i = 0; i < pos->al.samples_nr; i++) { 454e425da6cSJiri Olsa struct annotation_data *sample = &pos->al.samples[i]; 4550c4a5bceSMartin Liška 4563ab6db8dSJiri Olsa if (max_percent < sample->percent) 4573ab6db8dSJiri Olsa max_percent = sample->percent; 458c7e7b610SNamhyung Kim } 459c7e7b610SNamhyung Kim 46037236d5eSJiri Olsa if (max_percent < 0.01 && pos->al.ipc == 0) { 4615b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 462aca7a94dSNamhyung Kim continue; 463aca7a94dSNamhyung Kim } 464*b15636c6SJiri Olsa disasm_rb_tree__insert(&browser->entries, &pos->al); 465aca7a94dSNamhyung Kim } 466aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 467aca7a94dSNamhyung Kim 468aca7a94dSNamhyung Kim browser->curr_hot = rb_last(&browser->entries); 469aca7a94dSNamhyung Kim } 470aca7a94dSNamhyung Kim 471aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser) 472aca7a94dSNamhyung Kim { 47329ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 474887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bdl; 475aca7a94dSNamhyung Kim off_t offset = browser->b.index - browser->b.top_idx; 476aca7a94dSNamhyung Kim 477aca7a94dSNamhyung Kim browser->b.seek(&browser->b, offset, SEEK_CUR); 478a17c4ca0SJiri Olsa dl = list_entry(browser->b.top, struct disasm_line, al.node); 479887c0066SArnaldo Carvalho de Melo bdl = disasm_line__browser(dl); 480aca7a94dSNamhyung Kim 481e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 482887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < offset) 483887c0066SArnaldo Carvalho de Melo offset = bdl->idx; 484aca7a94dSNamhyung Kim 485aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_entries; 486e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = false; 487aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 488887c0066SArnaldo Carvalho de Melo browser->b.top_idx = bdl->idx - offset; 489887c0066SArnaldo Carvalho de Melo browser->b.index = bdl->idx; 490aca7a94dSNamhyung Kim } else { 491887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < 0) { 492aca7a94dSNamhyung Kim ui_helpline__puts("Only available for assembly lines."); 493aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 494aca7a94dSNamhyung Kim return false; 495aca7a94dSNamhyung Kim } 496aca7a94dSNamhyung Kim 497887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < offset) 498887c0066SArnaldo Carvalho de Melo offset = bdl->idx_asm; 499aca7a94dSNamhyung Kim 500aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_asm_entries; 501e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = true; 502aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 503887c0066SArnaldo Carvalho de Melo browser->b.top_idx = bdl->idx_asm - offset; 504887c0066SArnaldo Carvalho de Melo browser->b.index = bdl->idx_asm; 505aca7a94dSNamhyung Kim } 506aca7a94dSNamhyung Kim 507aca7a94dSNamhyung Kim return true; 508aca7a94dSNamhyung Kim } 509aca7a94dSNamhyung Kim 510e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser) 511e9823b21SArnaldo Carvalho de Melo { 512e9823b21SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 513e9823b21SArnaldo Carvalho de Melo browser->b.nr_entries = browser->nr_asm_entries; 514e9823b21SArnaldo Carvalho de Melo } 515e9823b21SArnaldo Carvalho de Melo 51634f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 51734f77abcSAdrian Hunter 51834f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title, 51934f77abcSAdrian Hunter size_t sz) 52034f77abcSAdrian Hunter { 52134f77abcSAdrian Hunter return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); 52234f77abcSAdrian Hunter } 52334f77abcSAdrian Hunter 524db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser, 525db8fd07aSNamhyung Kim struct perf_evsel *evsel, 5269783adf7SNamhyung Kim struct hist_browser_timer *hbt) 527aca7a94dSNamhyung Kim { 528aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 529657bcaf5SArnaldo Carvalho de Melo struct disasm_line *dl = browser->selection; 530aca7a94dSNamhyung Kim struct annotation *notes; 5311179e11bSAdrian Hunter struct addr_map_symbol target = { 5321179e11bSAdrian Hunter .map = ms->map, 5331d5077bdSAdrian Hunter .addr = map__objdump_2mem(ms->map, dl->ops.target.addr), 5341179e11bSAdrian Hunter }; 53534f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 536aca7a94dSNamhyung Kim 53775b49202SArnaldo Carvalho de Melo if (!ins__is_call(&dl->ins)) 538aca7a94dSNamhyung Kim return false; 539aca7a94dSNamhyung Kim 540be39db9fSArnaldo Carvalho de Melo if (map_groups__find_ams(&target) || 5411d5077bdSAdrian Hunter map__rip_2objdump(target.map, target.map->map_ip(target.map, 5421d5077bdSAdrian Hunter target.addr)) != 5431d5077bdSAdrian Hunter dl->ops.target.addr) { 544aca7a94dSNamhyung Kim ui_helpline__puts("The called function was not found."); 545aca7a94dSNamhyung Kim return true; 546aca7a94dSNamhyung Kim } 547aca7a94dSNamhyung Kim 5481179e11bSAdrian Hunter notes = symbol__annotation(target.sym); 549aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 550aca7a94dSNamhyung Kim 5511179e11bSAdrian Hunter if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) { 552aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 553aca7a94dSNamhyung Kim ui__warning("Not enough memory for annotating '%s' symbol!\n", 5541179e11bSAdrian Hunter target.sym->name); 555aca7a94dSNamhyung Kim return true; 556aca7a94dSNamhyung Kim } 557aca7a94dSNamhyung Kim 558aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 5591179e11bSAdrian Hunter symbol__tui_annotate(target.sym, target.map, evsel, hbt); 5601179e11bSAdrian Hunter sym_title(ms->sym, ms->map, title, sizeof(title)); 56134f77abcSAdrian Hunter ui_browser__show_title(&browser->b, title); 562aca7a94dSNamhyung Kim return true; 563aca7a94dSNamhyung Kim } 564aca7a94dSNamhyung Kim 56529ed6e76SArnaldo Carvalho de Melo static 56629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 567aca7a94dSNamhyung Kim s64 offset, s64 *idx) 568aca7a94dSNamhyung Kim { 569aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 570aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 571aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 57229ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 573aca7a94dSNamhyung Kim 574aca7a94dSNamhyung Kim *idx = 0; 575a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 576d5490b96SJiri Olsa if (pos->al.offset == offset) 577aca7a94dSNamhyung Kim return pos; 578a17c4ca0SJiri Olsa if (!disasm_line__filter(&browser->b, &pos->al.node)) 579aca7a94dSNamhyung Kim ++*idx; 580aca7a94dSNamhyung Kim } 581aca7a94dSNamhyung Kim 582aca7a94dSNamhyung Kim return NULL; 583aca7a94dSNamhyung Kim } 584aca7a94dSNamhyung Kim 585aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser) 586aca7a94dSNamhyung Kim { 587657bcaf5SArnaldo Carvalho de Melo struct disasm_line *dl = browser->selection; 5885252b1aeSArnaldo Carvalho de Melo u64 offset; 5894f9d0325SArnaldo Carvalho de Melo s64 idx; 590aca7a94dSNamhyung Kim 59175b49202SArnaldo Carvalho de Melo if (!ins__is_jump(&dl->ins)) 592aca7a94dSNamhyung Kim return false; 593aca7a94dSNamhyung Kim 5945252b1aeSArnaldo Carvalho de Melo offset = dl->ops.target.offset; 5955252b1aeSArnaldo Carvalho de Melo dl = annotate_browser__find_offset(browser, offset, &idx); 59629ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 5975252b1aeSArnaldo Carvalho de Melo ui_helpline__printf("Invalid jump offset: %" PRIx64, offset); 598aca7a94dSNamhyung Kim return true; 599aca7a94dSNamhyung Kim } 600aca7a94dSNamhyung Kim 60129ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 602aca7a94dSNamhyung Kim 603aca7a94dSNamhyung Kim return true; 604aca7a94dSNamhyung Kim } 605aca7a94dSNamhyung Kim 60629ed6e76SArnaldo Carvalho de Melo static 60729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser, 608aca7a94dSNamhyung Kim char *s, s64 *idx) 609aca7a94dSNamhyung Kim { 610aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 611aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 612aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 61329ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos = browser->selection; 614aca7a94dSNamhyung Kim 615aca7a94dSNamhyung Kim *idx = browser->b.index; 616a17c4ca0SJiri Olsa list_for_each_entry_continue(pos, ¬es->src->source, al.node) { 617a17c4ca0SJiri Olsa if (disasm_line__filter(&browser->b, &pos->al.node)) 618aca7a94dSNamhyung Kim continue; 619aca7a94dSNamhyung Kim 620aca7a94dSNamhyung Kim ++*idx; 621aca7a94dSNamhyung Kim 622d5490b96SJiri Olsa if (pos->al.line && strstr(pos->al.line, s) != NULL) 623aca7a94dSNamhyung Kim return pos; 624aca7a94dSNamhyung Kim } 625aca7a94dSNamhyung Kim 626aca7a94dSNamhyung Kim return NULL; 627aca7a94dSNamhyung Kim } 628aca7a94dSNamhyung Kim 629aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser) 630aca7a94dSNamhyung Kim { 63129ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 632aca7a94dSNamhyung Kim s64 idx; 633aca7a94dSNamhyung Kim 63429ed6e76SArnaldo Carvalho de Melo dl = annotate_browser__find_string(browser, browser->search_bf, &idx); 63529ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 636aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 637aca7a94dSNamhyung Kim return false; 638aca7a94dSNamhyung Kim } 639aca7a94dSNamhyung Kim 64029ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 641aca7a94dSNamhyung Kim browser->searching_backwards = false; 642aca7a94dSNamhyung Kim return true; 643aca7a94dSNamhyung Kim } 644aca7a94dSNamhyung Kim 64529ed6e76SArnaldo Carvalho de Melo static 64629ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 647aca7a94dSNamhyung Kim char *s, s64 *idx) 648aca7a94dSNamhyung Kim { 649aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 650aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 651aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 65229ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos = browser->selection; 653aca7a94dSNamhyung Kim 654aca7a94dSNamhyung Kim *idx = browser->b.index; 655a17c4ca0SJiri Olsa list_for_each_entry_continue_reverse(pos, ¬es->src->source, al.node) { 656a17c4ca0SJiri Olsa if (disasm_line__filter(&browser->b, &pos->al.node)) 657aca7a94dSNamhyung Kim continue; 658aca7a94dSNamhyung Kim 659aca7a94dSNamhyung Kim --*idx; 660aca7a94dSNamhyung Kim 661d5490b96SJiri Olsa if (pos->al.line && strstr(pos->al.line, s) != NULL) 662aca7a94dSNamhyung Kim return pos; 663aca7a94dSNamhyung Kim } 664aca7a94dSNamhyung Kim 665aca7a94dSNamhyung Kim return NULL; 666aca7a94dSNamhyung Kim } 667aca7a94dSNamhyung Kim 668aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser) 669aca7a94dSNamhyung Kim { 67029ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 671aca7a94dSNamhyung Kim s64 idx; 672aca7a94dSNamhyung Kim 67329ed6e76SArnaldo Carvalho de Melo dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 67429ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 675aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 676aca7a94dSNamhyung Kim return false; 677aca7a94dSNamhyung Kim } 678aca7a94dSNamhyung Kim 67929ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 680aca7a94dSNamhyung Kim browser->searching_backwards = true; 681aca7a94dSNamhyung Kim return true; 682aca7a94dSNamhyung Kim } 683aca7a94dSNamhyung Kim 684aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser, 685aca7a94dSNamhyung Kim int delay_secs) 686aca7a94dSNamhyung Kim { 687aca7a94dSNamhyung Kim if (ui_browser__input_window("Search", "String: ", browser->search_bf, 688aca7a94dSNamhyung Kim "ENTER: OK, ESC: Cancel", 689aca7a94dSNamhyung Kim delay_secs * 2) != K_ENTER || 690aca7a94dSNamhyung Kim !*browser->search_bf) 691aca7a94dSNamhyung Kim return false; 692aca7a94dSNamhyung Kim 693aca7a94dSNamhyung Kim return true; 694aca7a94dSNamhyung Kim } 695aca7a94dSNamhyung Kim 696aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) 697aca7a94dSNamhyung Kim { 698aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 699aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 700aca7a94dSNamhyung Kim 701aca7a94dSNamhyung Kim return false; 702aca7a94dSNamhyung Kim } 703aca7a94dSNamhyung Kim 704aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser, 705aca7a94dSNamhyung Kim int delay_secs) 706aca7a94dSNamhyung Kim { 707aca7a94dSNamhyung Kim if (!*browser->search_bf) 708aca7a94dSNamhyung Kim return annotate_browser__search(browser, delay_secs); 709aca7a94dSNamhyung Kim 710aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 711aca7a94dSNamhyung Kim } 712aca7a94dSNamhyung Kim 713aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser, 714aca7a94dSNamhyung Kim int delay_secs) 715aca7a94dSNamhyung Kim { 716aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 717aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 718aca7a94dSNamhyung Kim 719aca7a94dSNamhyung Kim return false; 720aca7a94dSNamhyung Kim } 721aca7a94dSNamhyung Kim 722aca7a94dSNamhyung Kim static 723aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, 724aca7a94dSNamhyung Kim int delay_secs) 725aca7a94dSNamhyung Kim { 726aca7a94dSNamhyung Kim if (!*browser->search_bf) 727aca7a94dSNamhyung Kim return annotate_browser__search_reverse(browser, delay_secs); 728aca7a94dSNamhyung Kim 729aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 730aca7a94dSNamhyung Kim } 731aca7a94dSNamhyung Kim 732e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser) 733e9823b21SArnaldo Carvalho de Melo { 734e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.use_offset) 735e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->min_addr_width; 736e9823b21SArnaldo Carvalho de Melo else 737e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->max_addr_width; 738e9823b21SArnaldo Carvalho de Melo 739e9823b21SArnaldo Carvalho de Melo browser->addr_width = browser->target_width; 740e9823b21SArnaldo Carvalho de Melo 741e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.show_nr_jumps) 742e9823b21SArnaldo Carvalho de Melo browser->addr_width += browser->jumps_width + 1; 743e9823b21SArnaldo Carvalho de Melo } 744e9823b21SArnaldo Carvalho de Melo 745db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser, 746db8fd07aSNamhyung Kim struct perf_evsel *evsel, 7479783adf7SNamhyung Kim struct hist_browser_timer *hbt) 748aca7a94dSNamhyung Kim { 749aca7a94dSNamhyung Kim struct rb_node *nd = NULL; 75005e8b080SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv; 751aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 75254e7a4e8SArnaldo Carvalho de Melo const char *help = "Press 'h' for help on key bindings"; 7539783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 754aca7a94dSNamhyung Kim int key; 75534f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 756aca7a94dSNamhyung Kim 75734f77abcSAdrian Hunter sym_title(sym, ms->map, title, sizeof(title)); 75834f77abcSAdrian Hunter if (ui_browser__show(&browser->b, title, help) < 0) 759aca7a94dSNamhyung Kim return -1; 760aca7a94dSNamhyung Kim 761db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 762aca7a94dSNamhyung Kim 76305e8b080SArnaldo Carvalho de Melo if (browser->curr_hot) { 76405e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, browser->curr_hot); 76505e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = false; 766aca7a94dSNamhyung Kim } 767aca7a94dSNamhyung Kim 76805e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 769aca7a94dSNamhyung Kim 770aca7a94dSNamhyung Kim while (1) { 77105e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 772aca7a94dSNamhyung Kim 773aca7a94dSNamhyung Kim if (delay_secs != 0) { 774db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 775aca7a94dSNamhyung Kim /* 776aca7a94dSNamhyung Kim * Current line focus got out of the list of most active 777aca7a94dSNamhyung Kim * lines, NULL it so that if TAB|UNTAB is pressed, we 778aca7a94dSNamhyung Kim * move to curr_hot (current hottest line). 779aca7a94dSNamhyung Kim */ 780aca7a94dSNamhyung Kim if (nd != NULL && RB_EMPTY_NODE(nd)) 781aca7a94dSNamhyung Kim nd = NULL; 782aca7a94dSNamhyung Kim } 783aca7a94dSNamhyung Kim 784aca7a94dSNamhyung Kim switch (key) { 785aca7a94dSNamhyung Kim case K_TIMER: 7869783adf7SNamhyung Kim if (hbt) 7879783adf7SNamhyung Kim hbt->timer(hbt->arg); 788aca7a94dSNamhyung Kim 789aca7a94dSNamhyung Kim if (delay_secs != 0) 790db8fd07aSNamhyung Kim symbol__annotate_decay_histogram(sym, evsel->idx); 791aca7a94dSNamhyung Kim continue; 792aca7a94dSNamhyung Kim case K_TAB: 793aca7a94dSNamhyung Kim if (nd != NULL) { 794aca7a94dSNamhyung Kim nd = rb_prev(nd); 795aca7a94dSNamhyung Kim if (nd == NULL) 79605e8b080SArnaldo Carvalho de Melo nd = rb_last(&browser->entries); 797aca7a94dSNamhyung Kim } else 79805e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 799aca7a94dSNamhyung Kim break; 800aca7a94dSNamhyung Kim case K_UNTAB: 801d4913cbdSMarkus Trippelsdorf if (nd != NULL) { 802aca7a94dSNamhyung Kim nd = rb_next(nd); 803aca7a94dSNamhyung Kim if (nd == NULL) 80405e8b080SArnaldo Carvalho de Melo nd = rb_first(&browser->entries); 805d4913cbdSMarkus Trippelsdorf } else 80605e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 807aca7a94dSNamhyung Kim break; 80854e7a4e8SArnaldo Carvalho de Melo case K_F1: 809aca7a94dSNamhyung Kim case 'h': 81005e8b080SArnaldo Carvalho de Melo ui_browser__help_window(&browser->b, 81154e7a4e8SArnaldo Carvalho de Melo "UP/DOWN/PGUP\n" 81254e7a4e8SArnaldo Carvalho de Melo "PGDN/SPACE Navigate\n" 81354e7a4e8SArnaldo Carvalho de Melo "q/ESC/CTRL+C Exit\n\n" 8147727a925SArnaldo Carvalho de Melo "ENTER Go to target\n" 8157727a925SArnaldo Carvalho de Melo "ESC Exit\n" 816eba9fac0SArnaldo Carvalho de Melo "H Go to hottest instruction\n" 817eba9fac0SArnaldo Carvalho de Melo "TAB/shift+TAB Cycle thru hottest instructions\n" 81854e7a4e8SArnaldo Carvalho de Melo "j Toggle showing jump to target arrows\n" 81954e7a4e8SArnaldo Carvalho de Melo "J Toggle showing number of jump sources on targets\n" 82054e7a4e8SArnaldo Carvalho de Melo "n Search next string\n" 82154e7a4e8SArnaldo Carvalho de Melo "o Toggle disassembler output/simplified view\n" 82254e7a4e8SArnaldo Carvalho de Melo "s Toggle source code view\n" 8233a555c77STaeung Song "t Circulate percent, total period, samples view\n" 82454e7a4e8SArnaldo Carvalho de Melo "/ Search string\n" 825e592488cSAndi Kleen "k Toggle line numbers\n" 82679ee47faSFeng Tang "r Run available scripts\n" 827fcd9fef9SArnaldo Carvalho de Melo "? Search string backwards\n"); 82854e7a4e8SArnaldo Carvalho de Melo continue; 82979ee47faSFeng Tang case 'r': 83079ee47faSFeng Tang { 83179ee47faSFeng Tang script_browse(NULL); 83279ee47faSFeng Tang continue; 83379ee47faSFeng Tang } 834e592488cSAndi Kleen case 'k': 835e592488cSAndi Kleen annotate_browser__opts.show_linenr = 836e592488cSAndi Kleen !annotate_browser__opts.show_linenr; 837e592488cSAndi Kleen break; 83854e7a4e8SArnaldo Carvalho de Melo case 'H': 83905e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 840aca7a94dSNamhyung Kim break; 841aca7a94dSNamhyung Kim case 's': 84205e8b080SArnaldo Carvalho de Melo if (annotate_browser__toggle_source(browser)) 843aca7a94dSNamhyung Kim ui_helpline__puts(help); 844aca7a94dSNamhyung Kim continue; 845aca7a94dSNamhyung Kim case 'o': 846e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset; 84705e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 848aca7a94dSNamhyung Kim continue; 8499d1ef56dSArnaldo Carvalho de Melo case 'j': 850e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows; 8519d1ef56dSArnaldo Carvalho de Melo continue; 8522402e4a9SArnaldo Carvalho de Melo case 'J': 853e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps; 85405e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 855e9823b21SArnaldo Carvalho de Melo continue; 856aca7a94dSNamhyung Kim case '/': 85705e8b080SArnaldo Carvalho de Melo if (annotate_browser__search(browser, delay_secs)) { 858aca7a94dSNamhyung Kim show_help: 859aca7a94dSNamhyung Kim ui_helpline__puts(help); 860aca7a94dSNamhyung Kim } 861aca7a94dSNamhyung Kim continue; 862aca7a94dSNamhyung Kim case 'n': 86305e8b080SArnaldo Carvalho de Melo if (browser->searching_backwards ? 86405e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search_reverse(browser, delay_secs) : 86505e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search(browser, delay_secs)) 866aca7a94dSNamhyung Kim goto show_help; 867aca7a94dSNamhyung Kim continue; 868aca7a94dSNamhyung Kim case '?': 86905e8b080SArnaldo Carvalho de Melo if (annotate_browser__search_reverse(browser, delay_secs)) 870aca7a94dSNamhyung Kim goto show_help; 871aca7a94dSNamhyung Kim continue; 872e9823b21SArnaldo Carvalho de Melo case 'D': { 873e9823b21SArnaldo Carvalho de Melo static int seq; 874e9823b21SArnaldo Carvalho de Melo ui_helpline__pop(); 875e9823b21SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d", 87605e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 87705e8b080SArnaldo Carvalho de Melo browser->b.height, 87805e8b080SArnaldo Carvalho de Melo browser->b.index, 87905e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 88005e8b080SArnaldo Carvalho de Melo browser->nr_asm_entries); 881e9823b21SArnaldo Carvalho de Melo } 882e9823b21SArnaldo Carvalho de Melo continue; 883aca7a94dSNamhyung Kim case K_ENTER: 884aca7a94dSNamhyung Kim case K_RIGHT: 88505e8b080SArnaldo Carvalho de Melo if (browser->selection == NULL) 886aca7a94dSNamhyung Kim ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 887d5490b96SJiri Olsa else if (browser->selection->al.offset == -1) 888aca7a94dSNamhyung Kim ui_helpline__puts("Actions are only available for assembly lines."); 88975b49202SArnaldo Carvalho de Melo else if (!browser->selection->ins.ops) 890c4cceae3SArnaldo Carvalho de Melo goto show_sup_ins; 89175b49202SArnaldo Carvalho de Melo else if (ins__is_ret(&browser->selection->ins)) 892c4cceae3SArnaldo Carvalho de Melo goto out; 8936ef94929SNaveen N. Rao else if (!(annotate_browser__jump(browser) || 894db8fd07aSNamhyung Kim annotate_browser__callq(browser, evsel, hbt))) { 895c4cceae3SArnaldo Carvalho de Melo show_sup_ins: 8966ef94929SNaveen N. Rao ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 897c4cceae3SArnaldo Carvalho de Melo } 898aca7a94dSNamhyung Kim continue; 8990c4a5bceSMartin Liška case 't': 9003a555c77STaeung Song if (annotate_browser__opts.show_total_period) { 9013a555c77STaeung Song annotate_browser__opts.show_total_period = false; 9023a555c77STaeung Song annotate_browser__opts.show_nr_samples = true; 9033a555c77STaeung Song } else if (annotate_browser__opts.show_nr_samples) 9043a555c77STaeung Song annotate_browser__opts.show_nr_samples = false; 9053a555c77STaeung Song else 9063a555c77STaeung Song annotate_browser__opts.show_total_period = true; 9070c4a5bceSMartin Liška annotate_browser__update_addr_width(browser); 9080c4a5bceSMartin Liška continue; 909aca7a94dSNamhyung Kim case K_LEFT: 910aca7a94dSNamhyung Kim case K_ESC: 911aca7a94dSNamhyung Kim case 'q': 912aca7a94dSNamhyung Kim case CTRL('c'): 913aca7a94dSNamhyung Kim goto out; 914aca7a94dSNamhyung Kim default: 915aca7a94dSNamhyung Kim continue; 916aca7a94dSNamhyung Kim } 917aca7a94dSNamhyung Kim 918aca7a94dSNamhyung Kim if (nd != NULL) 91905e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, nd); 920aca7a94dSNamhyung Kim } 921aca7a94dSNamhyung Kim out: 92205e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 923aca7a94dSNamhyung Kim return key; 924aca7a94dSNamhyung Kim } 925aca7a94dSNamhyung Kim 926d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, 927d5dbc518SArnaldo Carvalho de Melo struct hist_browser_timer *hbt) 928d5dbc518SArnaldo Carvalho de Melo { 9299cef4b0bSTaeung Song /* Set default value for show_total_period and show_nr_samples */ 9300c4a5bceSMartin Liška annotate_browser__opts.show_total_period = 9310c4a5bceSMartin Liška symbol_conf.show_total_period; 9329cef4b0bSTaeung Song annotate_browser__opts.show_nr_samples = 9339cef4b0bSTaeung Song symbol_conf.show_nr_samples; 9340c4a5bceSMartin Liška 935d5dbc518SArnaldo Carvalho de Melo return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); 936d5dbc518SArnaldo Carvalho de Melo } 937d5dbc518SArnaldo Carvalho de Melo 938db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 9399783adf7SNamhyung Kim struct hist_browser_timer *hbt) 940aca7a94dSNamhyung Kim { 941ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 942ed426915SNamhyung Kim SLang_reset_tty(); 943ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 944ed426915SNamhyung Kim 945d5dbc518SArnaldo Carvalho de Melo return map_symbol__tui_annotate(&he->ms, evsel, hbt); 946aca7a94dSNamhyung Kim } 947aca7a94dSNamhyung Kim 94830e863bbSAndi Kleen 94930e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end) 95030e863bbSAndi Kleen { 95130e863bbSAndi Kleen unsigned n_insn = 0; 95230e863bbSAndi Kleen u64 offset; 95330e863bbSAndi Kleen 95430e863bbSAndi Kleen for (offset = start; offset <= end; offset++) { 95530e863bbSAndi Kleen if (browser->offsets[offset]) 95630e863bbSAndi Kleen n_insn++; 95730e863bbSAndi Kleen } 95830e863bbSAndi Kleen return n_insn; 95930e863bbSAndi Kleen } 96030e863bbSAndi Kleen 96130e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end, 96230e863bbSAndi Kleen struct cyc_hist *ch) 96330e863bbSAndi Kleen { 96430e863bbSAndi Kleen unsigned n_insn; 96530e863bbSAndi Kleen u64 offset; 96630e863bbSAndi Kleen 96730e863bbSAndi Kleen n_insn = count_insn(browser, start, end); 96830e863bbSAndi Kleen if (n_insn && ch->num && ch->cycles) { 96930e863bbSAndi Kleen float ipc = n_insn / ((double)ch->cycles / (double)ch->num); 97030e863bbSAndi Kleen 97130e863bbSAndi Kleen /* Hide data when there are too many overlaps. */ 97230e863bbSAndi Kleen if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2) 97330e863bbSAndi Kleen return; 97430e863bbSAndi Kleen 97530e863bbSAndi Kleen for (offset = start; offset <= end; offset++) { 97630e863bbSAndi Kleen struct disasm_line *dl = browser->offsets[offset]; 97730e863bbSAndi Kleen 97830e863bbSAndi Kleen if (dl) 97937236d5eSJiri Olsa dl->al.ipc = ipc; 98030e863bbSAndi Kleen } 98130e863bbSAndi Kleen } 98230e863bbSAndi Kleen } 98330e863bbSAndi Kleen 98430e863bbSAndi Kleen /* 98530e863bbSAndi Kleen * This should probably be in util/annotate.c to share with the tty 98630e863bbSAndi Kleen * annotate, but right now we need the per byte offsets arrays, 98730e863bbSAndi Kleen * which are only here. 98830e863bbSAndi Kleen */ 98930e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size, 99030e863bbSAndi Kleen struct symbol *sym) 99130e863bbSAndi Kleen { 99230e863bbSAndi Kleen u64 offset; 99330e863bbSAndi Kleen struct annotation *notes = symbol__annotation(sym); 99430e863bbSAndi Kleen 99530e863bbSAndi Kleen if (!notes->src || !notes->src->cycles_hist) 99630e863bbSAndi Kleen return; 99730e863bbSAndi Kleen 99830e863bbSAndi Kleen pthread_mutex_lock(¬es->lock); 99930e863bbSAndi Kleen for (offset = 0; offset < size; ++offset) { 100030e863bbSAndi Kleen struct cyc_hist *ch; 100130e863bbSAndi Kleen 100230e863bbSAndi Kleen ch = ¬es->src->cycles_hist[offset]; 100330e863bbSAndi Kleen if (ch && ch->cycles) { 100430e863bbSAndi Kleen struct disasm_line *dl; 100530e863bbSAndi Kleen 100630e863bbSAndi Kleen if (ch->have_start) 100730e863bbSAndi Kleen count_and_fill(browser, ch->start, offset, ch); 100830e863bbSAndi Kleen dl = browser->offsets[offset]; 100930e863bbSAndi Kleen if (dl && ch->num_aggr) 101037236d5eSJiri Olsa dl->al.cycles = ch->cycles_aggr / ch->num_aggr; 101130e863bbSAndi Kleen browser->have_cycles = true; 101230e863bbSAndi Kleen } 101330e863bbSAndi Kleen } 101430e863bbSAndi Kleen pthread_mutex_unlock(¬es->lock); 101530e863bbSAndi Kleen } 101630e863bbSAndi Kleen 1017b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 1018b793a401SArnaldo Carvalho de Melo size_t size) 1019b793a401SArnaldo Carvalho de Melo { 1020b793a401SArnaldo Carvalho de Melo u64 offset; 102132ae1efdSNamhyung Kim struct map_symbol *ms = browser->b.priv; 102232ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 102332ae1efdSNamhyung Kim 102432ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 102532ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 102632ae1efdSNamhyung Kim return; 1027b793a401SArnaldo Carvalho de Melo 1028b793a401SArnaldo Carvalho de Melo for (offset = 0; offset < size; ++offset) { 1029b793a401SArnaldo Carvalho de Melo struct disasm_line *dl = browser->offsets[offset], *dlt; 1030b793a401SArnaldo Carvalho de Melo struct browser_disasm_line *bdlt; 1031b793a401SArnaldo Carvalho de Melo 1032865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(dl, sym)) 1033b793a401SArnaldo Carvalho de Melo continue; 1034b793a401SArnaldo Carvalho de Melo 103544d1a3edSArnaldo Carvalho de Melo dlt = browser->offsets[dl->ops.target.offset]; 10369481ede9SArnaldo Carvalho de Melo /* 10379481ede9SArnaldo Carvalho de Melo * FIXME: Oops, no jump target? Buggy disassembler? Or do we 10389481ede9SArnaldo Carvalho de Melo * have to adjust to the previous offset? 10399481ede9SArnaldo Carvalho de Melo */ 10409481ede9SArnaldo Carvalho de Melo if (dlt == NULL) 10419481ede9SArnaldo Carvalho de Melo continue; 10429481ede9SArnaldo Carvalho de Melo 1043b793a401SArnaldo Carvalho de Melo bdlt = disasm_line__browser(dlt); 10442402e4a9SArnaldo Carvalho de Melo if (++bdlt->jump_sources > browser->max_jump_sources) 10452402e4a9SArnaldo Carvalho de Melo browser->max_jump_sources = bdlt->jump_sources; 10462402e4a9SArnaldo Carvalho de Melo 10472402e4a9SArnaldo Carvalho de Melo ++browser->nr_jumps; 1048b793a401SArnaldo Carvalho de Melo } 1049b793a401SArnaldo Carvalho de Melo } 1050b793a401SArnaldo Carvalho de Melo 10512402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n) 10522402e4a9SArnaldo Carvalho de Melo { 10532402e4a9SArnaldo Carvalho de Melo if (n >= 100) 10542402e4a9SArnaldo Carvalho de Melo return 5; 10552402e4a9SArnaldo Carvalho de Melo if (n / 10) 10562402e4a9SArnaldo Carvalho de Melo return 2; 10572402e4a9SArnaldo Carvalho de Melo return 1; 10582402e4a9SArnaldo Carvalho de Melo } 10592402e4a9SArnaldo Carvalho de Melo 1060db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map, 1061db8fd07aSNamhyung Kim struct perf_evsel *evsel, 10629783adf7SNamhyung Kim struct hist_browser_timer *hbt) 1063aca7a94dSNamhyung Kim { 1064f8eb37bdSJiri Olsa struct disasm_line *pos; 1065aca7a94dSNamhyung Kim struct annotation *notes; 1066c0a58fb2SSamuel Liao size_t size; 1067aca7a94dSNamhyung Kim struct map_symbol ms = { 1068aca7a94dSNamhyung Kim .map = map, 1069aca7a94dSNamhyung Kim .sym = sym, 1070aca7a94dSNamhyung Kim }; 1071aca7a94dSNamhyung Kim struct annotate_browser browser = { 1072aca7a94dSNamhyung Kim .b = { 1073a3f895beSArnaldo Carvalho de Melo .refresh = annotate_browser__refresh, 1074aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 1075aca7a94dSNamhyung Kim .write = annotate_browser__write, 107629ed6e76SArnaldo Carvalho de Melo .filter = disasm_line__filter, 1077aca7a94dSNamhyung Kim .priv = &ms, 1078aca7a94dSNamhyung Kim .use_navkeypressed = true, 1079aca7a94dSNamhyung Kim }, 1080aca7a94dSNamhyung Kim }; 1081ee51d851SArnaldo Carvalho de Melo int ret = -1, err; 1082c7e7b610SNamhyung Kim int nr_pcnt = 1; 1083aca7a94dSNamhyung Kim 1084aca7a94dSNamhyung Kim if (sym == NULL) 1085aca7a94dSNamhyung Kim return -1; 1086aca7a94dSNamhyung Kim 1087c0a58fb2SSamuel Liao size = symbol__size(sym); 1088c0a58fb2SSamuel Liao 1089aca7a94dSNamhyung Kim if (map->dso->annotate_warned) 1090aca7a94dSNamhyung Kim return -1; 1091aca7a94dSNamhyung Kim 1092b793a401SArnaldo Carvalho de Melo browser.offsets = zalloc(size * sizeof(struct disasm_line *)); 1093b793a401SArnaldo Carvalho de Melo if (browser.offsets == NULL) { 1094b793a401SArnaldo Carvalho de Melo ui__error("Not enough memory!"); 1095b793a401SArnaldo Carvalho de Melo return -1; 1096b793a401SArnaldo Carvalho de Melo } 1097b793a401SArnaldo Carvalho de Melo 10983ab6db8dSJiri Olsa if (perf_evsel__is_group_event(evsel)) 1099c7e7b610SNamhyung Kim nr_pcnt = evsel->nr_members; 1100c7e7b610SNamhyung Kim 1101d03a686eSJiri Olsa err = symbol__annotate(sym, map, evsel, 11023ab6db8dSJiri Olsa sizeof(struct browser_disasm_line), &browser.arch, 110369fb09f6SJin Yao perf_evsel__env_cpuid(evsel)); 1104ee51d851SArnaldo Carvalho de Melo if (err) { 1105ee51d851SArnaldo Carvalho de Melo char msg[BUFSIZ]; 1106ee51d851SArnaldo Carvalho de Melo symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); 1107ee51d851SArnaldo Carvalho de Melo ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 1108b793a401SArnaldo Carvalho de Melo goto out_free_offsets; 1109aca7a94dSNamhyung Kim } 1110aca7a94dSNamhyung Kim 11117727a925SArnaldo Carvalho de Melo ui_helpline__push("Press ESC to exit"); 1112aca7a94dSNamhyung Kim 1113aca7a94dSNamhyung Kim notes = symbol__annotation(sym); 1114aca7a94dSNamhyung Kim browser.start = map__rip_2objdump(map, sym->start); 1115aca7a94dSNamhyung Kim 1116a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 1117887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos; 1118d5490b96SJiri Olsa size_t line_len = strlen(pos->al.line); 1119aca7a94dSNamhyung Kim 1120aca7a94dSNamhyung Kim if (browser.b.width < line_len) 1121aca7a94dSNamhyung Kim browser.b.width = line_len; 1122887c0066SArnaldo Carvalho de Melo bpos = disasm_line__browser(pos); 1123887c0066SArnaldo Carvalho de Melo bpos->idx = browser.nr_entries++; 1124d5490b96SJiri Olsa if (pos->al.offset != -1) { 1125887c0066SArnaldo Carvalho de Melo bpos->idx_asm = browser.nr_asm_entries++; 112697148a97SArnaldo Carvalho de Melo /* 112797148a97SArnaldo Carvalho de Melo * FIXME: short term bandaid to cope with assembly 112897148a97SArnaldo Carvalho de Melo * routines that comes with labels in the same column 112997148a97SArnaldo Carvalho de Melo * as the address in objdump, sigh. 113097148a97SArnaldo Carvalho de Melo * 113197148a97SArnaldo Carvalho de Melo * E.g. copy_user_generic_unrolled 113297148a97SArnaldo Carvalho de Melo */ 1133d5490b96SJiri Olsa if (pos->al.offset < (s64)size) 1134d5490b96SJiri Olsa browser.offsets[pos->al.offset] = pos; 1135b793a401SArnaldo Carvalho de Melo } else 1136887c0066SArnaldo Carvalho de Melo bpos->idx_asm = -1; 1137aca7a94dSNamhyung Kim } 1138aca7a94dSNamhyung Kim 1139b793a401SArnaldo Carvalho de Melo annotate_browser__mark_jump_targets(&browser, size); 114030e863bbSAndi Kleen annotate__compute_ipc(&browser, size, sym); 1141b793a401SArnaldo Carvalho de Melo 11422402e4a9SArnaldo Carvalho de Melo browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); 114383b1f2aaSArnaldo Carvalho de Melo browser.max_addr_width = hex_width(sym->end); 11442402e4a9SArnaldo Carvalho de Melo browser.jumps_width = width_jumps(browser.max_jump_sources); 1145c7e7b610SNamhyung Kim browser.nr_events = nr_pcnt; 1146aca7a94dSNamhyung Kim browser.b.nr_entries = browser.nr_entries; 1147aca7a94dSNamhyung Kim browser.b.entries = ¬es->src->source, 1148aca7a94dSNamhyung Kim browser.b.width += 18; /* Percentage */ 1149e9823b21SArnaldo Carvalho de Melo 1150e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 1151e9823b21SArnaldo Carvalho de Melo annotate_browser__init_asm_mode(&browser); 1152e9823b21SArnaldo Carvalho de Melo 1153e9823b21SArnaldo Carvalho de Melo annotate_browser__update_addr_width(&browser); 1154e9823b21SArnaldo Carvalho de Melo 1155db8fd07aSNamhyung Kim ret = annotate_browser__run(&browser, evsel, hbt); 1156f8eb37bdSJiri Olsa 1157f8eb37bdSJiri Olsa annotated_source__purge(notes->src); 1158b793a401SArnaldo Carvalho de Melo 1159b793a401SArnaldo Carvalho de Melo out_free_offsets: 1160b793a401SArnaldo Carvalho de Melo free(browser.offsets); 1161aca7a94dSNamhyung Kim return ret; 1162aca7a94dSNamhyung Kim } 1163c323cf04SArnaldo Carvalho de Melo 1164c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \ 1165c323cf04SArnaldo Carvalho de Melo { .name = #n, .value = &annotate_browser__opts.n, } 1166c323cf04SArnaldo Carvalho de Melo 1167c323cf04SArnaldo Carvalho de Melo /* 1168c323cf04SArnaldo Carvalho de Melo * Keep the entries sorted, they are bsearch'ed 1169c323cf04SArnaldo Carvalho de Melo */ 11707c3102b8SArnaldo Carvalho de Melo static struct annotate_config { 1171c323cf04SArnaldo Carvalho de Melo const char *name; 1172c323cf04SArnaldo Carvalho de Melo bool *value; 1173c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = { 1174c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(hide_src_code), 1175c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(jump_arrows), 1176e592488cSAndi Kleen ANNOTATE_CFG(show_linenr), 1177c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(show_nr_jumps), 11789cef4b0bSTaeung Song ANNOTATE_CFG(show_nr_samples), 11790c4a5bceSMartin Liška ANNOTATE_CFG(show_total_period), 118039ff7cdbSNamhyung Kim ANNOTATE_CFG(use_offset), 1181c323cf04SArnaldo Carvalho de Melo }; 1182c323cf04SArnaldo Carvalho de Melo 1183c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG 1184c323cf04SArnaldo Carvalho de Melo 1185c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp) 1186c323cf04SArnaldo Carvalho de Melo { 11877c3102b8SArnaldo Carvalho de Melo const struct annotate_config *cfg = cfgp; 1188c323cf04SArnaldo Carvalho de Melo 1189c323cf04SArnaldo Carvalho de Melo return strcmp(name, cfg->name); 1190c323cf04SArnaldo Carvalho de Melo } 1191c323cf04SArnaldo Carvalho de Melo 11921d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value, 11931d037ca1SIrina Tirdea void *data __maybe_unused) 1194c323cf04SArnaldo Carvalho de Melo { 11957c3102b8SArnaldo Carvalho de Melo struct annotate_config *cfg; 1196c323cf04SArnaldo Carvalho de Melo const char *name; 1197c323cf04SArnaldo Carvalho de Melo 11988e99b6d4SArnaldo Carvalho de Melo if (!strstarts(var, "annotate.")) 1199c323cf04SArnaldo Carvalho de Melo return 0; 1200c323cf04SArnaldo Carvalho de Melo 1201c323cf04SArnaldo Carvalho de Melo name = var + 9; 1202c323cf04SArnaldo Carvalho de Melo cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), 12037c3102b8SArnaldo Carvalho de Melo sizeof(struct annotate_config), annotate_config__cmp); 1204c323cf04SArnaldo Carvalho de Melo 1205c323cf04SArnaldo Carvalho de Melo if (cfg == NULL) 1206f06cff7cSArnaldo Carvalho de Melo ui__warning("%s variable unknown, ignoring...", var); 1207f06cff7cSArnaldo Carvalho de Melo else 1208c323cf04SArnaldo Carvalho de Melo *cfg->value = perf_config_bool(name, value); 1209c323cf04SArnaldo Carvalho de Melo return 0; 1210c323cf04SArnaldo Carvalho de Melo } 1211c323cf04SArnaldo Carvalho de Melo 1212c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void) 1213c323cf04SArnaldo Carvalho de Melo { 1214c323cf04SArnaldo Carvalho de Melo perf_config(annotate__config, NULL); 1215c323cf04SArnaldo Carvalho de Melo } 1216