#include "unwind.h" #include #include #include static std::string unknow_symbol("UNKNOWN"); static int unwind_frame_callback(struct unwind_entry *entry, void *arg) { //! todo: 未实现 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); } void diag_printf_raw_stack(int pid, int ns_pid, const char *comm, raw_stack_detail *raw_stack, int attach){ struct perf_sample stack_sample; entry_cb_arg_t unwind_arg; static u64 regs_buf[3]; printf("##C++ pid %d\n", pid); printf(" 用户态堆栈SP:%lx, BP:%lx, IP:%lx\n", raw_stack->sp, raw_stack->bp, raw_stack->ip); stack_sample.user_stack.offset = 0; stack_sample.user_stack.size = raw_stack->stack_size; stack_sample.user_stack.data = (char *)&raw_stack->stack[0]; stack_sample.user_regs.regs = regs_buf; stack_sample.user_regs.regs[PERF_REG_IP] = raw_stack->ip; stack_sample.user_regs.regs[PERF_REG_SP] = raw_stack->sp; stack_sample.user_regs.regs[PERF_REG_BP] = raw_stack->bp; unwind__get_entries(unwind_frame_callback, &unwind_arg, &g_symbol_parser, pid, ns_pid, &stack_sample); fflush(stdout); }