119 lines
3.0 KiB
C++
119 lines
3.0 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) {
|
|
// 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);
|
|
} |