131 lines
3.7 KiB
C++
131 lines
3.7 KiB
C++
#include "unwind.h"
|
||
|
||
#include <errno.h>
|
||
#include <stdio.h>
|
||
|
||
#include <string>
|
||
|
||
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(" 用户态堆栈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);
|
||
} |