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 250d957970SJiri Olsa struct browser_line { 26b793a401SArnaldo Carvalho de Melo u32 idx; 27b793a401SArnaldo Carvalho de Melo int idx_asm; 287d5b12f5SArnaldo Carvalho de Melo int jump_sources; 29b793a401SArnaldo Carvalho de Melo }; 30b793a401SArnaldo Carvalho de Melo 3198bc80b0SArnaldo Carvalho de Melo static struct annotation_options annotate_browser__opts = { 32e9823b21SArnaldo Carvalho de Melo .use_offset = true, 33e9823b21SArnaldo Carvalho de Melo .jump_arrows = true, 34e9823b21SArnaldo Carvalho de Melo }; 35e9823b21SArnaldo Carvalho de Melo 36dcaa3948SJin Yao struct arch; 37dcaa3948SJin Yao 38aca7a94dSNamhyung Kim struct annotate_browser { 39aca7a94dSNamhyung Kim struct ui_browser b; 40aca7a94dSNamhyung Kim struct rb_root entries; 41aca7a94dSNamhyung Kim struct rb_node *curr_hot; 427bcbcd58SJiri Olsa struct annotation_line *selection; 43e1b60b5bSJiri Olsa struct annotation_line **offsets; 44dcaa3948SJin Yao struct arch *arch; 45c7e7b610SNamhyung Kim int nr_events; 46aca7a94dSNamhyung Kim u64 start; 47aca7a94dSNamhyung Kim int nr_asm_entries; 48aca7a94dSNamhyung Kim int nr_entries; 492402e4a9SArnaldo Carvalho de Melo int max_jump_sources; 502402e4a9SArnaldo Carvalho de Melo int nr_jumps; 51aca7a94dSNamhyung Kim bool searching_backwards; 5230e863bbSAndi Kleen bool have_cycles; 5383b1f2aaSArnaldo Carvalho de Melo u8 addr_width; 542402e4a9SArnaldo Carvalho de Melo u8 jumps_width; 552402e4a9SArnaldo Carvalho de Melo u8 target_width; 5683b1f2aaSArnaldo Carvalho de Melo u8 min_addr_width; 5783b1f2aaSArnaldo Carvalho de Melo u8 max_addr_width; 58aca7a94dSNamhyung Kim char search_bf[128]; 59aca7a94dSNamhyung Kim }; 60aca7a94dSNamhyung Kim 61a5ef2702SJiri Olsa static inline struct browser_line *browser_line(struct annotation_line *al) 62aca7a94dSNamhyung Kim { 63a5ef2702SJiri Olsa void *ptr = al; 64a5ef2702SJiri Olsa 65a5ef2702SJiri Olsa ptr = container_of(al, struct disasm_line, al); 66a5ef2702SJiri Olsa return ptr - sizeof(struct browser_line); 67aca7a94dSNamhyung Kim } 68aca7a94dSNamhyung Kim 691d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, 701d037ca1SIrina Tirdea void *entry) 71aca7a94dSNamhyung Kim { 72e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 73d5490b96SJiri Olsa struct annotation_line *al = list_entry(entry, struct annotation_line, node); 74d5490b96SJiri Olsa 75d5490b96SJiri Olsa return al->offset == -1; 76aca7a94dSNamhyung Kim } 77aca7a94dSNamhyung Kim 78aca7a94dSNamhyung Kim return false; 79aca7a94dSNamhyung Kim } 80aca7a94dSNamhyung Kim 812402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, 822402e4a9SArnaldo Carvalho de Melo int nr, bool current) 832402e4a9SArnaldo Carvalho de Melo { 842402e4a9SArnaldo Carvalho de Melo if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) 852402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_SELECTED; 862402e4a9SArnaldo Carvalho de Melo if (nr == browser->max_jump_sources) 872402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_TOP; 882402e4a9SArnaldo Carvalho de Melo if (nr > 1) 892402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_MEDIUM; 902402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_NORMAL; 912402e4a9SArnaldo Carvalho de Melo } 922402e4a9SArnaldo Carvalho de Melo 932402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, 942402e4a9SArnaldo Carvalho de Melo int nr, bool current) 952402e4a9SArnaldo Carvalho de Melo { 962402e4a9SArnaldo Carvalho de Melo int color = annotate_browser__jumps_percent_color(browser, nr, current); 972402e4a9SArnaldo Carvalho de Melo return ui_browser__set_color(&browser->b, color); 982402e4a9SArnaldo Carvalho de Melo } 992402e4a9SArnaldo Carvalho de Melo 100f8f4aaeaSAndi Kleen static int annotate_browser__pcnt_width(struct annotate_browser *ab) 101f8f4aaeaSAndi Kleen { 1023861c4a4SArnaldo Carvalho de Melo return (annotate_browser__opts.show_total_period ? 12 : 7) * ab->nr_events; 103bc1e5d60SArnaldo Carvalho de Melo } 104f8f4aaeaSAndi Kleen 105bc1e5d60SArnaldo Carvalho de Melo static int annotate_browser__cycles_width(struct annotate_browser *ab) 106bc1e5d60SArnaldo Carvalho de Melo { 107c426e584SArnaldo Carvalho de Melo return ab->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; 108f8f4aaeaSAndi Kleen } 109f8f4aaeaSAndi Kleen 110a5433b3eSJiri Olsa static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser, 111a5433b3eSJiri Olsa char *bf, size_t size) 112aca7a94dSNamhyung Kim { 11375b49202SArnaldo Carvalho de Melo if (dl->ins.ops && dl->ins.ops->scnprintf) { 11475b49202SArnaldo Carvalho de Melo if (ins__is_jump(&dl->ins)) { 115d5490b96SJiri Olsa bool fwd = dl->ops.target.offset > dl->al.offset; 11651a0d455SArnaldo Carvalho de Melo 11705e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : 11851a0d455SArnaldo Carvalho de Melo SLSMG_UARROW_CHAR); 11951a0d455SArnaldo Carvalho de Melo SLsmg_write_char(' '); 12075b49202SArnaldo Carvalho de Melo } else if (ins__is_call(&dl->ins)) { 12105e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); 12288298f5aSArnaldo Carvalho de Melo SLsmg_write_char(' '); 12375b49202SArnaldo Carvalho de Melo } else if (ins__is_ret(&dl->ins)) { 12405e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); 1254ea08b52SArnaldo Carvalho de Melo SLsmg_write_char(' '); 1266ef94929SNaveen N. Rao } else { 1276ef94929SNaveen N. Rao ui_browser__write_nstring(browser, " ", 2); 1284ea08b52SArnaldo Carvalho de Melo } 1296ef94929SNaveen N. Rao } else { 1306ef94929SNaveen N. Rao ui_browser__write_nstring(browser, " ", 2); 1314ea08b52SArnaldo Carvalho de Melo } 1324ea08b52SArnaldo Carvalho de Melo 133a5433b3eSJiri Olsa disasm_line__scnprintf(dl, bf, size, !annotate_browser__opts.use_offset); 134a5433b3eSJiri Olsa } 135a5433b3eSJiri Olsa 136a5433b3eSJiri Olsa static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 137a5433b3eSJiri Olsa { 138a5433b3eSJiri Olsa struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 139a5433b3eSJiri Olsa struct annotation_line *al = list_entry(entry, struct annotation_line, node); 140a5433b3eSJiri Olsa struct browser_line *bl = browser_line(al); 141a5433b3eSJiri Olsa bool current_entry = ui_browser__is_current_entry(browser, row); 142a5433b3eSJiri Olsa bool change_color = (!annotate_browser__opts.hide_src_code && 143a5433b3eSJiri Olsa (!current_entry || (browser->use_navkeypressed && 144a5433b3eSJiri Olsa !browser->navkeypressed))); 145a5433b3eSJiri Olsa int width = browser->width, printed; 146a5433b3eSJiri Olsa int i, pcnt_width = annotate_browser__pcnt_width(ab), 147a5433b3eSJiri Olsa cycles_width = annotate_browser__cycles_width(ab); 148a5433b3eSJiri Olsa double percent_max = 0.0; 149a5433b3eSJiri Olsa char bf[256]; 150a5433b3eSJiri Olsa bool show_title = false; 151a5433b3eSJiri Olsa 152a5433b3eSJiri Olsa for (i = 0; i < ab->nr_events; i++) { 153a5433b3eSJiri Olsa if (al->samples[i].percent > percent_max) 154a5433b3eSJiri Olsa percent_max = al->samples[i].percent; 155a5433b3eSJiri Olsa } 156a5433b3eSJiri Olsa 157a5433b3eSJiri Olsa if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) { 158a5433b3eSJiri Olsa if (ab->have_cycles) { 159a5433b3eSJiri Olsa if (al->ipc == 0.0 && al->cycles == 0) 160a5433b3eSJiri Olsa show_title = true; 161a5433b3eSJiri Olsa } else 162a5433b3eSJiri Olsa show_title = true; 163a5433b3eSJiri Olsa } 164a5433b3eSJiri Olsa 165a5433b3eSJiri Olsa if (al->offset != -1 && percent_max != 0.0) { 166a5433b3eSJiri Olsa for (i = 0; i < ab->nr_events; i++) { 167a5433b3eSJiri Olsa ui_browser__set_percent_color(browser, 168a5433b3eSJiri Olsa al->samples[i].percent, 169a5433b3eSJiri Olsa current_entry); 170a5433b3eSJiri Olsa if (annotate_browser__opts.show_total_period) { 171a5433b3eSJiri Olsa ui_browser__printf(browser, "%11" PRIu64 " ", 172a5433b3eSJiri Olsa al->samples[i].he.period); 173a5433b3eSJiri Olsa } else if (annotate_browser__opts.show_nr_samples) { 174a5433b3eSJiri Olsa ui_browser__printf(browser, "%6" PRIu64 " ", 175a5433b3eSJiri Olsa al->samples[i].he.nr_samples); 176a5433b3eSJiri Olsa } else { 177a5433b3eSJiri Olsa ui_browser__printf(browser, "%6.2f ", 178a5433b3eSJiri Olsa al->samples[i].percent); 179a5433b3eSJiri Olsa } 180a5433b3eSJiri Olsa } 181a5433b3eSJiri Olsa } else { 182a5433b3eSJiri Olsa ui_browser__set_percent_color(browser, 0, current_entry); 183a5433b3eSJiri Olsa 184a5433b3eSJiri Olsa if (!show_title) 185a5433b3eSJiri Olsa ui_browser__write_nstring(browser, " ", pcnt_width); 186a5433b3eSJiri Olsa else { 187a5433b3eSJiri Olsa ui_browser__printf(browser, "%*s", pcnt_width, 188a5433b3eSJiri Olsa annotate_browser__opts.show_total_period ? "Period" : 189a5433b3eSJiri Olsa annotate_browser__opts.show_nr_samples ? "Samples" : "Percent"); 190a5433b3eSJiri Olsa } 191a5433b3eSJiri Olsa } 192a5433b3eSJiri Olsa if (ab->have_cycles) { 193a5433b3eSJiri Olsa if (al->ipc) 194c426e584SArnaldo Carvalho de Melo ui_browser__printf(browser, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc); 195a5433b3eSJiri Olsa else if (!show_title) 196c426e584SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", ANNOTATION__IPC_WIDTH); 197a5433b3eSJiri Olsa else 198c426e584SArnaldo Carvalho de Melo ui_browser__printf(browser, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); 199a5433b3eSJiri Olsa 200a5433b3eSJiri Olsa if (al->cycles) 201a5433b3eSJiri Olsa ui_browser__printf(browser, "%*" PRIu64 " ", 202c426e584SArnaldo Carvalho de Melo ANNOTATION__CYCLES_WIDTH - 1, al->cycles); 203a5433b3eSJiri Olsa else if (!show_title) 204c426e584SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, " ", ANNOTATION__CYCLES_WIDTH); 205a5433b3eSJiri Olsa else 206c426e584SArnaldo Carvalho de Melo ui_browser__printf(browser, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle"); 207a5433b3eSJiri Olsa } 208a5433b3eSJiri Olsa 209a5433b3eSJiri Olsa SLsmg_write_char(' '); 210a5433b3eSJiri Olsa 211a5433b3eSJiri Olsa /* The scroll bar isn't being used */ 212a5433b3eSJiri Olsa if (!browser->navkeypressed) 213a5433b3eSJiri Olsa width += 1; 214a5433b3eSJiri Olsa 215a5433b3eSJiri Olsa if (!*al->line) 216a5433b3eSJiri Olsa ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); 217a5433b3eSJiri Olsa else if (al->offset == -1) { 218a5433b3eSJiri Olsa if (al->line_nr && annotate_browser__opts.show_linenr) 219a5433b3eSJiri Olsa printed = scnprintf(bf, sizeof(bf), "%-*d ", 220a5433b3eSJiri Olsa ab->addr_width + 1, al->line_nr); 221a5433b3eSJiri Olsa else 222a5433b3eSJiri Olsa printed = scnprintf(bf, sizeof(bf), "%*s ", 223a5433b3eSJiri Olsa ab->addr_width, " "); 224a5433b3eSJiri Olsa ui_browser__write_nstring(browser, bf, printed); 225a5433b3eSJiri Olsa ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1); 226a5433b3eSJiri Olsa } else { 227a5433b3eSJiri Olsa u64 addr = al->offset; 228a5433b3eSJiri Olsa int color = -1; 229a5433b3eSJiri Olsa 230a5433b3eSJiri Olsa if (!annotate_browser__opts.use_offset) 231a5433b3eSJiri Olsa addr += ab->start; 232a5433b3eSJiri Olsa 233a5433b3eSJiri Olsa if (!annotate_browser__opts.use_offset) { 234a5433b3eSJiri Olsa printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); 235a5433b3eSJiri Olsa } else { 236a5433b3eSJiri Olsa if (bl->jump_sources) { 237a5433b3eSJiri Olsa if (annotate_browser__opts.show_nr_jumps) { 238a5433b3eSJiri Olsa int prev; 239a5433b3eSJiri Olsa printed = scnprintf(bf, sizeof(bf), "%*d ", 240a5433b3eSJiri Olsa ab->jumps_width, 241a5433b3eSJiri Olsa bl->jump_sources); 242a5433b3eSJiri Olsa prev = annotate_browser__set_jumps_percent_color(ab, bl->jump_sources, 243a5433b3eSJiri Olsa current_entry); 244a5433b3eSJiri Olsa ui_browser__write_nstring(browser, bf, printed); 245a5433b3eSJiri Olsa ui_browser__set_color(browser, prev); 246a5433b3eSJiri Olsa } 247a5433b3eSJiri Olsa 248a5433b3eSJiri Olsa printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", 249a5433b3eSJiri Olsa ab->target_width, addr); 250a5433b3eSJiri Olsa } else { 251a5433b3eSJiri Olsa printed = scnprintf(bf, sizeof(bf), "%*s ", 252a5433b3eSJiri Olsa ab->addr_width, " "); 253a5433b3eSJiri Olsa } 254a5433b3eSJiri Olsa } 255a5433b3eSJiri Olsa 256a5433b3eSJiri Olsa if (change_color) 257a5433b3eSJiri Olsa color = ui_browser__set_color(browser, HE_COLORSET_ADDR); 258a5433b3eSJiri Olsa ui_browser__write_nstring(browser, bf, printed); 259a5433b3eSJiri Olsa if (change_color) 260a5433b3eSJiri Olsa ui_browser__set_color(browser, color); 261a5433b3eSJiri Olsa 262a5433b3eSJiri Olsa disasm_line__write(disasm_line(al), browser, bf, sizeof(bf)); 263a5433b3eSJiri Olsa 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) 268a5433b3eSJiri Olsa ab->selection = al; 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); 3047bcbcd58SJiri Olsa struct disasm_line *cursor = disasm_line(ab->selection); 305a5ef2702SJiri Olsa struct annotation_line *target; 3060d957970SJiri Olsa struct browser_line *btarget, *bcursor; 30783b1f2aaSArnaldo Carvalho de Melo unsigned int from, to; 30832ae1efdSNamhyung Kim struct map_symbol *ms = ab->b.priv; 30932ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 310f8f4aaeaSAndi Kleen u8 pcnt_width = annotate_browser__pcnt_width(ab); 311*00ea0eb2SArnaldo Carvalho de Melo int width; 31232ae1efdSNamhyung Kim 31332ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 31432ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 31532ae1efdSNamhyung Kim return; 316a3f895beSArnaldo Carvalho de Melo 317865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(cursor, sym)) 318a3f895beSArnaldo Carvalho de Melo return; 319a3f895beSArnaldo Carvalho de Melo 3209c04409dSArnaldo Carvalho de Melo /* 3219c04409dSArnaldo Carvalho de Melo * This first was seen with a gcc function, _cpp_lex_token, that 3229c04409dSArnaldo Carvalho de Melo * has the usual jumps: 3239c04409dSArnaldo Carvalho de Melo * 3249c04409dSArnaldo Carvalho de Melo * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92> 3259c04409dSArnaldo Carvalho de Melo * 3269c04409dSArnaldo Carvalho de Melo * I.e. jumps to a label inside that function (_cpp_lex_token), and 3279c04409dSArnaldo Carvalho de Melo * those works, but also this kind: 3289c04409dSArnaldo Carvalho de Melo * 3299c04409dSArnaldo Carvalho de Melo * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72> 3309c04409dSArnaldo Carvalho de Melo * 3319c04409dSArnaldo Carvalho de Melo * I.e. jumps to another function, outside _cpp_lex_token, which 3329c04409dSArnaldo Carvalho de Melo * are not being correctly handled generating as a side effect references 3339c04409dSArnaldo Carvalho de Melo * to ab->offset[] entries that are set to NULL, so to make this code 3349c04409dSArnaldo Carvalho de Melo * more robust, check that here. 3359c04409dSArnaldo Carvalho de Melo * 3369c04409dSArnaldo Carvalho de Melo * A proper fix for will be put in place, looking at the function 3379c04409dSArnaldo Carvalho de Melo * name right after the '<' token and probably treating this like a 3389c04409dSArnaldo Carvalho de Melo * 'call' instruction. 3399c04409dSArnaldo Carvalho de Melo */ 340a5ef2702SJiri Olsa target = ab->offsets[cursor->ops.target.offset]; 3419c04409dSArnaldo Carvalho de Melo if (target == NULL) { 3429c04409dSArnaldo Carvalho de Melo ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n", 3439c04409dSArnaldo Carvalho de Melo cursor->ops.target.offset); 3449c04409dSArnaldo Carvalho de Melo return; 3459c04409dSArnaldo Carvalho de Melo } 3469d1ef56dSArnaldo Carvalho de Melo 347a5ef2702SJiri Olsa bcursor = browser_line(&cursor->al); 348daf25d43SJiri Olsa btarget = browser_line(target); 3499d1ef56dSArnaldo Carvalho de Melo 350e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 3519d1ef56dSArnaldo Carvalho de Melo from = bcursor->idx_asm; 352a3f895beSArnaldo Carvalho de Melo to = btarget->idx_asm; 353a3f895beSArnaldo Carvalho de Melo } else { 3549d1ef56dSArnaldo Carvalho de Melo from = (u64)bcursor->idx; 355a3f895beSArnaldo Carvalho de Melo to = (u64)btarget->idx; 356a3f895beSArnaldo Carvalho de Melo } 357a3f895beSArnaldo Carvalho de Melo 358*00ea0eb2SArnaldo Carvalho de Melo width = annotate_browser__cycles_width(ab); 359b40982e8SJin Yao 36078ce08dfSTaeung Song ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 361b40982e8SJin Yao __ui_browser__line_arrow(browser, 362b40982e8SJin Yao pcnt_width + 2 + ab->addr_width + width, 363c7e7b610SNamhyung Kim from, to); 3647e63a13aSJin Yao 3657e63a13aSJin Yao if (is_fused(ab, cursor)) { 3667e63a13aSJin Yao ui_browser__mark_fused(browser, 367b40982e8SJin Yao pcnt_width + 3 + ab->addr_width + width, 3687e63a13aSJin Yao from - 1, 3697e63a13aSJin Yao to > from ? true : false); 3707e63a13aSJin Yao } 371a3f895beSArnaldo Carvalho de Melo } 372a3f895beSArnaldo Carvalho de Melo 373a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser) 374a3f895beSArnaldo Carvalho de Melo { 375c7e7b610SNamhyung Kim struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 376a3f895beSArnaldo Carvalho de Melo int ret = ui_browser__list_head_refresh(browser); 377f8f4aaeaSAndi Kleen int pcnt_width = annotate_browser__pcnt_width(ab); 378a3f895beSArnaldo Carvalho de Melo 379e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.jump_arrows) 3809d1ef56dSArnaldo Carvalho de Melo annotate_browser__draw_current_jump(browser); 381a3f895beSArnaldo Carvalho de Melo 38283b1f2aaSArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_NORMAL); 383c7e7b610SNamhyung Kim __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); 384a3f895beSArnaldo Carvalho de Melo return ret; 385a3f895beSArnaldo Carvalho de Melo } 386a3f895beSArnaldo Carvalho de Melo 387b15636c6SJiri Olsa static int disasm__cmp(struct annotation_line *a, struct annotation_line *b) 388c7e7b610SNamhyung Kim { 389c7e7b610SNamhyung Kim int i; 390c7e7b610SNamhyung Kim 391b15636c6SJiri Olsa for (i = 0; i < a->samples_nr; i++) { 3920c4a5bceSMartin Liška if (a->samples[i].percent == b->samples[i].percent) 393c7e7b610SNamhyung Kim continue; 3940c4a5bceSMartin Liška return a->samples[i].percent < b->samples[i].percent; 395c7e7b610SNamhyung Kim } 396c7e7b610SNamhyung Kim return 0; 397c7e7b610SNamhyung Kim } 398c7e7b610SNamhyung Kim 399b15636c6SJiri Olsa static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al) 400aca7a94dSNamhyung Kim { 40129ed6e76SArnaldo Carvalho de Melo struct rb_node **p = &root->rb_node; 402aca7a94dSNamhyung Kim struct rb_node *parent = NULL; 4033ab6db8dSJiri Olsa struct annotation_line *l; 404aca7a94dSNamhyung Kim 405aca7a94dSNamhyung Kim while (*p != NULL) { 406aca7a94dSNamhyung Kim parent = *p; 4073ab6db8dSJiri Olsa l = rb_entry(parent, struct annotation_line, rb_node); 408c7e7b610SNamhyung Kim 409b15636c6SJiri Olsa if (disasm__cmp(al, l)) 410aca7a94dSNamhyung Kim p = &(*p)->rb_left; 411aca7a94dSNamhyung Kim else 412aca7a94dSNamhyung Kim p = &(*p)->rb_right; 413aca7a94dSNamhyung Kim } 4143ab6db8dSJiri Olsa rb_link_node(&al->rb_node, parent, p); 4153ab6db8dSJiri Olsa rb_insert_color(&al->rb_node, root); 416aca7a94dSNamhyung Kim } 417aca7a94dSNamhyung Kim 41805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser, 419ec03a77dSJiri Olsa struct annotation_line *pos, u32 idx) 420aca7a94dSNamhyung Kim { 421aca7a94dSNamhyung Kim unsigned back; 422aca7a94dSNamhyung Kim 42305e8b080SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(&browser->b); 42405e8b080SArnaldo Carvalho de Melo back = browser->b.height / 2; 42505e8b080SArnaldo Carvalho de Melo browser->b.top_idx = browser->b.index = idx; 426aca7a94dSNamhyung Kim 42705e8b080SArnaldo Carvalho de Melo while (browser->b.top_idx != 0 && back != 0) { 428ec03a77dSJiri Olsa pos = list_entry(pos->node.prev, struct annotation_line, node); 429aca7a94dSNamhyung Kim 430ec03a77dSJiri Olsa if (disasm_line__filter(&browser->b, &pos->node)) 431aca7a94dSNamhyung Kim continue; 432aca7a94dSNamhyung Kim 43305e8b080SArnaldo Carvalho de Melo --browser->b.top_idx; 434aca7a94dSNamhyung Kim --back; 435aca7a94dSNamhyung Kim } 436aca7a94dSNamhyung Kim 437ec03a77dSJiri Olsa browser->b.top = pos; 43805e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = true; 439aca7a94dSNamhyung Kim } 440aca7a94dSNamhyung Kim 441aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser, 442aca7a94dSNamhyung Kim struct rb_node *nd) 443aca7a94dSNamhyung Kim { 4440d957970SJiri Olsa struct browser_line *bpos; 445ec03a77dSJiri Olsa struct annotation_line *pos; 446a44b45f2SArnaldo Carvalho de Melo u32 idx; 447aca7a94dSNamhyung Kim 448ec03a77dSJiri Olsa pos = rb_entry(nd, struct annotation_line, rb_node); 449ec03a77dSJiri Olsa bpos = browser_line(pos); 4505b12adc8SJiri Olsa 451a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx; 452e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 453a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx_asm; 454a44b45f2SArnaldo Carvalho de Melo annotate_browser__set_top(browser, pos, idx); 455aca7a94dSNamhyung Kim browser->curr_hot = nd; 456aca7a94dSNamhyung Kim } 457aca7a94dSNamhyung Kim 458aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser, 459db8fd07aSNamhyung Kim struct perf_evsel *evsel) 460aca7a94dSNamhyung Kim { 461aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 462aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 463aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 464c4c72436SJiri Olsa struct disasm_line *pos; 465aca7a94dSNamhyung Kim 466aca7a94dSNamhyung Kim browser->entries = RB_ROOT; 467aca7a94dSNamhyung Kim 468aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 469aca7a94dSNamhyung Kim 470e425da6cSJiri Olsa symbol__calc_percent(sym, evsel); 471e425da6cSJiri Olsa 472a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 473c7e7b610SNamhyung Kim double max_percent = 0.0; 474c7e7b610SNamhyung Kim int i; 475e64aa75bSNamhyung Kim 476d5490b96SJiri Olsa if (pos->al.offset == -1) { 4775b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 478e64aa75bSNamhyung Kim continue; 479e64aa75bSNamhyung Kim } 480e64aa75bSNamhyung Kim 481b15636c6SJiri Olsa for (i = 0; i < pos->al.samples_nr; i++) { 482e425da6cSJiri Olsa struct annotation_data *sample = &pos->al.samples[i]; 4830c4a5bceSMartin Liška 4843ab6db8dSJiri Olsa if (max_percent < sample->percent) 4853ab6db8dSJiri Olsa max_percent = sample->percent; 486c7e7b610SNamhyung Kim } 487c7e7b610SNamhyung Kim 48837236d5eSJiri Olsa if (max_percent < 0.01 && pos->al.ipc == 0) { 4895b12adc8SJiri Olsa RB_CLEAR_NODE(&pos->al.rb_node); 490aca7a94dSNamhyung Kim continue; 491aca7a94dSNamhyung Kim } 492b15636c6SJiri Olsa disasm_rb_tree__insert(&browser->entries, &pos->al); 493aca7a94dSNamhyung Kim } 494aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 495aca7a94dSNamhyung Kim 496aca7a94dSNamhyung Kim browser->curr_hot = rb_last(&browser->entries); 497aca7a94dSNamhyung Kim } 498aca7a94dSNamhyung Kim 499aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser) 500aca7a94dSNamhyung Kim { 501ec03a77dSJiri Olsa struct annotation_line *al; 502a5ef2702SJiri Olsa struct browser_line *bl; 503aca7a94dSNamhyung Kim off_t offset = browser->b.index - browser->b.top_idx; 504aca7a94dSNamhyung Kim 505aca7a94dSNamhyung Kim browser->b.seek(&browser->b, offset, SEEK_CUR); 506ec03a77dSJiri Olsa al = list_entry(browser->b.top, struct annotation_line, node); 507ec03a77dSJiri Olsa bl = browser_line(al); 508aca7a94dSNamhyung Kim 509e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 510a5ef2702SJiri Olsa if (bl->idx_asm < offset) 511a5ef2702SJiri Olsa offset = bl->idx; 512aca7a94dSNamhyung Kim 513aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_entries; 514e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = false; 515aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 516a5ef2702SJiri Olsa browser->b.top_idx = bl->idx - offset; 517a5ef2702SJiri Olsa browser->b.index = bl->idx; 518aca7a94dSNamhyung Kim } else { 519a5ef2702SJiri Olsa if (bl->idx_asm < 0) { 520aca7a94dSNamhyung Kim ui_helpline__puts("Only available for assembly lines."); 521aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 522aca7a94dSNamhyung Kim return false; 523aca7a94dSNamhyung Kim } 524aca7a94dSNamhyung Kim 525a5ef2702SJiri Olsa if (bl->idx_asm < offset) 526a5ef2702SJiri Olsa offset = bl->idx_asm; 527aca7a94dSNamhyung Kim 528aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_asm_entries; 529e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = true; 530aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 531a5ef2702SJiri Olsa browser->b.top_idx = bl->idx_asm - offset; 532a5ef2702SJiri Olsa browser->b.index = bl->idx_asm; 533aca7a94dSNamhyung Kim } 534aca7a94dSNamhyung Kim 535aca7a94dSNamhyung Kim return true; 536aca7a94dSNamhyung Kim } 537aca7a94dSNamhyung Kim 538e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser) 539e9823b21SArnaldo Carvalho de Melo { 540e9823b21SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 541e9823b21SArnaldo Carvalho de Melo browser->b.nr_entries = browser->nr_asm_entries; 542e9823b21SArnaldo Carvalho de Melo } 543e9823b21SArnaldo Carvalho de Melo 54434f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 54534f77abcSAdrian Hunter 54634f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title, 54734f77abcSAdrian Hunter size_t sz) 54834f77abcSAdrian Hunter { 54934f77abcSAdrian Hunter return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); 55034f77abcSAdrian Hunter } 55134f77abcSAdrian Hunter 552db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser, 553db8fd07aSNamhyung Kim struct perf_evsel *evsel, 5549783adf7SNamhyung Kim struct hist_browser_timer *hbt) 555aca7a94dSNamhyung Kim { 556aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 5577bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 558aca7a94dSNamhyung Kim struct annotation *notes; 55934f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 560aca7a94dSNamhyung Kim 56175b49202SArnaldo Carvalho de Melo if (!ins__is_call(&dl->ins)) 562aca7a94dSNamhyung Kim return false; 563aca7a94dSNamhyung Kim 564696703afSArnaldo Carvalho de Melo if (!dl->ops.target.sym) { 565aca7a94dSNamhyung Kim ui_helpline__puts("The called function was not found."); 566aca7a94dSNamhyung Kim return true; 567aca7a94dSNamhyung Kim } 568aca7a94dSNamhyung Kim 569696703afSArnaldo Carvalho de Melo notes = symbol__annotation(dl->ops.target.sym); 570aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 571aca7a94dSNamhyung Kim 572696703afSArnaldo Carvalho de Melo if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) { 573aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 574aca7a94dSNamhyung Kim ui__warning("Not enough memory for annotating '%s' symbol!\n", 575696703afSArnaldo Carvalho de Melo dl->ops.target.sym->name); 576aca7a94dSNamhyung Kim return true; 577aca7a94dSNamhyung Kim } 578aca7a94dSNamhyung Kim 579aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 580696703afSArnaldo Carvalho de Melo symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt); 5811179e11bSAdrian Hunter sym_title(ms->sym, ms->map, title, sizeof(title)); 58234f77abcSAdrian Hunter ui_browser__show_title(&browser->b, title); 583aca7a94dSNamhyung Kim return true; 584aca7a94dSNamhyung Kim } 585aca7a94dSNamhyung Kim 58629ed6e76SArnaldo Carvalho de Melo static 58729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 588aca7a94dSNamhyung Kim s64 offset, s64 *idx) 589aca7a94dSNamhyung Kim { 590aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 591aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 592aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 59329ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 594aca7a94dSNamhyung Kim 595aca7a94dSNamhyung Kim *idx = 0; 596a17c4ca0SJiri Olsa list_for_each_entry(pos, ¬es->src->source, al.node) { 597d5490b96SJiri Olsa if (pos->al.offset == offset) 598aca7a94dSNamhyung Kim return pos; 599a17c4ca0SJiri Olsa if (!disasm_line__filter(&browser->b, &pos->al.node)) 600aca7a94dSNamhyung Kim ++*idx; 601aca7a94dSNamhyung Kim } 602aca7a94dSNamhyung Kim 603aca7a94dSNamhyung Kim return NULL; 604aca7a94dSNamhyung Kim } 605aca7a94dSNamhyung Kim 606aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser) 607aca7a94dSNamhyung Kim { 6087bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 6095252b1aeSArnaldo Carvalho de Melo u64 offset; 6104f9d0325SArnaldo Carvalho de Melo s64 idx; 611aca7a94dSNamhyung Kim 61275b49202SArnaldo Carvalho de Melo if (!ins__is_jump(&dl->ins)) 613aca7a94dSNamhyung Kim return false; 614aca7a94dSNamhyung Kim 6155252b1aeSArnaldo Carvalho de Melo offset = dl->ops.target.offset; 6165252b1aeSArnaldo Carvalho de Melo dl = annotate_browser__find_offset(browser, offset, &idx); 61729ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 6185252b1aeSArnaldo Carvalho de Melo ui_helpline__printf("Invalid jump offset: %" PRIx64, offset); 619aca7a94dSNamhyung Kim return true; 620aca7a94dSNamhyung Kim } 621aca7a94dSNamhyung Kim 622ec03a77dSJiri Olsa annotate_browser__set_top(browser, &dl->al, idx); 623aca7a94dSNamhyung Kim 624aca7a94dSNamhyung Kim return true; 625aca7a94dSNamhyung Kim } 626aca7a94dSNamhyung Kim 62729ed6e76SArnaldo Carvalho de Melo static 6289213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser, 629aca7a94dSNamhyung Kim char *s, s64 *idx) 630aca7a94dSNamhyung Kim { 631aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 632aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 633aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 6349213afbdSJiri Olsa struct annotation_line *al = browser->selection; 635aca7a94dSNamhyung Kim 636aca7a94dSNamhyung Kim *idx = browser->b.index; 6379213afbdSJiri Olsa list_for_each_entry_continue(al, ¬es->src->source, node) { 6389213afbdSJiri Olsa if (disasm_line__filter(&browser->b, &al->node)) 639aca7a94dSNamhyung Kim continue; 640aca7a94dSNamhyung Kim 641aca7a94dSNamhyung Kim ++*idx; 642aca7a94dSNamhyung Kim 6439213afbdSJiri Olsa if (al->line && strstr(al->line, s) != NULL) 6449213afbdSJiri Olsa return al; 645aca7a94dSNamhyung Kim } 646aca7a94dSNamhyung Kim 647aca7a94dSNamhyung Kim return NULL; 648aca7a94dSNamhyung Kim } 649aca7a94dSNamhyung Kim 650aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser) 651aca7a94dSNamhyung Kim { 6529213afbdSJiri Olsa struct annotation_line *al; 653aca7a94dSNamhyung Kim s64 idx; 654aca7a94dSNamhyung Kim 6559213afbdSJiri Olsa al = annotate_browser__find_string(browser, browser->search_bf, &idx); 6569213afbdSJiri Olsa if (al == NULL) { 657aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 658aca7a94dSNamhyung Kim return false; 659aca7a94dSNamhyung Kim } 660aca7a94dSNamhyung Kim 661ec03a77dSJiri Olsa annotate_browser__set_top(browser, al, idx); 662aca7a94dSNamhyung Kim browser->searching_backwards = false; 663aca7a94dSNamhyung Kim return true; 664aca7a94dSNamhyung Kim } 665aca7a94dSNamhyung Kim 66629ed6e76SArnaldo Carvalho de Melo static 6679213afbdSJiri Olsa struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 668aca7a94dSNamhyung Kim char *s, s64 *idx) 669aca7a94dSNamhyung Kim { 670aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 671aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 672aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 6739213afbdSJiri Olsa struct annotation_line *al = browser->selection; 674aca7a94dSNamhyung Kim 675aca7a94dSNamhyung Kim *idx = browser->b.index; 6769213afbdSJiri Olsa list_for_each_entry_continue_reverse(al, ¬es->src->source, node) { 6779213afbdSJiri Olsa if (disasm_line__filter(&browser->b, &al->node)) 678aca7a94dSNamhyung Kim continue; 679aca7a94dSNamhyung Kim 680aca7a94dSNamhyung Kim --*idx; 681aca7a94dSNamhyung Kim 6829213afbdSJiri Olsa if (al->line && strstr(al->line, s) != NULL) 6839213afbdSJiri Olsa return al; 684aca7a94dSNamhyung Kim } 685aca7a94dSNamhyung Kim 686aca7a94dSNamhyung Kim return NULL; 687aca7a94dSNamhyung Kim } 688aca7a94dSNamhyung Kim 689aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser) 690aca7a94dSNamhyung Kim { 6919213afbdSJiri Olsa struct annotation_line *al; 692aca7a94dSNamhyung Kim s64 idx; 693aca7a94dSNamhyung Kim 6949213afbdSJiri Olsa al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 6959213afbdSJiri Olsa if (al == NULL) { 696aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 697aca7a94dSNamhyung Kim return false; 698aca7a94dSNamhyung Kim } 699aca7a94dSNamhyung Kim 700ec03a77dSJiri Olsa annotate_browser__set_top(browser, al, idx); 701aca7a94dSNamhyung Kim browser->searching_backwards = true; 702aca7a94dSNamhyung Kim return true; 703aca7a94dSNamhyung Kim } 704aca7a94dSNamhyung Kim 705aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser, 706aca7a94dSNamhyung Kim int delay_secs) 707aca7a94dSNamhyung Kim { 708aca7a94dSNamhyung Kim if (ui_browser__input_window("Search", "String: ", browser->search_bf, 709aca7a94dSNamhyung Kim "ENTER: OK, ESC: Cancel", 710aca7a94dSNamhyung Kim delay_secs * 2) != K_ENTER || 711aca7a94dSNamhyung Kim !*browser->search_bf) 712aca7a94dSNamhyung Kim return false; 713aca7a94dSNamhyung Kim 714aca7a94dSNamhyung Kim return true; 715aca7a94dSNamhyung Kim } 716aca7a94dSNamhyung Kim 717aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) 718aca7a94dSNamhyung Kim { 719aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 720aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 721aca7a94dSNamhyung Kim 722aca7a94dSNamhyung Kim return false; 723aca7a94dSNamhyung Kim } 724aca7a94dSNamhyung Kim 725aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser, 726aca7a94dSNamhyung Kim int delay_secs) 727aca7a94dSNamhyung Kim { 728aca7a94dSNamhyung Kim if (!*browser->search_bf) 729aca7a94dSNamhyung Kim return annotate_browser__search(browser, delay_secs); 730aca7a94dSNamhyung Kim 731aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 732aca7a94dSNamhyung Kim } 733aca7a94dSNamhyung Kim 734aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser, 735aca7a94dSNamhyung Kim int delay_secs) 736aca7a94dSNamhyung Kim { 737aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 738aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 739aca7a94dSNamhyung Kim 740aca7a94dSNamhyung Kim return false; 741aca7a94dSNamhyung Kim } 742aca7a94dSNamhyung Kim 743aca7a94dSNamhyung Kim static 744aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, 745aca7a94dSNamhyung Kim int delay_secs) 746aca7a94dSNamhyung Kim { 747aca7a94dSNamhyung Kim if (!*browser->search_bf) 748aca7a94dSNamhyung Kim return annotate_browser__search_reverse(browser, delay_secs); 749aca7a94dSNamhyung Kim 750aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 751aca7a94dSNamhyung Kim } 752aca7a94dSNamhyung Kim 753e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser) 754e9823b21SArnaldo Carvalho de Melo { 755e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.use_offset) 756e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->min_addr_width; 757e9823b21SArnaldo Carvalho de Melo else 758e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->max_addr_width; 759e9823b21SArnaldo Carvalho de Melo 760e9823b21SArnaldo Carvalho de Melo browser->addr_width = browser->target_width; 761e9823b21SArnaldo Carvalho de Melo 762e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.show_nr_jumps) 763e9823b21SArnaldo Carvalho de Melo browser->addr_width += browser->jumps_width + 1; 764e9823b21SArnaldo Carvalho de Melo } 765e9823b21SArnaldo Carvalho de Melo 766db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser, 767db8fd07aSNamhyung Kim struct perf_evsel *evsel, 7689783adf7SNamhyung Kim struct hist_browser_timer *hbt) 769aca7a94dSNamhyung Kim { 770aca7a94dSNamhyung Kim struct rb_node *nd = NULL; 77105e8b080SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv; 772aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 77354e7a4e8SArnaldo Carvalho de Melo const char *help = "Press 'h' for help on key bindings"; 7749783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 775aca7a94dSNamhyung Kim int key; 77634f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 777aca7a94dSNamhyung Kim 77834f77abcSAdrian Hunter sym_title(sym, ms->map, title, sizeof(title)); 77934f77abcSAdrian Hunter if (ui_browser__show(&browser->b, title, help) < 0) 780aca7a94dSNamhyung Kim return -1; 781aca7a94dSNamhyung Kim 782db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 783aca7a94dSNamhyung Kim 78405e8b080SArnaldo Carvalho de Melo if (browser->curr_hot) { 78505e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, browser->curr_hot); 78605e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = false; 787aca7a94dSNamhyung Kim } 788aca7a94dSNamhyung Kim 78905e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 790aca7a94dSNamhyung Kim 791aca7a94dSNamhyung Kim while (1) { 79205e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 793aca7a94dSNamhyung Kim 794aca7a94dSNamhyung Kim if (delay_secs != 0) { 795db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 796aca7a94dSNamhyung Kim /* 797aca7a94dSNamhyung Kim * Current line focus got out of the list of most active 798aca7a94dSNamhyung Kim * lines, NULL it so that if TAB|UNTAB is pressed, we 799aca7a94dSNamhyung Kim * move to curr_hot (current hottest line). 800aca7a94dSNamhyung Kim */ 801aca7a94dSNamhyung Kim if (nd != NULL && RB_EMPTY_NODE(nd)) 802aca7a94dSNamhyung Kim nd = NULL; 803aca7a94dSNamhyung Kim } 804aca7a94dSNamhyung Kim 805aca7a94dSNamhyung Kim switch (key) { 806aca7a94dSNamhyung Kim case K_TIMER: 8079783adf7SNamhyung Kim if (hbt) 8089783adf7SNamhyung Kim hbt->timer(hbt->arg); 809aca7a94dSNamhyung Kim 810aca7a94dSNamhyung Kim if (delay_secs != 0) 811db8fd07aSNamhyung Kim symbol__annotate_decay_histogram(sym, evsel->idx); 812aca7a94dSNamhyung Kim continue; 813aca7a94dSNamhyung Kim case K_TAB: 814aca7a94dSNamhyung Kim if (nd != NULL) { 815aca7a94dSNamhyung Kim nd = rb_prev(nd); 816aca7a94dSNamhyung Kim if (nd == NULL) 81705e8b080SArnaldo Carvalho de Melo nd = rb_last(&browser->entries); 818aca7a94dSNamhyung Kim } else 81905e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 820aca7a94dSNamhyung Kim break; 821aca7a94dSNamhyung Kim case K_UNTAB: 822d4913cbdSMarkus Trippelsdorf if (nd != NULL) { 823aca7a94dSNamhyung Kim nd = rb_next(nd); 824aca7a94dSNamhyung Kim if (nd == NULL) 82505e8b080SArnaldo Carvalho de Melo nd = rb_first(&browser->entries); 826d4913cbdSMarkus Trippelsdorf } else 82705e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 828aca7a94dSNamhyung Kim break; 82954e7a4e8SArnaldo Carvalho de Melo case K_F1: 830aca7a94dSNamhyung Kim case 'h': 83105e8b080SArnaldo Carvalho de Melo ui_browser__help_window(&browser->b, 83254e7a4e8SArnaldo Carvalho de Melo "UP/DOWN/PGUP\n" 83354e7a4e8SArnaldo Carvalho de Melo "PGDN/SPACE Navigate\n" 83454e7a4e8SArnaldo Carvalho de Melo "q/ESC/CTRL+C Exit\n\n" 8357727a925SArnaldo Carvalho de Melo "ENTER Go to target\n" 8367727a925SArnaldo Carvalho de Melo "ESC Exit\n" 837eba9fac0SArnaldo Carvalho de Melo "H Go to hottest instruction\n" 838eba9fac0SArnaldo Carvalho de Melo "TAB/shift+TAB Cycle thru hottest instructions\n" 83954e7a4e8SArnaldo Carvalho de Melo "j Toggle showing jump to target arrows\n" 84054e7a4e8SArnaldo Carvalho de Melo "J Toggle showing number of jump sources on targets\n" 84154e7a4e8SArnaldo Carvalho de Melo "n Search next string\n" 84254e7a4e8SArnaldo Carvalho de Melo "o Toggle disassembler output/simplified view\n" 84354e7a4e8SArnaldo Carvalho de Melo "s Toggle source code view\n" 8443a555c77STaeung Song "t Circulate percent, total period, samples view\n" 84554e7a4e8SArnaldo Carvalho de Melo "/ Search string\n" 846e592488cSAndi Kleen "k Toggle line numbers\n" 84779ee47faSFeng Tang "r Run available scripts\n" 848fcd9fef9SArnaldo Carvalho de Melo "? Search string backwards\n"); 84954e7a4e8SArnaldo Carvalho de Melo continue; 85079ee47faSFeng Tang case 'r': 85179ee47faSFeng Tang { 85279ee47faSFeng Tang script_browse(NULL); 85379ee47faSFeng Tang continue; 85479ee47faSFeng Tang } 855e592488cSAndi Kleen case 'k': 856e592488cSAndi Kleen annotate_browser__opts.show_linenr = 857e592488cSAndi Kleen !annotate_browser__opts.show_linenr; 858e592488cSAndi Kleen break; 85954e7a4e8SArnaldo Carvalho de Melo case 'H': 86005e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 861aca7a94dSNamhyung Kim break; 862aca7a94dSNamhyung Kim case 's': 86305e8b080SArnaldo Carvalho de Melo if (annotate_browser__toggle_source(browser)) 864aca7a94dSNamhyung Kim ui_helpline__puts(help); 865aca7a94dSNamhyung Kim continue; 866aca7a94dSNamhyung Kim case 'o': 867e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset; 86805e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 869aca7a94dSNamhyung Kim continue; 8709d1ef56dSArnaldo Carvalho de Melo case 'j': 871e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows; 8729d1ef56dSArnaldo Carvalho de Melo continue; 8732402e4a9SArnaldo Carvalho de Melo case 'J': 874e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps; 87505e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 876e9823b21SArnaldo Carvalho de Melo continue; 877aca7a94dSNamhyung Kim case '/': 87805e8b080SArnaldo Carvalho de Melo if (annotate_browser__search(browser, delay_secs)) { 879aca7a94dSNamhyung Kim show_help: 880aca7a94dSNamhyung Kim ui_helpline__puts(help); 881aca7a94dSNamhyung Kim } 882aca7a94dSNamhyung Kim continue; 883aca7a94dSNamhyung Kim case 'n': 88405e8b080SArnaldo Carvalho de Melo if (browser->searching_backwards ? 88505e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search_reverse(browser, delay_secs) : 88605e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search(browser, delay_secs)) 887aca7a94dSNamhyung Kim goto show_help; 888aca7a94dSNamhyung Kim continue; 889aca7a94dSNamhyung Kim case '?': 89005e8b080SArnaldo Carvalho de Melo if (annotate_browser__search_reverse(browser, delay_secs)) 891aca7a94dSNamhyung Kim goto show_help; 892aca7a94dSNamhyung Kim continue; 893e9823b21SArnaldo Carvalho de Melo case 'D': { 894e9823b21SArnaldo Carvalho de Melo static int seq; 895e9823b21SArnaldo Carvalho de Melo ui_helpline__pop(); 896e9823b21SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d", 89705e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 89805e8b080SArnaldo Carvalho de Melo browser->b.height, 89905e8b080SArnaldo Carvalho de Melo browser->b.index, 90005e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 90105e8b080SArnaldo Carvalho de Melo browser->nr_asm_entries); 902e9823b21SArnaldo Carvalho de Melo } 903e9823b21SArnaldo Carvalho de Melo continue; 904aca7a94dSNamhyung Kim case K_ENTER: 905aca7a94dSNamhyung Kim case K_RIGHT: 9067bcbcd58SJiri Olsa { 9077bcbcd58SJiri Olsa struct disasm_line *dl = disasm_line(browser->selection); 9087bcbcd58SJiri Olsa 90905e8b080SArnaldo Carvalho de Melo if (browser->selection == NULL) 910aca7a94dSNamhyung Kim ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 9117bcbcd58SJiri Olsa else if (browser->selection->offset == -1) 912aca7a94dSNamhyung Kim ui_helpline__puts("Actions are only available for assembly lines."); 9137bcbcd58SJiri Olsa else if (!dl->ins.ops) 914c4cceae3SArnaldo Carvalho de Melo goto show_sup_ins; 9157bcbcd58SJiri Olsa else if (ins__is_ret(&dl->ins)) 916c4cceae3SArnaldo Carvalho de Melo goto out; 9176ef94929SNaveen N. Rao else if (!(annotate_browser__jump(browser) || 918db8fd07aSNamhyung Kim annotate_browser__callq(browser, evsel, hbt))) { 919c4cceae3SArnaldo Carvalho de Melo show_sup_ins: 9206ef94929SNaveen N. Rao ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 921c4cceae3SArnaldo Carvalho de Melo } 922aca7a94dSNamhyung Kim continue; 9237bcbcd58SJiri Olsa } 9240c4a5bceSMartin Liška case 't': 9253a555c77STaeung Song if (annotate_browser__opts.show_total_period) { 9263a555c77STaeung Song annotate_browser__opts.show_total_period = false; 9273a555c77STaeung Song annotate_browser__opts.show_nr_samples = true; 9283a555c77STaeung Song } else if (annotate_browser__opts.show_nr_samples) 9293a555c77STaeung Song annotate_browser__opts.show_nr_samples = false; 9303a555c77STaeung Song else 9313a555c77STaeung Song annotate_browser__opts.show_total_period = true; 9320c4a5bceSMartin Liška annotate_browser__update_addr_width(browser); 9330c4a5bceSMartin Liška continue; 934aca7a94dSNamhyung Kim case K_LEFT: 935aca7a94dSNamhyung Kim case K_ESC: 936aca7a94dSNamhyung Kim case 'q': 937aca7a94dSNamhyung Kim case CTRL('c'): 938aca7a94dSNamhyung Kim goto out; 939aca7a94dSNamhyung Kim default: 940aca7a94dSNamhyung Kim continue; 941aca7a94dSNamhyung Kim } 942aca7a94dSNamhyung Kim 943aca7a94dSNamhyung Kim if (nd != NULL) 94405e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, nd); 945aca7a94dSNamhyung Kim } 946aca7a94dSNamhyung Kim out: 94705e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 948aca7a94dSNamhyung Kim return key; 949aca7a94dSNamhyung Kim } 950aca7a94dSNamhyung Kim 951d5dbc518SArnaldo Carvalho de Melo int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, 952d5dbc518SArnaldo Carvalho de Melo struct hist_browser_timer *hbt) 953d5dbc518SArnaldo Carvalho de Melo { 9549cef4b0bSTaeung Song /* Set default value for show_total_period and show_nr_samples */ 9550c4a5bceSMartin Liška annotate_browser__opts.show_total_period = 9560c4a5bceSMartin Liška symbol_conf.show_total_period; 9579cef4b0bSTaeung Song annotate_browser__opts.show_nr_samples = 9589cef4b0bSTaeung Song symbol_conf.show_nr_samples; 9590c4a5bceSMartin Liška 960d5dbc518SArnaldo Carvalho de Melo return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); 961d5dbc518SArnaldo Carvalho de Melo } 962d5dbc518SArnaldo Carvalho de Melo 963db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 9649783adf7SNamhyung Kim struct hist_browser_timer *hbt) 965aca7a94dSNamhyung Kim { 966ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 967ed426915SNamhyung Kim SLang_reset_tty(); 968ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 969ed426915SNamhyung Kim 970d5dbc518SArnaldo Carvalho de Melo return map_symbol__tui_annotate(&he->ms, evsel, hbt); 971aca7a94dSNamhyung Kim } 972aca7a94dSNamhyung Kim 97330e863bbSAndi Kleen 97430e863bbSAndi Kleen static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end) 97530e863bbSAndi Kleen { 97630e863bbSAndi Kleen unsigned n_insn = 0; 97730e863bbSAndi Kleen u64 offset; 97830e863bbSAndi Kleen 97930e863bbSAndi Kleen for (offset = start; offset <= end; offset++) { 98030e863bbSAndi Kleen if (browser->offsets[offset]) 98130e863bbSAndi Kleen n_insn++; 98230e863bbSAndi Kleen } 98330e863bbSAndi Kleen return n_insn; 98430e863bbSAndi Kleen } 98530e863bbSAndi Kleen 98630e863bbSAndi Kleen static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end, 98730e863bbSAndi Kleen struct cyc_hist *ch) 98830e863bbSAndi Kleen { 98930e863bbSAndi Kleen unsigned n_insn; 99030e863bbSAndi Kleen u64 offset; 99130e863bbSAndi Kleen 99230e863bbSAndi Kleen n_insn = count_insn(browser, start, end); 99330e863bbSAndi Kleen if (n_insn && ch->num && ch->cycles) { 99430e863bbSAndi Kleen float ipc = n_insn / ((double)ch->cycles / (double)ch->num); 99530e863bbSAndi Kleen 99630e863bbSAndi Kleen /* Hide data when there are too many overlaps. */ 99730e863bbSAndi Kleen if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2) 99830e863bbSAndi Kleen return; 99930e863bbSAndi Kleen 100030e863bbSAndi Kleen for (offset = start; offset <= end; offset++) { 1001e1b60b5bSJiri Olsa struct annotation_line *al = browser->offsets[offset]; 100230e863bbSAndi Kleen 1003e1b60b5bSJiri Olsa if (al) 1004e1b60b5bSJiri Olsa al->ipc = ipc; 100530e863bbSAndi Kleen } 100630e863bbSAndi Kleen } 100730e863bbSAndi Kleen } 100830e863bbSAndi Kleen 100930e863bbSAndi Kleen /* 101030e863bbSAndi Kleen * This should probably be in util/annotate.c to share with the tty 101130e863bbSAndi Kleen * annotate, but right now we need the per byte offsets arrays, 101230e863bbSAndi Kleen * which are only here. 101330e863bbSAndi Kleen */ 101430e863bbSAndi Kleen static void annotate__compute_ipc(struct annotate_browser *browser, size_t size, 101530e863bbSAndi Kleen struct symbol *sym) 101630e863bbSAndi Kleen { 101730e863bbSAndi Kleen u64 offset; 101830e863bbSAndi Kleen struct annotation *notes = symbol__annotation(sym); 101930e863bbSAndi Kleen 102030e863bbSAndi Kleen if (!notes->src || !notes->src->cycles_hist) 102130e863bbSAndi Kleen return; 102230e863bbSAndi Kleen 102330e863bbSAndi Kleen pthread_mutex_lock(¬es->lock); 102430e863bbSAndi Kleen for (offset = 0; offset < size; ++offset) { 102530e863bbSAndi Kleen struct cyc_hist *ch; 102630e863bbSAndi Kleen 102730e863bbSAndi Kleen ch = ¬es->src->cycles_hist[offset]; 102830e863bbSAndi Kleen if (ch && ch->cycles) { 1029e1b60b5bSJiri Olsa struct annotation_line *al; 103030e863bbSAndi Kleen 103130e863bbSAndi Kleen if (ch->have_start) 103230e863bbSAndi Kleen count_and_fill(browser, ch->start, offset, ch); 1033e1b60b5bSJiri Olsa al = browser->offsets[offset]; 1034e1b60b5bSJiri Olsa if (al && ch->num_aggr) 1035e1b60b5bSJiri Olsa al->cycles = ch->cycles_aggr / ch->num_aggr; 103630e863bbSAndi Kleen browser->have_cycles = true; 103730e863bbSAndi Kleen } 103830e863bbSAndi Kleen } 103930e863bbSAndi Kleen pthread_mutex_unlock(¬es->lock); 104030e863bbSAndi Kleen } 104130e863bbSAndi Kleen 1042b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 1043b793a401SArnaldo Carvalho de Melo size_t size) 1044b793a401SArnaldo Carvalho de Melo { 1045b793a401SArnaldo Carvalho de Melo u64 offset; 104632ae1efdSNamhyung Kim struct map_symbol *ms = browser->b.priv; 104732ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 104832ae1efdSNamhyung Kim 104932ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 105032ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 105132ae1efdSNamhyung Kim return; 1052b793a401SArnaldo Carvalho de Melo 1053b793a401SArnaldo Carvalho de Melo for (offset = 0; offset < size; ++offset) { 1054e1b60b5bSJiri Olsa struct annotation_line *al = browser->offsets[offset]; 1055a5ef2702SJiri Olsa struct disasm_line *dl; 1056a5ef2702SJiri Olsa struct browser_line *blt; 1057b793a401SArnaldo Carvalho de Melo 1058e1b60b5bSJiri Olsa dl = disasm_line(al); 1059e1b60b5bSJiri Olsa 1060865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(dl, sym)) 1061b793a401SArnaldo Carvalho de Melo continue; 1062b793a401SArnaldo Carvalho de Melo 1063e1b60b5bSJiri Olsa al = browser->offsets[dl->ops.target.offset]; 1064e1b60b5bSJiri Olsa 10659481ede9SArnaldo Carvalho de Melo /* 10669481ede9SArnaldo Carvalho de Melo * FIXME: Oops, no jump target? Buggy disassembler? Or do we 10679481ede9SArnaldo Carvalho de Melo * have to adjust to the previous offset? 10689481ede9SArnaldo Carvalho de Melo */ 1069a5ef2702SJiri Olsa if (al == NULL) 10709481ede9SArnaldo Carvalho de Melo continue; 10719481ede9SArnaldo Carvalho de Melo 1072a5ef2702SJiri Olsa blt = browser_line(al); 1073a5ef2702SJiri Olsa if (++blt->jump_sources > browser->max_jump_sources) 1074a5ef2702SJiri Olsa browser->max_jump_sources = blt->jump_sources; 10752402e4a9SArnaldo Carvalho de Melo 10762402e4a9SArnaldo Carvalho de Melo ++browser->nr_jumps; 1077b793a401SArnaldo Carvalho de Melo } 1078b793a401SArnaldo Carvalho de Melo } 1079b793a401SArnaldo Carvalho de Melo 10802402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n) 10812402e4a9SArnaldo Carvalho de Melo { 10822402e4a9SArnaldo Carvalho de Melo if (n >= 100) 10832402e4a9SArnaldo Carvalho de Melo return 5; 10842402e4a9SArnaldo Carvalho de Melo if (n / 10) 10852402e4a9SArnaldo Carvalho de Melo return 2; 10862402e4a9SArnaldo Carvalho de Melo return 1; 10872402e4a9SArnaldo Carvalho de Melo } 10882402e4a9SArnaldo Carvalho de Melo 1089db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map, 1090db8fd07aSNamhyung Kim struct perf_evsel *evsel, 10919783adf7SNamhyung Kim struct hist_browser_timer *hbt) 1092aca7a94dSNamhyung Kim { 1093e1b60b5bSJiri Olsa struct annotation_line *al; 1094aca7a94dSNamhyung Kim struct annotation *notes; 1095c0a58fb2SSamuel Liao size_t size; 1096aca7a94dSNamhyung Kim struct map_symbol ms = { 1097aca7a94dSNamhyung Kim .map = map, 1098aca7a94dSNamhyung Kim .sym = sym, 1099aca7a94dSNamhyung Kim }; 1100aca7a94dSNamhyung Kim struct annotate_browser browser = { 1101aca7a94dSNamhyung Kim .b = { 1102a3f895beSArnaldo Carvalho de Melo .refresh = annotate_browser__refresh, 1103aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 1104aca7a94dSNamhyung Kim .write = annotate_browser__write, 110529ed6e76SArnaldo Carvalho de Melo .filter = disasm_line__filter, 1106aca7a94dSNamhyung Kim .priv = &ms, 1107aca7a94dSNamhyung Kim .use_navkeypressed = true, 1108aca7a94dSNamhyung Kim }, 1109aca7a94dSNamhyung Kim }; 1110ee51d851SArnaldo Carvalho de Melo int ret = -1, err; 1111c7e7b610SNamhyung Kim int nr_pcnt = 1; 1112aca7a94dSNamhyung Kim 1113aca7a94dSNamhyung Kim if (sym == NULL) 1114aca7a94dSNamhyung Kim return -1; 1115aca7a94dSNamhyung Kim 1116c0a58fb2SSamuel Liao size = symbol__size(sym); 1117c0a58fb2SSamuel Liao 1118aca7a94dSNamhyung Kim if (map->dso->annotate_warned) 1119aca7a94dSNamhyung Kim return -1; 1120aca7a94dSNamhyung Kim 1121e1b60b5bSJiri Olsa browser.offsets = zalloc(size * sizeof(struct annotation_line *)); 1122b793a401SArnaldo Carvalho de Melo if (browser.offsets == NULL) { 1123b793a401SArnaldo Carvalho de Melo ui__error("Not enough memory!"); 1124b793a401SArnaldo Carvalho de Melo return -1; 1125b793a401SArnaldo Carvalho de Melo } 1126b793a401SArnaldo Carvalho de Melo 11273ab6db8dSJiri Olsa if (perf_evsel__is_group_event(evsel)) 1128c7e7b610SNamhyung Kim nr_pcnt = evsel->nr_members; 1129c7e7b610SNamhyung Kim 11305449f13cSArnaldo Carvalho de Melo err = symbol__annotate(sym, map, evsel, sizeof(struct browser_line), &browser.arch); 1131ee51d851SArnaldo Carvalho de Melo if (err) { 1132ee51d851SArnaldo Carvalho de Melo char msg[BUFSIZ]; 1133ee51d851SArnaldo Carvalho de Melo symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); 1134ee51d851SArnaldo Carvalho de Melo ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 1135b793a401SArnaldo Carvalho de Melo goto out_free_offsets; 1136aca7a94dSNamhyung Kim } 1137aca7a94dSNamhyung Kim 113805d3f1a1SJiri Olsa symbol__calc_percent(sym, evsel); 113905d3f1a1SJiri Olsa 11407727a925SArnaldo Carvalho de Melo ui_helpline__push("Press ESC to exit"); 1141aca7a94dSNamhyung Kim 1142aca7a94dSNamhyung Kim notes = symbol__annotation(sym); 1143aca7a94dSNamhyung Kim browser.start = map__rip_2objdump(map, sym->start); 1144aca7a94dSNamhyung Kim 1145e1b60b5bSJiri Olsa list_for_each_entry(al, ¬es->src->source, node) { 11460d957970SJiri Olsa struct browser_line *bpos; 1147e1b60b5bSJiri Olsa size_t line_len = strlen(al->line); 1148aca7a94dSNamhyung Kim 1149aca7a94dSNamhyung Kim if (browser.b.width < line_len) 1150aca7a94dSNamhyung Kim browser.b.width = line_len; 1151a5ef2702SJiri Olsa bpos = browser_line(al); 1152887c0066SArnaldo Carvalho de Melo bpos->idx = browser.nr_entries++; 1153e1b60b5bSJiri Olsa if (al->offset != -1) { 1154887c0066SArnaldo Carvalho de Melo bpos->idx_asm = browser.nr_asm_entries++; 115597148a97SArnaldo Carvalho de Melo /* 115697148a97SArnaldo Carvalho de Melo * FIXME: short term bandaid to cope with assembly 115797148a97SArnaldo Carvalho de Melo * routines that comes with labels in the same column 115897148a97SArnaldo Carvalho de Melo * as the address in objdump, sigh. 115997148a97SArnaldo Carvalho de Melo * 116097148a97SArnaldo Carvalho de Melo * E.g. copy_user_generic_unrolled 116197148a97SArnaldo Carvalho de Melo */ 1162e1b60b5bSJiri Olsa if (al->offset < (s64)size) 1163e1b60b5bSJiri Olsa browser.offsets[al->offset] = al; 1164b793a401SArnaldo Carvalho de Melo } else 1165887c0066SArnaldo Carvalho de Melo bpos->idx_asm = -1; 1166aca7a94dSNamhyung Kim } 1167aca7a94dSNamhyung Kim 1168b793a401SArnaldo Carvalho de Melo annotate_browser__mark_jump_targets(&browser, size); 116930e863bbSAndi Kleen annotate__compute_ipc(&browser, size, sym); 1170b793a401SArnaldo Carvalho de Melo 11712402e4a9SArnaldo Carvalho de Melo browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); 117283b1f2aaSArnaldo Carvalho de Melo browser.max_addr_width = hex_width(sym->end); 11732402e4a9SArnaldo Carvalho de Melo browser.jumps_width = width_jumps(browser.max_jump_sources); 1174c7e7b610SNamhyung Kim browser.nr_events = nr_pcnt; 1175aca7a94dSNamhyung Kim browser.b.nr_entries = browser.nr_entries; 1176aca7a94dSNamhyung Kim browser.b.entries = ¬es->src->source, 1177aca7a94dSNamhyung Kim browser.b.width += 18; /* Percentage */ 1178e9823b21SArnaldo Carvalho de Melo 1179e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 1180e9823b21SArnaldo Carvalho de Melo annotate_browser__init_asm_mode(&browser); 1181e9823b21SArnaldo Carvalho de Melo 1182e9823b21SArnaldo Carvalho de Melo annotate_browser__update_addr_width(&browser); 1183e9823b21SArnaldo Carvalho de Melo 1184db8fd07aSNamhyung Kim ret = annotate_browser__run(&browser, evsel, hbt); 1185f8eb37bdSJiri Olsa 1186f8eb37bdSJiri Olsa annotated_source__purge(notes->src); 1187b793a401SArnaldo Carvalho de Melo 1188b793a401SArnaldo Carvalho de Melo out_free_offsets: 1189b793a401SArnaldo Carvalho de Melo free(browser.offsets); 1190aca7a94dSNamhyung Kim return ret; 1191aca7a94dSNamhyung Kim } 1192c323cf04SArnaldo Carvalho de Melo 1193c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \ 1194c323cf04SArnaldo Carvalho de Melo { .name = #n, .value = &annotate_browser__opts.n, } 1195c323cf04SArnaldo Carvalho de Melo 1196c323cf04SArnaldo Carvalho de Melo /* 1197c323cf04SArnaldo Carvalho de Melo * Keep the entries sorted, they are bsearch'ed 1198c323cf04SArnaldo Carvalho de Melo */ 11997c3102b8SArnaldo Carvalho de Melo static struct annotate_config { 1200c323cf04SArnaldo Carvalho de Melo const char *name; 1201c323cf04SArnaldo Carvalho de Melo bool *value; 1202c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = { 1203c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(hide_src_code), 1204c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(jump_arrows), 1205e592488cSAndi Kleen ANNOTATE_CFG(show_linenr), 1206c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(show_nr_jumps), 12079cef4b0bSTaeung Song ANNOTATE_CFG(show_nr_samples), 12080c4a5bceSMartin Liška ANNOTATE_CFG(show_total_period), 120939ff7cdbSNamhyung Kim ANNOTATE_CFG(use_offset), 1210c323cf04SArnaldo Carvalho de Melo }; 1211c323cf04SArnaldo Carvalho de Melo 1212c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG 1213c323cf04SArnaldo Carvalho de Melo 1214c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp) 1215c323cf04SArnaldo Carvalho de Melo { 12167c3102b8SArnaldo Carvalho de Melo const struct annotate_config *cfg = cfgp; 1217c323cf04SArnaldo Carvalho de Melo 1218c323cf04SArnaldo Carvalho de Melo return strcmp(name, cfg->name); 1219c323cf04SArnaldo Carvalho de Melo } 1220c323cf04SArnaldo Carvalho de Melo 12211d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value, 12221d037ca1SIrina Tirdea void *data __maybe_unused) 1223c323cf04SArnaldo Carvalho de Melo { 12247c3102b8SArnaldo Carvalho de Melo struct annotate_config *cfg; 1225c323cf04SArnaldo Carvalho de Melo const char *name; 1226c323cf04SArnaldo Carvalho de Melo 12278e99b6d4SArnaldo Carvalho de Melo if (!strstarts(var, "annotate.")) 1228c323cf04SArnaldo Carvalho de Melo return 0; 1229c323cf04SArnaldo Carvalho de Melo 1230c323cf04SArnaldo Carvalho de Melo name = var + 9; 1231c323cf04SArnaldo Carvalho de Melo cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), 12327c3102b8SArnaldo Carvalho de Melo sizeof(struct annotate_config), annotate_config__cmp); 1233c323cf04SArnaldo Carvalho de Melo 1234c323cf04SArnaldo Carvalho de Melo if (cfg == NULL) 1235f06cff7cSArnaldo Carvalho de Melo ui__warning("%s variable unknown, ignoring...", var); 1236f06cff7cSArnaldo Carvalho de Melo else 1237c323cf04SArnaldo Carvalho de Melo *cfg->value = perf_config_bool(name, value); 1238c323cf04SArnaldo Carvalho de Melo return 0; 1239c323cf04SArnaldo Carvalho de Melo } 1240c323cf04SArnaldo Carvalho de Melo 1241c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void) 1242c323cf04SArnaldo Carvalho de Melo { 1243c323cf04SArnaldo Carvalho de Melo perf_config(annotate__config, NULL); 1244c323cf04SArnaldo Carvalho de Melo } 1245