1aca7a94dSNamhyung Kim #include "../../util/util.h" 2aca7a94dSNamhyung Kim #include "../browser.h" 3aca7a94dSNamhyung Kim #include "../helpline.h" 4aca7a94dSNamhyung Kim #include "../ui.h" 5aca7a94dSNamhyung Kim #include "../util.h" 6aca7a94dSNamhyung Kim #include "../../util/annotate.h" 7aca7a94dSNamhyung Kim #include "../../util/hist.h" 8aca7a94dSNamhyung Kim #include "../../util/sort.h" 9aca7a94dSNamhyung Kim #include "../../util/symbol.h" 10db8fd07aSNamhyung Kim #include "../../util/evsel.h" 1141840d21STaeung Song #include "../../util/config.h" 1269fb09f6SJin Yao #include "../../util/evlist.h" 13fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 14aca7a94dSNamhyung Kim #include <pthread.h> 15877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 168e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h> 17b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h> 18aca7a94dSNamhyung Kim 190c4a5bceSMartin Liška struct disasm_line_samples { 200c4a5bceSMartin Liška double percent; 210c4a5bceSMartin Liška u64 nr; 220c4a5bceSMartin Liška }; 230c4a5bceSMartin Liška 24f8f4aaeaSAndi Kleen #define IPC_WIDTH 6 25f8f4aaeaSAndi Kleen #define CYCLES_WIDTH 6 26f8f4aaeaSAndi Kleen 27b793a401SArnaldo Carvalho de Melo struct browser_disasm_line { 28b793a401SArnaldo Carvalho de Melo struct rb_node rb_node; 29b793a401SArnaldo Carvalho de Melo u32 idx; 30b793a401SArnaldo Carvalho de Melo int idx_asm; 317d5b12f5SArnaldo Carvalho de Melo int jump_sources; 32c7e7b610SNamhyung Kim /* 33c7e7b610SNamhyung Kim * actual length of this array is saved on the nr_events field 34c7e7b610SNamhyung Kim * of the struct annotate_browser 35c7e7b610SNamhyung Kim */ 360c4a5bceSMartin Liška struct disasm_line_samples samples[1]; 37b793a401SArnaldo Carvalho de Melo }; 38b793a401SArnaldo Carvalho de Melo 39e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt { 40e9823b21SArnaldo Carvalho de Melo bool hide_src_code, 41e9823b21SArnaldo Carvalho de Melo use_offset, 42e9823b21SArnaldo Carvalho de Melo jump_arrows, 43e592488cSAndi Kleen show_linenr, 440c4a5bceSMartin Liška show_nr_jumps, 450c4a5bceSMartin Liška show_total_period; 46e9823b21SArnaldo Carvalho de Melo } annotate_browser__opts = { 47e9823b21SArnaldo Carvalho de Melo .use_offset = true, 48e9823b21SArnaldo Carvalho de Melo .jump_arrows = true, 49e9823b21SArnaldo Carvalho de Melo }; 50e9823b21SArnaldo Carvalho de Melo 51dcaa3948SJin Yao struct arch; 52dcaa3948SJin Yao 53aca7a94dSNamhyung Kim struct annotate_browser { 54aca7a94dSNamhyung Kim struct ui_browser b; 55aca7a94dSNamhyung Kim struct rb_root entries; 56aca7a94dSNamhyung Kim struct rb_node *curr_hot; 5729ed6e76SArnaldo Carvalho de Melo struct disasm_line *selection; 58b793a401SArnaldo Carvalho de Melo struct disasm_line **offsets; 59dcaa3948SJin Yao struct arch *arch; 60c7e7b610SNamhyung Kim int nr_events; 61aca7a94dSNamhyung Kim u64 start; 62aca7a94dSNamhyung Kim int nr_asm_entries; 63aca7a94dSNamhyung Kim int nr_entries; 642402e4a9SArnaldo Carvalho de Melo int max_jump_sources; 652402e4a9SArnaldo Carvalho de Melo int nr_jumps; 66aca7a94dSNamhyung Kim bool searching_backwards; 6730e863bbSAndi Kleen bool have_cycles; 6883b1f2aaSArnaldo Carvalho de Melo u8 addr_width; 692402e4a9SArnaldo Carvalho de Melo u8 jumps_width; 702402e4a9SArnaldo Carvalho de Melo u8 target_width; 7183b1f2aaSArnaldo Carvalho de Melo u8 min_addr_width; 7283b1f2aaSArnaldo Carvalho de Melo u8 max_addr_width; 73aca7a94dSNamhyung Kim char search_bf[128]; 74aca7a94dSNamhyung Kim }; 75aca7a94dSNamhyung Kim 76887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl) 77aca7a94dSNamhyung Kim { 78887c0066SArnaldo Carvalho de Melo return (struct browser_disasm_line *)(dl + 1); 79aca7a94dSNamhyung Kim } 80aca7a94dSNamhyung Kim 811d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, 821d037ca1SIrina Tirdea void *entry) 83aca7a94dSNamhyung Kim { 84e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 8529ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl = list_entry(entry, struct disasm_line, node); 8629ed6e76SArnaldo Carvalho de Melo return dl->offset == -1; 87aca7a94dSNamhyung Kim } 88aca7a94dSNamhyung Kim 89aca7a94dSNamhyung Kim return false; 90aca7a94dSNamhyung Kim } 91aca7a94dSNamhyung Kim 922402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, 932402e4a9SArnaldo Carvalho de Melo int nr, bool current) 942402e4a9SArnaldo Carvalho de Melo { 952402e4a9SArnaldo Carvalho de Melo if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) 962402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_SELECTED; 972402e4a9SArnaldo Carvalho de Melo if (nr == browser->max_jump_sources) 982402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_TOP; 992402e4a9SArnaldo Carvalho de Melo if (nr > 1) 1002402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_MEDIUM; 1012402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_NORMAL; 1022402e4a9SArnaldo Carvalho de Melo } 1032402e4a9SArnaldo Carvalho de Melo 1042402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, 1052402e4a9SArnaldo Carvalho de Melo int nr, bool current) 1062402e4a9SArnaldo Carvalho de Melo { 1072402e4a9SArnaldo Carvalho de Melo int color = annotate_browser__jumps_percent_color(browser, nr, current); 1082402e4a9SArnaldo Carvalho de Melo return ui_browser__set_color(&browser->b, color); 1092402e4a9SArnaldo Carvalho de Melo } 1102402e4a9SArnaldo Carvalho de Melo 111f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab) 112f8f4aaeaSAndi Kleen { 113f8f4aaeaSAndi Kleen int w = 7 * ab->nr_events; 114f8f4aaeaSAndi Kleen 115f8f4aaeaSAndi Kleen if (ab->have_cycles) 116f8f4aaeaSAndi Kleen w += IPC_WIDTH + CYCLES_WIDTH; 117f8f4aaeaSAndi Kleen return w; 118f8f4aaeaSAndi Kleen } 119f8f4aaeaSAndi Kleen 12005e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 121aca7a94dSNamhyung Kim { 12205e8b080SArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 12329ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl = list_entry(entry, struct disasm_line, node); 124b793a401SArnaldo Carvalho de Melo struct browser_disasm_line *bdl = disasm_line__browser(dl); 12505e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(browser, row); 126e9823b21SArnaldo Carvalho de Melo bool change_color = (!annotate_browser__opts.hide_src_code && 12705e8b080SArnaldo Carvalho de Melo (!current_entry || (browser->use_navkeypressed && 12805e8b080SArnaldo Carvalho de Melo !browser->navkeypressed))); 12905e8b080SArnaldo Carvalho de Melo int width = browser->width, printed; 130f8f4aaeaSAndi Kleen int i, pcnt_width = annotate_browser__pcnt_width(ab); 131c7e7b610SNamhyung Kim double percent_max = 0.0; 13283b1f2aaSArnaldo Carvalho de Melo char bf[256]; 133ec27ae18SJin Yao bool show_title = false; 134aca7a94dSNamhyung Kim 135c7e7b610SNamhyung Kim for (i = 0; i < ab->nr_events; i++) { 1360c4a5bceSMartin Liška if (bdl->samples[i].percent > percent_max) 1370c4a5bceSMartin Liška percent_max = bdl->samples[i].percent; 138c7e7b610SNamhyung Kim } 139c7e7b610SNamhyung Kim 140ec27ae18SJin Yao if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) { 141ec27ae18SJin Yao if (ab->have_cycles) { 142ec27ae18SJin Yao if (dl->ipc == 0.0 && dl->cycles == 0) 143ec27ae18SJin Yao show_title = true; 144ec27ae18SJin Yao } else 145ec27ae18SJin Yao show_title = true; 146ec27ae18SJin Yao } 147ec27ae18SJin Yao 148c7e7b610SNamhyung Kim if (dl->offset != -1 && percent_max != 0.0) { 149c7e7b610SNamhyung Kim for (i = 0; i < ab->nr_events; i++) { 1500c4a5bceSMartin Liška ui_browser__set_percent_color(browser, 1510c4a5bceSMartin Liška bdl->samples[i].percent, 152c7e7b610SNamhyung Kim current_entry); 153517dfdb3SArnaldo Carvalho de Melo if (annotate_browser__opts.show_total_period) { 154517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%6" PRIu64 " ", 1550c4a5bceSMartin Liška bdl->samples[i].nr); 156517dfdb3SArnaldo Carvalho de Melo } else { 157517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%6.2f ", 158517dfdb3SArnaldo Carvalho de Melo bdl->samples[i].percent); 159517dfdb3SArnaldo Carvalho de Melo } 160c7e7b610SNamhyung Kim } 161aca7a94dSNamhyung Kim } else { 16205e8b080SArnaldo Carvalho de Melo ui_browser__set_percent_color(browser, 0, current_entry); 163ec27ae18SJin Yao 164ec27ae18SJin Yao if (!show_title) 16526270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); 166ec27ae18SJin Yao else 167ec27ae18SJin Yao ui_browser__printf(browser, "%*s", 7, "Percent"); 168f8f4aaeaSAndi Kleen } 169f8f4aaeaSAndi Kleen if (ab->have_cycles) { 170f8f4aaeaSAndi Kleen if (dl->ipc) 171517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc); 172ec27ae18SJin Yao else if (!show_title) 17326270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", IPC_WIDTH); 174ec27ae18SJin Yao else 175ec27ae18SJin Yao ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC"); 176ec27ae18SJin Yao 177f8f4aaeaSAndi Kleen if (dl->cycles) 178517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%*" PRIu64 " ", 179f8f4aaeaSAndi Kleen CYCLES_WIDTH - 1, dl->cycles); 180ec27ae18SJin Yao else if (!show_title) 18126270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); 182ec27ae18SJin Yao else 183ec27ae18SJin Yao ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle"); 184aca7a94dSNamhyung Kim } 185aca7a94dSNamhyung Kim 186cf2dacc5SArnaldo Carvalho de Melo SLsmg_write_char(' '); 187aca7a94dSNamhyung Kim 188aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 18905e8b080SArnaldo Carvalho de Melo if (!browser->navkeypressed) 190aca7a94dSNamhyung Kim width += 1; 191aca7a94dSNamhyung Kim 19229ed6e76SArnaldo Carvalho de Melo if (!*dl->line) 19326270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", width - pcnt_width); 19483b1f2aaSArnaldo Carvalho de Melo else if (dl->offset == -1) { 195e592488cSAndi Kleen if (dl->line_nr && annotate_browser__opts.show_linenr) 196e592488cSAndi Kleen printed = scnprintf(bf, sizeof(bf), "%-*d ", 197e592488cSAndi Kleen ab->addr_width + 1, dl->line_nr); 198e592488cSAndi Kleen else 19983b1f2aaSArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*s ", 20083b1f2aaSArnaldo Carvalho de Melo ab->addr_width, " "); 20126270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, printed); 20226270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1); 20383b1f2aaSArnaldo Carvalho de Melo } else { 20429ed6e76SArnaldo Carvalho de Melo u64 addr = dl->offset; 20583b1f2aaSArnaldo Carvalho de Melo int color = -1; 206aca7a94dSNamhyung Kim 207e9823b21SArnaldo Carvalho de Melo if (!annotate_browser__opts.use_offset) 208aca7a94dSNamhyung Kim addr += ab->start; 209aca7a94dSNamhyung Kim 210e9823b21SArnaldo Carvalho de Melo if (!annotate_browser__opts.use_offset) { 211aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); 21261e04b33SArnaldo Carvalho de Melo } else { 2137d5b12f5SArnaldo Carvalho de Melo if (bdl->jump_sources) { 214e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.show_nr_jumps) { 2152402e4a9SArnaldo Carvalho de Melo int prev; 2162402e4a9SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*d ", 2172402e4a9SArnaldo Carvalho de Melo ab->jumps_width, 2182402e4a9SArnaldo Carvalho de Melo bdl->jump_sources); 2192402e4a9SArnaldo Carvalho de Melo prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources, 2202402e4a9SArnaldo Carvalho de Melo current_entry); 22126270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, printed); 22205e8b080SArnaldo Carvalho de Melo ui_browser__set_color(browser, prev); 2232402e4a9SArnaldo Carvalho de Melo } 2242402e4a9SArnaldo Carvalho de Melo 22561e04b33SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", 2262402e4a9SArnaldo Carvalho de Melo ab->target_width, addr); 22761e04b33SArnaldo Carvalho de Melo } else { 22861e04b33SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*s ", 22983b1f2aaSArnaldo Carvalho de Melo ab->addr_width, " "); 23061e04b33SArnaldo Carvalho de Melo } 23161e04b33SArnaldo Carvalho de Melo } 232b793a401SArnaldo Carvalho de Melo 233aca7a94dSNamhyung Kim if (change_color) 23405e8b080SArnaldo Carvalho de Melo color = ui_browser__set_color(browser, HE_COLORSET_ADDR); 23526270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, printed); 236aca7a94dSNamhyung Kim if (change_color) 23705e8b080SArnaldo Carvalho de Melo ui_browser__set_color(browser, color); 23875b49202SArnaldo Carvalho de Melo if (dl->ins.ops && dl->ins.ops->scnprintf) { 23975b49202SArnaldo Carvalho de Melo if (ins__is_jump(&dl->ins)) { 240e216874cSRavi Bangoria bool fwd = dl->ops.target.offset > dl->offset; 24151a0d455SArnaldo Carvalho de Melo 24205e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : 24351a0d455SArnaldo Carvalho de Melo SLSMG_UARROW_CHAR); 24451a0d455SArnaldo Carvalho de Melo SLsmg_write_char(' '); 24575b49202SArnaldo Carvalho de Melo } else if (ins__is_call(&dl->ins)) { 24605e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); 24788298f5aSArnaldo Carvalho de Melo SLsmg_write_char(' '); 24875b49202SArnaldo Carvalho de Melo } else if (ins__is_ret(&dl->ins)) { 24905e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); 2504ea08b52SArnaldo Carvalho de Melo SLsmg_write_char(' '); 2516ef94929SNaveen N. Rao } else { 2526ef94929SNaveen N. Rao ui_browser__write_nstring(browser, " ", 2); 2534ea08b52SArnaldo Carvalho de Melo } 2546ef94929SNaveen N. Rao } else { 2556ef94929SNaveen N. Rao ui_browser__write_nstring(browser, " ", 2); 2564ea08b52SArnaldo Carvalho de Melo } 2574ea08b52SArnaldo Carvalho de Melo 258e9823b21SArnaldo Carvalho de Melo disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 25926270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed); 260aca7a94dSNamhyung Kim } 261aca7a94dSNamhyung Kim 262aca7a94dSNamhyung Kim if (current_entry) 26329ed6e76SArnaldo Carvalho de Melo ab->selection = dl; 264aca7a94dSNamhyung Kim } 265aca7a94dSNamhyung Kim 266865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) 267865c66c4SFrederik Deweerdt { 26875b49202SArnaldo Carvalho de Melo if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) 269865c66c4SFrederik Deweerdt || !disasm_line__has_offset(dl) 270e216874cSRavi Bangoria || dl->ops.target.offset < 0 271e216874cSRavi Bangoria || dl->ops.target.offset >= (s64)symbol__size(sym)) 272865c66c4SFrederik Deweerdt return false; 273865c66c4SFrederik Deweerdt 274865c66c4SFrederik Deweerdt return true; 275865c66c4SFrederik Deweerdt } 276865c66c4SFrederik Deweerdt 2777e63a13aSJin Yao static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor) 2787e63a13aSJin Yao { 2797e63a13aSJin Yao struct disasm_line *pos = list_prev_entry(cursor, node); 2807e63a13aSJin Yao const char *name; 2817e63a13aSJin Yao 2827e63a13aSJin Yao if (!pos) 2837e63a13aSJin Yao return false; 2847e63a13aSJin Yao 2857e63a13aSJin Yao if (ins__is_lock(&pos->ins)) 2867e63a13aSJin Yao name = pos->ops.locked.ins.name; 2877e63a13aSJin Yao else 2887e63a13aSJin Yao name = pos->ins.name; 2897e63a13aSJin Yao 2907e63a13aSJin Yao if (!name || !cursor->ins.name) 2917e63a13aSJin Yao return false; 2927e63a13aSJin Yao 2937e63a13aSJin Yao return ins__is_fused(ab->arch, name, cursor->ins.name); 2947e63a13aSJin Yao } 2957e63a13aSJin Yao 2969d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser) 297a3f895beSArnaldo Carvalho de Melo { 298a3f895beSArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 2999d1ef56dSArnaldo Carvalho de Melo struct disasm_line *cursor = ab->selection, *target; 3009d1ef56dSArnaldo Carvalho de Melo struct browser_disasm_line *btarget, *bcursor; 30183b1f2aaSArnaldo Carvalho de Melo unsigned int from, to; 30232ae1efdSNamhyung Kim struct map_symbol *ms = ab->b.priv; 30332ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 304f8f4aaeaSAndi Kleen u8 pcnt_width = annotate_browser__pcnt_width(ab); 30532ae1efdSNamhyung Kim 30632ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 30732ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 30832ae1efdSNamhyung Kim return; 309a3f895beSArnaldo Carvalho de Melo 310865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(cursor, sym)) 311a3f895beSArnaldo Carvalho de Melo return; 312a3f895beSArnaldo Carvalho de Melo 3139d1ef56dSArnaldo Carvalho de Melo target = ab->offsets[cursor->ops.target.offset]; 3149d1ef56dSArnaldo Carvalho de Melo if (!target) 3159d1ef56dSArnaldo Carvalho de Melo return; 3169d1ef56dSArnaldo Carvalho de Melo 3179d1ef56dSArnaldo Carvalho de Melo bcursor = disasm_line__browser(cursor); 3189d1ef56dSArnaldo Carvalho de Melo btarget = disasm_line__browser(target); 3199d1ef56dSArnaldo Carvalho de Melo 320e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 3219d1ef56dSArnaldo Carvalho de Melo from = bcursor->idx_asm; 322a3f895beSArnaldo Carvalho de Melo to = btarget->idx_asm; 323a3f895beSArnaldo Carvalho de Melo } else { 3249d1ef56dSArnaldo Carvalho de Melo from = (u64)bcursor->idx; 325a3f895beSArnaldo Carvalho de Melo to = (u64)btarget->idx; 326a3f895beSArnaldo Carvalho de Melo } 327a3f895beSArnaldo Carvalho de Melo 32878ce08dfSTaeung Song ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 329c7e7b610SNamhyung Kim __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 330c7e7b610SNamhyung Kim from, to); 3317e63a13aSJin Yao 3327e63a13aSJin Yao if (is_fused(ab, cursor)) { 3337e63a13aSJin Yao ui_browser__mark_fused(browser, 3347e63a13aSJin Yao pcnt_width + 3 + ab->addr_width, 3357e63a13aSJin Yao from - 1, 3367e63a13aSJin Yao to > from ? true : false); 3377e63a13aSJin Yao } 338a3f895beSArnaldo Carvalho de Melo } 339a3f895beSArnaldo Carvalho de Melo 340a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser) 341a3f895beSArnaldo Carvalho de Melo { 342c7e7b610SNamhyung Kim struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 343a3f895beSArnaldo Carvalho de Melo int ret = ui_browser__list_head_refresh(browser); 344f8f4aaeaSAndi Kleen int pcnt_width = annotate_browser__pcnt_width(ab); 345a3f895beSArnaldo Carvalho de Melo 346e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.jump_arrows) 3479d1ef56dSArnaldo Carvalho de Melo annotate_browser__draw_current_jump(browser); 348a3f895beSArnaldo Carvalho de Melo 34983b1f2aaSArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_NORMAL); 350c7e7b610SNamhyung Kim __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); 351a3f895beSArnaldo Carvalho de Melo return ret; 352a3f895beSArnaldo Carvalho de Melo } 353a3f895beSArnaldo Carvalho de Melo 354c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a, 355c7e7b610SNamhyung Kim struct browser_disasm_line *b, int nr_pcnt) 356c7e7b610SNamhyung Kim { 357c7e7b610SNamhyung Kim int i; 358c7e7b610SNamhyung Kim 359c7e7b610SNamhyung Kim for (i = 0; i < nr_pcnt; i++) { 3600c4a5bceSMartin Liška if (a->samples[i].percent == b->samples[i].percent) 361c7e7b610SNamhyung Kim continue; 3620c4a5bceSMartin Liška return a->samples[i].percent < b->samples[i].percent; 363c7e7b610SNamhyung Kim } 364c7e7b610SNamhyung Kim return 0; 365c7e7b610SNamhyung Kim } 366c7e7b610SNamhyung Kim 367c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl, 368c7e7b610SNamhyung Kim int nr_events) 369aca7a94dSNamhyung Kim { 37029ed6e76SArnaldo Carvalho de Melo struct rb_node **p = &root->rb_node; 371aca7a94dSNamhyung Kim struct rb_node *parent = NULL; 372887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *l; 373aca7a94dSNamhyung Kim 374aca7a94dSNamhyung Kim while (*p != NULL) { 375aca7a94dSNamhyung Kim parent = *p; 376887c0066SArnaldo Carvalho de Melo l = rb_entry(parent, struct browser_disasm_line, rb_node); 377c7e7b610SNamhyung Kim 378c7e7b610SNamhyung Kim if (disasm__cmp(bdl, l, nr_events)) 379aca7a94dSNamhyung Kim p = &(*p)->rb_left; 380aca7a94dSNamhyung Kim else 381aca7a94dSNamhyung Kim p = &(*p)->rb_right; 382aca7a94dSNamhyung Kim } 383887c0066SArnaldo Carvalho de Melo rb_link_node(&bdl->rb_node, parent, p); 384887c0066SArnaldo Carvalho de Melo rb_insert_color(&bdl->rb_node, root); 385aca7a94dSNamhyung Kim } 386aca7a94dSNamhyung Kim 38705e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser, 38829ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos, u32 idx) 389aca7a94dSNamhyung Kim { 390aca7a94dSNamhyung Kim unsigned back; 391aca7a94dSNamhyung Kim 39205e8b080SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(&browser->b); 39305e8b080SArnaldo Carvalho de Melo back = browser->b.height / 2; 39405e8b080SArnaldo Carvalho de Melo browser->b.top_idx = browser->b.index = idx; 395aca7a94dSNamhyung Kim 39605e8b080SArnaldo Carvalho de Melo while (browser->b.top_idx != 0 && back != 0) { 39729ed6e76SArnaldo Carvalho de Melo pos = list_entry(pos->node.prev, struct disasm_line, node); 398aca7a94dSNamhyung Kim 39905e8b080SArnaldo Carvalho de Melo if (disasm_line__filter(&browser->b, &pos->node)) 400aca7a94dSNamhyung Kim continue; 401aca7a94dSNamhyung Kim 40205e8b080SArnaldo Carvalho de Melo --browser->b.top_idx; 403aca7a94dSNamhyung Kim --back; 404aca7a94dSNamhyung Kim } 405aca7a94dSNamhyung Kim 40605e8b080SArnaldo Carvalho de Melo browser->b.top = pos; 40705e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = true; 408aca7a94dSNamhyung Kim } 409aca7a94dSNamhyung Kim 410aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser, 411aca7a94dSNamhyung Kim struct rb_node *nd) 412aca7a94dSNamhyung Kim { 413887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos; 41429ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 415a44b45f2SArnaldo Carvalho de Melo u32 idx; 416aca7a94dSNamhyung Kim 417887c0066SArnaldo Carvalho de Melo bpos = rb_entry(nd, struct browser_disasm_line, rb_node); 418887c0066SArnaldo Carvalho de Melo pos = ((struct disasm_line *)bpos) - 1; 419a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx; 420e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 421a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx_asm; 422a44b45f2SArnaldo Carvalho de Melo annotate_browser__set_top(browser, pos, idx); 423aca7a94dSNamhyung Kim browser->curr_hot = nd; 424aca7a94dSNamhyung Kim } 425aca7a94dSNamhyung Kim 426aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser, 427db8fd07aSNamhyung Kim struct perf_evsel *evsel) 428aca7a94dSNamhyung Kim { 429aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 430aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 431aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 432e64aa75bSNamhyung Kim struct disasm_line *pos, *next; 433e64aa75bSNamhyung Kim s64 len = symbol__size(sym); 434aca7a94dSNamhyung Kim 435aca7a94dSNamhyung Kim browser->entries = RB_ROOT; 436aca7a94dSNamhyung Kim 437aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 438aca7a94dSNamhyung Kim 439aca7a94dSNamhyung Kim list_for_each_entry(pos, ¬es->src->source, node) { 440887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos = disasm_line__browser(pos); 441e64aa75bSNamhyung Kim const char *path = NULL; 442c7e7b610SNamhyung Kim double max_percent = 0.0; 443c7e7b610SNamhyung Kim int i; 444e64aa75bSNamhyung Kim 445e64aa75bSNamhyung Kim if (pos->offset == -1) { 446e64aa75bSNamhyung Kim RB_CLEAR_NODE(&bpos->rb_node); 447e64aa75bSNamhyung Kim continue; 448e64aa75bSNamhyung Kim } 449e64aa75bSNamhyung Kim 450e64aa75bSNamhyung Kim next = disasm__get_next_ip_line(¬es->src->source, pos); 451c7e7b610SNamhyung Kim 452c7e7b610SNamhyung Kim for (i = 0; i < browser->nr_events; i++) { 453*896bccd3STaeung Song struct sym_hist_entry sample; 4540c4a5bceSMartin Liška 4550c4a5bceSMartin Liška bpos->samples[i].percent = disasm__calc_percent(notes, 456c7e7b610SNamhyung Kim evsel->idx + i, 457c7e7b610SNamhyung Kim pos->offset, 458c7e7b610SNamhyung Kim next ? next->offset : len, 459*896bccd3STaeung Song &path, &sample); 460*896bccd3STaeung Song bpos->samples[i].nr = sample.nr_samples; 461e64aa75bSNamhyung Kim 4620c4a5bceSMartin Liška if (max_percent < bpos->samples[i].percent) 4630c4a5bceSMartin Liška max_percent = bpos->samples[i].percent; 464c7e7b610SNamhyung Kim } 465c7e7b610SNamhyung Kim 46630e863bbSAndi Kleen if (max_percent < 0.01 && pos->ipc == 0) { 467887c0066SArnaldo Carvalho de Melo RB_CLEAR_NODE(&bpos->rb_node); 468aca7a94dSNamhyung Kim continue; 469aca7a94dSNamhyung Kim } 470c7e7b610SNamhyung Kim disasm_rb_tree__insert(&browser->entries, bpos, 471c7e7b610SNamhyung Kim browser->nr_events); 472aca7a94dSNamhyung Kim } 473aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 474aca7a94dSNamhyung Kim 475aca7a94dSNamhyung Kim browser->curr_hot = rb_last(&browser->entries); 476aca7a94dSNamhyung Kim } 477aca7a94dSNamhyung Kim 478aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser) 479aca7a94dSNamhyung Kim { 48029ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 481887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bdl; 482aca7a94dSNamhyung Kim off_t offset = browser->b.index - browser->b.top_idx; 483aca7a94dSNamhyung Kim 484aca7a94dSNamhyung Kim browser->b.seek(&browser->b, offset, SEEK_CUR); 48529ed6e76SArnaldo Carvalho de Melo dl = list_entry(browser->b.top, struct disasm_line, node); 486887c0066SArnaldo Carvalho de Melo bdl = disasm_line__browser(dl); 487aca7a94dSNamhyung Kim 488e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 489887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < offset) 490887c0066SArnaldo Carvalho de Melo offset = bdl->idx; 491aca7a94dSNamhyung Kim 492aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_entries; 493e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = false; 494aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 495887c0066SArnaldo Carvalho de Melo browser->b.top_idx = bdl->idx - offset; 496887c0066SArnaldo Carvalho de Melo browser->b.index = bdl->idx; 497aca7a94dSNamhyung Kim } else { 498887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < 0) { 499aca7a94dSNamhyung Kim ui_helpline__puts("Only available for assembly lines."); 500aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 501aca7a94dSNamhyung Kim return false; 502aca7a94dSNamhyung Kim } 503aca7a94dSNamhyung Kim 504887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < offset) 505887c0066SArnaldo Carvalho de Melo offset = bdl->idx_asm; 506aca7a94dSNamhyung Kim 507aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_asm_entries; 508e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = true; 509aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 510887c0066SArnaldo Carvalho de Melo browser->b.top_idx = bdl->idx_asm - offset; 511887c0066SArnaldo Carvalho de Melo browser->b.index = bdl->idx_asm; 512aca7a94dSNamhyung Kim } 513aca7a94dSNamhyung Kim 514aca7a94dSNamhyung Kim return true; 515aca7a94dSNamhyung Kim } 516aca7a94dSNamhyung Kim 517e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser) 518e9823b21SArnaldo Carvalho de Melo { 519e9823b21SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 520e9823b21SArnaldo Carvalho de Melo browser->b.nr_entries = browser->nr_asm_entries; 521e9823b21SArnaldo Carvalho de Melo } 522e9823b21SArnaldo Carvalho de Melo 52334f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 52434f77abcSAdrian Hunter 52534f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title, 52634f77abcSAdrian Hunter size_t sz) 52734f77abcSAdrian Hunter { 52834f77abcSAdrian Hunter return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); 52934f77abcSAdrian Hunter } 53034f77abcSAdrian Hunter 531db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser, 532db8fd07aSNamhyung Kim struct perf_evsel *evsel, 5339783adf7SNamhyung Kim struct hist_browser_timer *hbt) 534aca7a94dSNamhyung Kim { 535aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 536657bcaf5SArnaldo Carvalho de Melo struct disasm_line *dl = browser->selection; 537aca7a94dSNamhyung Kim struct annotation *notes; 5381179e11bSAdrian Hunter struct addr_map_symbol target = { 5391179e11bSAdrian Hunter .map = ms->map, 5401d5077bdSAdrian Hunter .addr = map__objdump_2mem(ms->map, dl->ops.target.addr), 5411179e11bSAdrian Hunter }; 54234f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 543aca7a94dSNamhyung Kim 54475b49202SArnaldo Carvalho de Melo if (!ins__is_call(&dl->ins)) 545aca7a94dSNamhyung Kim return false; 546aca7a94dSNamhyung Kim 547be39db9fSArnaldo Carvalho de Melo if (map_groups__find_ams(&target) || 5481d5077bdSAdrian Hunter map__rip_2objdump(target.map, target.map->map_ip(target.map, 5491d5077bdSAdrian Hunter target.addr)) != 5501d5077bdSAdrian Hunter dl->ops.target.addr) { 551aca7a94dSNamhyung Kim ui_helpline__puts("The called function was not found."); 552aca7a94dSNamhyung Kim return true; 553aca7a94dSNamhyung Kim } 554aca7a94dSNamhyung Kim 5551179e11bSAdrian Hunter notes = symbol__annotation(target.sym); 556aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 557aca7a94dSNamhyung Kim 5581179e11bSAdrian Hunter if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) { 559aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 560aca7a94dSNamhyung Kim ui__warning("Not enough memory for annotating '%s' symbol!\n", 5611179e11bSAdrian Hunter target.sym->name); 562aca7a94dSNamhyung Kim return true; 563aca7a94dSNamhyung Kim } 564aca7a94dSNamhyung Kim 565aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 5661179e11bSAdrian Hunter symbol__tui_annotate(target.sym, target.map, evsel, hbt); 5671179e11bSAdrian Hunter sym_title(ms->sym, ms->map, title, sizeof(title)); 56834f77abcSAdrian Hunter ui_browser__show_title(&browser->b, title); 569aca7a94dSNamhyung Kim return true; 570aca7a94dSNamhyung Kim } 571aca7a94dSNamhyung Kim 57229ed6e76SArnaldo Carvalho de Melo static 57329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 574aca7a94dSNamhyung Kim s64 offset, s64 *idx) 575aca7a94dSNamhyung Kim { 576aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 577aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 578aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 57929ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 580aca7a94dSNamhyung Kim 581aca7a94dSNamhyung Kim *idx = 0; 582aca7a94dSNamhyung Kim list_for_each_entry(pos, ¬es->src->source, node) { 583aca7a94dSNamhyung Kim if (pos->offset == offset) 584aca7a94dSNamhyung Kim return pos; 58529ed6e76SArnaldo Carvalho de Melo if (!disasm_line__filter(&browser->b, &pos->node)) 586aca7a94dSNamhyung Kim ++*idx; 587aca7a94dSNamhyung Kim } 588aca7a94dSNamhyung Kim 589aca7a94dSNamhyung Kim return NULL; 590aca7a94dSNamhyung Kim } 591aca7a94dSNamhyung Kim 592aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser) 593aca7a94dSNamhyung Kim { 594657bcaf5SArnaldo Carvalho de Melo struct disasm_line *dl = browser->selection; 5955252b1aeSArnaldo Carvalho de Melo u64 offset; 5964f9d0325SArnaldo Carvalho de Melo s64 idx; 597aca7a94dSNamhyung Kim 59875b49202SArnaldo Carvalho de Melo if (!ins__is_jump(&dl->ins)) 599aca7a94dSNamhyung Kim return false; 600aca7a94dSNamhyung Kim 6015252b1aeSArnaldo Carvalho de Melo offset = dl->ops.target.offset; 6025252b1aeSArnaldo Carvalho de Melo dl = annotate_browser__find_offset(browser, offset, &idx); 60329ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 6045252b1aeSArnaldo Carvalho de Melo ui_helpline__printf("Invalid jump offset: %" PRIx64, offset); 605aca7a94dSNamhyung Kim return true; 606aca7a94dSNamhyung Kim } 607aca7a94dSNamhyung Kim 60829ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 609aca7a94dSNamhyung Kim 610aca7a94dSNamhyung Kim return true; 611aca7a94dSNamhyung Kim } 612aca7a94dSNamhyung Kim 61329ed6e76SArnaldo Carvalho de Melo static 61429ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser, 615aca7a94dSNamhyung Kim char *s, s64 *idx) 616aca7a94dSNamhyung Kim { 617aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 618aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 619aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 62029ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos = browser->selection; 621aca7a94dSNamhyung Kim 622aca7a94dSNamhyung Kim *idx = browser->b.index; 623aca7a94dSNamhyung Kim list_for_each_entry_continue(pos, ¬es->src->source, node) { 62429ed6e76SArnaldo Carvalho de Melo if (disasm_line__filter(&browser->b, &pos->node)) 625aca7a94dSNamhyung Kim continue; 626aca7a94dSNamhyung Kim 627aca7a94dSNamhyung Kim ++*idx; 628aca7a94dSNamhyung Kim 629aca7a94dSNamhyung Kim if (pos->line && strstr(pos->line, s) != NULL) 630aca7a94dSNamhyung Kim return pos; 631aca7a94dSNamhyung Kim } 632aca7a94dSNamhyung Kim 633aca7a94dSNamhyung Kim return NULL; 634aca7a94dSNamhyung Kim } 635aca7a94dSNamhyung Kim 636aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser) 637aca7a94dSNamhyung Kim { 63829ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 639aca7a94dSNamhyung Kim s64 idx; 640aca7a94dSNamhyung Kim 64129ed6e76SArnaldo Carvalho de Melo dl = annotate_browser__find_string(browser, browser->search_bf, &idx); 64229ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 643aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 644aca7a94dSNamhyung Kim return false; 645aca7a94dSNamhyung Kim } 646aca7a94dSNamhyung Kim 64729ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 648aca7a94dSNamhyung Kim browser->searching_backwards = false; 649aca7a94dSNamhyung Kim return true; 650aca7a94dSNamhyung Kim } 651aca7a94dSNamhyung Kim 65229ed6e76SArnaldo Carvalho de Melo static 65329ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 654aca7a94dSNamhyung Kim char *s, s64 *idx) 655aca7a94dSNamhyung Kim { 656aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 657aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 658aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 65929ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos = browser->selection; 660aca7a94dSNamhyung Kim 661aca7a94dSNamhyung Kim *idx = browser->b.index; 662aca7a94dSNamhyung Kim list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) { 66329ed6e76SArnaldo Carvalho de Melo if (disasm_line__filter(&browser->b, &pos->node)) 664aca7a94dSNamhyung Kim continue; 665aca7a94dSNamhyung Kim 666aca7a94dSNamhyung Kim --*idx; 667aca7a94dSNamhyung Kim 668aca7a94dSNamhyung Kim if (pos->line && strstr(pos->line, s) != NULL) 669aca7a94dSNamhyung Kim return pos; 670aca7a94dSNamhyung Kim } 671aca7a94dSNamhyung Kim 672aca7a94dSNamhyung Kim return NULL; 673aca7a94dSNamhyung Kim } 674aca7a94dSNamhyung Kim 675aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser) 676aca7a94dSNamhyung Kim { 67729ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 678aca7a94dSNamhyung Kim s64 idx; 679aca7a94dSNamhyung Kim 68029ed6e76SArnaldo Carvalho de Melo dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 68129ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 682aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 683aca7a94dSNamhyung Kim return false; 684aca7a94dSNamhyung Kim } 685aca7a94dSNamhyung Kim 68629ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 687aca7a94dSNamhyung Kim browser->searching_backwards = true; 688aca7a94dSNamhyung Kim return true; 689aca7a94dSNamhyung Kim } 690aca7a94dSNamhyung Kim 691aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser, 692aca7a94dSNamhyung Kim int delay_secs) 693aca7a94dSNamhyung Kim { 694aca7a94dSNamhyung Kim if (ui_browser__input_window("Search", "String: ", browser->search_bf, 695aca7a94dSNamhyung Kim "ENTER: OK, ESC: Cancel", 696aca7a94dSNamhyung Kim delay_secs * 2) != K_ENTER || 697aca7a94dSNamhyung Kim !*browser->search_bf) 698aca7a94dSNamhyung Kim return false; 699aca7a94dSNamhyung Kim 700aca7a94dSNamhyung Kim return true; 701aca7a94dSNamhyung Kim } 702aca7a94dSNamhyung Kim 703aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) 704aca7a94dSNamhyung Kim { 705aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 706aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 707aca7a94dSNamhyung Kim 708aca7a94dSNamhyung Kim return false; 709aca7a94dSNamhyung Kim } 710aca7a94dSNamhyung Kim 711aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser, 712aca7a94dSNamhyung Kim int delay_secs) 713aca7a94dSNamhyung Kim { 714aca7a94dSNamhyung Kim if (!*browser->search_bf) 715aca7a94dSNamhyung Kim return annotate_browser__search(browser, delay_secs); 716aca7a94dSNamhyung Kim 717aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 718aca7a94dSNamhyung Kim } 719aca7a94dSNamhyung Kim 720aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser, 721aca7a94dSNamhyung Kim int delay_secs) 722aca7a94dSNamhyung Kim { 723aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 724aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 725aca7a94dSNamhyung Kim 726aca7a94dSNamhyung Kim return false; 727aca7a94dSNamhyung Kim } 728aca7a94dSNamhyung Kim 729aca7a94dSNamhyung Kim static 730aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, 731aca7a94dSNamhyung Kim int delay_secs) 732aca7a94dSNamhyung Kim { 733aca7a94dSNamhyung Kim if (!*browser->search_bf) 734aca7a94dSNamhyung Kim return annotate_browser__search_reverse(browser, delay_secs); 735aca7a94dSNamhyung Kim 736aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 737aca7a94dSNamhyung Kim } 738aca7a94dSNamhyung Kim 739e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser) 740e9823b21SArnaldo Carvalho de Melo { 741e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.use_offset) 742e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->min_addr_width; 743e9823b21SArnaldo Carvalho de Melo else 744e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->max_addr_width; 745e9823b21SArnaldo Carvalho de Melo 746e9823b21SArnaldo Carvalho de Melo browser->addr_width = browser->target_width; 747e9823b21SArnaldo Carvalho de Melo 748e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.show_nr_jumps) 749e9823b21SArnaldo Carvalho de Melo browser->addr_width += browser->jumps_width + 1; 750e9823b21SArnaldo Carvalho de Melo } 751e9823b21SArnaldo Carvalho de Melo 752db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser, 753db8fd07aSNamhyung Kim struct perf_evsel *evsel, 7549783adf7SNamhyung Kim struct hist_browser_timer *hbt) 755aca7a94dSNamhyung Kim { 756aca7a94dSNamhyung Kim struct rb_node *nd = NULL; 75705e8b080SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv; 758aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 75954e7a4e8SArnaldo Carvalho de Melo const char *help = "Press 'h' for help on key bindings"; 7609783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 761aca7a94dSNamhyung Kim int key; 76234f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 763aca7a94dSNamhyung Kim 76434f77abcSAdrian Hunter sym_title(sym, ms->map, title, sizeof(title)); 76534f77abcSAdrian Hunter if (ui_browser__show(&browser->b, title, help) < 0) 766aca7a94dSNamhyung Kim return -1; 767aca7a94dSNamhyung Kim 768db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 769aca7a94dSNamhyung Kim 77005e8b080SArnaldo Carvalho de Melo if (browser->curr_hot) { 77105e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, browser->curr_hot); 77205e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = false; 773aca7a94dSNamhyung Kim } 774aca7a94dSNamhyung Kim 77505e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 776aca7a94dSNamhyung Kim 777aca7a94dSNamhyung Kim while (1) { 77805e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 779aca7a94dSNamhyung Kim 780aca7a94dSNamhyung Kim if (delay_secs != 0) { 781db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 782aca7a94dSNamhyung Kim /* 783aca7a94dSNamhyung Kim * Current line focus got out of the list of most active 784aca7a94dSNamhyung Kim * lines, NULL it so that if TAB|UNTAB is pressed, we 785aca7a94dSNamhyung Kim * move to curr_hot (current hottest line). 786aca7a94dSNamhyung Kim */ 787aca7a94dSNamhyung Kim if (nd != NULL && RB_EMPTY_NODE(nd)) 788aca7a94dSNamhyung Kim nd = NULL; 789aca7a94dSNamhyung Kim } 790aca7a94dSNamhyung Kim 791aca7a94dSNamhyung Kim switch (key) { 792aca7a94dSNamhyung Kim case K_TIMER: 7939783adf7SNamhyung Kim if (hbt) 7949783adf7SNamhyung Kim hbt->timer(hbt->arg); 795aca7a94dSNamhyung Kim 796aca7a94dSNamhyung Kim if (delay_secs != 0) 797db8fd07aSNamhyung Kim symbol__annotate_decay_histogram(sym, evsel->idx); 798aca7a94dSNamhyung Kim continue; 799aca7a94dSNamhyung Kim case K_TAB: 800aca7a94dSNamhyung Kim if (nd != NULL) { 801aca7a94dSNamhyung Kim nd = rb_prev(nd); 802aca7a94dSNamhyung Kim if (nd == NULL) 80305e8b080SArnaldo Carvalho de Melo nd = rb_last(&browser->entries); 804aca7a94dSNamhyung Kim } else 80505e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 806aca7a94dSNamhyung Kim break; 807aca7a94dSNamhyung Kim case K_UNTAB: 808d4913cbdSMarkus Trippelsdorf if (nd != NULL) { 809aca7a94dSNamhyung Kim nd = rb_next(nd); 810aca7a94dSNamhyung Kim if (nd == NULL) 81105e8b080SArnaldo Carvalho de Melo nd = rb_first(&browser->entries); 812d4913cbdSMarkus Trippelsdorf } else 81305e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 814aca7a94dSNamhyung Kim break; 81554e7a4e8SArnaldo Carvalho de Melo case K_F1: 816aca7a94dSNamhyung Kim case 'h': 81705e8b080SArnaldo Carvalho de Melo ui_browser__help_window(&browser->b, 81854e7a4e8SArnaldo Carvalho de Melo "UP/DOWN/PGUP\n" 81954e7a4e8SArnaldo Carvalho de Melo "PGDN/SPACE Navigate\n" 82054e7a4e8SArnaldo Carvalho de Melo "q/ESC/CTRL+C Exit\n\n" 8217727a925SArnaldo Carvalho de Melo "ENTER Go to target\n" 8227727a925SArnaldo Carvalho de Melo "ESC Exit\n" 823107baecaSArnaldo Carvalho de Melo "H Cycle thru hottest instructions\n" 82454e7a4e8SArnaldo Carvalho de Melo "j Toggle showing jump to target arrows\n" 82554e7a4e8SArnaldo Carvalho de Melo "J Toggle showing number of jump sources on targets\n" 82654e7a4e8SArnaldo Carvalho de Melo "n Search next string\n" 82754e7a4e8SArnaldo Carvalho de Melo "o Toggle disassembler output/simplified view\n" 82854e7a4e8SArnaldo Carvalho de Melo "s Toggle source code view\n" 8290c4a5bceSMartin Liška "t Toggle total period view\n" 83054e7a4e8SArnaldo Carvalho de Melo "/ Search string\n" 831e592488cSAndi Kleen "k Toggle line numbers\n" 83279ee47faSFeng Tang "r Run available scripts\n" 833fcd9fef9SArnaldo Carvalho de Melo "? Search string backwards\n"); 83454e7a4e8SArnaldo Carvalho de Melo continue; 83579ee47faSFeng Tang case 'r': 83679ee47faSFeng Tang { 83779ee47faSFeng Tang script_browse(NULL); 83879ee47faSFeng Tang continue; 83979ee47faSFeng Tang } 840e592488cSAndi Kleen case 'k': 841e592488cSAndi Kleen annotate_browser__opts.show_linenr = 842e592488cSAndi Kleen !annotate_browser__opts.show_linenr; 843e592488cSAndi Kleen break; 84454e7a4e8SArnaldo Carvalho de Melo case 'H': 84505e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 846aca7a94dSNamhyung Kim break; 847aca7a94dSNamhyung Kim case 's': 84805e8b080SArnaldo Carvalho de Melo if (annotate_browser__toggle_source(browser)) 849aca7a94dSNamhyung Kim ui_helpline__puts(help); 850aca7a94dSNamhyung Kim continue; 851aca7a94dSNamhyung Kim case 'o': 852e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset; 85305e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 854aca7a94dSNamhyung Kim continue; 8559d1ef56dSArnaldo Carvalho de Melo case 'j': 856e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows; 8579d1ef56dSArnaldo Carvalho de Melo continue; 8582402e4a9SArnaldo Carvalho de Melo case 'J': 859e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps; 86005e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 861e9823b21SArnaldo Carvalho de Melo continue; 862aca7a94dSNamhyung Kim case '/': 86305e8b080SArnaldo Carvalho de Melo if (annotate_browser__search(browser, delay_secs)) { 864aca7a94dSNamhyung Kim show_help: 865aca7a94dSNamhyung Kim ui_helpline__puts(help); 866aca7a94dSNamhyung Kim } 867aca7a94dSNamhyung Kim continue; 868aca7a94dSNamhyung Kim case 'n': 86905e8b080SArnaldo Carvalho de Melo if (browser->searching_backwards ? 87005e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search_reverse(browser, delay_secs) : 87105e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search(browser, delay_secs)) 872aca7a94dSNamhyung Kim goto show_help; 873aca7a94dSNamhyung Kim continue; 874aca7a94dSNamhyung Kim case '?': 87505e8b080SArnaldo Carvalho de Melo if (annotate_browser__search_reverse(browser, delay_secs)) 876aca7a94dSNamhyung Kim goto show_help; 877aca7a94dSNamhyung Kim continue; 878e9823b21SArnaldo Carvalho de Melo case 'D': { 879e9823b21SArnaldo Carvalho de Melo static int seq; 880e9823b21SArnaldo Carvalho de Melo ui_helpline__pop(); 881e9823b21SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d", 88205e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 88305e8b080SArnaldo Carvalho de Melo browser->b.height, 88405e8b080SArnaldo Carvalho de Melo browser->b.index, 88505e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 88605e8b080SArnaldo Carvalho de Melo browser->nr_asm_entries); 887e9823b21SArnaldo Carvalho de Melo } 888e9823b21SArnaldo Carvalho de Melo continue; 889aca7a94dSNamhyung Kim case K_ENTER: 890aca7a94dSNamhyung Kim case K_RIGHT: 89105e8b080SArnaldo Carvalho de Melo if (browser->selection == NULL) 892aca7a94dSNamhyung Kim ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 89305e8b080SArnaldo Carvalho de Melo else if (browser->selection->offset == -1) 894aca7a94dSNamhyung Kim ui_helpline__puts("Actions are only available for assembly lines."); 89575b49202SArnaldo Carvalho de Melo else if (!browser->selection->ins.ops) 896c4cceae3SArnaldo Carvalho de Melo goto show_sup_ins; 89775b49202SArnaldo Carvalho de Melo else if (ins__is_ret(&browser->selection->ins)) 898c4cceae3SArnaldo Carvalho de Melo goto out; 8996ef94929SNaveen N. Rao else if (!(annotate_browser__jump(browser) || 900db8fd07aSNamhyung Kim annotate_browser__callq(browser, evsel, hbt))) { 901c4cceae3SArnaldo Carvalho de Melo show_sup_ins: 9026ef94929SNaveen N. Rao ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 903c4cceae3SArnaldo Carvalho de Melo } 904aca7a94dSNamhyung Kim continue; 9050c4a5bceSMartin Liška case 't': 9060c4a5bceSMartin Liška annotate_browser__opts.show_total_period = 9070c4a5bceSMartin Liška !annotate_browser__opts.show_total_period; 9080c4a5bceSMartin Liška annotate_browser__update_addr_width(browser); 9090c4a5bceSMartin Liška continue; 910aca7a94dSNamhyung Kim case K_LEFT: 911aca7a94dSNamhyung Kim case K_ESC: 912aca7a94dSNamhyung Kim case 'q': 913aca7a94dSNamhyung Kim case CTRL('c'): 914aca7a94dSNamhyung Kim goto out; 915aca7a94dSNamhyung Kim default: 916aca7a94dSNamhyung Kim continue; 917aca7a94dSNamhyung Kim } 918aca7a94dSNamhyung Kim 919aca7a94dSNamhyung Kim if (nd != NULL) 92005e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, nd); 921aca7a94dSNamhyung Kim } 922aca7a94dSNamhyung Kim out: 92305e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 924aca7a94dSNamhyung Kim return key; 925aca7a94dSNamhyung Kim } 926aca7a94dSNamhyung Kim 927d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, 928d5dbc518SArnaldo Carvalho de Melo struct hist_browser_timer *hbt) 929d5dbc518SArnaldo Carvalho de Melo { 9300c4a5bceSMartin Liška /* Set default value for show_total_period. */ 9310c4a5bceSMartin Liška annotate_browser__opts.show_total_period = 9320c4a5bceSMartin Liška symbol_conf.show_total_period; 9330c4a5bceSMartin Liška 934d5dbc518SArnaldo Carvalho de Melo return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); 935d5dbc518SArnaldo Carvalho de Melo } 936d5dbc518SArnaldo Carvalho de Melo 937db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 9389783adf7SNamhyung Kim struct hist_browser_timer *hbt) 939aca7a94dSNamhyung Kim { 940ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 941ed426915SNamhyung Kim SLang_reset_tty(); 942ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 943ed426915SNamhyung Kim 944d5dbc518SArnaldo Carvalho de Melo return map_symbol__tui_annotate(&he->ms, evsel, hbt); 945aca7a94dSNamhyung Kim } 946aca7a94dSNamhyung Kim 94730e863bbSAndi Kleen 94830e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end) 94930e863bbSAndi Kleen { 95030e863bbSAndi Kleen unsigned n_insn = 0; 95130e863bbSAndi Kleen u64 offset; 95230e863bbSAndi Kleen 95330e863bbSAndi Kleen for (offset = start; offset <= end; offset++) { 95430e863bbSAndi Kleen if (browser->offsets[offset]) 95530e863bbSAndi Kleen n_insn++; 95630e863bbSAndi Kleen } 95730e863bbSAndi Kleen return n_insn; 95830e863bbSAndi Kleen } 95930e863bbSAndi Kleen 96030e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end, 96130e863bbSAndi Kleen struct cyc_hist *ch) 96230e863bbSAndi Kleen { 96330e863bbSAndi Kleen unsigned n_insn; 96430e863bbSAndi Kleen u64 offset; 96530e863bbSAndi Kleen 96630e863bbSAndi Kleen n_insn = count_insn(browser, start, end); 96730e863bbSAndi Kleen if (n_insn && ch->num && ch->cycles) { 96830e863bbSAndi Kleen float ipc = n_insn / ((double)ch->cycles / (double)ch->num); 96930e863bbSAndi Kleen 97030e863bbSAndi Kleen /* Hide data when there are too many overlaps. */ 97130e863bbSAndi Kleen if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2) 97230e863bbSAndi Kleen return; 97330e863bbSAndi Kleen 97430e863bbSAndi Kleen for (offset = start; offset <= end; offset++) { 97530e863bbSAndi Kleen struct disasm_line *dl = browser->offsets[offset]; 97630e863bbSAndi Kleen 97730e863bbSAndi Kleen if (dl) 97830e863bbSAndi Kleen dl->ipc = ipc; 97930e863bbSAndi Kleen } 98030e863bbSAndi Kleen } 98130e863bbSAndi Kleen } 98230e863bbSAndi Kleen 98330e863bbSAndi Kleen /* 98430e863bbSAndi Kleen * This should probably be in util/annotate.c to share with the tty 98530e863bbSAndi Kleen * annotate, but right now we need the per byte offsets arrays, 98630e863bbSAndi Kleen * which are only here. 98730e863bbSAndi Kleen */ 98830e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size, 98930e863bbSAndi Kleen struct symbol *sym) 99030e863bbSAndi Kleen { 99130e863bbSAndi Kleen u64 offset; 99230e863bbSAndi Kleen struct annotation *notes = symbol__annotation(sym); 99330e863bbSAndi Kleen 99430e863bbSAndi Kleen if (!notes->src || !notes->src->cycles_hist) 99530e863bbSAndi Kleen return; 99630e863bbSAndi Kleen 99730e863bbSAndi Kleen pthread_mutex_lock(¬es->lock); 99830e863bbSAndi Kleen for (offset = 0; offset < size; ++offset) { 99930e863bbSAndi Kleen struct cyc_hist *ch; 100030e863bbSAndi Kleen 100130e863bbSAndi Kleen ch = ¬es->src->cycles_hist[offset]; 100230e863bbSAndi Kleen if (ch && ch->cycles) { 100330e863bbSAndi Kleen struct disasm_line *dl; 100430e863bbSAndi Kleen 100530e863bbSAndi Kleen if (ch->have_start) 100630e863bbSAndi Kleen count_and_fill(browser, ch->start, offset, ch); 100730e863bbSAndi Kleen dl = browser->offsets[offset]; 100830e863bbSAndi Kleen if (dl && ch->num_aggr) 100930e863bbSAndi Kleen dl->cycles = ch->cycles_aggr / ch->num_aggr; 101030e863bbSAndi Kleen browser->have_cycles = true; 101130e863bbSAndi Kleen } 101230e863bbSAndi Kleen } 101330e863bbSAndi Kleen pthread_mutex_unlock(¬es->lock); 101430e863bbSAndi Kleen } 101530e863bbSAndi Kleen 1016b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 1017b793a401SArnaldo Carvalho de Melo size_t size) 1018b793a401SArnaldo Carvalho de Melo { 1019b793a401SArnaldo Carvalho de Melo u64 offset; 102032ae1efdSNamhyung Kim struct map_symbol *ms = browser->b.priv; 102132ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 102232ae1efdSNamhyung Kim 102332ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 102432ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 102532ae1efdSNamhyung Kim return; 1026b793a401SArnaldo Carvalho de Melo 1027b793a401SArnaldo Carvalho de Melo for (offset = 0; offset < size; ++offset) { 1028b793a401SArnaldo Carvalho de Melo struct disasm_line *dl = browser->offsets[offset], *dlt; 1029b793a401SArnaldo Carvalho de Melo struct browser_disasm_line *bdlt; 1030b793a401SArnaldo Carvalho de Melo 1031865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(dl, sym)) 1032b793a401SArnaldo Carvalho de Melo continue; 1033b793a401SArnaldo Carvalho de Melo 103444d1a3edSArnaldo Carvalho de Melo dlt = browser->offsets[dl->ops.target.offset]; 10359481ede9SArnaldo Carvalho de Melo /* 10369481ede9SArnaldo Carvalho de Melo * FIXME: Oops, no jump target? Buggy disassembler? Or do we 10379481ede9SArnaldo Carvalho de Melo * have to adjust to the previous offset? 10389481ede9SArnaldo Carvalho de Melo */ 10399481ede9SArnaldo Carvalho de Melo if (dlt == NULL) 10409481ede9SArnaldo Carvalho de Melo continue; 10419481ede9SArnaldo Carvalho de Melo 1042b793a401SArnaldo Carvalho de Melo bdlt = disasm_line__browser(dlt); 10432402e4a9SArnaldo Carvalho de Melo if (++bdlt->jump_sources > browser->max_jump_sources) 10442402e4a9SArnaldo Carvalho de Melo browser->max_jump_sources = bdlt->jump_sources; 10452402e4a9SArnaldo Carvalho de Melo 10462402e4a9SArnaldo Carvalho de Melo ++browser->nr_jumps; 1047b793a401SArnaldo Carvalho de Melo } 1048b793a401SArnaldo Carvalho de Melo } 1049b793a401SArnaldo Carvalho de Melo 10502402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n) 10512402e4a9SArnaldo Carvalho de Melo { 10522402e4a9SArnaldo Carvalho de Melo if (n >= 100) 10532402e4a9SArnaldo Carvalho de Melo return 5; 10542402e4a9SArnaldo Carvalho de Melo if (n / 10) 10552402e4a9SArnaldo Carvalho de Melo return 2; 10562402e4a9SArnaldo Carvalho de Melo return 1; 10572402e4a9SArnaldo Carvalho de Melo } 10582402e4a9SArnaldo Carvalho de Melo 1059db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map, 1060db8fd07aSNamhyung Kim struct perf_evsel *evsel, 10619783adf7SNamhyung Kim struct hist_browser_timer *hbt) 1062aca7a94dSNamhyung Kim { 106329ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos, *n; 1064aca7a94dSNamhyung Kim struct annotation *notes; 1065c0a58fb2SSamuel Liao size_t size; 1066aca7a94dSNamhyung Kim struct map_symbol ms = { 1067aca7a94dSNamhyung Kim .map = map, 1068aca7a94dSNamhyung Kim .sym = sym, 1069aca7a94dSNamhyung Kim }; 1070aca7a94dSNamhyung Kim struct annotate_browser browser = { 1071aca7a94dSNamhyung Kim .b = { 1072a3f895beSArnaldo Carvalho de Melo .refresh = annotate_browser__refresh, 1073aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 1074aca7a94dSNamhyung Kim .write = annotate_browser__write, 107529ed6e76SArnaldo Carvalho de Melo .filter = disasm_line__filter, 1076aca7a94dSNamhyung Kim .priv = &ms, 1077aca7a94dSNamhyung Kim .use_navkeypressed = true, 1078aca7a94dSNamhyung Kim }, 1079aca7a94dSNamhyung Kim }; 1080ee51d851SArnaldo Carvalho de Melo int ret = -1, err; 1081c7e7b610SNamhyung Kim int nr_pcnt = 1; 1082c7e7b610SNamhyung Kim size_t sizeof_bdl = sizeof(struct browser_disasm_line); 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 1098c7e7b610SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1099c7e7b610SNamhyung Kim nr_pcnt = evsel->nr_members; 11000c4a5bceSMartin Liška sizeof_bdl += sizeof(struct disasm_line_samples) * 11010c4a5bceSMartin Liška (nr_pcnt - 1); 1102c7e7b610SNamhyung Kim } 1103c7e7b610SNamhyung Kim 1104dcaa3948SJin Yao err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 110569fb09f6SJin Yao sizeof_bdl, &browser.arch, 110669fb09f6SJin Yao perf_evsel__env_cpuid(evsel)); 1107ee51d851SArnaldo Carvalho de Melo if (err) { 1108ee51d851SArnaldo Carvalho de Melo char msg[BUFSIZ]; 1109ee51d851SArnaldo Carvalho de Melo symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); 1110ee51d851SArnaldo Carvalho de Melo ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 1111b793a401SArnaldo Carvalho de Melo goto out_free_offsets; 1112aca7a94dSNamhyung Kim } 1113aca7a94dSNamhyung Kim 11147727a925SArnaldo Carvalho de Melo ui_helpline__push("Press ESC to exit"); 1115aca7a94dSNamhyung Kim 1116aca7a94dSNamhyung Kim notes = symbol__annotation(sym); 1117aca7a94dSNamhyung Kim browser.start = map__rip_2objdump(map, sym->start); 1118aca7a94dSNamhyung Kim 1119aca7a94dSNamhyung Kim list_for_each_entry(pos, ¬es->src->source, node) { 1120887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos; 1121aca7a94dSNamhyung Kim size_t line_len = strlen(pos->line); 1122aca7a94dSNamhyung Kim 1123aca7a94dSNamhyung Kim if (browser.b.width < line_len) 1124aca7a94dSNamhyung Kim browser.b.width = line_len; 1125887c0066SArnaldo Carvalho de Melo bpos = disasm_line__browser(pos); 1126887c0066SArnaldo Carvalho de Melo bpos->idx = browser.nr_entries++; 1127b793a401SArnaldo Carvalho de Melo if (pos->offset != -1) { 1128887c0066SArnaldo Carvalho de Melo bpos->idx_asm = browser.nr_asm_entries++; 112997148a97SArnaldo Carvalho de Melo /* 113097148a97SArnaldo Carvalho de Melo * FIXME: short term bandaid to cope with assembly 113197148a97SArnaldo Carvalho de Melo * routines that comes with labels in the same column 113297148a97SArnaldo Carvalho de Melo * as the address in objdump, sigh. 113397148a97SArnaldo Carvalho de Melo * 113497148a97SArnaldo Carvalho de Melo * E.g. copy_user_generic_unrolled 113597148a97SArnaldo Carvalho de Melo */ 113697148a97SArnaldo Carvalho de Melo if (pos->offset < (s64)size) 1137b793a401SArnaldo Carvalho de Melo browser.offsets[pos->offset] = pos; 1138b793a401SArnaldo Carvalho de Melo } else 1139887c0066SArnaldo Carvalho de Melo bpos->idx_asm = -1; 1140aca7a94dSNamhyung Kim } 1141aca7a94dSNamhyung Kim 1142b793a401SArnaldo Carvalho de Melo annotate_browser__mark_jump_targets(&browser, size); 114330e863bbSAndi Kleen annotate__compute_ipc(&browser, size, sym); 1144b793a401SArnaldo Carvalho de Melo 11452402e4a9SArnaldo Carvalho de Melo browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); 114683b1f2aaSArnaldo Carvalho de Melo browser.max_addr_width = hex_width(sym->end); 11472402e4a9SArnaldo Carvalho de Melo browser.jumps_width = width_jumps(browser.max_jump_sources); 1148c7e7b610SNamhyung Kim browser.nr_events = nr_pcnt; 1149aca7a94dSNamhyung Kim browser.b.nr_entries = browser.nr_entries; 1150aca7a94dSNamhyung Kim browser.b.entries = ¬es->src->source, 1151aca7a94dSNamhyung Kim browser.b.width += 18; /* Percentage */ 1152e9823b21SArnaldo Carvalho de Melo 1153e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 1154e9823b21SArnaldo Carvalho de Melo annotate_browser__init_asm_mode(&browser); 1155e9823b21SArnaldo Carvalho de Melo 1156e9823b21SArnaldo Carvalho de Melo annotate_browser__update_addr_width(&browser); 1157e9823b21SArnaldo Carvalho de Melo 1158db8fd07aSNamhyung Kim ret = annotate_browser__run(&browser, evsel, hbt); 1159aca7a94dSNamhyung Kim list_for_each_entry_safe(pos, n, ¬es->src->source, node) { 1160aca7a94dSNamhyung Kim list_del(&pos->node); 116129ed6e76SArnaldo Carvalho de Melo disasm_line__free(pos); 1162aca7a94dSNamhyung Kim } 1163b793a401SArnaldo Carvalho de Melo 1164b793a401SArnaldo Carvalho de Melo out_free_offsets: 1165b793a401SArnaldo Carvalho de Melo free(browser.offsets); 1166aca7a94dSNamhyung Kim return ret; 1167aca7a94dSNamhyung Kim } 1168c323cf04SArnaldo Carvalho de Melo 1169c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \ 1170c323cf04SArnaldo Carvalho de Melo { .name = #n, .value = &annotate_browser__opts.n, } 1171c323cf04SArnaldo Carvalho de Melo 1172c323cf04SArnaldo Carvalho de Melo /* 1173c323cf04SArnaldo Carvalho de Melo * Keep the entries sorted, they are bsearch'ed 1174c323cf04SArnaldo Carvalho de Melo */ 11757c3102b8SArnaldo Carvalho de Melo static struct annotate_config { 1176c323cf04SArnaldo Carvalho de Melo const char *name; 1177c323cf04SArnaldo Carvalho de Melo bool *value; 1178c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = { 1179c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(hide_src_code), 1180c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(jump_arrows), 1181e592488cSAndi Kleen ANNOTATE_CFG(show_linenr), 1182c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(show_nr_jumps), 11830c4a5bceSMartin Liška ANNOTATE_CFG(show_total_period), 118439ff7cdbSNamhyung Kim ANNOTATE_CFG(use_offset), 1185c323cf04SArnaldo Carvalho de Melo }; 1186c323cf04SArnaldo Carvalho de Melo 1187c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG 1188c323cf04SArnaldo Carvalho de Melo 1189c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp) 1190c323cf04SArnaldo Carvalho de Melo { 11917c3102b8SArnaldo Carvalho de Melo const struct annotate_config *cfg = cfgp; 1192c323cf04SArnaldo Carvalho de Melo 1193c323cf04SArnaldo Carvalho de Melo return strcmp(name, cfg->name); 1194c323cf04SArnaldo Carvalho de Melo } 1195c323cf04SArnaldo Carvalho de Melo 11961d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value, 11971d037ca1SIrina Tirdea void *data __maybe_unused) 1198c323cf04SArnaldo Carvalho de Melo { 11997c3102b8SArnaldo Carvalho de Melo struct annotate_config *cfg; 1200c323cf04SArnaldo Carvalho de Melo const char *name; 1201c323cf04SArnaldo Carvalho de Melo 12028e99b6d4SArnaldo Carvalho de Melo if (!strstarts(var, "annotate.")) 1203c323cf04SArnaldo Carvalho de Melo return 0; 1204c323cf04SArnaldo Carvalho de Melo 1205c323cf04SArnaldo Carvalho de Melo name = var + 9; 1206c323cf04SArnaldo Carvalho de Melo cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), 12077c3102b8SArnaldo Carvalho de Melo sizeof(struct annotate_config), annotate_config__cmp); 1208c323cf04SArnaldo Carvalho de Melo 1209c323cf04SArnaldo Carvalho de Melo if (cfg == NULL) 1210f06cff7cSArnaldo Carvalho de Melo ui__warning("%s variable unknown, ignoring...", var); 1211f06cff7cSArnaldo Carvalho de Melo else 1212c323cf04SArnaldo Carvalho de Melo *cfg->value = perf_config_bool(name, value); 1213c323cf04SArnaldo Carvalho de Melo return 0; 1214c323cf04SArnaldo Carvalho de Melo } 1215c323cf04SArnaldo Carvalho de Melo 1216c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void) 1217c323cf04SArnaldo Carvalho de Melo { 1218c323cf04SArnaldo Carvalho de Melo perf_config(annotate__config, NULL); 1219c323cf04SArnaldo Carvalho de Melo } 1220