#include "unwind.h" #include #include #include static std::string unknow_symbol("UNKNOWN"); // static int unwind_frame_callback(struct unwind_entry *entry, void *arg) { // symbol sym; // std::string symbol; // Use std::string instead of string // elf_file file; // sym.reset(entry->ip); // if (g_symbol_parser.find_symbol_in_cache(entry->pid, entry->ip, symbol)) { // printf("#~ 0x%lx %s ([symbol])\n", entry->ip, symbol.c_str()); // return 0; // } // if (g_symbol_parser.get_symbol_info(entry->pid, sym, file)) { // if (g_symbol_parser.find_elf_symbol(sym, file, entry->pid, // entry->pid_ns)) { // printf("#~ 0x%lx %s ([symbol])\n", entry->ip, sym.name.c_str()); // g_symbol_parser.putin_symbol_cache(entry->pid, entry->ip, sym.name); // } else { // printf("#~ 0x%lx %s ([symbol])\n", entry->ip, // "(unknown)[symbol]"); g_symbol_parser.putin_symbol_cache(entry->pid, // entry->ip, unknow_symbol); // } // } else { // printf("#~ 0x%lx %s ([symbol])\n", entry->ip, // "(unknown)[vma,elf]"); g_symbol_parser.putin_symbol_cache(entry->pid, // entry->ip, unknow_symbol); // } // return 0; // } /* * Optimization point. */ static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id) { /* we only support 3 registers. RIP, RSP and RBP */ if (id < 0 || id > 2) return -EINVAL; *valp = regs->regs[id]; return 0; } static int entry(u64 ip, int pid, int pid_ns, unwind_entry_cb_t cb, void *arg) { struct unwind_entry e; e.ip = ip; e.pid = pid; e.pid_ns = pid_ns; return cb(&e, arg); } static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, void *arg) { unw_addr_space_t addr_space; unw_cursor_t c; entry_cb_arg_t *cb_arg = (entry_cb_arg_t *)arg; int ret; int loops = 0; addr_space = unw_create_addr_space(&accessors, 0); if (!addr_space) { // pr_err("unwind: Can't create unwind address space.\n"); return -ENOMEM; } unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); ret = unw_init_remote(&c, addr_space, ui); /* @ui is args */ while (!ret && (unw_step(&c) > 0)) { unw_word_t ip; unw_get_reg(&c, UNW_REG_IP, &ip); // get IP from current step; cb_arg->arg = &c; ret = entry(ip, ui->pid, ui->pid_ns, cb, cb_arg); loops++; if (loops >= 50) break; } unw_destroy_addr_space(addr_space); return ret; } int unwind__get_entries(unwind_entry_cb_t cb, void *arg, symbol_parser *sp, int pid, int pid_ns, struct perf_sample *data) { unw_word_t ip; struct unwind_info ui = { .sample = data, .pid = pid, .pid_ns = pid_ns, .sp = sp, }; int ret; if (!data->user_regs.regs) return -EINVAL; ret = reg_value(&ip, &data->user_regs, PERF_REG_IP); if (ret) return ret; ret = entry(ip, pid, pid_ns, cb, arg); if (ret) return -ENOMEM; return get_entries(&ui, cb, arg); }