move register-related code to separate files, move DWARF module & handle
to pst_context, move get_frame() from pst_handler to pst_function
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "logger/log.h"
|
||||
#include "common.h"
|
||||
#include "dwarf_operations.h"
|
||||
#include "registers.h"
|
||||
|
||||
extern SC_LogBase* logger;
|
||||
extern dwarf_reg_map reg_map[];
|
||||
@@ -86,7 +87,7 @@ bool dwarf_value::get_generic(uint64_t& v)
|
||||
void __pst_context::print_stack(int max, uint64_t next_cfa)
|
||||
{
|
||||
log(SEVERITY_DEBUG, "CFA = %#lX, NEXT_CFA = %#lX, SP = %#lX", cfa, next_cfa, sp);
|
||||
buff[0] = 0; offset = 0;
|
||||
clean_print();
|
||||
int i = 0;
|
||||
if(cfa > sp) {
|
||||
print("Args: ");
|
||||
@@ -104,7 +105,7 @@ void __pst_context::print_stack(int max, uint64_t next_cfa)
|
||||
|
||||
void __pst_context::print_registers(int from, int to)
|
||||
{
|
||||
buff[0] = 0; offset = 0;
|
||||
clean_print();
|
||||
for(int i = from; i < regnum && i <= to; ++i) {
|
||||
unw_word_t regval;
|
||||
if(!unw_get_reg(curr_frame, reg_map[i].regno, ®val)) {
|
||||
|
||||
+23
-6
@@ -8,16 +8,20 @@
|
||||
#include "logger/log.h"
|
||||
#include "linkedlist.h"
|
||||
|
||||
#define USE_LIBUNWIND
|
||||
|
||||
typedef struct __pst_context {
|
||||
__pst_context(ucontext_t* hctx) : hcontext(hctx)
|
||||
{
|
||||
offset = 0;
|
||||
buff[0] = 0;
|
||||
clean_print();
|
||||
base_addr = 0;
|
||||
sp = 0;
|
||||
cfa = 0;
|
||||
curr_frame = NULL;
|
||||
next_frame = NULL;
|
||||
frame = NULL;
|
||||
dwfl = NULL;
|
||||
module = NULL;
|
||||
}
|
||||
|
||||
bool print(const char* fmt, ...);
|
||||
@@ -25,18 +29,31 @@ typedef struct __pst_context {
|
||||
uint32_t print_expr_block(Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr = 0);
|
||||
void print_registers(int from, int to);
|
||||
void print_stack(int max, uint64_t next_cfa);
|
||||
void clean_print() {
|
||||
buff[0] = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
const char* get_print() {
|
||||
return buff;
|
||||
}
|
||||
|
||||
ucontext_t* hcontext; // context of signal handler
|
||||
unw_context_t context; // context of stack trace
|
||||
unw_cursor_t cursor;
|
||||
unw_cursor_t* curr_frame; // currently examined frame of context
|
||||
unw_cursor_t* next_frame; // caller frame
|
||||
unw_cursor_t* curr_frame; // callee libunwind frame
|
||||
unw_cursor_t* next_frame; // caller libunwind frame
|
||||
Dwarf_Addr base_addr; // base address where process loaded
|
||||
|
||||
char buff[8192]; // stack trace buffer
|
||||
uint32_t offset; // offset in the 'buff'
|
||||
Dwarf_Addr sp;
|
||||
Dwarf_Addr cfa;
|
||||
Dwarf_Frame* frame; // currently examined libdwfl frame
|
||||
Dwfl* dwfl; // DWARF context
|
||||
Dwfl_Module* module; // currently processed CU
|
||||
|
||||
protected:
|
||||
char buff[8192]; // stack trace buffer
|
||||
uint32_t offset; // offset in the 'buff'
|
||||
} pst_context;
|
||||
|
||||
|
||||
|
||||
@@ -11,82 +11,6 @@
|
||||
#include "dwarf_operations.h"
|
||||
#include "common.h"
|
||||
|
||||
dwarf_reg_map reg_map[] = {
|
||||
// GP Registers
|
||||
{0x0, "RAX", DW_OP_reg0},
|
||||
{0x1, "RDX", DW_OP_reg1},
|
||||
{0x2, "RCX", DW_OP_reg2},
|
||||
{0x3, "RBX", DW_OP_reg3},
|
||||
{0x4, "RSI", DW_OP_reg4},
|
||||
{0x5, "RDI", DW_OP_reg5},
|
||||
{0x6, "RBP", DW_OP_reg6},
|
||||
{0x7, "RSP", DW_OP_reg7},
|
||||
// Extended GP Registers
|
||||
{0x8, "R8", DW_OP_reg8},
|
||||
{0x9, "R9", DW_OP_reg9},
|
||||
{0xA, "R10", DW_OP_reg10},
|
||||
{0xB, "R11", DW_OP_reg11},
|
||||
{0xC, "R12", DW_OP_reg12},
|
||||
{0xD, "R13", DW_OP_reg13},
|
||||
{0xE, "R14", DW_OP_reg14},
|
||||
{0xF, "R15", DW_OP_reg15},
|
||||
{0x10, "RIP", DW_OP_reg16}, // Return Address (RA) mapped to RIP
|
||||
// SSE Vector Registers
|
||||
{0x11, "XMM0", DW_OP_reg17},
|
||||
{0x12, "XMM1", DW_OP_reg18},
|
||||
{0x13, "XMM2", DW_OP_reg19},
|
||||
{0x14, "XMM3", DW_OP_reg20},
|
||||
{0x15, "XMM4", DW_OP_reg21},
|
||||
{0x16, "XMM5", DW_OP_reg22},
|
||||
{0x17, "XMM6", DW_OP_reg23},
|
||||
{0x18, "XMM7", DW_OP_reg24},
|
||||
{0x19, "XMM8", DW_OP_reg25},
|
||||
{0x1a, "XMM9", DW_OP_reg26},
|
||||
{0x1b, "XMM10", DW_OP_reg27},
|
||||
{0x1c, "XMM11", DW_OP_reg28},
|
||||
{0x1d, "XMM12", DW_OP_reg29},
|
||||
{0x1e, "XMM13", DW_OP_reg30},
|
||||
{0x1f, "XMM14", DW_OP_reg31},
|
||||
|
||||
// GP Registers
|
||||
{0x0, "RAX", DW_OP_breg0},
|
||||
{0x1, "RDX", DW_OP_breg1},
|
||||
{0x2, "RCX", DW_OP_breg2},
|
||||
{0x3, "RBX", DW_OP_breg3},
|
||||
{0x4, "RSI", DW_OP_breg4},
|
||||
{0x5, "RDI", DW_OP_breg5},
|
||||
{0x6, "RBP", DW_OP_breg6},
|
||||
{0x7, "RSP", DW_OP_breg7},
|
||||
// Extended GP Registers
|
||||
{0x8, "R8", DW_OP_breg8},
|
||||
{0x9, "R9", DW_OP_breg9},
|
||||
{0xA, "R10", DW_OP_breg10},
|
||||
{0xB, "R11", DW_OP_breg11},
|
||||
{0xC, "R12", DW_OP_breg12},
|
||||
{0xD, "R13", DW_OP_breg13},
|
||||
{0xE, "R14", DW_OP_breg14},
|
||||
{0xF, "R15", DW_OP_breg15},
|
||||
{0x10, "RIP", DW_OP_breg16}, // Return Address (RA) mapped to RIP
|
||||
// SSE Vector Registers
|
||||
{0x11, "XMM0", DW_OP_breg17},
|
||||
{0x12, "XMM1", DW_OP_breg18},
|
||||
{0x13, "XMM2", DW_OP_breg19},
|
||||
{0x14, "XMM3", DW_OP_breg20},
|
||||
{0x15, "XMM4", DW_OP_breg21},
|
||||
{0x16, "XMM5", DW_OP_breg22},
|
||||
{0x17, "XMM6", DW_OP_breg23},
|
||||
{0x18, "XMM7", DW_OP_breg24},
|
||||
{0x19, "XMM8", DW_OP_breg25},
|
||||
{0x1a, "XMM9", DW_OP_breg26},
|
||||
{0x1b, "XMM10", DW_OP_breg27},
|
||||
{0x1c, "XMM11", DW_OP_breg28},
|
||||
{0x1d, "XMM12", DW_OP_breg29},
|
||||
{0x1e, "XMM13", DW_OP_breg30},
|
||||
{0x1f, "XMM14", DW_OP_breg31},
|
||||
};
|
||||
|
||||
int regnum = sizeof(reg_map) / sizeof(dwarf_reg_map);
|
||||
|
||||
// not implemented operations
|
||||
bool dw_op_notimpl(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||
{
|
||||
@@ -1055,18 +979,6 @@ dwarf_op_map op_map[] = {
|
||||
{DW_OP_GNU_entry_value, "DW_OP_GNU_entry_value", dw_op_notimpl}, // seems that it's equal to DW_OP_entry_value from DWARF 5
|
||||
};
|
||||
|
||||
int find_regnum(uint32_t op)
|
||||
{
|
||||
for(uint32_t i = 0; i < sizeof(reg_map) / sizeof(dwarf_reg_map); ++i) {
|
||||
if(reg_map[i].op_num == op) {
|
||||
return reg_map[i].regno;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const dwarf_op_map* find_op_map(int op)
|
||||
{
|
||||
for(uint32_t i = 0; i < sizeof(op_map) / sizeof(dwarf_op_map); ++i) {
|
||||
|
||||
@@ -129,11 +129,5 @@ typedef struct __dwarf_op_map {
|
||||
dwarf_operation operation; // function which handles operation
|
||||
} dwarf_op_map;
|
||||
|
||||
typedef struct __dwarf_reg_map {
|
||||
int regno; // platform-dependent register number
|
||||
const char* regname; // register name
|
||||
uint32_t op_num; // number of DWARF DW_OP_reg(x)/DW_OP_breg(x) operation corresponds to this register
|
||||
} dwarf_reg_map;
|
||||
|
||||
const dwarf_op_map* find_op_map(int op);
|
||||
int find_regnum(uint32_t op);
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* registers.cpp
|
||||
*
|
||||
* Created on: Jan 27, 2020
|
||||
* Author: nnosov
|
||||
*/
|
||||
|
||||
#include <dwarf.h>
|
||||
#include <elfutils/libdwfl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "registers.h"
|
||||
#include "dwarf_operations.h"
|
||||
|
||||
dwarf_reg_map reg_map[] = {
|
||||
// GP Registers
|
||||
{0x0, "RAX", DW_OP_reg0},
|
||||
{0x1, "RDX", DW_OP_reg1},
|
||||
{0x2, "RCX", DW_OP_reg2},
|
||||
{0x3, "RBX", DW_OP_reg3},
|
||||
{0x4, "RSI", DW_OP_reg4},
|
||||
{0x5, "RDI", DW_OP_reg5},
|
||||
{0x6, "RBP", DW_OP_reg6},
|
||||
{0x7, "RSP", DW_OP_reg7}, // Stack pointer address (SP) mapped to RSP
|
||||
// Extended GP Registers
|
||||
{0x8, "R8", DW_OP_reg8},
|
||||
{0x9, "R9", DW_OP_reg9},
|
||||
{0xA, "R10", DW_OP_reg10},
|
||||
{0xB, "R11", DW_OP_reg11},
|
||||
{0xC, "R12", DW_OP_reg12},
|
||||
{0xD, "R13", DW_OP_reg13},
|
||||
{0xE, "R14", DW_OP_reg14},
|
||||
{0xF, "R15", DW_OP_reg15},
|
||||
{0x10, "RIP", DW_OP_reg16}, // Return Address (RA) mapped to RIP
|
||||
// SSE Vector Registers
|
||||
{0x11, "XMM0", DW_OP_reg17},
|
||||
{0x12, "XMM1", DW_OP_reg18},
|
||||
{0x13, "XMM2", DW_OP_reg19},
|
||||
{0x14, "XMM3", DW_OP_reg20},
|
||||
{0x15, "XMM4", DW_OP_reg21},
|
||||
{0x16, "XMM5", DW_OP_reg22},
|
||||
{0x17, "XMM6", DW_OP_reg23},
|
||||
{0x18, "XMM7", DW_OP_reg24},
|
||||
{0x19, "XMM8", DW_OP_reg25},
|
||||
{0x1a, "XMM9", DW_OP_reg26},
|
||||
{0x1b, "XMM10", DW_OP_reg27},
|
||||
{0x1c, "XMM11", DW_OP_reg28},
|
||||
{0x1d, "XMM12", DW_OP_reg29},
|
||||
{0x1e, "XMM13", DW_OP_reg30},
|
||||
{0x1f, "XMM14", DW_OP_reg31},
|
||||
|
||||
// GP Registers
|
||||
{0x0, "RAX", DW_OP_breg0},
|
||||
{0x1, "RDX", DW_OP_breg1},
|
||||
{0x2, "RCX", DW_OP_breg2},
|
||||
{0x3, "RBX", DW_OP_breg3},
|
||||
{0x4, "RSI", DW_OP_breg4},
|
||||
{0x5, "RDI", DW_OP_breg5},
|
||||
{0x6, "RBP", DW_OP_breg6},
|
||||
{0x7, "RSP", DW_OP_breg7},
|
||||
// Extended GP Registers
|
||||
{0x8, "R8", DW_OP_breg8},
|
||||
{0x9, "R9", DW_OP_breg9},
|
||||
{0xA, "R10", DW_OP_breg10},
|
||||
{0xB, "R11", DW_OP_breg11},
|
||||
{0xC, "R12", DW_OP_breg12},
|
||||
{0xD, "R13", DW_OP_breg13},
|
||||
{0xE, "R14", DW_OP_breg14},
|
||||
{0xF, "R15", DW_OP_breg15},
|
||||
{0x10, "RIP", DW_OP_breg16}, // Return Address (RA) mapped to RIP
|
||||
// SSE Vector Registers
|
||||
{0x11, "XMM0", DW_OP_breg17},
|
||||
{0x12, "XMM1", DW_OP_breg18},
|
||||
{0x13, "XMM2", DW_OP_breg19},
|
||||
{0x14, "XMM3", DW_OP_breg20},
|
||||
{0x15, "XMM4", DW_OP_breg21},
|
||||
{0x16, "XMM5", DW_OP_breg22},
|
||||
{0x17, "XMM6", DW_OP_breg23},
|
||||
{0x18, "XMM7", DW_OP_breg24},
|
||||
{0x19, "XMM8", DW_OP_breg25},
|
||||
{0x1a, "XMM9", DW_OP_breg26},
|
||||
{0x1b, "XMM10", DW_OP_breg27},
|
||||
{0x1c, "XMM11", DW_OP_breg28},
|
||||
{0x1d, "XMM12", DW_OP_breg29},
|
||||
{0x1e, "XMM13", DW_OP_breg30},
|
||||
{0x1f, "XMM14", DW_OP_breg31},
|
||||
};
|
||||
|
||||
int regnum = sizeof(reg_map) / sizeof(dwarf_reg_map);
|
||||
|
||||
int find_regnum(uint32_t op)
|
||||
{
|
||||
for(int i = 0; i < regnum; ++i) {
|
||||
if(reg_map[i].op_num == op) {
|
||||
return reg_map[i].regno;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
pst_reg_error pst_get_reg(pst_context* ctx, int regno, uint64_t& regval)
|
||||
{
|
||||
#ifdef USE_LIBUNWIND
|
||||
int ret = unw_get_reg(ctx->curr_frame, regno, ®val);
|
||||
switch (ret) {
|
||||
case UNW_EUNSPEC:
|
||||
return REG_CFI_ERROR;
|
||||
break;
|
||||
case UNW_EBADREG:
|
||||
return REG_UNDEFINED;
|
||||
break;
|
||||
default:
|
||||
return REG_UNDEFINED;
|
||||
break;
|
||||
}
|
||||
|
||||
return REG_OK;
|
||||
#else
|
||||
Dwarf_Op ops_mem[3];
|
||||
Dwarf_Op* ops;
|
||||
size_t nops;
|
||||
char str[512];
|
||||
if(dwarf_frame_register(ctx->frame, regno, ops_mem, &ops, &nops) != -1) {
|
||||
if(nops != 0 || ops != ops_mem) {
|
||||
if(nops != 0 || ops != NULL) {
|
||||
str[0] = 0;
|
||||
ctx->print_expr_block(ops, nops, str, sizeof(str));
|
||||
dwarf_stack st(ctx);
|
||||
if(st.calc_expression(ops, nops, NULL) && st.get_value(regval)) {
|
||||
ctx->log(SEVERITY_DEBUG, "CFI register 0x%X(%s) expression: %s ==> %#lX", regno, reg_map[regno].regname, str, regval);
|
||||
return REG_OK;
|
||||
} else {
|
||||
ctx->log(SEVERITY_ERROR, "Failed to calculate register 0x%X(%s) CFI expression %s", regno, reg_map[regno].regname, str);
|
||||
return REG_EXPR_ERROR;
|
||||
}
|
||||
} else {
|
||||
ctx->log(SEVERITY_DEBUG, "CFI expression for register 0x%X(%s) is SAME VALUE", regno, reg_map[regno].regname);
|
||||
return REG_SAME;
|
||||
}
|
||||
} else {
|
||||
ctx->log(SEVERITY_DEBUG, "CFI expression for register 0x%X(%s) is UNDEFINED", regno, reg_map[regno].regname);
|
||||
return REG_UNDEFINED;
|
||||
}
|
||||
|
||||
} else {
|
||||
ctx->log(SEVERITY_ERROR, "Failed to get CFI expression for register 0x%X", regno);
|
||||
}
|
||||
|
||||
return REG_CFI_ERROR;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef struct __dwarf_reg_map {
|
||||
int regno; // platform-dependent register number
|
||||
const char* regname; // register name
|
||||
uint32_t op_num; // number of DWARF DW_OP_reg(x)/DW_OP_breg(x) operation corresponds to this register
|
||||
} dwarf_reg_map;
|
||||
|
||||
int find_regnum(uint32_t op);
|
||||
|
||||
typedef enum {
|
||||
REG_OK = 0,
|
||||
REG_UNDEFINED,
|
||||
REG_SAME,
|
||||
REG_CFI_ERROR,
|
||||
REG_EXPR_ERROR
|
||||
} pst_reg_error;
|
||||
|
||||
typedef struct __pst_frame : public SC_ListNode {
|
||||
__pst_frame() {
|
||||
memset(reg_state, REG_UNDEFINED, sizeof(reg_state));
|
||||
memset(regs, 0, sizeof(regs));
|
||||
cfa = 0;
|
||||
}
|
||||
int32_t reg_state[128];
|
||||
uint64_t regs[128];
|
||||
uint64_t cfa;
|
||||
} pst_frame;
|
||||
|
||||
pst_reg_error pst_get_reg(pst_context* ctx, int regno, uint64_t& regval);
|
||||
+49
-70
@@ -767,6 +767,7 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
|
||||
bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
||||
{
|
||||
die = d;
|
||||
get_frame();
|
||||
|
||||
Dwarf_Attribute attr_mem;
|
||||
Dwarf_Attribute* attr;
|
||||
@@ -786,8 +787,8 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
||||
ctx->log(SEVERITY_INFO, "Function %s(...): LOW_PC = %#lX, HIGH_PC = %#lX, offset from base address: 0x%lX, START_PC = 0x%lX, offset from start of function: 0x%lX",
|
||||
dwarf_diename(d), lowpc, highpc, pc - ctx->base_addr, info.start_ip, info.start_ip - ctx->base_addr);
|
||||
ctx->print_registers(0x0, 0x10);
|
||||
ctx->log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), parent ? parent->sp : 0, ctx->buff);
|
||||
ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->buff);
|
||||
ctx->log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), parent ? parent->sp : 0, ctx->get_print());
|
||||
ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->get_print());
|
||||
|
||||
// determine function's stack frame base
|
||||
attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem);
|
||||
@@ -884,11 +885,11 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr)
|
||||
bool __pst_function::unwind(Dwarf_Addr addr)
|
||||
{
|
||||
pc = addr;
|
||||
|
||||
Dwfl_Line *dwline = dwfl_getsrc(dwfl, addr);
|
||||
Dwfl_Line *dwline = dwfl_getsrc(ctx->dwfl, addr);
|
||||
if(dwline != NULL) {
|
||||
Dwarf_Addr addr;
|
||||
const char* filename = dwfl_lineinfo (dwline, &addr, &line, NULL, NULL, NULL);
|
||||
@@ -908,7 +909,7 @@ bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr)
|
||||
ctx->print("%p", (void*)addr);
|
||||
}
|
||||
|
||||
const char* addrname = dwfl_module_addrname(module, addr);
|
||||
const char* addrname = dwfl_module_addrname(ctx->module, addr);
|
||||
char* demangle_name = NULL;
|
||||
if(addrname) {
|
||||
int status;
|
||||
@@ -935,42 +936,44 @@ bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool __pst_handler::get_frame(pst_function* fun)
|
||||
bool __pst_function::get_frame()
|
||||
{
|
||||
// get CFI (Call Frame Information) for current module
|
||||
// from handle_cfi()
|
||||
Dwarf_Addr mod_bias = 0;
|
||||
Dwarf_CFI* cfi = dwfl_module_eh_cfi(module, &mod_bias); // rty .eh_cfi first
|
||||
Dwarf_CFI* cfi = dwfl_module_eh_cfi(ctx->module, &mod_bias); // rty .eh_cfi first
|
||||
if(!cfi) { // then try .debug_fame second
|
||||
cfi = dwfl_module_dwarf_cfi(module, &mod_bias);
|
||||
cfi = dwfl_module_dwarf_cfi(ctx->module, &mod_bias);
|
||||
}
|
||||
if(!cfi) {
|
||||
ctx.log(SEVERITY_ERROR, "Cannot find CFI for module");
|
||||
return false;
|
||||
}
|
||||
|
||||
// get frame of CFI for address
|
||||
int result = dwarf_cfi_addrframe (cfi, fun->pc - mod_bias, &frame);
|
||||
if (result != 0) {
|
||||
ctx.log(SEVERITY_ERROR, "Failed to find CFI frame for module");
|
||||
ctx->log(SEVERITY_ERROR, "Cannot find CFI for module");
|
||||
return false;
|
||||
}
|
||||
|
||||
// get frame of CFI for address
|
||||
int result = dwarf_cfi_addrframe (cfi, pc - mod_bias, &frame);
|
||||
if (result != 0) {
|
||||
ctx->log(SEVERITY_ERROR, "Failed to find CFI frame for module");
|
||||
return false;
|
||||
}
|
||||
|
||||
// setup context to match frame
|
||||
ctx->frame = frame;
|
||||
|
||||
// get return register and PC range for function
|
||||
Dwarf_Addr start = fun->pc;
|
||||
Dwarf_Addr end = fun->pc;
|
||||
Dwarf_Addr start = pc;
|
||||
Dwarf_Addr end = pc;
|
||||
bool signalp;
|
||||
int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp);
|
||||
if(ra_regno >= 0) {
|
||||
start += mod_bias;
|
||||
end += mod_bias;
|
||||
reginfo info; info.regno = ra_regno;
|
||||
dwfl_module_register_names(module, regname_callback, &info);
|
||||
ctx.log(SEVERITY_INFO, "Function %s(...): '.eh/debug frame' info: PC range: => [%#" PRIx64 ", %#" PRIx64 "], return register: %s, in_signal = %s",
|
||||
fun->name.c_str(), start, end, info.regname, signalp ? "true" : "false");
|
||||
dwfl_module_register_names(ctx->module, regname_callback, &info);
|
||||
ctx->log(SEVERITY_INFO, "Function %s(...): '.eh/debug frame' info: PC range: => [%#" PRIx64 ", %#" PRIx64 "], return register: %s, in_signal = %s",
|
||||
name.c_str(), start, end, info.regname, signalp ? "true" : "false");
|
||||
} else {
|
||||
ctx.log(SEVERITY_WARNING, "Return address register info unavailable (%s)", dwarf_errmsg(0));
|
||||
ctx->log(SEVERITY_WARNING, "Return address register info unavailable (%s)", dwarf_errmsg(0));
|
||||
}
|
||||
|
||||
// finally get CFA (Canonical Frame Address)
|
||||
@@ -979,45 +982,21 @@ bool __pst_handler::get_frame(pst_function* fun)
|
||||
Dwarf_Op dummy;
|
||||
Dwarf_Op *cfa_ops = &dummy;
|
||||
size_t cfa_nops;
|
||||
result = dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops);
|
||||
char str[1024]; str[0] = 0;
|
||||
ctx.print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
||||
// ctx.log(SEVERITY_INFO, "CFA expression: \"%s\"", str);
|
||||
dwarf_stack st(&ctx);
|
||||
uint64_t v;
|
||||
if(st.calc_expression(cfa_ops, cfa_nops, NULL) && st.get_value(v)) {
|
||||
//ctx.sp = v;
|
||||
ctx.log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fun->name.c_str(), str, v);
|
||||
fun->cfa = v;
|
||||
} else {
|
||||
ctx.log(SEVERITY_ERROR, "Failed to calculate CFA expression");
|
||||
if(dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops)) {
|
||||
ctx->log(SEVERITY_ERROR, "Failed to get CFA for frame");
|
||||
return false;
|
||||
}
|
||||
char str[1024]; str[0] = 0;
|
||||
ctx->print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
||||
dwarf_stack st(ctx);
|
||||
if(st.calc_expression(cfa_ops, cfa_nops, NULL) && st.get_value(cfa)) {
|
||||
//ctx.sp = v;
|
||||
ctx->log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", name.c_str(), str, cfa);
|
||||
|
||||
Dwarf_Op ops_mem[3];
|
||||
Dwarf_Op* ops;
|
||||
size_t nops;
|
||||
int regno = 0x5;
|
||||
if(dwarf_frame_register(frame, regno, ops_mem, &ops, &nops) != -1) {
|
||||
if(nops != 0 || ops != ops_mem) {
|
||||
if(nops != 0 || ops != NULL) {
|
||||
str[0] = 0;
|
||||
ctx.print_expr_block (ops, nops, str, sizeof(str));
|
||||
ctx.log(SEVERITY_INFO, "Function %s(...): CFI register location expression: %s", str);
|
||||
st.clear();
|
||||
if(st.calc_expression(ops, nops, NULL) && st.get_value(v)) {
|
||||
ctx.log(SEVERITY_DEBUG, "CFI register 0x%X expression: %s ==> %#lX", regno, str, v);
|
||||
} else {
|
||||
ctx.log(SEVERITY_ERROR, "Failed to calculate register 0x%X CFI expression %s", regno, str);
|
||||
}
|
||||
} else {
|
||||
ctx.log(SEVERITY_DEBUG, "CFI expression for register 0x%X is SAME VALUE", regno);
|
||||
}
|
||||
} else {
|
||||
ctx.log(SEVERITY_DEBUG, "CFI expression for register 0x%X is UNDEFINED", regno);
|
||||
}
|
||||
|
||||
// setup context to match CFA for frame
|
||||
ctx->cfa = cfa;
|
||||
} else {
|
||||
ctx.log(SEVERITY_ERROR, "Failed to get CFI expression for register 0x%X", regno);
|
||||
ctx->log(SEVERITY_ERROR, "Failed to calculate CFA expression");
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1027,8 +1006,8 @@ bool __pst_handler::get_dwarf_function(pst_function* fun)
|
||||
{
|
||||
Dwarf_Addr mod_cu = 0;
|
||||
// get CU(Compilation Unit) debug definition
|
||||
module = dwfl_addrmodule(dwfl, fun->pc);
|
||||
Dwarf_Die* cdie = dwfl_module_addrdie(module, fun->pc, &mod_cu);
|
||||
ctx.module = dwfl_addrmodule(ctx.dwfl, fun->pc);
|
||||
Dwarf_Die* cdie = dwfl_module_addrdie(ctx.module, fun->pc, &mod_cu);
|
||||
//Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias);
|
||||
if(!cdie) {
|
||||
ctx.log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", fun->pc);
|
||||
@@ -1102,12 +1081,13 @@ pst_function* __pst_handler::last_function()
|
||||
|
||||
bool __pst_handler::handle_dwarf()
|
||||
{
|
||||
ctx.clean_print();
|
||||
Dl_info info;
|
||||
|
||||
//for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) {
|
||||
for(pst_function* fun = (pst_function*)functions.Last(); fun; fun = (pst_function*)functions.Prev(fun)) {
|
||||
dladdr((void*)(fun->pc), &info);
|
||||
module = dwfl_addrmodule(dwfl, fun->pc);
|
||||
ctx.module = dwfl_addrmodule(ctx.dwfl, fun->pc);
|
||||
ctx.base_addr = (uint64_t)info.dli_fbase;
|
||||
ctx.log(SEVERITY_INFO, "Function %s(...): module name: %s, base address: %p, CFA: %#lX", fun->name.c_str(), info.dli_fname, info.dli_fbase, fun->parent ? fun->parent->sp : 0);
|
||||
ctx.curr_frame = &fun->cursor;
|
||||
@@ -1118,7 +1098,6 @@ bool __pst_handler::handle_dwarf()
|
||||
} else {
|
||||
ctx.next_frame = 0;
|
||||
}
|
||||
get_frame(fun);
|
||||
ctx.cfa = fun->cfa;
|
||||
|
||||
ctx.curr_frame = &fun->cursor;
|
||||
@@ -1134,7 +1113,7 @@ bool __pst_handler::handle_dwarf()
|
||||
|
||||
void __pst_handler::print_dwarf()
|
||||
{
|
||||
ctx.offset = 0;
|
||||
ctx.clean_print();
|
||||
ctx.print("DWARF-based stack trace information:\n");
|
||||
uint32_t idx = 0;
|
||||
for(pst_function* function = next_function(NULL); function; function = next_function(function)) {
|
||||
@@ -1156,6 +1135,7 @@ Dwfl_Callbacks callbacks = {
|
||||
|
||||
bool __pst_handler::unwind()
|
||||
{
|
||||
ctx.clean_print();
|
||||
#ifdef REG_RIP // x86_64
|
||||
caller = (void *) ctx.hcontext->uc_mcontext.gregs[REG_RIP];
|
||||
ctx.sp = ctx.hcontext->uc_mcontext.gregs[REG_RSP];
|
||||
@@ -1175,7 +1155,6 @@ bool __pst_handler::unwind()
|
||||
#else
|
||||
# error "unknown architecture!"
|
||||
#endif
|
||||
ctx.offset = 0;
|
||||
|
||||
//handle = dlopen(NULL, RTLD_NOW);
|
||||
Dl_info info;
|
||||
@@ -1183,13 +1162,13 @@ bool __pst_handler::unwind()
|
||||
ctx.base_addr = (uint64_t)info.dli_fbase;
|
||||
ctx.log(SEVERITY_INFO, "Process address information: PC address: %p, base address: %p, object name: %s", caller, info.dli_fbase, info.dli_fname);
|
||||
|
||||
dwfl = dwfl_begin(&callbacks);
|
||||
if(dwfl == NULL) {
|
||||
ctx.dwfl = dwfl_begin(&callbacks);
|
||||
if(ctx.dwfl == NULL) {
|
||||
ctx.print("Failed to initialize libdw session for parse stack frames");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dwfl_linux_proc_report(dwfl, getpid()) != 0 || dwfl_report_end(dwfl, NULL, NULL) !=0) {
|
||||
if(dwfl_linux_proc_report(ctx.dwfl, getpid()) != 0 || dwfl_report_end(ctx.dwfl, NULL, NULL) !=0) {
|
||||
ctx.print("Failed to parse debug section of executable");
|
||||
return false;
|
||||
}
|
||||
@@ -1218,12 +1197,12 @@ bool __pst_handler::unwind()
|
||||
}
|
||||
|
||||
ctx.print("[%-2d] ", i);
|
||||
module = dwfl_addrmodule(dwfl, addr);
|
||||
ctx.module = dwfl_addrmodule(ctx.dwfl, addr);
|
||||
pst_function* last = last_function();
|
||||
pst_function* fun = add_function(NULL);
|
||||
fun->sp = sp;
|
||||
ctx.log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, addr, sp);
|
||||
if(!fun->unwind(dwfl, module, addr)) {
|
||||
if(!fun->unwind(addr)) {
|
||||
del_function(fun);
|
||||
} else {
|
||||
if(last) {
|
||||
|
||||
@@ -179,10 +179,14 @@ typedef struct __pst_function : public SC_ListNode {
|
||||
parent = _parent;
|
||||
sp = 0;
|
||||
cfa = 0;
|
||||
frame = NULL;
|
||||
}
|
||||
|
||||
~__pst_function() {
|
||||
clear();
|
||||
if(frame) {
|
||||
free(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void clear();
|
||||
@@ -196,13 +200,15 @@ typedef struct __pst_function : public SC_ListNode {
|
||||
pst_call_site* call_site_by_origin(const char* origin);
|
||||
pst_call_site* call_site_by_target(uint64_t target);
|
||||
|
||||
bool unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr);
|
||||
bool unwind(Dwarf_Addr addr);
|
||||
bool handle_dwarf(Dwarf_Die* d);
|
||||
bool print_dwarf();
|
||||
bool handle_lexical_block(Dwarf_Die* result);
|
||||
bool handle_call_site(Dwarf_Die* result);
|
||||
pst_call_site* find_call_site(__pst_function* callee);
|
||||
|
||||
bool get_frame();
|
||||
|
||||
Dwarf_Addr lowpc; // offset to start of the function against base address
|
||||
Dwarf_Addr highpc; // offset to the next address after the end of the function against base address
|
||||
Dwarf_Die* die; // DWARF DIE containing definition of the function
|
||||
@@ -221,6 +227,7 @@ typedef struct __pst_function : public SC_ListNode {
|
||||
int line; // line in code where function is defined
|
||||
std::string file; // file name (DWARF Compilation Unit) where function is defined
|
||||
__pst_function* parent; // parent function in call trace (caller)
|
||||
Dwarf_Frame* frame; // function's stack frame
|
||||
pst_context* ctx; // context of unwinding
|
||||
} pst_function;
|
||||
|
||||
@@ -228,8 +235,6 @@ typedef struct __pst_handler {
|
||||
__pst_handler(ucontext_t* hctx) : ctx(hctx)
|
||||
{
|
||||
caller = NULL;
|
||||
module = NULL;
|
||||
dwfl = NULL;
|
||||
frame = NULL;
|
||||
addr = 0;
|
||||
handle = 0;
|
||||
@@ -253,14 +258,11 @@ typedef struct __pst_handler {
|
||||
bool handle_dwarf();
|
||||
void print_dwarf();
|
||||
bool unwind();
|
||||
bool get_frame(pst_function* fun);
|
||||
bool get_dwarf_function(pst_function* fun);
|
||||
|
||||
pst_context ctx; // context of unwinding
|
||||
void* handle; // process handle
|
||||
Dwarf_Addr addr; // address of currently processed function
|
||||
Dwfl* dwfl; // DWARF context
|
||||
Dwfl_Module* module; // currently processed CU
|
||||
Dwarf_Frame* frame; // currently processed stack frame
|
||||
void* caller; // pointer to the function which requested to unwind stack
|
||||
SC_ListHead functions; // list of functions in stack frame
|
||||
|
||||
Reference in New Issue
Block a user