1aca7a94dSNamhyung Kim #include "../../util/util.h" 2aca7a94dSNamhyung Kim #include "../browser.h" 3aca7a94dSNamhyung Kim #include "../helpline.h" 4aca7a94dSNamhyung Kim #include "../libslang.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" 12aca7a94dSNamhyung Kim #include <pthread.h> 13aca7a94dSNamhyung Kim 14b793a401SArnaldo Carvalho de Melo struct browser_disasm_line { 15b793a401SArnaldo Carvalho de Melo struct rb_node rb_node; 16b793a401SArnaldo Carvalho de Melo u32 idx; 17b793a401SArnaldo Carvalho de Melo int idx_asm; 187d5b12f5SArnaldo Carvalho de Melo int jump_sources; 19c7e7b610SNamhyung Kim /* 20c7e7b610SNamhyung Kim * actual length of this array is saved on the nr_events field 21c7e7b610SNamhyung Kim * of the struct annotate_browser 22c7e7b610SNamhyung Kim */ 23ab77df67SNamhyung Kim double percent[1]; 24b793a401SArnaldo Carvalho de Melo }; 25b793a401SArnaldo Carvalho de Melo 26e9823b21SArnaldo Carvalho de Melo static struct annotate_browser_opt { 27e9823b21SArnaldo Carvalho de Melo bool hide_src_code, 28e9823b21SArnaldo Carvalho de Melo use_offset, 29e9823b21SArnaldo Carvalho de Melo jump_arrows, 30e9823b21SArnaldo Carvalho de Melo show_nr_jumps; 31e9823b21SArnaldo Carvalho de Melo } 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 36aca7a94dSNamhyung Kim struct annotate_browser { 37aca7a94dSNamhyung Kim struct ui_browser b; 38aca7a94dSNamhyung Kim struct rb_root entries; 39aca7a94dSNamhyung Kim struct rb_node *curr_hot; 4029ed6e76SArnaldo Carvalho de Melo struct disasm_line *selection; 41b793a401SArnaldo Carvalho de Melo struct disasm_line **offsets; 42c7e7b610SNamhyung Kim int nr_events; 43aca7a94dSNamhyung Kim u64 start; 44aca7a94dSNamhyung Kim int nr_asm_entries; 45aca7a94dSNamhyung Kim int nr_entries; 462402e4a9SArnaldo Carvalho de Melo int max_jump_sources; 472402e4a9SArnaldo Carvalho de Melo int nr_jumps; 48aca7a94dSNamhyung Kim bool searching_backwards; 4983b1f2aaSArnaldo Carvalho de Melo u8 addr_width; 502402e4a9SArnaldo Carvalho de Melo u8 jumps_width; 512402e4a9SArnaldo Carvalho de Melo u8 target_width; 5283b1f2aaSArnaldo Carvalho de Melo u8 min_addr_width; 5383b1f2aaSArnaldo Carvalho de Melo u8 max_addr_width; 54aca7a94dSNamhyung Kim char search_bf[128]; 55aca7a94dSNamhyung Kim }; 56aca7a94dSNamhyung Kim 57887c0066SArnaldo Carvalho de Melo static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl) 58aca7a94dSNamhyung Kim { 59887c0066SArnaldo Carvalho de Melo return (struct browser_disasm_line *)(dl + 1); 60aca7a94dSNamhyung Kim } 61aca7a94dSNamhyung Kim 621d037ca1SIrina Tirdea static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, 631d037ca1SIrina Tirdea void *entry) 64aca7a94dSNamhyung Kim { 65e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 6629ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl = list_entry(entry, struct disasm_line, node); 6729ed6e76SArnaldo Carvalho de Melo return dl->offset == -1; 68aca7a94dSNamhyung Kim } 69aca7a94dSNamhyung Kim 70aca7a94dSNamhyung Kim return false; 71aca7a94dSNamhyung Kim } 72aca7a94dSNamhyung Kim 732402e4a9SArnaldo Carvalho de Melo static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, 742402e4a9SArnaldo Carvalho de Melo int nr, bool current) 752402e4a9SArnaldo Carvalho de Melo { 762402e4a9SArnaldo Carvalho de Melo if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) 772402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_SELECTED; 782402e4a9SArnaldo Carvalho de Melo if (nr == browser->max_jump_sources) 792402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_TOP; 802402e4a9SArnaldo Carvalho de Melo if (nr > 1) 812402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_MEDIUM; 822402e4a9SArnaldo Carvalho de Melo return HE_COLORSET_NORMAL; 832402e4a9SArnaldo Carvalho de Melo } 842402e4a9SArnaldo Carvalho de Melo 852402e4a9SArnaldo Carvalho de Melo static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, 862402e4a9SArnaldo Carvalho de Melo int nr, bool current) 872402e4a9SArnaldo Carvalho de Melo { 882402e4a9SArnaldo Carvalho de Melo int color = annotate_browser__jumps_percent_color(browser, nr, current); 892402e4a9SArnaldo Carvalho de Melo return ui_browser__set_color(&browser->b, color); 902402e4a9SArnaldo Carvalho de Melo } 912402e4a9SArnaldo Carvalho de Melo 9205e8b080SArnaldo Carvalho de Melo static void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 93aca7a94dSNamhyung Kim { 9405e8b080SArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 9529ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl = list_entry(entry, struct disasm_line, node); 96b793a401SArnaldo Carvalho de Melo struct browser_disasm_line *bdl = disasm_line__browser(dl); 9705e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(browser, row); 98e9823b21SArnaldo Carvalho de Melo bool change_color = (!annotate_browser__opts.hide_src_code && 9905e8b080SArnaldo Carvalho de Melo (!current_entry || (browser->use_navkeypressed && 10005e8b080SArnaldo Carvalho de Melo !browser->navkeypressed))); 10105e8b080SArnaldo Carvalho de Melo int width = browser->width, printed; 102c7e7b610SNamhyung Kim int i, pcnt_width = 7 * ab->nr_events; 103c7e7b610SNamhyung Kim double percent_max = 0.0; 10483b1f2aaSArnaldo Carvalho de Melo char bf[256]; 105aca7a94dSNamhyung Kim 106c7e7b610SNamhyung Kim for (i = 0; i < ab->nr_events; i++) { 107c7e7b610SNamhyung Kim if (bdl->percent[i] > percent_max) 108c7e7b610SNamhyung Kim percent_max = bdl->percent[i]; 109c7e7b610SNamhyung Kim } 110c7e7b610SNamhyung Kim 111c7e7b610SNamhyung Kim if (dl->offset != -1 && percent_max != 0.0) { 112c7e7b610SNamhyung Kim for (i = 0; i < ab->nr_events; i++) { 113c7e7b610SNamhyung Kim ui_browser__set_percent_color(browser, bdl->percent[i], 114c7e7b610SNamhyung Kim current_entry); 115c7e7b610SNamhyung Kim slsmg_printf("%6.2f ", bdl->percent[i]); 116c7e7b610SNamhyung Kim } 117aca7a94dSNamhyung Kim } else { 11805e8b080SArnaldo Carvalho de Melo ui_browser__set_percent_color(browser, 0, current_entry); 119c7e7b610SNamhyung Kim slsmg_write_nstring(" ", pcnt_width); 120aca7a94dSNamhyung Kim } 121aca7a94dSNamhyung Kim 122cf2dacc5SArnaldo Carvalho de Melo SLsmg_write_char(' '); 123aca7a94dSNamhyung Kim 124aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 12505e8b080SArnaldo Carvalho de Melo if (!browser->navkeypressed) 126aca7a94dSNamhyung Kim width += 1; 127aca7a94dSNamhyung Kim 12829ed6e76SArnaldo Carvalho de Melo if (!*dl->line) 129c7e7b610SNamhyung Kim slsmg_write_nstring(" ", width - pcnt_width); 13083b1f2aaSArnaldo Carvalho de Melo else if (dl->offset == -1) { 13183b1f2aaSArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*s ", 13283b1f2aaSArnaldo Carvalho de Melo ab->addr_width, " "); 13383b1f2aaSArnaldo Carvalho de Melo slsmg_write_nstring(bf, printed); 134c7e7b610SNamhyung Kim slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1); 13583b1f2aaSArnaldo Carvalho de Melo } else { 13629ed6e76SArnaldo Carvalho de Melo u64 addr = dl->offset; 13783b1f2aaSArnaldo Carvalho de Melo int color = -1; 138aca7a94dSNamhyung Kim 139e9823b21SArnaldo Carvalho de Melo if (!annotate_browser__opts.use_offset) 140aca7a94dSNamhyung Kim addr += ab->start; 141aca7a94dSNamhyung Kim 142e9823b21SArnaldo Carvalho de Melo if (!annotate_browser__opts.use_offset) { 143aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); 14461e04b33SArnaldo Carvalho de Melo } else { 1457d5b12f5SArnaldo Carvalho de Melo if (bdl->jump_sources) { 146e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.show_nr_jumps) { 1472402e4a9SArnaldo Carvalho de Melo int prev; 1482402e4a9SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*d ", 1492402e4a9SArnaldo Carvalho de Melo ab->jumps_width, 1502402e4a9SArnaldo Carvalho de Melo bdl->jump_sources); 1512402e4a9SArnaldo Carvalho de Melo prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources, 1522402e4a9SArnaldo Carvalho de Melo current_entry); 1532402e4a9SArnaldo Carvalho de Melo slsmg_write_nstring(bf, printed); 15405e8b080SArnaldo Carvalho de Melo ui_browser__set_color(browser, prev); 1552402e4a9SArnaldo Carvalho de Melo } 1562402e4a9SArnaldo Carvalho de Melo 15761e04b33SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", 1582402e4a9SArnaldo Carvalho de Melo ab->target_width, addr); 15961e04b33SArnaldo Carvalho de Melo } else { 16061e04b33SArnaldo Carvalho de Melo printed = scnprintf(bf, sizeof(bf), "%*s ", 16183b1f2aaSArnaldo Carvalho de Melo ab->addr_width, " "); 16261e04b33SArnaldo Carvalho de Melo } 16361e04b33SArnaldo Carvalho de Melo } 164b793a401SArnaldo Carvalho de Melo 165aca7a94dSNamhyung Kim if (change_color) 16605e8b080SArnaldo Carvalho de Melo color = ui_browser__set_color(browser, HE_COLORSET_ADDR); 167aca7a94dSNamhyung Kim slsmg_write_nstring(bf, printed); 168aca7a94dSNamhyung Kim if (change_color) 16905e8b080SArnaldo Carvalho de Melo ui_browser__set_color(browser, color); 17028548d78SArnaldo Carvalho de Melo if (dl->ins && dl->ins->ops->scnprintf) { 17151a0d455SArnaldo Carvalho de Melo if (ins__is_jump(dl->ins)) { 17244d1a3edSArnaldo Carvalho de Melo bool fwd = dl->ops.target.offset > (u64)dl->offset; 17351a0d455SArnaldo Carvalho de Melo 17405e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : 17551a0d455SArnaldo Carvalho de Melo SLSMG_UARROW_CHAR); 17651a0d455SArnaldo Carvalho de Melo SLsmg_write_char(' '); 17788298f5aSArnaldo Carvalho de Melo } else if (ins__is_call(dl->ins)) { 17805e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); 17988298f5aSArnaldo Carvalho de Melo SLsmg_write_char(' '); 18051a0d455SArnaldo Carvalho de Melo } else { 18151a0d455SArnaldo Carvalho de Melo slsmg_write_nstring(" ", 2); 18251a0d455SArnaldo Carvalho de Melo } 1834ea08b52SArnaldo Carvalho de Melo } else { 1844ea08b52SArnaldo Carvalho de Melo if (strcmp(dl->name, "retq")) { 1854ea08b52SArnaldo Carvalho de Melo slsmg_write_nstring(" ", 2); 1864ea08b52SArnaldo Carvalho de Melo } else { 18705e8b080SArnaldo Carvalho de Melo ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); 1884ea08b52SArnaldo Carvalho de Melo SLsmg_write_char(' '); 1894ea08b52SArnaldo Carvalho de Melo } 1904ea08b52SArnaldo Carvalho de Melo } 1914ea08b52SArnaldo Carvalho de Melo 192e9823b21SArnaldo Carvalho de Melo disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 193c7e7b610SNamhyung Kim slsmg_write_nstring(bf, width - pcnt_width - 3 - printed); 194aca7a94dSNamhyung Kim } 195aca7a94dSNamhyung Kim 196aca7a94dSNamhyung Kim if (current_entry) 19729ed6e76SArnaldo Carvalho de Melo ab->selection = dl; 198aca7a94dSNamhyung Kim } 199aca7a94dSNamhyung Kim 200865c66c4SFrederik Deweerdt static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) 201865c66c4SFrederik Deweerdt { 202865c66c4SFrederik Deweerdt if (!dl || !dl->ins || !ins__is_jump(dl->ins) 203865c66c4SFrederik Deweerdt || !disasm_line__has_offset(dl) 204865c66c4SFrederik Deweerdt || dl->ops.target.offset >= symbol__size(sym)) 205865c66c4SFrederik Deweerdt return false; 206865c66c4SFrederik Deweerdt 207865c66c4SFrederik Deweerdt return true; 208865c66c4SFrederik Deweerdt } 209865c66c4SFrederik Deweerdt 2109d1ef56dSArnaldo Carvalho de Melo static void annotate_browser__draw_current_jump(struct ui_browser *browser) 211a3f895beSArnaldo Carvalho de Melo { 212a3f895beSArnaldo Carvalho de Melo struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 2139d1ef56dSArnaldo Carvalho de Melo struct disasm_line *cursor = ab->selection, *target; 2149d1ef56dSArnaldo Carvalho de Melo struct browser_disasm_line *btarget, *bcursor; 21583b1f2aaSArnaldo Carvalho de Melo unsigned int from, to; 21632ae1efdSNamhyung Kim struct map_symbol *ms = ab->b.priv; 21732ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 218c7e7b610SNamhyung Kim u8 pcnt_width = 7; 21932ae1efdSNamhyung Kim 22032ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 22132ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 22232ae1efdSNamhyung Kim return; 223a3f895beSArnaldo Carvalho de Melo 224865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(cursor, sym)) 225a3f895beSArnaldo Carvalho de Melo return; 226a3f895beSArnaldo Carvalho de Melo 2279d1ef56dSArnaldo Carvalho de Melo target = ab->offsets[cursor->ops.target.offset]; 2289d1ef56dSArnaldo Carvalho de Melo if (!target) 2299d1ef56dSArnaldo Carvalho de Melo return; 2309d1ef56dSArnaldo Carvalho de Melo 2319d1ef56dSArnaldo Carvalho de Melo bcursor = disasm_line__browser(cursor); 2329d1ef56dSArnaldo Carvalho de Melo btarget = disasm_line__browser(target); 2339d1ef56dSArnaldo Carvalho de Melo 234e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 2359d1ef56dSArnaldo Carvalho de Melo from = bcursor->idx_asm; 236a3f895beSArnaldo Carvalho de Melo to = btarget->idx_asm; 237a3f895beSArnaldo Carvalho de Melo } else { 2389d1ef56dSArnaldo Carvalho de Melo from = (u64)bcursor->idx; 239a3f895beSArnaldo Carvalho de Melo to = (u64)btarget->idx; 240a3f895beSArnaldo Carvalho de Melo } 241a3f895beSArnaldo Carvalho de Melo 242c7e7b610SNamhyung Kim pcnt_width *= ab->nr_events; 243c7e7b610SNamhyung Kim 244a3f895beSArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_CODE); 245c7e7b610SNamhyung Kim __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 246c7e7b610SNamhyung Kim from, to); 247a3f895beSArnaldo Carvalho de Melo } 248a3f895beSArnaldo Carvalho de Melo 249a3f895beSArnaldo Carvalho de Melo static unsigned int annotate_browser__refresh(struct ui_browser *browser) 250a3f895beSArnaldo Carvalho de Melo { 251c7e7b610SNamhyung Kim struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 252a3f895beSArnaldo Carvalho de Melo int ret = ui_browser__list_head_refresh(browser); 253c7e7b610SNamhyung Kim int pcnt_width; 254c7e7b610SNamhyung Kim 255c7e7b610SNamhyung Kim pcnt_width = 7 * ab->nr_events; 256a3f895beSArnaldo Carvalho de Melo 257e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.jump_arrows) 2589d1ef56dSArnaldo Carvalho de Melo annotate_browser__draw_current_jump(browser); 259a3f895beSArnaldo Carvalho de Melo 26083b1f2aaSArnaldo Carvalho de Melo ui_browser__set_color(browser, HE_COLORSET_NORMAL); 261c7e7b610SNamhyung Kim __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); 262a3f895beSArnaldo Carvalho de Melo return ret; 263a3f895beSArnaldo Carvalho de Melo } 264a3f895beSArnaldo Carvalho de Melo 265c7e7b610SNamhyung Kim static int disasm__cmp(struct browser_disasm_line *a, 266c7e7b610SNamhyung Kim struct browser_disasm_line *b, int nr_pcnt) 267c7e7b610SNamhyung Kim { 268c7e7b610SNamhyung Kim int i; 269c7e7b610SNamhyung Kim 270c7e7b610SNamhyung Kim for (i = 0; i < nr_pcnt; i++) { 271c7e7b610SNamhyung Kim if (a->percent[i] == b->percent[i]) 272c7e7b610SNamhyung Kim continue; 273c7e7b610SNamhyung Kim return a->percent[i] < b->percent[i]; 274c7e7b610SNamhyung Kim } 275c7e7b610SNamhyung Kim return 0; 276c7e7b610SNamhyung Kim } 277c7e7b610SNamhyung Kim 278c7e7b610SNamhyung Kim static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl, 279c7e7b610SNamhyung Kim int nr_events) 280aca7a94dSNamhyung Kim { 28129ed6e76SArnaldo Carvalho de Melo struct rb_node **p = &root->rb_node; 282aca7a94dSNamhyung Kim struct rb_node *parent = NULL; 283887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *l; 284aca7a94dSNamhyung Kim 285aca7a94dSNamhyung Kim while (*p != NULL) { 286aca7a94dSNamhyung Kim parent = *p; 287887c0066SArnaldo Carvalho de Melo l = rb_entry(parent, struct browser_disasm_line, rb_node); 288c7e7b610SNamhyung Kim 289c7e7b610SNamhyung Kim if (disasm__cmp(bdl, l, nr_events)) 290aca7a94dSNamhyung Kim p = &(*p)->rb_left; 291aca7a94dSNamhyung Kim else 292aca7a94dSNamhyung Kim p = &(*p)->rb_right; 293aca7a94dSNamhyung Kim } 294887c0066SArnaldo Carvalho de Melo rb_link_node(&bdl->rb_node, parent, p); 295887c0066SArnaldo Carvalho de Melo rb_insert_color(&bdl->rb_node, root); 296aca7a94dSNamhyung Kim } 297aca7a94dSNamhyung Kim 29805e8b080SArnaldo Carvalho de Melo static void annotate_browser__set_top(struct annotate_browser *browser, 29929ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos, u32 idx) 300aca7a94dSNamhyung Kim { 301aca7a94dSNamhyung Kim unsigned back; 302aca7a94dSNamhyung Kim 30305e8b080SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(&browser->b); 30405e8b080SArnaldo Carvalho de Melo back = browser->b.height / 2; 30505e8b080SArnaldo Carvalho de Melo browser->b.top_idx = browser->b.index = idx; 306aca7a94dSNamhyung Kim 30705e8b080SArnaldo Carvalho de Melo while (browser->b.top_idx != 0 && back != 0) { 30829ed6e76SArnaldo Carvalho de Melo pos = list_entry(pos->node.prev, struct disasm_line, node); 309aca7a94dSNamhyung Kim 31005e8b080SArnaldo Carvalho de Melo if (disasm_line__filter(&browser->b, &pos->node)) 311aca7a94dSNamhyung Kim continue; 312aca7a94dSNamhyung Kim 31305e8b080SArnaldo Carvalho de Melo --browser->b.top_idx; 314aca7a94dSNamhyung Kim --back; 315aca7a94dSNamhyung Kim } 316aca7a94dSNamhyung Kim 31705e8b080SArnaldo Carvalho de Melo browser->b.top = pos; 31805e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = true; 319aca7a94dSNamhyung Kim } 320aca7a94dSNamhyung Kim 321aca7a94dSNamhyung Kim static void annotate_browser__set_rb_top(struct annotate_browser *browser, 322aca7a94dSNamhyung Kim struct rb_node *nd) 323aca7a94dSNamhyung Kim { 324887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos; 32529ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 326a44b45f2SArnaldo Carvalho de Melo u32 idx; 327aca7a94dSNamhyung Kim 328887c0066SArnaldo Carvalho de Melo bpos = rb_entry(nd, struct browser_disasm_line, rb_node); 329887c0066SArnaldo Carvalho de Melo pos = ((struct disasm_line *)bpos) - 1; 330a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx; 331e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 332a44b45f2SArnaldo Carvalho de Melo idx = bpos->idx_asm; 333a44b45f2SArnaldo Carvalho de Melo annotate_browser__set_top(browser, pos, idx); 334aca7a94dSNamhyung Kim browser->curr_hot = nd; 335aca7a94dSNamhyung Kim } 336aca7a94dSNamhyung Kim 337aca7a94dSNamhyung Kim static void annotate_browser__calc_percent(struct annotate_browser *browser, 338db8fd07aSNamhyung Kim struct perf_evsel *evsel) 339aca7a94dSNamhyung Kim { 340aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 341aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 342aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 343e64aa75bSNamhyung Kim struct disasm_line *pos, *next; 344e64aa75bSNamhyung Kim s64 len = symbol__size(sym); 345aca7a94dSNamhyung Kim 346aca7a94dSNamhyung Kim browser->entries = RB_ROOT; 347aca7a94dSNamhyung Kim 348aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 349aca7a94dSNamhyung Kim 350aca7a94dSNamhyung Kim list_for_each_entry(pos, ¬es->src->source, node) { 351887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos = disasm_line__browser(pos); 352e64aa75bSNamhyung Kim const char *path = NULL; 353c7e7b610SNamhyung Kim double max_percent = 0.0; 354c7e7b610SNamhyung Kim int i; 355e64aa75bSNamhyung Kim 356e64aa75bSNamhyung Kim if (pos->offset == -1) { 357e64aa75bSNamhyung Kim RB_CLEAR_NODE(&bpos->rb_node); 358e64aa75bSNamhyung Kim continue; 359e64aa75bSNamhyung Kim } 360e64aa75bSNamhyung Kim 361e64aa75bSNamhyung Kim next = disasm__get_next_ip_line(¬es->src->source, pos); 362c7e7b610SNamhyung Kim 363c7e7b610SNamhyung Kim for (i = 0; i < browser->nr_events; i++) { 364c7e7b610SNamhyung Kim bpos->percent[i] = disasm__calc_percent(notes, 365c7e7b610SNamhyung Kim evsel->idx + i, 366c7e7b610SNamhyung Kim pos->offset, 367c7e7b610SNamhyung Kim next ? next->offset : len, 368e64aa75bSNamhyung Kim &path); 369e64aa75bSNamhyung Kim 370c7e7b610SNamhyung Kim if (max_percent < bpos->percent[i]) 371c7e7b610SNamhyung Kim max_percent = bpos->percent[i]; 372c7e7b610SNamhyung Kim } 373c7e7b610SNamhyung Kim 374c7e7b610SNamhyung Kim if (max_percent < 0.01) { 375887c0066SArnaldo Carvalho de Melo RB_CLEAR_NODE(&bpos->rb_node); 376aca7a94dSNamhyung Kim continue; 377aca7a94dSNamhyung Kim } 378c7e7b610SNamhyung Kim disasm_rb_tree__insert(&browser->entries, bpos, 379c7e7b610SNamhyung Kim browser->nr_events); 380aca7a94dSNamhyung Kim } 381aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 382aca7a94dSNamhyung Kim 383aca7a94dSNamhyung Kim browser->curr_hot = rb_last(&browser->entries); 384aca7a94dSNamhyung Kim } 385aca7a94dSNamhyung Kim 386aca7a94dSNamhyung Kim static bool annotate_browser__toggle_source(struct annotate_browser *browser) 387aca7a94dSNamhyung Kim { 38829ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 389887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bdl; 390aca7a94dSNamhyung Kim off_t offset = browser->b.index - browser->b.top_idx; 391aca7a94dSNamhyung Kim 392aca7a94dSNamhyung Kim browser->b.seek(&browser->b, offset, SEEK_CUR); 39329ed6e76SArnaldo Carvalho de Melo dl = list_entry(browser->b.top, struct disasm_line, node); 394887c0066SArnaldo Carvalho de Melo bdl = disasm_line__browser(dl); 395aca7a94dSNamhyung Kim 396e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) { 397887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < offset) 398887c0066SArnaldo Carvalho de Melo offset = bdl->idx; 399aca7a94dSNamhyung Kim 400aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_entries; 401e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = false; 402aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 403887c0066SArnaldo Carvalho de Melo browser->b.top_idx = bdl->idx - offset; 404887c0066SArnaldo Carvalho de Melo browser->b.index = bdl->idx; 405aca7a94dSNamhyung Kim } else { 406887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < 0) { 407aca7a94dSNamhyung Kim ui_helpline__puts("Only available for assembly lines."); 408aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 409aca7a94dSNamhyung Kim return false; 410aca7a94dSNamhyung Kim } 411aca7a94dSNamhyung Kim 412887c0066SArnaldo Carvalho de Melo if (bdl->idx_asm < offset) 413887c0066SArnaldo Carvalho de Melo offset = bdl->idx_asm; 414aca7a94dSNamhyung Kim 415aca7a94dSNamhyung Kim browser->b.nr_entries = browser->nr_asm_entries; 416e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.hide_src_code = true; 417aca7a94dSNamhyung Kim browser->b.seek(&browser->b, -offset, SEEK_CUR); 418887c0066SArnaldo Carvalho de Melo browser->b.top_idx = bdl->idx_asm - offset; 419887c0066SArnaldo Carvalho de Melo browser->b.index = bdl->idx_asm; 420aca7a94dSNamhyung Kim } 421aca7a94dSNamhyung Kim 422aca7a94dSNamhyung Kim return true; 423aca7a94dSNamhyung Kim } 424aca7a94dSNamhyung Kim 425e9823b21SArnaldo Carvalho de Melo static void annotate_browser__init_asm_mode(struct annotate_browser *browser) 426e9823b21SArnaldo Carvalho de Melo { 427e9823b21SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 428e9823b21SArnaldo Carvalho de Melo browser->b.nr_entries = browser->nr_asm_entries; 429e9823b21SArnaldo Carvalho de Melo } 430e9823b21SArnaldo Carvalho de Melo 43134f77abcSAdrian Hunter #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 43234f77abcSAdrian Hunter 43334f77abcSAdrian Hunter static int sym_title(struct symbol *sym, struct map *map, char *title, 43434f77abcSAdrian Hunter size_t sz) 43534f77abcSAdrian Hunter { 43634f77abcSAdrian Hunter return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); 43734f77abcSAdrian Hunter } 43834f77abcSAdrian Hunter 439db8fd07aSNamhyung Kim static bool annotate_browser__callq(struct annotate_browser *browser, 440db8fd07aSNamhyung Kim struct perf_evsel *evsel, 4419783adf7SNamhyung Kim struct hist_browser_timer *hbt) 442aca7a94dSNamhyung Kim { 443aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 444657bcaf5SArnaldo Carvalho de Melo struct disasm_line *dl = browser->selection; 445aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 446aca7a94dSNamhyung Kim struct annotation *notes; 447aca7a94dSNamhyung Kim struct symbol *target; 448aca7a94dSNamhyung Kim u64 ip; 44934f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 450aca7a94dSNamhyung Kim 451d86b0597SArnaldo Carvalho de Melo if (!ins__is_call(dl->ins)) 452aca7a94dSNamhyung Kim return false; 453aca7a94dSNamhyung Kim 45444d1a3edSArnaldo Carvalho de Melo ip = ms->map->map_ip(ms->map, dl->ops.target.addr); 455aca7a94dSNamhyung Kim target = map__find_symbol(ms->map, ip, NULL); 456aca7a94dSNamhyung Kim if (target == NULL) { 457aca7a94dSNamhyung Kim ui_helpline__puts("The called function was not found."); 458aca7a94dSNamhyung Kim return true; 459aca7a94dSNamhyung Kim } 460aca7a94dSNamhyung Kim 461aca7a94dSNamhyung Kim notes = symbol__annotation(target); 462aca7a94dSNamhyung Kim pthread_mutex_lock(¬es->lock); 463aca7a94dSNamhyung Kim 464aca7a94dSNamhyung Kim if (notes->src == NULL && symbol__alloc_hist(target) < 0) { 465aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 466aca7a94dSNamhyung Kim ui__warning("Not enough memory for annotating '%s' symbol!\n", 467aca7a94dSNamhyung Kim target->name); 468aca7a94dSNamhyung Kim return true; 469aca7a94dSNamhyung Kim } 470aca7a94dSNamhyung Kim 471aca7a94dSNamhyung Kim pthread_mutex_unlock(¬es->lock); 472db8fd07aSNamhyung Kim symbol__tui_annotate(target, ms->map, evsel, hbt); 47334f77abcSAdrian Hunter sym_title(sym, ms->map, title, sizeof(title)); 47434f77abcSAdrian Hunter ui_browser__show_title(&browser->b, title); 475aca7a94dSNamhyung Kim return true; 476aca7a94dSNamhyung Kim } 477aca7a94dSNamhyung Kim 47829ed6e76SArnaldo Carvalho de Melo static 47929ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 480aca7a94dSNamhyung Kim s64 offset, s64 *idx) 481aca7a94dSNamhyung Kim { 482aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 483aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 484aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 48529ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos; 486aca7a94dSNamhyung Kim 487aca7a94dSNamhyung Kim *idx = 0; 488aca7a94dSNamhyung Kim list_for_each_entry(pos, ¬es->src->source, node) { 489aca7a94dSNamhyung Kim if (pos->offset == offset) 490aca7a94dSNamhyung Kim return pos; 49129ed6e76SArnaldo Carvalho de Melo if (!disasm_line__filter(&browser->b, &pos->node)) 492aca7a94dSNamhyung Kim ++*idx; 493aca7a94dSNamhyung Kim } 494aca7a94dSNamhyung Kim 495aca7a94dSNamhyung Kim return NULL; 496aca7a94dSNamhyung Kim } 497aca7a94dSNamhyung Kim 498aca7a94dSNamhyung Kim static bool annotate_browser__jump(struct annotate_browser *browser) 499aca7a94dSNamhyung Kim { 500657bcaf5SArnaldo Carvalho de Melo struct disasm_line *dl = browser->selection; 5014f9d0325SArnaldo Carvalho de Melo s64 idx; 502aca7a94dSNamhyung Kim 503d86b0597SArnaldo Carvalho de Melo if (!ins__is_jump(dl->ins)) 504aca7a94dSNamhyung Kim return false; 505aca7a94dSNamhyung Kim 50644d1a3edSArnaldo Carvalho de Melo dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx); 50729ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 508*e6f65388SIngo Molnar ui_helpline__puts("Invalid jump offset"); 509aca7a94dSNamhyung Kim return true; 510aca7a94dSNamhyung Kim } 511aca7a94dSNamhyung Kim 51229ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 513aca7a94dSNamhyung Kim 514aca7a94dSNamhyung Kim return true; 515aca7a94dSNamhyung Kim } 516aca7a94dSNamhyung Kim 51729ed6e76SArnaldo Carvalho de Melo static 51829ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser, 519aca7a94dSNamhyung Kim char *s, s64 *idx) 520aca7a94dSNamhyung Kim { 521aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 522aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 523aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 52429ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos = browser->selection; 525aca7a94dSNamhyung Kim 526aca7a94dSNamhyung Kim *idx = browser->b.index; 527aca7a94dSNamhyung Kim list_for_each_entry_continue(pos, ¬es->src->source, node) { 52829ed6e76SArnaldo Carvalho de Melo if (disasm_line__filter(&browser->b, &pos->node)) 529aca7a94dSNamhyung Kim continue; 530aca7a94dSNamhyung Kim 531aca7a94dSNamhyung Kim ++*idx; 532aca7a94dSNamhyung Kim 533aca7a94dSNamhyung Kim if (pos->line && strstr(pos->line, s) != NULL) 534aca7a94dSNamhyung Kim return pos; 535aca7a94dSNamhyung Kim } 536aca7a94dSNamhyung Kim 537aca7a94dSNamhyung Kim return NULL; 538aca7a94dSNamhyung Kim } 539aca7a94dSNamhyung Kim 540aca7a94dSNamhyung Kim static bool __annotate_browser__search(struct annotate_browser *browser) 541aca7a94dSNamhyung Kim { 54229ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 543aca7a94dSNamhyung Kim s64 idx; 544aca7a94dSNamhyung Kim 54529ed6e76SArnaldo Carvalho de Melo dl = annotate_browser__find_string(browser, browser->search_bf, &idx); 54629ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 547aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 548aca7a94dSNamhyung Kim return false; 549aca7a94dSNamhyung Kim } 550aca7a94dSNamhyung Kim 55129ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 552aca7a94dSNamhyung Kim browser->searching_backwards = false; 553aca7a94dSNamhyung Kim return true; 554aca7a94dSNamhyung Kim } 555aca7a94dSNamhyung Kim 55629ed6e76SArnaldo Carvalho de Melo static 55729ed6e76SArnaldo Carvalho de Melo struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 558aca7a94dSNamhyung Kim char *s, s64 *idx) 559aca7a94dSNamhyung Kim { 560aca7a94dSNamhyung Kim struct map_symbol *ms = browser->b.priv; 561aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 562aca7a94dSNamhyung Kim struct annotation *notes = symbol__annotation(sym); 56329ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos = browser->selection; 564aca7a94dSNamhyung Kim 565aca7a94dSNamhyung Kim *idx = browser->b.index; 566aca7a94dSNamhyung Kim list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) { 56729ed6e76SArnaldo Carvalho de Melo if (disasm_line__filter(&browser->b, &pos->node)) 568aca7a94dSNamhyung Kim continue; 569aca7a94dSNamhyung Kim 570aca7a94dSNamhyung Kim --*idx; 571aca7a94dSNamhyung Kim 572aca7a94dSNamhyung Kim if (pos->line && strstr(pos->line, s) != NULL) 573aca7a94dSNamhyung Kim return pos; 574aca7a94dSNamhyung Kim } 575aca7a94dSNamhyung Kim 576aca7a94dSNamhyung Kim return NULL; 577aca7a94dSNamhyung Kim } 578aca7a94dSNamhyung Kim 579aca7a94dSNamhyung Kim static bool __annotate_browser__search_reverse(struct annotate_browser *browser) 580aca7a94dSNamhyung Kim { 58129ed6e76SArnaldo Carvalho de Melo struct disasm_line *dl; 582aca7a94dSNamhyung Kim s64 idx; 583aca7a94dSNamhyung Kim 58429ed6e76SArnaldo Carvalho de Melo dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 58529ed6e76SArnaldo Carvalho de Melo if (dl == NULL) { 586aca7a94dSNamhyung Kim ui_helpline__puts("String not found!"); 587aca7a94dSNamhyung Kim return false; 588aca7a94dSNamhyung Kim } 589aca7a94dSNamhyung Kim 59029ed6e76SArnaldo Carvalho de Melo annotate_browser__set_top(browser, dl, idx); 591aca7a94dSNamhyung Kim browser->searching_backwards = true; 592aca7a94dSNamhyung Kim return true; 593aca7a94dSNamhyung Kim } 594aca7a94dSNamhyung Kim 595aca7a94dSNamhyung Kim static bool annotate_browser__search_window(struct annotate_browser *browser, 596aca7a94dSNamhyung Kim int delay_secs) 597aca7a94dSNamhyung Kim { 598aca7a94dSNamhyung Kim if (ui_browser__input_window("Search", "String: ", browser->search_bf, 599aca7a94dSNamhyung Kim "ENTER: OK, ESC: Cancel", 600aca7a94dSNamhyung Kim delay_secs * 2) != K_ENTER || 601aca7a94dSNamhyung Kim !*browser->search_bf) 602aca7a94dSNamhyung Kim return false; 603aca7a94dSNamhyung Kim 604aca7a94dSNamhyung Kim return true; 605aca7a94dSNamhyung Kim } 606aca7a94dSNamhyung Kim 607aca7a94dSNamhyung Kim static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) 608aca7a94dSNamhyung Kim { 609aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 610aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 611aca7a94dSNamhyung Kim 612aca7a94dSNamhyung Kim return false; 613aca7a94dSNamhyung Kim } 614aca7a94dSNamhyung Kim 615aca7a94dSNamhyung Kim static bool annotate_browser__continue_search(struct annotate_browser *browser, 616aca7a94dSNamhyung Kim int delay_secs) 617aca7a94dSNamhyung Kim { 618aca7a94dSNamhyung Kim if (!*browser->search_bf) 619aca7a94dSNamhyung Kim return annotate_browser__search(browser, delay_secs); 620aca7a94dSNamhyung Kim 621aca7a94dSNamhyung Kim return __annotate_browser__search(browser); 622aca7a94dSNamhyung Kim } 623aca7a94dSNamhyung Kim 624aca7a94dSNamhyung Kim static bool annotate_browser__search_reverse(struct annotate_browser *browser, 625aca7a94dSNamhyung Kim int delay_secs) 626aca7a94dSNamhyung Kim { 627aca7a94dSNamhyung Kim if (annotate_browser__search_window(browser, delay_secs)) 628aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 629aca7a94dSNamhyung Kim 630aca7a94dSNamhyung Kim return false; 631aca7a94dSNamhyung Kim } 632aca7a94dSNamhyung Kim 633aca7a94dSNamhyung Kim static 634aca7a94dSNamhyung Kim bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, 635aca7a94dSNamhyung Kim int delay_secs) 636aca7a94dSNamhyung Kim { 637aca7a94dSNamhyung Kim if (!*browser->search_bf) 638aca7a94dSNamhyung Kim return annotate_browser__search_reverse(browser, delay_secs); 639aca7a94dSNamhyung Kim 640aca7a94dSNamhyung Kim return __annotate_browser__search_reverse(browser); 641aca7a94dSNamhyung Kim } 642aca7a94dSNamhyung Kim 643e9823b21SArnaldo Carvalho de Melo static void annotate_browser__update_addr_width(struct annotate_browser *browser) 644e9823b21SArnaldo Carvalho de Melo { 645e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.use_offset) 646e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->min_addr_width; 647e9823b21SArnaldo Carvalho de Melo else 648e9823b21SArnaldo Carvalho de Melo browser->target_width = browser->max_addr_width; 649e9823b21SArnaldo Carvalho de Melo 650e9823b21SArnaldo Carvalho de Melo browser->addr_width = browser->target_width; 651e9823b21SArnaldo Carvalho de Melo 652e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.show_nr_jumps) 653e9823b21SArnaldo Carvalho de Melo browser->addr_width += browser->jumps_width + 1; 654e9823b21SArnaldo Carvalho de Melo } 655e9823b21SArnaldo Carvalho de Melo 656db8fd07aSNamhyung Kim static int annotate_browser__run(struct annotate_browser *browser, 657db8fd07aSNamhyung Kim struct perf_evsel *evsel, 6589783adf7SNamhyung Kim struct hist_browser_timer *hbt) 659aca7a94dSNamhyung Kim { 660aca7a94dSNamhyung Kim struct rb_node *nd = NULL; 66105e8b080SArnaldo Carvalho de Melo struct map_symbol *ms = browser->b.priv; 662aca7a94dSNamhyung Kim struct symbol *sym = ms->sym; 66354e7a4e8SArnaldo Carvalho de Melo const char *help = "Press 'h' for help on key bindings"; 6649783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 665aca7a94dSNamhyung Kim int key; 66634f77abcSAdrian Hunter char title[SYM_TITLE_MAX_SIZE]; 667aca7a94dSNamhyung Kim 66834f77abcSAdrian Hunter sym_title(sym, ms->map, title, sizeof(title)); 66934f77abcSAdrian Hunter if (ui_browser__show(&browser->b, title, help) < 0) 670aca7a94dSNamhyung Kim return -1; 671aca7a94dSNamhyung Kim 672db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 673aca7a94dSNamhyung Kim 67405e8b080SArnaldo Carvalho de Melo if (browser->curr_hot) { 67505e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, browser->curr_hot); 67605e8b080SArnaldo Carvalho de Melo browser->b.navkeypressed = false; 677aca7a94dSNamhyung Kim } 678aca7a94dSNamhyung Kim 67905e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 680aca7a94dSNamhyung Kim 681aca7a94dSNamhyung Kim while (1) { 68205e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 683aca7a94dSNamhyung Kim 684aca7a94dSNamhyung Kim if (delay_secs != 0) { 685db8fd07aSNamhyung Kim annotate_browser__calc_percent(browser, evsel); 686aca7a94dSNamhyung Kim /* 687aca7a94dSNamhyung Kim * Current line focus got out of the list of most active 688aca7a94dSNamhyung Kim * lines, NULL it so that if TAB|UNTAB is pressed, we 689aca7a94dSNamhyung Kim * move to curr_hot (current hottest line). 690aca7a94dSNamhyung Kim */ 691aca7a94dSNamhyung Kim if (nd != NULL && RB_EMPTY_NODE(nd)) 692aca7a94dSNamhyung Kim nd = NULL; 693aca7a94dSNamhyung Kim } 694aca7a94dSNamhyung Kim 695aca7a94dSNamhyung Kim switch (key) { 696aca7a94dSNamhyung Kim case K_TIMER: 6979783adf7SNamhyung Kim if (hbt) 6989783adf7SNamhyung Kim hbt->timer(hbt->arg); 699aca7a94dSNamhyung Kim 700aca7a94dSNamhyung Kim if (delay_secs != 0) 701db8fd07aSNamhyung Kim symbol__annotate_decay_histogram(sym, evsel->idx); 702aca7a94dSNamhyung Kim continue; 703aca7a94dSNamhyung Kim case K_TAB: 704aca7a94dSNamhyung Kim if (nd != NULL) { 705aca7a94dSNamhyung Kim nd = rb_prev(nd); 706aca7a94dSNamhyung Kim if (nd == NULL) 70705e8b080SArnaldo Carvalho de Melo nd = rb_last(&browser->entries); 708aca7a94dSNamhyung Kim } else 70905e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 710aca7a94dSNamhyung Kim break; 711aca7a94dSNamhyung Kim case K_UNTAB: 712aca7a94dSNamhyung Kim if (nd != NULL) 713aca7a94dSNamhyung Kim nd = rb_next(nd); 714aca7a94dSNamhyung Kim if (nd == NULL) 71505e8b080SArnaldo Carvalho de Melo nd = rb_first(&browser->entries); 716aca7a94dSNamhyung Kim else 71705e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 718aca7a94dSNamhyung Kim break; 71954e7a4e8SArnaldo Carvalho de Melo case K_F1: 720aca7a94dSNamhyung Kim case 'h': 72105e8b080SArnaldo Carvalho de Melo ui_browser__help_window(&browser->b, 72254e7a4e8SArnaldo Carvalho de Melo "UP/DOWN/PGUP\n" 72354e7a4e8SArnaldo Carvalho de Melo "PGDN/SPACE Navigate\n" 72454e7a4e8SArnaldo Carvalho de Melo "q/ESC/CTRL+C Exit\n\n" 72554e7a4e8SArnaldo Carvalho de Melo "-> Go to target\n" 72654e7a4e8SArnaldo Carvalho de Melo "<- Exit\n" 727107baecaSArnaldo Carvalho de Melo "H Cycle thru hottest instructions\n" 72854e7a4e8SArnaldo Carvalho de Melo "j Toggle showing jump to target arrows\n" 72954e7a4e8SArnaldo Carvalho de Melo "J Toggle showing number of jump sources on targets\n" 73054e7a4e8SArnaldo Carvalho de Melo "n Search next string\n" 73154e7a4e8SArnaldo Carvalho de Melo "o Toggle disassembler output/simplified view\n" 73254e7a4e8SArnaldo Carvalho de Melo "s Toggle source code view\n" 73354e7a4e8SArnaldo Carvalho de Melo "/ Search string\n" 73479ee47faSFeng Tang "r Run available scripts\n" 735fcd9fef9SArnaldo Carvalho de Melo "? Search string backwards\n"); 73654e7a4e8SArnaldo Carvalho de Melo continue; 73779ee47faSFeng Tang case 'r': 73879ee47faSFeng Tang { 73979ee47faSFeng Tang script_browse(NULL); 74079ee47faSFeng Tang continue; 74179ee47faSFeng Tang } 74254e7a4e8SArnaldo Carvalho de Melo case 'H': 74305e8b080SArnaldo Carvalho de Melo nd = browser->curr_hot; 744aca7a94dSNamhyung Kim break; 745aca7a94dSNamhyung Kim case 's': 74605e8b080SArnaldo Carvalho de Melo if (annotate_browser__toggle_source(browser)) 747aca7a94dSNamhyung Kim ui_helpline__puts(help); 748aca7a94dSNamhyung Kim continue; 749aca7a94dSNamhyung Kim case 'o': 750e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset; 75105e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 752aca7a94dSNamhyung Kim continue; 7539d1ef56dSArnaldo Carvalho de Melo case 'j': 754e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows; 7559d1ef56dSArnaldo Carvalho de Melo continue; 7562402e4a9SArnaldo Carvalho de Melo case 'J': 757e9823b21SArnaldo Carvalho de Melo annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps; 75805e8b080SArnaldo Carvalho de Melo annotate_browser__update_addr_width(browser); 759e9823b21SArnaldo Carvalho de Melo continue; 760aca7a94dSNamhyung Kim case '/': 76105e8b080SArnaldo Carvalho de Melo if (annotate_browser__search(browser, delay_secs)) { 762aca7a94dSNamhyung Kim show_help: 763aca7a94dSNamhyung Kim ui_helpline__puts(help); 764aca7a94dSNamhyung Kim } 765aca7a94dSNamhyung Kim continue; 766aca7a94dSNamhyung Kim case 'n': 76705e8b080SArnaldo Carvalho de Melo if (browser->searching_backwards ? 76805e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search_reverse(browser, delay_secs) : 76905e8b080SArnaldo Carvalho de Melo annotate_browser__continue_search(browser, delay_secs)) 770aca7a94dSNamhyung Kim goto show_help; 771aca7a94dSNamhyung Kim continue; 772aca7a94dSNamhyung Kim case '?': 77305e8b080SArnaldo Carvalho de Melo if (annotate_browser__search_reverse(browser, delay_secs)) 774aca7a94dSNamhyung Kim goto show_help; 775aca7a94dSNamhyung Kim continue; 776e9823b21SArnaldo Carvalho de Melo case 'D': { 777e9823b21SArnaldo Carvalho de Melo static int seq; 778e9823b21SArnaldo Carvalho de Melo ui_helpline__pop(); 779e9823b21SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d", 78005e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 78105e8b080SArnaldo Carvalho de Melo browser->b.height, 78205e8b080SArnaldo Carvalho de Melo browser->b.index, 78305e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 78405e8b080SArnaldo Carvalho de Melo browser->nr_asm_entries); 785e9823b21SArnaldo Carvalho de Melo } 786e9823b21SArnaldo Carvalho de Melo continue; 787aca7a94dSNamhyung Kim case K_ENTER: 788aca7a94dSNamhyung Kim case K_RIGHT: 78905e8b080SArnaldo Carvalho de Melo if (browser->selection == NULL) 790aca7a94dSNamhyung Kim ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 79105e8b080SArnaldo Carvalho de Melo else if (browser->selection->offset == -1) 792aca7a94dSNamhyung Kim ui_helpline__puts("Actions are only available for assembly lines."); 79305e8b080SArnaldo Carvalho de Melo else if (!browser->selection->ins) { 79405e8b080SArnaldo Carvalho de Melo if (strcmp(browser->selection->name, "retq")) 795c4cceae3SArnaldo Carvalho de Melo goto show_sup_ins; 796c4cceae3SArnaldo Carvalho de Melo goto out; 79705e8b080SArnaldo Carvalho de Melo } else if (!(annotate_browser__jump(browser) || 798db8fd07aSNamhyung Kim annotate_browser__callq(browser, evsel, hbt))) { 799c4cceae3SArnaldo Carvalho de Melo show_sup_ins: 800c4cceae3SArnaldo Carvalho de Melo ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 801c4cceae3SArnaldo Carvalho de Melo } 802aca7a94dSNamhyung Kim continue; 803aca7a94dSNamhyung Kim case K_LEFT: 804aca7a94dSNamhyung Kim case K_ESC: 805aca7a94dSNamhyung Kim case 'q': 806aca7a94dSNamhyung Kim case CTRL('c'): 807aca7a94dSNamhyung Kim goto out; 808aca7a94dSNamhyung Kim default: 809aca7a94dSNamhyung Kim continue; 810aca7a94dSNamhyung Kim } 811aca7a94dSNamhyung Kim 812aca7a94dSNamhyung Kim if (nd != NULL) 81305e8b080SArnaldo Carvalho de Melo annotate_browser__set_rb_top(browser, nd); 814aca7a94dSNamhyung Kim } 815aca7a94dSNamhyung Kim out: 81605e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 817aca7a94dSNamhyung Kim return key; 818aca7a94dSNamhyung Kim } 819aca7a94dSNamhyung Kim 820db8fd07aSNamhyung Kim int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 8219783adf7SNamhyung Kim struct hist_browser_timer *hbt) 822aca7a94dSNamhyung Kim { 823db8fd07aSNamhyung Kim return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt); 824aca7a94dSNamhyung Kim } 825aca7a94dSNamhyung Kim 826b793a401SArnaldo Carvalho de Melo static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 827b793a401SArnaldo Carvalho de Melo size_t size) 828b793a401SArnaldo Carvalho de Melo { 829b793a401SArnaldo Carvalho de Melo u64 offset; 83032ae1efdSNamhyung Kim struct map_symbol *ms = browser->b.priv; 83132ae1efdSNamhyung Kim struct symbol *sym = ms->sym; 83232ae1efdSNamhyung Kim 83332ae1efdSNamhyung Kim /* PLT symbols contain external offsets */ 83432ae1efdSNamhyung Kim if (strstr(sym->name, "@plt")) 83532ae1efdSNamhyung Kim return; 836b793a401SArnaldo Carvalho de Melo 837b793a401SArnaldo Carvalho de Melo for (offset = 0; offset < size; ++offset) { 838b793a401SArnaldo Carvalho de Melo struct disasm_line *dl = browser->offsets[offset], *dlt; 839b793a401SArnaldo Carvalho de Melo struct browser_disasm_line *bdlt; 840b793a401SArnaldo Carvalho de Melo 841865c66c4SFrederik Deweerdt if (!disasm_line__is_valid_jump(dl, sym)) 842b793a401SArnaldo Carvalho de Melo continue; 843b793a401SArnaldo Carvalho de Melo 84444d1a3edSArnaldo Carvalho de Melo dlt = browser->offsets[dl->ops.target.offset]; 8459481ede9SArnaldo Carvalho de Melo /* 8469481ede9SArnaldo Carvalho de Melo * FIXME: Oops, no jump target? Buggy disassembler? Or do we 8479481ede9SArnaldo Carvalho de Melo * have to adjust to the previous offset? 8489481ede9SArnaldo Carvalho de Melo */ 8499481ede9SArnaldo Carvalho de Melo if (dlt == NULL) 8509481ede9SArnaldo Carvalho de Melo continue; 8519481ede9SArnaldo Carvalho de Melo 852b793a401SArnaldo Carvalho de Melo bdlt = disasm_line__browser(dlt); 8532402e4a9SArnaldo Carvalho de Melo if (++bdlt->jump_sources > browser->max_jump_sources) 8542402e4a9SArnaldo Carvalho de Melo browser->max_jump_sources = bdlt->jump_sources; 8552402e4a9SArnaldo Carvalho de Melo 8562402e4a9SArnaldo Carvalho de Melo ++browser->nr_jumps; 857b793a401SArnaldo Carvalho de Melo } 858b793a401SArnaldo Carvalho de Melo 859b793a401SArnaldo Carvalho de Melo } 860b793a401SArnaldo Carvalho de Melo 8612402e4a9SArnaldo Carvalho de Melo static inline int width_jumps(int n) 8622402e4a9SArnaldo Carvalho de Melo { 8632402e4a9SArnaldo Carvalho de Melo if (n >= 100) 8642402e4a9SArnaldo Carvalho de Melo return 5; 8652402e4a9SArnaldo Carvalho de Melo if (n / 10) 8662402e4a9SArnaldo Carvalho de Melo return 2; 8672402e4a9SArnaldo Carvalho de Melo return 1; 8682402e4a9SArnaldo Carvalho de Melo } 8692402e4a9SArnaldo Carvalho de Melo 870db8fd07aSNamhyung Kim int symbol__tui_annotate(struct symbol *sym, struct map *map, 871db8fd07aSNamhyung Kim struct perf_evsel *evsel, 8729783adf7SNamhyung Kim struct hist_browser_timer *hbt) 873aca7a94dSNamhyung Kim { 87429ed6e76SArnaldo Carvalho de Melo struct disasm_line *pos, *n; 875aca7a94dSNamhyung Kim struct annotation *notes; 876c0a58fb2SSamuel Liao size_t size; 877aca7a94dSNamhyung Kim struct map_symbol ms = { 878aca7a94dSNamhyung Kim .map = map, 879aca7a94dSNamhyung Kim .sym = sym, 880aca7a94dSNamhyung Kim }; 881aca7a94dSNamhyung Kim struct annotate_browser browser = { 882aca7a94dSNamhyung Kim .b = { 883a3f895beSArnaldo Carvalho de Melo .refresh = annotate_browser__refresh, 884aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 885aca7a94dSNamhyung Kim .write = annotate_browser__write, 88629ed6e76SArnaldo Carvalho de Melo .filter = disasm_line__filter, 887aca7a94dSNamhyung Kim .priv = &ms, 888aca7a94dSNamhyung Kim .use_navkeypressed = true, 889aca7a94dSNamhyung Kim }, 890aca7a94dSNamhyung Kim }; 891b793a401SArnaldo Carvalho de Melo int ret = -1; 892c7e7b610SNamhyung Kim int nr_pcnt = 1; 893c7e7b610SNamhyung Kim size_t sizeof_bdl = sizeof(struct browser_disasm_line); 894aca7a94dSNamhyung Kim 895aca7a94dSNamhyung Kim if (sym == NULL) 896aca7a94dSNamhyung Kim return -1; 897aca7a94dSNamhyung Kim 898c0a58fb2SSamuel Liao size = symbol__size(sym); 899c0a58fb2SSamuel Liao 900aca7a94dSNamhyung Kim if (map->dso->annotate_warned) 901aca7a94dSNamhyung Kim return -1; 902aca7a94dSNamhyung Kim 903b793a401SArnaldo Carvalho de Melo browser.offsets = zalloc(size * sizeof(struct disasm_line *)); 904b793a401SArnaldo Carvalho de Melo if (browser.offsets == NULL) { 905b793a401SArnaldo Carvalho de Melo ui__error("Not enough memory!"); 906b793a401SArnaldo Carvalho de Melo return -1; 907b793a401SArnaldo Carvalho de Melo } 908b793a401SArnaldo Carvalho de Melo 909c7e7b610SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 910c7e7b610SNamhyung Kim nr_pcnt = evsel->nr_members; 911c7e7b610SNamhyung Kim sizeof_bdl += sizeof(double) * (nr_pcnt - 1); 912c7e7b610SNamhyung Kim } 913c7e7b610SNamhyung Kim 914c7e7b610SNamhyung Kim if (symbol__annotate(sym, map, sizeof_bdl) < 0) { 915aca7a94dSNamhyung Kim ui__error("%s", ui_helpline__last_msg); 916b793a401SArnaldo Carvalho de Melo goto out_free_offsets; 917aca7a94dSNamhyung Kim } 918aca7a94dSNamhyung Kim 919aca7a94dSNamhyung Kim ui_helpline__push("Press <- or ESC to exit"); 920aca7a94dSNamhyung Kim 921aca7a94dSNamhyung Kim notes = symbol__annotation(sym); 922aca7a94dSNamhyung Kim browser.start = map__rip_2objdump(map, sym->start); 923aca7a94dSNamhyung Kim 924aca7a94dSNamhyung Kim list_for_each_entry(pos, ¬es->src->source, node) { 925887c0066SArnaldo Carvalho de Melo struct browser_disasm_line *bpos; 926aca7a94dSNamhyung Kim size_t line_len = strlen(pos->line); 927aca7a94dSNamhyung Kim 928aca7a94dSNamhyung Kim if (browser.b.width < line_len) 929aca7a94dSNamhyung Kim browser.b.width = line_len; 930887c0066SArnaldo Carvalho de Melo bpos = disasm_line__browser(pos); 931887c0066SArnaldo Carvalho de Melo bpos->idx = browser.nr_entries++; 932b793a401SArnaldo Carvalho de Melo if (pos->offset != -1) { 933887c0066SArnaldo Carvalho de Melo bpos->idx_asm = browser.nr_asm_entries++; 93497148a97SArnaldo Carvalho de Melo /* 93597148a97SArnaldo Carvalho de Melo * FIXME: short term bandaid to cope with assembly 93697148a97SArnaldo Carvalho de Melo * routines that comes with labels in the same column 93797148a97SArnaldo Carvalho de Melo * as the address in objdump, sigh. 93897148a97SArnaldo Carvalho de Melo * 93997148a97SArnaldo Carvalho de Melo * E.g. copy_user_generic_unrolled 94097148a97SArnaldo Carvalho de Melo */ 94197148a97SArnaldo Carvalho de Melo if (pos->offset < (s64)size) 942b793a401SArnaldo Carvalho de Melo browser.offsets[pos->offset] = pos; 943b793a401SArnaldo Carvalho de Melo } else 944887c0066SArnaldo Carvalho de Melo bpos->idx_asm = -1; 945aca7a94dSNamhyung Kim } 946aca7a94dSNamhyung Kim 947b793a401SArnaldo Carvalho de Melo annotate_browser__mark_jump_targets(&browser, size); 948b793a401SArnaldo Carvalho de Melo 9492402e4a9SArnaldo Carvalho de Melo browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); 95083b1f2aaSArnaldo Carvalho de Melo browser.max_addr_width = hex_width(sym->end); 9512402e4a9SArnaldo Carvalho de Melo browser.jumps_width = width_jumps(browser.max_jump_sources); 952c7e7b610SNamhyung Kim browser.nr_events = nr_pcnt; 953aca7a94dSNamhyung Kim browser.b.nr_entries = browser.nr_entries; 954aca7a94dSNamhyung Kim browser.b.entries = ¬es->src->source, 955aca7a94dSNamhyung Kim browser.b.width += 18; /* Percentage */ 956e9823b21SArnaldo Carvalho de Melo 957e9823b21SArnaldo Carvalho de Melo if (annotate_browser__opts.hide_src_code) 958e9823b21SArnaldo Carvalho de Melo annotate_browser__init_asm_mode(&browser); 959e9823b21SArnaldo Carvalho de Melo 960e9823b21SArnaldo Carvalho de Melo annotate_browser__update_addr_width(&browser); 961e9823b21SArnaldo Carvalho de Melo 962db8fd07aSNamhyung Kim ret = annotate_browser__run(&browser, evsel, hbt); 963aca7a94dSNamhyung Kim list_for_each_entry_safe(pos, n, ¬es->src->source, node) { 964aca7a94dSNamhyung Kim list_del(&pos->node); 96529ed6e76SArnaldo Carvalho de Melo disasm_line__free(pos); 966aca7a94dSNamhyung Kim } 967b793a401SArnaldo Carvalho de Melo 968b793a401SArnaldo Carvalho de Melo out_free_offsets: 969b793a401SArnaldo Carvalho de Melo free(browser.offsets); 970aca7a94dSNamhyung Kim return ret; 971aca7a94dSNamhyung Kim } 972c323cf04SArnaldo Carvalho de Melo 973c323cf04SArnaldo Carvalho de Melo #define ANNOTATE_CFG(n) \ 974c323cf04SArnaldo Carvalho de Melo { .name = #n, .value = &annotate_browser__opts.n, } 975c323cf04SArnaldo Carvalho de Melo 976c323cf04SArnaldo Carvalho de Melo /* 977c323cf04SArnaldo Carvalho de Melo * Keep the entries sorted, they are bsearch'ed 978c323cf04SArnaldo Carvalho de Melo */ 9797c3102b8SArnaldo Carvalho de Melo static struct annotate_config { 980c323cf04SArnaldo Carvalho de Melo const char *name; 981c323cf04SArnaldo Carvalho de Melo bool *value; 982c323cf04SArnaldo Carvalho de Melo } annotate__configs[] = { 983c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(hide_src_code), 984c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(jump_arrows), 985c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(show_nr_jumps), 986c323cf04SArnaldo Carvalho de Melo ANNOTATE_CFG(use_offset), 987c323cf04SArnaldo Carvalho de Melo }; 988c323cf04SArnaldo Carvalho de Melo 989c323cf04SArnaldo Carvalho de Melo #undef ANNOTATE_CFG 990c323cf04SArnaldo Carvalho de Melo 991c323cf04SArnaldo Carvalho de Melo static int annotate_config__cmp(const void *name, const void *cfgp) 992c323cf04SArnaldo Carvalho de Melo { 9937c3102b8SArnaldo Carvalho de Melo const struct annotate_config *cfg = cfgp; 994c323cf04SArnaldo Carvalho de Melo 995c323cf04SArnaldo Carvalho de Melo return strcmp(name, cfg->name); 996c323cf04SArnaldo Carvalho de Melo } 997c323cf04SArnaldo Carvalho de Melo 9981d037ca1SIrina Tirdea static int annotate__config(const char *var, const char *value, 9991d037ca1SIrina Tirdea void *data __maybe_unused) 1000c323cf04SArnaldo Carvalho de Melo { 10017c3102b8SArnaldo Carvalho de Melo struct annotate_config *cfg; 1002c323cf04SArnaldo Carvalho de Melo const char *name; 1003c323cf04SArnaldo Carvalho de Melo 1004c323cf04SArnaldo Carvalho de Melo if (prefixcmp(var, "annotate.") != 0) 1005c323cf04SArnaldo Carvalho de Melo return 0; 1006c323cf04SArnaldo Carvalho de Melo 1007c323cf04SArnaldo Carvalho de Melo name = var + 9; 1008c323cf04SArnaldo Carvalho de Melo cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), 10097c3102b8SArnaldo Carvalho de Melo sizeof(struct annotate_config), annotate_config__cmp); 1010c323cf04SArnaldo Carvalho de Melo 1011c323cf04SArnaldo Carvalho de Melo if (cfg == NULL) 1012c323cf04SArnaldo Carvalho de Melo return -1; 1013c323cf04SArnaldo Carvalho de Melo 1014c323cf04SArnaldo Carvalho de Melo *cfg->value = perf_config_bool(name, value); 1015c323cf04SArnaldo Carvalho de Melo return 0; 1016c323cf04SArnaldo Carvalho de Melo } 1017c323cf04SArnaldo Carvalho de Melo 1018c323cf04SArnaldo Carvalho de Melo void annotate_browser__init(void) 1019c323cf04SArnaldo Carvalho de Melo { 1020c323cf04SArnaldo Carvalho de Melo perf_config(annotate__config, NULL); 1021c323cf04SArnaldo Carvalho de Melo } 1022