diff --git a/framework/common.cpp b/framework/common.cpp index 64a6fdc..3717c9c 100644 --- a/framework/common.cpp +++ b/framework/common.cpp @@ -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)) { diff --git a/framework/common.h b/framework/common.h index 2912baa..b4523f8 100644 --- a/framework/common.h +++ b/framework/common.h @@ -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; diff --git a/framework/dwarf_operations.cpp b/framework/dwarf_operations.cpp index 7582049..defd2d9 100644 --- a/framework/dwarf_operations.cpp +++ b/framework/dwarf_operations.cpp @@ -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) { diff --git a/framework/dwarf_operations.h b/framework/dwarf_operations.h index c0f1551..8d84462 100644 --- a/framework/dwarf_operations.h +++ b/framework/dwarf_operations.h @@ -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); diff --git a/framework/registers.cpp b/framework/registers.cpp new file mode 100644 index 0000000..6c029d5 --- /dev/null +++ b/framework/registers.cpp @@ -0,0 +1,152 @@ +/* + * registers.cpp + * + * Created on: Jan 27, 2020 + * Author: nnosov + */ + +#include +#include + +#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 +} diff --git a/framework/registers.h b/framework/registers.h new file mode 100644 index 0000000..b5bc7d9 --- /dev/null +++ b/framework/registers.h @@ -0,0 +1,33 @@ +#pragma once + +#include + + +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); diff --git a/framework/sysutils.cpp b/framework/sysutils.cpp index 8316f11..db2764f 100644 --- a/framework/sysutils.cpp +++ b/framework/sysutils.cpp @@ -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) { diff --git a/framework/sysutils.h b/framework/sysutils.h index 2ce0006..e99bb7f 100644 --- a/framework/sysutils.h +++ b/framework/sysutils.h @@ -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 diff --git a/main.cpp b/main.cpp index b4ac07a..7ccb4b6 100644 --- a/main.cpp +++ b/main.cpp @@ -67,16 +67,17 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context) logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig)); bool ret = false; pst_handler handler((ucontext_t*)context); + if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE)) { ret = handler.unwind(); } if(ret) { - logger->Log(SEVERITY_INFO, "%s", handler.ctx.buff); + logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print()); handler.handle_dwarf(); handler.print_dwarf(); - logger->Log(SEVERITY_INFO, "%s", handler.ctx.buff); + logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print()); } else { logger->Log(SEVERITY_ERROR, "No stack trace obtained"); }