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:
2020-01-28 14:24:32 +04:00
parent f9635841f6
commit c2fdeccd34
9 changed files with 271 additions and 180 deletions
+3 -2
View File
@@ -17,6 +17,7 @@
#include "logger/log.h" #include "logger/log.h"
#include "common.h" #include "common.h"
#include "dwarf_operations.h" #include "dwarf_operations.h"
#include "registers.h"
extern SC_LogBase* logger; extern SC_LogBase* logger;
extern dwarf_reg_map reg_map[]; 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) 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); log(SEVERITY_DEBUG, "CFA = %#lX, NEXT_CFA = %#lX, SP = %#lX", cfa, next_cfa, sp);
buff[0] = 0; offset = 0; clean_print();
int i = 0; int i = 0;
if(cfa > sp) { if(cfa > sp) {
print("Args: "); 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) 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) { for(int i = from; i < regnum && i <= to; ++i) {
unw_word_t regval; unw_word_t regval;
if(!unw_get_reg(curr_frame, reg_map[i].regno, &regval)) { if(!unw_get_reg(curr_frame, reg_map[i].regno, &regval)) {
+23 -6
View File
@@ -8,16 +8,20 @@
#include "logger/log.h" #include "logger/log.h"
#include "linkedlist.h" #include "linkedlist.h"
#define USE_LIBUNWIND
typedef struct __pst_context { typedef struct __pst_context {
__pst_context(ucontext_t* hctx) : hcontext(hctx) __pst_context(ucontext_t* hctx) : hcontext(hctx)
{ {
offset = 0; clean_print();
buff[0] = 0;
base_addr = 0; base_addr = 0;
sp = 0; sp = 0;
cfa = 0; cfa = 0;
curr_frame = NULL; curr_frame = NULL;
next_frame = NULL; next_frame = NULL;
frame = NULL;
dwfl = NULL;
module = NULL;
} }
bool print(const char* fmt, ...); 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); 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_registers(int from, int to);
void print_stack(int max, uint64_t next_cfa); 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 ucontext_t* hcontext; // context of signal handler
unw_context_t context; // context of stack trace unw_context_t context; // context of stack trace
unw_cursor_t cursor; unw_cursor_t cursor;
unw_cursor_t* curr_frame; // currently examined frame of context unw_cursor_t* curr_frame; // callee libunwind frame
unw_cursor_t* next_frame; // caller frame unw_cursor_t* next_frame; // caller libunwind frame
Dwarf_Addr base_addr; // base address where process loaded 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 sp;
Dwarf_Addr cfa; 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; } pst_context;
-88
View File
@@ -11,82 +11,6 @@
#include "dwarf_operations.h" #include "dwarf_operations.h"
#include "common.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 // not implemented operations
bool dw_op_notimpl(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) 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 {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) const dwarf_op_map* find_op_map(int op)
{ {
for(uint32_t i = 0; i < sizeof(op_map) / sizeof(dwarf_op_map); ++i) { for(uint32_t i = 0; i < sizeof(op_map) / sizeof(dwarf_op_map); ++i) {
-6
View File
@@ -129,11 +129,5 @@ typedef struct __dwarf_op_map {
dwarf_operation operation; // function which handles operation dwarf_operation operation; // function which handles operation
} dwarf_op_map; } 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); const dwarf_op_map* find_op_map(int op);
int find_regnum(uint32_t op); int find_regnum(uint32_t op);
+152
View File
@@ -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, &regval);
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
}
+33
View File
@@ -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
View File
@@ -767,6 +767,7 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
bool __pst_function::handle_dwarf(Dwarf_Die* d) bool __pst_function::handle_dwarf(Dwarf_Die* d)
{ {
die = d; die = d;
get_frame();
Dwarf_Attribute attr_mem; Dwarf_Attribute attr_mem;
Dwarf_Attribute* attr; 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", 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); dwarf_diename(d), lowpc, highpc, pc - ctx->base_addr, info.start_ip, info.start_ip - ctx->base_addr);
ctx->print_registers(0x0, 0x10); 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(...): CFA: %#lX %s", dwarf_diename(d), parent ? parent->sp : 0, ctx->get_print());
ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->buff); ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->get_print());
// determine function's stack frame base // determine function's stack frame base
attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem); attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem);
@@ -884,11 +885,11 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
return true; return true;
} }
bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr) bool __pst_function::unwind(Dwarf_Addr addr)
{ {
pc = addr; pc = addr;
Dwfl_Line *dwline = dwfl_getsrc(dwfl, addr); Dwfl_Line *dwline = dwfl_getsrc(ctx->dwfl, addr);
if(dwline != NULL) { if(dwline != NULL) {
Dwarf_Addr addr; Dwarf_Addr addr;
const char* filename = dwfl_lineinfo (dwline, &addr, &line, NULL, NULL, NULL); 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); 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; char* demangle_name = NULL;
if(addrname) { if(addrname) {
int status; int status;
@@ -935,42 +936,44 @@ bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr)
return true; return true;
} }
bool __pst_function::get_frame()
bool __pst_handler::get_frame(pst_function* fun)
{ {
// get CFI (Call Frame Information) for current module // get CFI (Call Frame Information) for current module
// from handle_cfi() // from handle_cfi()
Dwarf_Addr mod_bias = 0; 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 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) { if(!cfi) {
ctx.log(SEVERITY_ERROR, "Cannot find CFI 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, fun->pc - mod_bias, &frame);
if (result != 0) {
ctx.log(SEVERITY_ERROR, "Failed to find CFI frame for module");
return false; 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 // get return register and PC range for function
Dwarf_Addr start = fun->pc; Dwarf_Addr start = pc;
Dwarf_Addr end = fun->pc; Dwarf_Addr end = pc;
bool signalp; bool signalp;
int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp); int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp);
if(ra_regno >= 0) { if(ra_regno >= 0) {
start += mod_bias; start += mod_bias;
end += mod_bias; end += mod_bias;
reginfo info; info.regno = ra_regno; reginfo info; info.regno = ra_regno;
dwfl_module_register_names(module, regname_callback, &info); 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", 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"); name.c_str(), start, end, info.regname, signalp ? "true" : "false");
} else { } 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) // finally get CFA (Canonical Frame Address)
@@ -979,45 +982,21 @@ bool __pst_handler::get_frame(pst_function* fun)
Dwarf_Op dummy; Dwarf_Op dummy;
Dwarf_Op *cfa_ops = &dummy; Dwarf_Op *cfa_ops = &dummy;
size_t cfa_nops; size_t cfa_nops;
result = dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops); if(dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops)) {
char str[1024]; str[0] = 0; ctx->log(SEVERITY_ERROR, "Failed to get CFA for frame");
ctx.print_expr_block (cfa_ops, cfa_nops, str, sizeof(str)); return false;
// 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");
} }
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]; // setup context to match CFA for frame
Dwarf_Op* ops; ctx->cfa = cfa;
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);
}
} else { } 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; return true;
@@ -1027,8 +1006,8 @@ bool __pst_handler::get_dwarf_function(pst_function* fun)
{ {
Dwarf_Addr mod_cu = 0; Dwarf_Addr mod_cu = 0;
// get CU(Compilation Unit) debug definition // get CU(Compilation Unit) debug definition
module = dwfl_addrmodule(dwfl, fun->pc); ctx.module = dwfl_addrmodule(ctx.dwfl, fun->pc);
Dwarf_Die* cdie = dwfl_module_addrdie(module, fun->pc, &mod_cu); Dwarf_Die* cdie = dwfl_module_addrdie(ctx.module, fun->pc, &mod_cu);
//Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias); //Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias);
if(!cdie) { if(!cdie) {
ctx.log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", fun->pc); 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() bool __pst_handler::handle_dwarf()
{ {
ctx.clean_print();
Dl_info info; Dl_info info;
//for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) { //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)) { for(pst_function* fun = (pst_function*)functions.Last(); fun; fun = (pst_function*)functions.Prev(fun)) {
dladdr((void*)(fun->pc), &info); 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.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.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; ctx.curr_frame = &fun->cursor;
@@ -1118,7 +1098,6 @@ bool __pst_handler::handle_dwarf()
} else { } else {
ctx.next_frame = 0; ctx.next_frame = 0;
} }
get_frame(fun);
ctx.cfa = fun->cfa; ctx.cfa = fun->cfa;
ctx.curr_frame = &fun->cursor; ctx.curr_frame = &fun->cursor;
@@ -1134,7 +1113,7 @@ bool __pst_handler::handle_dwarf()
void __pst_handler::print_dwarf() void __pst_handler::print_dwarf()
{ {
ctx.offset = 0; ctx.clean_print();
ctx.print("DWARF-based stack trace information:\n"); ctx.print("DWARF-based stack trace information:\n");
uint32_t idx = 0; uint32_t idx = 0;
for(pst_function* function = next_function(NULL); function; function = next_function(function)) { for(pst_function* function = next_function(NULL); function; function = next_function(function)) {
@@ -1156,6 +1135,7 @@ Dwfl_Callbacks callbacks = {
bool __pst_handler::unwind() bool __pst_handler::unwind()
{ {
ctx.clean_print();
#ifdef REG_RIP // x86_64 #ifdef REG_RIP // x86_64
caller = (void *) ctx.hcontext->uc_mcontext.gregs[REG_RIP]; caller = (void *) ctx.hcontext->uc_mcontext.gregs[REG_RIP];
ctx.sp = ctx.hcontext->uc_mcontext.gregs[REG_RSP]; ctx.sp = ctx.hcontext->uc_mcontext.gregs[REG_RSP];
@@ -1175,7 +1155,6 @@ bool __pst_handler::unwind()
#else #else
# error "unknown architecture!" # error "unknown architecture!"
#endif #endif
ctx.offset = 0;
//handle = dlopen(NULL, RTLD_NOW); //handle = dlopen(NULL, RTLD_NOW);
Dl_info info; Dl_info info;
@@ -1183,13 +1162,13 @@ bool __pst_handler::unwind()
ctx.base_addr = (uint64_t)info.dli_fbase; 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); 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); ctx.dwfl = dwfl_begin(&callbacks);
if(dwfl == NULL) { if(ctx.dwfl == NULL) {
ctx.print("Failed to initialize libdw session for parse stack frames"); ctx.print("Failed to initialize libdw session for parse stack frames");
return false; 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"); ctx.print("Failed to parse debug section of executable");
return false; return false;
} }
@@ -1218,12 +1197,12 @@ bool __pst_handler::unwind()
} }
ctx.print("[%-2d] ", i); ctx.print("[%-2d] ", i);
module = dwfl_addrmodule(dwfl, addr); ctx.module = dwfl_addrmodule(ctx.dwfl, addr);
pst_function* last = last_function(); pst_function* last = last_function();
pst_function* fun = add_function(NULL); pst_function* fun = add_function(NULL);
fun->sp = sp; fun->sp = sp;
ctx.log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, addr, 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); del_function(fun);
} else { } else {
if(last) { if(last) {
+8 -6
View File
@@ -179,10 +179,14 @@ typedef struct __pst_function : public SC_ListNode {
parent = _parent; parent = _parent;
sp = 0; sp = 0;
cfa = 0; cfa = 0;
frame = NULL;
} }
~__pst_function() { ~__pst_function() {
clear(); clear();
if(frame) {
free(frame);
}
} }
void clear(); 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_origin(const char* origin);
pst_call_site* call_site_by_target(uint64_t target); 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 handle_dwarf(Dwarf_Die* d);
bool print_dwarf(); bool print_dwarf();
bool handle_lexical_block(Dwarf_Die* result); bool handle_lexical_block(Dwarf_Die* result);
bool handle_call_site(Dwarf_Die* result); bool handle_call_site(Dwarf_Die* result);
pst_call_site* find_call_site(__pst_function* callee); 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 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_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 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 int line; // line in code where function is defined
std::string file; // file name (DWARF Compilation Unit) 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) __pst_function* parent; // parent function in call trace (caller)
Dwarf_Frame* frame; // function's stack frame
pst_context* ctx; // context of unwinding pst_context* ctx; // context of unwinding
} pst_function; } pst_function;
@@ -228,8 +235,6 @@ typedef struct __pst_handler {
__pst_handler(ucontext_t* hctx) : ctx(hctx) __pst_handler(ucontext_t* hctx) : ctx(hctx)
{ {
caller = NULL; caller = NULL;
module = NULL;
dwfl = NULL;
frame = NULL; frame = NULL;
addr = 0; addr = 0;
handle = 0; handle = 0;
@@ -253,14 +258,11 @@ typedef struct __pst_handler {
bool handle_dwarf(); bool handle_dwarf();
void print_dwarf(); void print_dwarf();
bool unwind(); bool unwind();
bool get_frame(pst_function* fun);
bool get_dwarf_function(pst_function* fun); bool get_dwarf_function(pst_function* fun);
pst_context ctx; // context of unwinding pst_context ctx; // context of unwinding
void* handle; // process handle void* handle; // process handle
Dwarf_Addr addr; // address of currently processed function 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 Dwarf_Frame* frame; // currently processed stack frame
void* caller; // pointer to the function which requested to unwind stack void* caller; // pointer to the function which requested to unwind stack
SC_ListHead functions; // list of functions in stack frame SC_ListHead functions; // list of functions in stack frame
+3 -2
View File
@@ -67,16 +67,17 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context)
logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig)); logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig));
bool ret = false; bool ret = false;
pst_handler handler((ucontext_t*)context); pst_handler handler((ucontext_t*)context);
if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE)) if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE))
{ {
ret = handler.unwind(); ret = handler.unwind();
} }
if(ret) { if(ret) {
logger->Log(SEVERITY_INFO, "%s", handler.ctx.buff); logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print());
handler.handle_dwarf(); handler.handle_dwarf();
handler.print_dwarf(); handler.print_dwarf();
logger->Log(SEVERITY_INFO, "%s", handler.ctx.buff); logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print());
} else { } else {
logger->Log(SEVERITY_ERROR, "No stack trace obtained"); logger->Log(SEVERITY_ERROR, "No stack trace obtained");
} }