18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include "../browser.h" 38c2ecf20Sopenharmony_ci#include "../helpline.h" 48c2ecf20Sopenharmony_ci#include "../ui.h" 58c2ecf20Sopenharmony_ci#include "../../util/annotate.h" 68c2ecf20Sopenharmony_ci#include "../../util/debug.h" 78c2ecf20Sopenharmony_ci#include "../../util/dso.h" 88c2ecf20Sopenharmony_ci#include "../../util/hist.h" 98c2ecf20Sopenharmony_ci#include "../../util/sort.h" 108c2ecf20Sopenharmony_ci#include "../../util/map.h" 118c2ecf20Sopenharmony_ci#include "../../util/symbol.h" 128c2ecf20Sopenharmony_ci#include "../../util/evsel.h" 138c2ecf20Sopenharmony_ci#include "../../util/evlist.h" 148c2ecf20Sopenharmony_ci#include <inttypes.h> 158c2ecf20Sopenharmony_ci#include <pthread.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 198c2ecf20Sopenharmony_ci#include <sys/ttydefaults.h> 208c2ecf20Sopenharmony_ci#include <asm/bug.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct disasm_line_samples { 238c2ecf20Sopenharmony_ci double percent; 248c2ecf20Sopenharmony_ci struct sym_hist_entry he; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct arch; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct annotate_browser { 308c2ecf20Sopenharmony_ci struct ui_browser b; 318c2ecf20Sopenharmony_ci struct rb_root entries; 328c2ecf20Sopenharmony_ci struct rb_node *curr_hot; 338c2ecf20Sopenharmony_ci struct annotation_line *selection; 348c2ecf20Sopenharmony_ci struct arch *arch; 358c2ecf20Sopenharmony_ci struct annotation_options *opts; 368c2ecf20Sopenharmony_ci bool searching_backwards; 378c2ecf20Sopenharmony_ci char search_bf[128]; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic inline struct annotation *browser__annotation(struct ui_browser *browser) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct map_symbol *ms = browser->priv; 438c2ecf20Sopenharmony_ci return symbol__annotation(ms->sym); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic bool disasm_line__filter(struct ui_browser *browser, void *entry) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(browser); 498c2ecf20Sopenharmony_ci struct annotation_line *al = list_entry(entry, struct annotation_line, node); 508c2ecf20Sopenharmony_ci return annotation_line__filter(al, notes); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(browser); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (current && (!browser->use_navkeypressed || browser->navkeypressed)) 588c2ecf20Sopenharmony_ci return HE_COLORSET_SELECTED; 598c2ecf20Sopenharmony_ci if (nr == notes->max_jump_sources) 608c2ecf20Sopenharmony_ci return HE_COLORSET_TOP; 618c2ecf20Sopenharmony_ci if (nr > 1) 628c2ecf20Sopenharmony_ci return HE_COLORSET_MEDIUM; 638c2ecf20Sopenharmony_ci return HE_COLORSET_NORMAL; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int color = ui_browser__jumps_percent_color(browser, nr, current); 698c2ecf20Sopenharmony_ci return ui_browser__set_color(browser, color); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int annotate_browser__set_color(void *browser, int color) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci return ui_browser__set_color(browser, color); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void annotate_browser__write_graph(void *browser, int graph) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci ui_browser__write_graph(browser, graph); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void annotate_browser__set_percent_color(void *browser, double percent, bool current) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci ui_browser__set_percent_color(browser, percent, current); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void annotate_browser__printf(void *browser, const char *fmt, ...) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci va_list args; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci va_start(args, fmt); 928c2ecf20Sopenharmony_ci ui_browser__vprintf(browser, fmt, args); 938c2ecf20Sopenharmony_ci va_end(args); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void annotate_browser__write(struct ui_browser *browser, void *entry, int row) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 998c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(browser); 1008c2ecf20Sopenharmony_ci struct annotation_line *al = list_entry(entry, struct annotation_line, node); 1018c2ecf20Sopenharmony_ci const bool is_current_entry = ui_browser__is_current_entry(browser, row); 1028c2ecf20Sopenharmony_ci struct annotation_write_ops ops = { 1038c2ecf20Sopenharmony_ci .first_line = row == 0, 1048c2ecf20Sopenharmony_ci .current_entry = is_current_entry, 1058c2ecf20Sopenharmony_ci .change_color = (!notes->options->hide_src_code && 1068c2ecf20Sopenharmony_ci (!is_current_entry || 1078c2ecf20Sopenharmony_ci (browser->use_navkeypressed && 1088c2ecf20Sopenharmony_ci !browser->navkeypressed))), 1098c2ecf20Sopenharmony_ci .width = browser->width, 1108c2ecf20Sopenharmony_ci .obj = browser, 1118c2ecf20Sopenharmony_ci .set_color = annotate_browser__set_color, 1128c2ecf20Sopenharmony_ci .set_percent_color = annotate_browser__set_percent_color, 1138c2ecf20Sopenharmony_ci .set_jumps_percent_color = ui_browser__set_jumps_percent_color, 1148c2ecf20Sopenharmony_ci .printf = annotate_browser__printf, 1158c2ecf20Sopenharmony_ci .write_graph = annotate_browser__write_graph, 1168c2ecf20Sopenharmony_ci }; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* The scroll bar isn't being used */ 1198c2ecf20Sopenharmony_ci if (!browser->navkeypressed) 1208c2ecf20Sopenharmony_ci ops.width += 1; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci annotation_line__write(al, notes, &ops, ab->opts); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (ops.current_entry) 1258c2ecf20Sopenharmony_ci ab->selection = al; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct disasm_line *pos = list_prev_entry(cursor, al.node); 1318c2ecf20Sopenharmony_ci const char *name; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!pos) 1348c2ecf20Sopenharmony_ci return false; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (ins__is_lock(&pos->ins)) 1378c2ecf20Sopenharmony_ci name = pos->ops.locked.ins.name; 1388c2ecf20Sopenharmony_ci else 1398c2ecf20Sopenharmony_ci name = pos->ins.name; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!name || !cursor->ins.name) 1428c2ecf20Sopenharmony_ci return false; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return ins__is_fused(ab->arch, name, cursor->ins.name); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void annotate_browser__draw_current_jump(struct ui_browser *browser) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 1508c2ecf20Sopenharmony_ci struct disasm_line *cursor = disasm_line(ab->selection); 1518c2ecf20Sopenharmony_ci struct annotation_line *target; 1528c2ecf20Sopenharmony_ci unsigned int from, to; 1538c2ecf20Sopenharmony_ci struct map_symbol *ms = ab->b.priv; 1548c2ecf20Sopenharmony_ci struct symbol *sym = ms->sym; 1558c2ecf20Sopenharmony_ci struct annotation *notes = symbol__annotation(sym); 1568c2ecf20Sopenharmony_ci u8 pcnt_width = annotation__pcnt_width(notes); 1578c2ecf20Sopenharmony_ci int width; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* PLT symbols contain external offsets */ 1608c2ecf20Sopenharmony_ci if (strstr(sym->name, "@plt")) 1618c2ecf20Sopenharmony_ci return; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (!disasm_line__is_valid_local_jump(cursor, sym)) 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * This first was seen with a gcc function, _cpp_lex_token, that 1688c2ecf20Sopenharmony_ci * has the usual jumps: 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92> 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * I.e. jumps to a label inside that function (_cpp_lex_token), and 1738c2ecf20Sopenharmony_ci * those works, but also this kind: 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * │1159e8b: ↓ jne c469be <cpp_named_operator2name@@Base+0xa72> 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * I.e. jumps to another function, outside _cpp_lex_token, which 1788c2ecf20Sopenharmony_ci * are not being correctly handled generating as a side effect references 1798c2ecf20Sopenharmony_ci * to ab->offset[] entries that are set to NULL, so to make this code 1808c2ecf20Sopenharmony_ci * more robust, check that here. 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * A proper fix for will be put in place, looking at the function 1838c2ecf20Sopenharmony_ci * name right after the '<' token and probably treating this like a 1848c2ecf20Sopenharmony_ci * 'call' instruction. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci target = notes->offsets[cursor->ops.target.offset]; 1878c2ecf20Sopenharmony_ci if (target == NULL) { 1888c2ecf20Sopenharmony_ci ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n", 1898c2ecf20Sopenharmony_ci cursor->ops.target.offset); 1908c2ecf20Sopenharmony_ci return; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (notes->options->hide_src_code) { 1948c2ecf20Sopenharmony_ci from = cursor->al.idx_asm; 1958c2ecf20Sopenharmony_ci to = target->idx_asm; 1968c2ecf20Sopenharmony_ci } else { 1978c2ecf20Sopenharmony_ci from = (u64)cursor->al.idx; 1988c2ecf20Sopenharmony_ci to = (u64)target->idx; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci width = annotation__cycles_width(notes); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 2048c2ecf20Sopenharmony_ci __ui_browser__line_arrow(browser, 2058c2ecf20Sopenharmony_ci pcnt_width + 2 + notes->widths.addr + width, 2068c2ecf20Sopenharmony_ci from, to); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (is_fused(ab, cursor)) { 2098c2ecf20Sopenharmony_ci ui_browser__mark_fused(browser, 2108c2ecf20Sopenharmony_ci pcnt_width + 3 + notes->widths.addr + width, 2118c2ecf20Sopenharmony_ci from - 1, 2128c2ecf20Sopenharmony_ci to > from); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic unsigned int annotate_browser__refresh(struct ui_browser *browser) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(browser); 2198c2ecf20Sopenharmony_ci int ret = ui_browser__list_head_refresh(browser); 2208c2ecf20Sopenharmony_ci int pcnt_width = annotation__pcnt_width(notes); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (notes->options->jump_arrows) 2238c2ecf20Sopenharmony_ci annotate_browser__draw_current_jump(browser); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ui_browser__set_color(browser, HE_COLORSET_NORMAL); 2268c2ecf20Sopenharmony_ci __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1); 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic double disasm__cmp(struct annotation_line *a, struct annotation_line *b, 2318c2ecf20Sopenharmony_ci int percent_type) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int i; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci for (i = 0; i < a->data_nr; i++) { 2368c2ecf20Sopenharmony_ci if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type]) 2378c2ecf20Sopenharmony_ci continue; 2388c2ecf20Sopenharmony_ci return a->data[i].percent[percent_type] - 2398c2ecf20Sopenharmony_ci b->data[i].percent[percent_type]; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void disasm_rb_tree__insert(struct annotate_browser *browser, 2458c2ecf20Sopenharmony_ci struct annotation_line *al) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct rb_root *root = &browser->entries; 2488c2ecf20Sopenharmony_ci struct rb_node **p = &root->rb_node; 2498c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 2508c2ecf20Sopenharmony_ci struct annotation_line *l; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci while (*p != NULL) { 2538c2ecf20Sopenharmony_ci parent = *p; 2548c2ecf20Sopenharmony_ci l = rb_entry(parent, struct annotation_line, rb_node); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (disasm__cmp(al, l, browser->opts->percent_type) < 0) 2578c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 2588c2ecf20Sopenharmony_ci else 2598c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci rb_link_node(&al->rb_node, parent, p); 2628c2ecf20Sopenharmony_ci rb_insert_color(&al->rb_node, root); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void annotate_browser__set_top(struct annotate_browser *browser, 2668c2ecf20Sopenharmony_ci struct annotation_line *pos, u32 idx) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(&browser->b); 2698c2ecf20Sopenharmony_ci unsigned back; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ui_browser__refresh_dimensions(&browser->b); 2728c2ecf20Sopenharmony_ci back = browser->b.height / 2; 2738c2ecf20Sopenharmony_ci browser->b.top_idx = browser->b.index = idx; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci while (browser->b.top_idx != 0 && back != 0) { 2768c2ecf20Sopenharmony_ci pos = list_entry(pos->node.prev, struct annotation_line, node); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (annotation_line__filter(pos, notes)) 2798c2ecf20Sopenharmony_ci continue; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci --browser->b.top_idx; 2828c2ecf20Sopenharmony_ci --back; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci browser->b.top = pos; 2868c2ecf20Sopenharmony_ci browser->b.navkeypressed = true; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void annotate_browser__set_rb_top(struct annotate_browser *browser, 2908c2ecf20Sopenharmony_ci struct rb_node *nd) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(&browser->b); 2938c2ecf20Sopenharmony_ci struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node); 2948c2ecf20Sopenharmony_ci u32 idx = pos->idx; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (notes->options->hide_src_code) 2978c2ecf20Sopenharmony_ci idx = pos->idx_asm; 2988c2ecf20Sopenharmony_ci annotate_browser__set_top(browser, pos, idx); 2998c2ecf20Sopenharmony_ci browser->curr_hot = nd; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void annotate_browser__calc_percent(struct annotate_browser *browser, 3038c2ecf20Sopenharmony_ci struct evsel *evsel) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct map_symbol *ms = browser->b.priv; 3068c2ecf20Sopenharmony_ci struct symbol *sym = ms->sym; 3078c2ecf20Sopenharmony_ci struct annotation *notes = symbol__annotation(sym); 3088c2ecf20Sopenharmony_ci struct disasm_line *pos; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci browser->entries = RB_ROOT; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci pthread_mutex_lock(¬es->lock); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci symbol__calc_percent(sym, evsel); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci list_for_each_entry(pos, ¬es->src->source, al.node) { 3178c2ecf20Sopenharmony_ci double max_percent = 0.0; 3188c2ecf20Sopenharmony_ci int i; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (pos->al.offset == -1) { 3218c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&pos->al.rb_node); 3228c2ecf20Sopenharmony_ci continue; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci for (i = 0; i < pos->al.data_nr; i++) { 3268c2ecf20Sopenharmony_ci double percent; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci percent = annotation_data__percent(&pos->al.data[i], 3298c2ecf20Sopenharmony_ci browser->opts->percent_type); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (max_percent < percent) 3328c2ecf20Sopenharmony_ci max_percent = percent; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (max_percent < 0.01 && pos->al.ipc == 0) { 3368c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&pos->al.rb_node); 3378c2ecf20Sopenharmony_ci continue; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci disasm_rb_tree__insert(browser, &pos->al); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci pthread_mutex_unlock(¬es->lock); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci browser->curr_hot = rb_last(&browser->entries); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic bool annotate_browser__toggle_source(struct annotate_browser *browser) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(&browser->b); 3498c2ecf20Sopenharmony_ci struct annotation_line *al; 3508c2ecf20Sopenharmony_ci off_t offset = browser->b.index - browser->b.top_idx; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci browser->b.seek(&browser->b, offset, SEEK_CUR); 3538c2ecf20Sopenharmony_ci al = list_entry(browser->b.top, struct annotation_line, node); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (notes->options->hide_src_code) { 3568c2ecf20Sopenharmony_ci if (al->idx_asm < offset) 3578c2ecf20Sopenharmony_ci offset = al->idx; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci browser->b.nr_entries = notes->nr_entries; 3608c2ecf20Sopenharmony_ci notes->options->hide_src_code = false; 3618c2ecf20Sopenharmony_ci browser->b.seek(&browser->b, -offset, SEEK_CUR); 3628c2ecf20Sopenharmony_ci browser->b.top_idx = al->idx - offset; 3638c2ecf20Sopenharmony_ci browser->b.index = al->idx; 3648c2ecf20Sopenharmony_ci } else { 3658c2ecf20Sopenharmony_ci if (al->idx_asm < 0) { 3668c2ecf20Sopenharmony_ci ui_helpline__puts("Only available for assembly lines."); 3678c2ecf20Sopenharmony_ci browser->b.seek(&browser->b, -offset, SEEK_CUR); 3688c2ecf20Sopenharmony_ci return false; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (al->idx_asm < offset) 3728c2ecf20Sopenharmony_ci offset = al->idx_asm; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci browser->b.nr_entries = notes->nr_asm_entries; 3758c2ecf20Sopenharmony_ci notes->options->hide_src_code = true; 3768c2ecf20Sopenharmony_ci browser->b.seek(&browser->b, -offset, SEEK_CUR); 3778c2ecf20Sopenharmony_ci browser->b.top_idx = al->idx_asm - offset; 3788c2ecf20Sopenharmony_ci browser->b.index = al->idx_asm; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return true; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void ui_browser__init_asm_mode(struct ui_browser *browser) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(browser); 3878c2ecf20Sopenharmony_ci ui_browser__reset_index(browser); 3888c2ecf20Sopenharmony_ci browser->nr_entries = notes->nr_asm_entries; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic int sym_title(struct symbol *sym, struct map *map, char *title, 3948c2ecf20Sopenharmony_ci size_t sz, int percent_type) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name, 3978c2ecf20Sopenharmony_ci percent_type_str(percent_type)); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/* 4018c2ecf20Sopenharmony_ci * This can be called from external jumps, i.e. jumps from one functon 4028c2ecf20Sopenharmony_ci * to another, like from the kernel's entry_SYSCALL_64 function to the 4038c2ecf20Sopenharmony_ci * swapgs_restore_regs_and_return_to_usermode() function. 4048c2ecf20Sopenharmony_ci * 4058c2ecf20Sopenharmony_ci * So all we check here is that dl->ops.target.sym is set, if it is, just 4068c2ecf20Sopenharmony_ci * go to that function and when exiting from its disassembly, come back 4078c2ecf20Sopenharmony_ci * to the calling function. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_cistatic bool annotate_browser__callq(struct annotate_browser *browser, 4108c2ecf20Sopenharmony_ci struct evsel *evsel, 4118c2ecf20Sopenharmony_ci struct hist_browser_timer *hbt) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct map_symbol *ms = browser->b.priv, target_ms; 4148c2ecf20Sopenharmony_ci struct disasm_line *dl = disasm_line(browser->selection); 4158c2ecf20Sopenharmony_ci struct annotation *notes; 4168c2ecf20Sopenharmony_ci char title[SYM_TITLE_MAX_SIZE]; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!dl->ops.target.sym) { 4198c2ecf20Sopenharmony_ci ui_helpline__puts("The called function was not found."); 4208c2ecf20Sopenharmony_ci return true; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci notes = symbol__annotation(dl->ops.target.sym); 4248c2ecf20Sopenharmony_ci pthread_mutex_lock(¬es->lock); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) { 4278c2ecf20Sopenharmony_ci pthread_mutex_unlock(¬es->lock); 4288c2ecf20Sopenharmony_ci ui__warning("Not enough memory for annotating '%s' symbol!\n", 4298c2ecf20Sopenharmony_ci dl->ops.target.sym->name); 4308c2ecf20Sopenharmony_ci return true; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci target_ms.maps = ms->maps; 4348c2ecf20Sopenharmony_ci target_ms.map = ms->map; 4358c2ecf20Sopenharmony_ci target_ms.sym = dl->ops.target.sym; 4368c2ecf20Sopenharmony_ci pthread_mutex_unlock(¬es->lock); 4378c2ecf20Sopenharmony_ci symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts); 4388c2ecf20Sopenharmony_ci sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type); 4398c2ecf20Sopenharmony_ci ui_browser__show_title(&browser->b, title); 4408c2ecf20Sopenharmony_ci return true; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic 4448c2ecf20Sopenharmony_cistruct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser, 4458c2ecf20Sopenharmony_ci s64 offset, s64 *idx) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(&browser->b); 4488c2ecf20Sopenharmony_ci struct disasm_line *pos; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci *idx = 0; 4518c2ecf20Sopenharmony_ci list_for_each_entry(pos, ¬es->src->source, al.node) { 4528c2ecf20Sopenharmony_ci if (pos->al.offset == offset) 4538c2ecf20Sopenharmony_ci return pos; 4548c2ecf20Sopenharmony_ci if (!annotation_line__filter(&pos->al, notes)) 4558c2ecf20Sopenharmony_ci ++*idx; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return NULL; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic bool annotate_browser__jump(struct annotate_browser *browser, 4628c2ecf20Sopenharmony_ci struct evsel *evsel, 4638c2ecf20Sopenharmony_ci struct hist_browser_timer *hbt) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct disasm_line *dl = disasm_line(browser->selection); 4668c2ecf20Sopenharmony_ci u64 offset; 4678c2ecf20Sopenharmony_ci s64 idx; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (!ins__is_jump(&dl->ins)) 4708c2ecf20Sopenharmony_ci return false; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (dl->ops.target.outside) { 4738c2ecf20Sopenharmony_ci annotate_browser__callq(browser, evsel, hbt); 4748c2ecf20Sopenharmony_ci return true; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci offset = dl->ops.target.offset; 4788c2ecf20Sopenharmony_ci dl = annotate_browser__find_offset(browser, offset, &idx); 4798c2ecf20Sopenharmony_ci if (dl == NULL) { 4808c2ecf20Sopenharmony_ci ui_helpline__printf("Invalid jump offset: %" PRIx64, offset); 4818c2ecf20Sopenharmony_ci return true; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci annotate_browser__set_top(browser, &dl->al, idx); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return true; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic 4908c2ecf20Sopenharmony_cistruct annotation_line *annotate_browser__find_string(struct annotate_browser *browser, 4918c2ecf20Sopenharmony_ci char *s, s64 *idx) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(&browser->b); 4948c2ecf20Sopenharmony_ci struct annotation_line *al = browser->selection; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci *idx = browser->b.index; 4978c2ecf20Sopenharmony_ci list_for_each_entry_continue(al, ¬es->src->source, node) { 4988c2ecf20Sopenharmony_ci if (annotation_line__filter(al, notes)) 4998c2ecf20Sopenharmony_ci continue; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci ++*idx; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (al->line && strstr(al->line, s) != NULL) 5048c2ecf20Sopenharmony_ci return al; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return NULL; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic bool __annotate_browser__search(struct annotate_browser *browser) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct annotation_line *al; 5138c2ecf20Sopenharmony_ci s64 idx; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci al = annotate_browser__find_string(browser, browser->search_bf, &idx); 5168c2ecf20Sopenharmony_ci if (al == NULL) { 5178c2ecf20Sopenharmony_ci ui_helpline__puts("String not found!"); 5188c2ecf20Sopenharmony_ci return false; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci annotate_browser__set_top(browser, al, idx); 5228c2ecf20Sopenharmony_ci browser->searching_backwards = false; 5238c2ecf20Sopenharmony_ci return true; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic 5278c2ecf20Sopenharmony_cistruct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser, 5288c2ecf20Sopenharmony_ci char *s, s64 *idx) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct annotation *notes = browser__annotation(&browser->b); 5318c2ecf20Sopenharmony_ci struct annotation_line *al = browser->selection; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci *idx = browser->b.index; 5348c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(al, ¬es->src->source, node) { 5358c2ecf20Sopenharmony_ci if (annotation_line__filter(al, notes)) 5368c2ecf20Sopenharmony_ci continue; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci --*idx; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (al->line && strstr(al->line, s) != NULL) 5418c2ecf20Sopenharmony_ci return al; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return NULL; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic bool __annotate_browser__search_reverse(struct annotate_browser *browser) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct annotation_line *al; 5508c2ecf20Sopenharmony_ci s64 idx; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 5538c2ecf20Sopenharmony_ci if (al == NULL) { 5548c2ecf20Sopenharmony_ci ui_helpline__puts("String not found!"); 5558c2ecf20Sopenharmony_ci return false; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci annotate_browser__set_top(browser, al, idx); 5598c2ecf20Sopenharmony_ci browser->searching_backwards = true; 5608c2ecf20Sopenharmony_ci return true; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic bool annotate_browser__search_window(struct annotate_browser *browser, 5648c2ecf20Sopenharmony_ci int delay_secs) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci if (ui_browser__input_window("Search", "String: ", browser->search_bf, 5678c2ecf20Sopenharmony_ci "ENTER: OK, ESC: Cancel", 5688c2ecf20Sopenharmony_ci delay_secs * 2) != K_ENTER || 5698c2ecf20Sopenharmony_ci !*browser->search_bf) 5708c2ecf20Sopenharmony_ci return false; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return true; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic bool annotate_browser__search(struct annotate_browser *browser, int delay_secs) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci if (annotate_browser__search_window(browser, delay_secs)) 5788c2ecf20Sopenharmony_ci return __annotate_browser__search(browser); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return false; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic bool annotate_browser__continue_search(struct annotate_browser *browser, 5848c2ecf20Sopenharmony_ci int delay_secs) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci if (!*browser->search_bf) 5878c2ecf20Sopenharmony_ci return annotate_browser__search(browser, delay_secs); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return __annotate_browser__search(browser); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic bool annotate_browser__search_reverse(struct annotate_browser *browser, 5938c2ecf20Sopenharmony_ci int delay_secs) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci if (annotate_browser__search_window(browser, delay_secs)) 5968c2ecf20Sopenharmony_ci return __annotate_browser__search_reverse(browser); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return false; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic 6028c2ecf20Sopenharmony_cibool annotate_browser__continue_search_reverse(struct annotate_browser *browser, 6038c2ecf20Sopenharmony_ci int delay_secs) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci if (!*browser->search_bf) 6068c2ecf20Sopenharmony_ci return annotate_browser__search_reverse(browser, delay_secs); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return __annotate_browser__search_reverse(browser); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 6148c2ecf20Sopenharmony_ci struct map_symbol *ms = browser->priv; 6158c2ecf20Sopenharmony_ci struct symbol *sym = ms->sym; 6168c2ecf20Sopenharmony_ci char symbol_dso[SYM_TITLE_MAX_SIZE]; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (ui_browser__show(browser, title, help) < 0) 6198c2ecf20Sopenharmony_ci return -1; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ui_browser__gotorc_title(browser, 0, 0); 6248c2ecf20Sopenharmony_ci ui_browser__set_color(browser, HE_COLORSET_ROOT); 6258c2ecf20Sopenharmony_ci ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic void 6308c2ecf20Sopenharmony_ciswitch_percent_type(struct annotation_options *opts, bool base) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci switch (opts->percent_type) { 6338c2ecf20Sopenharmony_ci case PERCENT_HITS_LOCAL: 6348c2ecf20Sopenharmony_ci if (base) 6358c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_PERIOD_LOCAL; 6368c2ecf20Sopenharmony_ci else 6378c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_HITS_GLOBAL; 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci case PERCENT_HITS_GLOBAL: 6408c2ecf20Sopenharmony_ci if (base) 6418c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_PERIOD_GLOBAL; 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_HITS_LOCAL; 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci case PERCENT_PERIOD_LOCAL: 6468c2ecf20Sopenharmony_ci if (base) 6478c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_HITS_LOCAL; 6488c2ecf20Sopenharmony_ci else 6498c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_PERIOD_GLOBAL; 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci case PERCENT_PERIOD_GLOBAL: 6528c2ecf20Sopenharmony_ci if (base) 6538c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_HITS_GLOBAL; 6548c2ecf20Sopenharmony_ci else 6558c2ecf20Sopenharmony_ci opts->percent_type = PERCENT_PERIOD_LOCAL; 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci default: 6588c2ecf20Sopenharmony_ci WARN_ON(1); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int annotate_browser__run(struct annotate_browser *browser, 6638c2ecf20Sopenharmony_ci struct evsel *evsel, 6648c2ecf20Sopenharmony_ci struct hist_browser_timer *hbt) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct rb_node *nd = NULL; 6678c2ecf20Sopenharmony_ci struct hists *hists = evsel__hists(evsel); 6688c2ecf20Sopenharmony_ci struct map_symbol *ms = browser->b.priv; 6698c2ecf20Sopenharmony_ci struct symbol *sym = ms->sym; 6708c2ecf20Sopenharmony_ci struct annotation *notes = symbol__annotation(ms->sym); 6718c2ecf20Sopenharmony_ci const char *help = "Press 'h' for help on key bindings"; 6728c2ecf20Sopenharmony_ci int delay_secs = hbt ? hbt->refresh : 0; 6738c2ecf20Sopenharmony_ci char title[256]; 6748c2ecf20Sopenharmony_ci int key; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci hists__scnprintf_title(hists, title, sizeof(title)); 6778c2ecf20Sopenharmony_ci if (annotate_browser__show(&browser->b, title, help) < 0) 6788c2ecf20Sopenharmony_ci return -1; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci annotate_browser__calc_percent(browser, evsel); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (browser->curr_hot) { 6838c2ecf20Sopenharmony_ci annotate_browser__set_rb_top(browser, browser->curr_hot); 6848c2ecf20Sopenharmony_ci browser->b.navkeypressed = false; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci nd = browser->curr_hot; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci while (1) { 6908c2ecf20Sopenharmony_ci key = ui_browser__run(&browser->b, delay_secs); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (delay_secs != 0) { 6938c2ecf20Sopenharmony_ci annotate_browser__calc_percent(browser, evsel); 6948c2ecf20Sopenharmony_ci /* 6958c2ecf20Sopenharmony_ci * Current line focus got out of the list of most active 6968c2ecf20Sopenharmony_ci * lines, NULL it so that if TAB|UNTAB is pressed, we 6978c2ecf20Sopenharmony_ci * move to curr_hot (current hottest line). 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci if (nd != NULL && RB_EMPTY_NODE(nd)) 7008c2ecf20Sopenharmony_ci nd = NULL; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci switch (key) { 7048c2ecf20Sopenharmony_ci case K_TIMER: 7058c2ecf20Sopenharmony_ci if (hbt) 7068c2ecf20Sopenharmony_ci hbt->timer(hbt->arg); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (delay_secs != 0) { 7098c2ecf20Sopenharmony_ci symbol__annotate_decay_histogram(sym, evsel->idx); 7108c2ecf20Sopenharmony_ci hists__scnprintf_title(hists, title, sizeof(title)); 7118c2ecf20Sopenharmony_ci annotate_browser__show(&browser->b, title, help); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci continue; 7148c2ecf20Sopenharmony_ci case K_TAB: 7158c2ecf20Sopenharmony_ci if (nd != NULL) { 7168c2ecf20Sopenharmony_ci nd = rb_prev(nd); 7178c2ecf20Sopenharmony_ci if (nd == NULL) 7188c2ecf20Sopenharmony_ci nd = rb_last(&browser->entries); 7198c2ecf20Sopenharmony_ci } else 7208c2ecf20Sopenharmony_ci nd = browser->curr_hot; 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci case K_UNTAB: 7238c2ecf20Sopenharmony_ci if (nd != NULL) { 7248c2ecf20Sopenharmony_ci nd = rb_next(nd); 7258c2ecf20Sopenharmony_ci if (nd == NULL) 7268c2ecf20Sopenharmony_ci nd = rb_first(&browser->entries); 7278c2ecf20Sopenharmony_ci } else 7288c2ecf20Sopenharmony_ci nd = browser->curr_hot; 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci case K_F1: 7318c2ecf20Sopenharmony_ci case 'h': 7328c2ecf20Sopenharmony_ci ui_browser__help_window(&browser->b, 7338c2ecf20Sopenharmony_ci "UP/DOWN/PGUP\n" 7348c2ecf20Sopenharmony_ci "PGDN/SPACE Navigate\n" 7358c2ecf20Sopenharmony_ci "q/ESC/CTRL+C Exit\n\n" 7368c2ecf20Sopenharmony_ci "ENTER Go to target\n" 7378c2ecf20Sopenharmony_ci "ESC Exit\n" 7388c2ecf20Sopenharmony_ci "H Go to hottest instruction\n" 7398c2ecf20Sopenharmony_ci "TAB/shift+TAB Cycle thru hottest instructions\n" 7408c2ecf20Sopenharmony_ci "j Toggle showing jump to target arrows\n" 7418c2ecf20Sopenharmony_ci "J Toggle showing number of jump sources on targets\n" 7428c2ecf20Sopenharmony_ci "n Search next string\n" 7438c2ecf20Sopenharmony_ci "o Toggle disassembler output/simplified view\n" 7448c2ecf20Sopenharmony_ci "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n" 7458c2ecf20Sopenharmony_ci "s Toggle source code view\n" 7468c2ecf20Sopenharmony_ci "t Circulate percent, total period, samples view\n" 7478c2ecf20Sopenharmony_ci "c Show min/max cycle\n" 7488c2ecf20Sopenharmony_ci "/ Search string\n" 7498c2ecf20Sopenharmony_ci "k Toggle line numbers\n" 7508c2ecf20Sopenharmony_ci "P Print to [symbol_name].annotation file.\n" 7518c2ecf20Sopenharmony_ci "r Run available scripts\n" 7528c2ecf20Sopenharmony_ci "p Toggle percent type [local/global]\n" 7538c2ecf20Sopenharmony_ci "b Toggle percent base [period/hits]\n" 7548c2ecf20Sopenharmony_ci "? Search string backwards\n"); 7558c2ecf20Sopenharmony_ci continue; 7568c2ecf20Sopenharmony_ci case 'r': 7578c2ecf20Sopenharmony_ci script_browse(NULL, NULL); 7588c2ecf20Sopenharmony_ci annotate_browser__show(&browser->b, title, help); 7598c2ecf20Sopenharmony_ci continue; 7608c2ecf20Sopenharmony_ci case 'k': 7618c2ecf20Sopenharmony_ci notes->options->show_linenr = !notes->options->show_linenr; 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci case 'H': 7648c2ecf20Sopenharmony_ci nd = browser->curr_hot; 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci case 's': 7678c2ecf20Sopenharmony_ci if (annotate_browser__toggle_source(browser)) 7688c2ecf20Sopenharmony_ci ui_helpline__puts(help); 7698c2ecf20Sopenharmony_ci continue; 7708c2ecf20Sopenharmony_ci case 'o': 7718c2ecf20Sopenharmony_ci notes->options->use_offset = !notes->options->use_offset; 7728c2ecf20Sopenharmony_ci annotation__update_column_widths(notes); 7738c2ecf20Sopenharmony_ci continue; 7748c2ecf20Sopenharmony_ci case 'O': 7758c2ecf20Sopenharmony_ci if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL) 7768c2ecf20Sopenharmony_ci notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL; 7778c2ecf20Sopenharmony_ci continue; 7788c2ecf20Sopenharmony_ci case 'j': 7798c2ecf20Sopenharmony_ci notes->options->jump_arrows = !notes->options->jump_arrows; 7808c2ecf20Sopenharmony_ci continue; 7818c2ecf20Sopenharmony_ci case 'J': 7828c2ecf20Sopenharmony_ci notes->options->show_nr_jumps = !notes->options->show_nr_jumps; 7838c2ecf20Sopenharmony_ci annotation__update_column_widths(notes); 7848c2ecf20Sopenharmony_ci continue; 7858c2ecf20Sopenharmony_ci case '/': 7868c2ecf20Sopenharmony_ci if (annotate_browser__search(browser, delay_secs)) { 7878c2ecf20Sopenharmony_cishow_help: 7888c2ecf20Sopenharmony_ci ui_helpline__puts(help); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci continue; 7918c2ecf20Sopenharmony_ci case 'n': 7928c2ecf20Sopenharmony_ci if (browser->searching_backwards ? 7938c2ecf20Sopenharmony_ci annotate_browser__continue_search_reverse(browser, delay_secs) : 7948c2ecf20Sopenharmony_ci annotate_browser__continue_search(browser, delay_secs)) 7958c2ecf20Sopenharmony_ci goto show_help; 7968c2ecf20Sopenharmony_ci continue; 7978c2ecf20Sopenharmony_ci case '?': 7988c2ecf20Sopenharmony_ci if (annotate_browser__search_reverse(browser, delay_secs)) 7998c2ecf20Sopenharmony_ci goto show_help; 8008c2ecf20Sopenharmony_ci continue; 8018c2ecf20Sopenharmony_ci case 'D': { 8028c2ecf20Sopenharmony_ci static int seq; 8038c2ecf20Sopenharmony_ci ui_helpline__pop(); 8048c2ecf20Sopenharmony_ci ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d", 8058c2ecf20Sopenharmony_ci seq++, browser->b.nr_entries, 8068c2ecf20Sopenharmony_ci browser->b.height, 8078c2ecf20Sopenharmony_ci browser->b.index, 8088c2ecf20Sopenharmony_ci browser->b.top_idx, 8098c2ecf20Sopenharmony_ci notes->nr_asm_entries); 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci continue; 8128c2ecf20Sopenharmony_ci case K_ENTER: 8138c2ecf20Sopenharmony_ci case K_RIGHT: 8148c2ecf20Sopenharmony_ci { 8158c2ecf20Sopenharmony_ci struct disasm_line *dl = disasm_line(browser->selection); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (browser->selection == NULL) 8188c2ecf20Sopenharmony_ci ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 8198c2ecf20Sopenharmony_ci else if (browser->selection->offset == -1) 8208c2ecf20Sopenharmony_ci ui_helpline__puts("Actions are only available for assembly lines."); 8218c2ecf20Sopenharmony_ci else if (!dl->ins.ops) 8228c2ecf20Sopenharmony_ci goto show_sup_ins; 8238c2ecf20Sopenharmony_ci else if (ins__is_ret(&dl->ins)) 8248c2ecf20Sopenharmony_ci goto out; 8258c2ecf20Sopenharmony_ci else if (!(annotate_browser__jump(browser, evsel, hbt) || 8268c2ecf20Sopenharmony_ci annotate_browser__callq(browser, evsel, hbt))) { 8278c2ecf20Sopenharmony_cishow_sup_ins: 8288c2ecf20Sopenharmony_ci ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci continue; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci case 'P': 8338c2ecf20Sopenharmony_ci map_symbol__annotation_dump(ms, evsel, browser->opts); 8348c2ecf20Sopenharmony_ci continue; 8358c2ecf20Sopenharmony_ci case 't': 8368c2ecf20Sopenharmony_ci if (symbol_conf.show_total_period) { 8378c2ecf20Sopenharmony_ci symbol_conf.show_total_period = false; 8388c2ecf20Sopenharmony_ci symbol_conf.show_nr_samples = true; 8398c2ecf20Sopenharmony_ci } else if (symbol_conf.show_nr_samples) 8408c2ecf20Sopenharmony_ci symbol_conf.show_nr_samples = false; 8418c2ecf20Sopenharmony_ci else 8428c2ecf20Sopenharmony_ci symbol_conf.show_total_period = true; 8438c2ecf20Sopenharmony_ci annotation__update_column_widths(notes); 8448c2ecf20Sopenharmony_ci continue; 8458c2ecf20Sopenharmony_ci case 'c': 8468c2ecf20Sopenharmony_ci if (notes->options->show_minmax_cycle) 8478c2ecf20Sopenharmony_ci notes->options->show_minmax_cycle = false; 8488c2ecf20Sopenharmony_ci else 8498c2ecf20Sopenharmony_ci notes->options->show_minmax_cycle = true; 8508c2ecf20Sopenharmony_ci annotation__update_column_widths(notes); 8518c2ecf20Sopenharmony_ci continue; 8528c2ecf20Sopenharmony_ci case 'p': 8538c2ecf20Sopenharmony_ci case 'b': 8548c2ecf20Sopenharmony_ci switch_percent_type(browser->opts, key == 'b'); 8558c2ecf20Sopenharmony_ci hists__scnprintf_title(hists, title, sizeof(title)); 8568c2ecf20Sopenharmony_ci annotate_browser__show(&browser->b, title, help); 8578c2ecf20Sopenharmony_ci continue; 8588c2ecf20Sopenharmony_ci case K_LEFT: 8598c2ecf20Sopenharmony_ci case K_ESC: 8608c2ecf20Sopenharmony_ci case 'q': 8618c2ecf20Sopenharmony_ci case CTRL('c'): 8628c2ecf20Sopenharmony_ci goto out; 8638c2ecf20Sopenharmony_ci default: 8648c2ecf20Sopenharmony_ci continue; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (nd != NULL) 8688c2ecf20Sopenharmony_ci annotate_browser__set_rb_top(browser, nd); 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ciout: 8718c2ecf20Sopenharmony_ci ui_browser__hide(&browser->b); 8728c2ecf20Sopenharmony_ci return key; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ciint map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, 8768c2ecf20Sopenharmony_ci struct hist_browser_timer *hbt, 8778c2ecf20Sopenharmony_ci struct annotation_options *opts) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci return symbol__tui_annotate(ms, evsel, hbt, opts); 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ciint hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, 8838c2ecf20Sopenharmony_ci struct hist_browser_timer *hbt, 8848c2ecf20Sopenharmony_ci struct annotation_options *opts) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci /* reset abort key so that it can get Ctrl-C as a key */ 8878c2ecf20Sopenharmony_ci SLang_reset_tty(); 8888c2ecf20Sopenharmony_ci SLang_init_tty(0, 0, 0); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts); 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ciint symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, 8948c2ecf20Sopenharmony_ci struct hist_browser_timer *hbt, 8958c2ecf20Sopenharmony_ci struct annotation_options *opts) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct symbol *sym = ms->sym; 8988c2ecf20Sopenharmony_ci struct annotation *notes = symbol__annotation(sym); 8998c2ecf20Sopenharmony_ci struct annotate_browser browser = { 9008c2ecf20Sopenharmony_ci .b = { 9018c2ecf20Sopenharmony_ci .refresh = annotate_browser__refresh, 9028c2ecf20Sopenharmony_ci .seek = ui_browser__list_head_seek, 9038c2ecf20Sopenharmony_ci .write = annotate_browser__write, 9048c2ecf20Sopenharmony_ci .filter = disasm_line__filter, 9058c2ecf20Sopenharmony_ci .extra_title_lines = 1, /* for hists__scnprintf_title() */ 9068c2ecf20Sopenharmony_ci .priv = ms, 9078c2ecf20Sopenharmony_ci .use_navkeypressed = true, 9088c2ecf20Sopenharmony_ci }, 9098c2ecf20Sopenharmony_ci .opts = opts, 9108c2ecf20Sopenharmony_ci }; 9118c2ecf20Sopenharmony_ci int ret = -1, err; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (sym == NULL) 9148c2ecf20Sopenharmony_ci return -1; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (ms->map->dso->annotate_warned) 9178c2ecf20Sopenharmony_ci return -1; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci err = symbol__annotate2(ms, evsel, opts, &browser.arch); 9208c2ecf20Sopenharmony_ci if (err) { 9218c2ecf20Sopenharmony_ci char msg[BUFSIZ]; 9228c2ecf20Sopenharmony_ci symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); 9238c2ecf20Sopenharmony_ci ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 9248c2ecf20Sopenharmony_ci goto out_free_offsets; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci ui_helpline__push("Press ESC to exit"); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci browser.b.width = notes->max_line_len; 9308c2ecf20Sopenharmony_ci browser.b.nr_entries = notes->nr_entries; 9318c2ecf20Sopenharmony_ci browser.b.entries = ¬es->src->source, 9328c2ecf20Sopenharmony_ci browser.b.width += 18; /* Percentage */ 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (notes->options->hide_src_code) 9358c2ecf20Sopenharmony_ci ui_browser__init_asm_mode(&browser.b); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci ret = annotate_browser__run(&browser, evsel, hbt); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci annotated_source__purge(notes->src); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ciout_free_offsets: 9428c2ecf20Sopenharmony_ci zfree(¬es->offsets); 9438c2ecf20Sopenharmony_ci return ret; 9448c2ecf20Sopenharmony_ci} 945