global refactoring: use libunwind to get stack frame, get rid on process
base address, better DWARF DW_OP_XXX handling, initial implementation of parameter's values retrieval
This commit is contained in:
@@ -49,7 +49,7 @@ SRC = $(shell find . -name '*.cpp')
|
|||||||
#OBJ = $(patsubst %.cpp,%.o,$(addprefix $(BUILD_DIR)/,$(notdir $(SRC))))
|
#OBJ = $(patsubst %.cpp,%.o,$(addprefix $(BUILD_DIR)/,$(notdir $(SRC))))
|
||||||
OBJ = $(BUILD_DIR)/main.o
|
OBJ = $(BUILD_DIR)/main.o
|
||||||
|
|
||||||
LIBS = -L./ -lpthread -lpq -lpqtypes -luuid -lrabbitmq -ljson-c -lcrypto -ldl -lcurl -ldw -lxml2 -lmicrohttpd -larchive -lmagic
|
LIBS = -L./ -lpthread -lpq -lpqtypes -luuid -lrabbitmq -ljson-c -lcrypto -ldl -lcurl -ldw -lxml2 -lmicrohttpd -larchive -lmagic -lunwind -lunwind-x86_64
|
||||||
ATR_LIBS = ./build/libframework.a
|
ATR_LIBS = ./build/libframework.a
|
||||||
|
|
||||||
INCS = -I./ \
|
INCS = -I./ \
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* common.cpp
|
||||||
|
*
|
||||||
|
* Created on: Jan 8, 2020
|
||||||
|
* Author: nnosov
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
dwarf_op_map dw_op[] = {
|
||||||
|
{0x23, 0x0, 0, "DW_OP_plus_uconst"},
|
||||||
|
// Register location descriptions. From DWARF 5, section 2.6.1.1.3:
|
||||||
|
// Register location descriptions describe an object (or a piece of an object) that resides in a register.
|
||||||
|
// A register location description must stand alone as the entire description of an object or a piece of an object.
|
||||||
|
{0x50, 0x0, "RAX", "DW_OP_reg0"},
|
||||||
|
{0x51, 0x1, "RDX", "DW_OP_reg1"},
|
||||||
|
{0x52, 0x2, "RCX", "DW_OP_reg2"},
|
||||||
|
{0x53, 0x3, "RBX", "DW_OP_reg3"},
|
||||||
|
{0x54, 0x4, "RSI", "DW_OP_reg4"},
|
||||||
|
{0x55, 0x5, "RDI", "DW_OP_reg5"},
|
||||||
|
{0x56, 0x6, "RBP", "DW_OP_reg6"},
|
||||||
|
{0x57, 0x7, "RSP", "DW_OP_reg7"},
|
||||||
|
{0x58, 0x8, "R8", "DW_OP_reg8"},
|
||||||
|
{0x59, 0x9, "R9", "DW_OP_reg9"},
|
||||||
|
{0x5A, 0xA, "R10", "DW_OP_reg10"},
|
||||||
|
{0x5B, 0xB, "R11", "DW_OP_reg11"},
|
||||||
|
{0x5C, 0xC, "R12", "DW_OP_reg12"},
|
||||||
|
{0x5D, 0xD, "R13", "DW_OP_reg13"},
|
||||||
|
{0x5E, 0xE, "R14", "DW_OP_reg14"},
|
||||||
|
{0x5F, 0xF, "R15", "DW_OP_reg15"},
|
||||||
|
{0x60, 0x10, "RIP", "DW_OP_reg16"},
|
||||||
|
|
||||||
|
// Register values. DWARF5, section 2.5.1.2
|
||||||
|
// Register values are used to describe an object (or a piece of an object) that is located in memory at an address that is contained in
|
||||||
|
// a register (possibly offset by some constant)
|
||||||
|
{0x70, 0x0, "RAX", "DW_OP_breg0"},
|
||||||
|
{0x71, 0x1, "RDX", "DW_OP_breg1"},
|
||||||
|
{0x72, 0x2, "RCX", "DW_OP_breg2"},
|
||||||
|
{0x73, 0x3, "RBX", "DW_OP_breg3"},
|
||||||
|
{0x74, 0x4, "RSI", "DW_OP_breg4"},
|
||||||
|
{0x75, 0x5, "RDI", "DW_OP_breg5"},
|
||||||
|
{0x76, 0x6, "RBP", "DW_OP_breg6"},
|
||||||
|
{0x77, 0x7, "RSP", "DW_OP_breg7"},
|
||||||
|
{0x78, 0x8, "R8", "DW_OP_breg8"},
|
||||||
|
{0x79, 0x9, "R9", "DW_OP_breg9"},
|
||||||
|
{0x7A, 0xA, "R10", "DW_OP_breg10"},
|
||||||
|
{0x7B, 0xB, "R11", "DW_OP_breg11"},
|
||||||
|
{0x7C, 0xC, "R12", "DW_OP_breg12"},
|
||||||
|
{0x7D, 0xD, "R13", "DW_OP_breg13"},
|
||||||
|
{0x7E, 0xE, "R14", "DW_OP_breg14"},
|
||||||
|
{0x7F, 0xF, "R15", "DW_OP_breg15"},
|
||||||
|
{0x80, 0x10, "RIP", "DW_OP_breg16"},
|
||||||
|
|
||||||
|
// The DW_OP_fbreg operation provides a signed LEB128 offset from the address specified by the location description in the DW_AT_frame_base
|
||||||
|
// attribute of the current function. This is typically a stack pointer register plus or minus some offset
|
||||||
|
{0x91, -1, "", "DW_OP_fbreg"},
|
||||||
|
{0x92, -1, "", "DW_OP_bregx"},
|
||||||
|
{0x9C, -1, "", "DW_OP_call_frame_cfa"},
|
||||||
|
// DWARF5, Section 2.6.1.1.4:
|
||||||
|
// he DW_OP_stack_value operation specifies that the object does not exist in memory but its value is nonetheless known and is at the top of the DWARF
|
||||||
|
// expression stack. In this form of location description, the DWARF expression represents the actual value of the object, rather than its location.
|
||||||
|
// The DW_OP_stack_value operation terminates the expression.
|
||||||
|
{0x9F, -1, "", "DW_OP_stack_value"},
|
||||||
|
//
|
||||||
|
{0xF3, -1, "", "DW_OP_GNU_entry_value"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const dwarf_op_map* find_op_map(int op)
|
||||||
|
{
|
||||||
|
for(uint32_t i = 0; i < sizeof(dw_op) / sizeof(dwarf_op_map); ++i) {
|
||||||
|
if(dw_op[i].op_num == op) {
|
||||||
|
return &dw_op[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t decode_sleb128(uint8_t *sleb128)
|
||||||
|
{
|
||||||
|
int32_t num = 0, shift = 0, size = 0;
|
||||||
|
do {
|
||||||
|
num |= ((*sleb128 & 0x7f) << shift);
|
||||||
|
shift += 7;
|
||||||
|
size += 8;
|
||||||
|
} while(*sleb128++ & 0x80);
|
||||||
|
if((shift < size) && (*(--sleb128) & 0x40)) {
|
||||||
|
num |= - (1 << shift);
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t decode_uleb128(uint8_t *uleb128)
|
||||||
|
{
|
||||||
|
uint32_t num = 0, shift = 0;
|
||||||
|
do {
|
||||||
|
num |= ((*uleb128 & 0x7f) << shift);
|
||||||
|
shift += 7;
|
||||||
|
} while(*uleb128++ & 0x80);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct __dwarf_op_map {
|
||||||
|
int op_num; // DWARF Operation DW_OP_XXX
|
||||||
|
int regno; // platform-dependent register number if present
|
||||||
|
const char* regname; // register name if regno specified
|
||||||
|
const char* op_name; // string representation of an operation
|
||||||
|
} dwarf_op_map;
|
||||||
|
|
||||||
|
const dwarf_op_map* find_op_map(int op);
|
||||||
|
int32_t decode_sleb128(uint8_t *sleb128);
|
||||||
|
uint32_t decode_uleb128(uint8_t *uleb128);
|
||||||
+360
-221
@@ -20,28 +20,51 @@
|
|||||||
|
|
||||||
extern SC_LogBase* logger;
|
extern SC_LogBase* logger;
|
||||||
|
|
||||||
char __stack_trace[8192];
|
#define USEI_LIBUNWIND
|
||||||
|
|
||||||
|
#ifdef USEI_LIBUNWIND
|
||||||
|
#include <libunwind.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
Dwarf_Frame* frame = 0;
|
#include "common.h"
|
||||||
Dwarf_Frame* prev_frame = 0;
|
|
||||||
Dwfl_Module* module;
|
bool __pst_context::print(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
bool nret = true;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
int size = sizeof(buff) - offset;
|
||||||
|
int ret = vsnprintf(buff + offset, size, fmt, args);
|
||||||
|
if(ret >= size || ret < 0) {
|
||||||
|
nret = false;
|
||||||
|
}
|
||||||
|
offset += ret;
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return nret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __pst_context::log(SC_LogSeverity severity, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
uint32_t str_len = 0;
|
||||||
|
char str[PATH_MAX]; str[0] = 0;
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
str_len += vsnprintf(str + str_len, sizeof(str) - str_len, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
logger->Log(severity, "%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
// dwfl_addrsegment() possibly can be used to check address validity
|
// dwfl_addrsegment() possibly can be used to check address validity
|
||||||
// dwarf_getattrs() allows to enumerate all DIE attributes
|
// dwarf_getattrs() allows to enumerate all DIE attributes
|
||||||
// dwarf_getfuncs() allows to enumerate functions within CU
|
// dwarf_getfuncs() allows to enumerate functions within CU
|
||||||
|
|
||||||
static void print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias, const char* prefix);
|
|
||||||
|
|
||||||
bool is_location_form(int form)
|
bool is_location_form(int form)
|
||||||
{
|
{
|
||||||
if (form == DW_FORM_block1 ||
|
if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block ||
|
||||||
form == DW_FORM_block2 ||
|
form == DW_FORM_data4 || form == DW_FORM_data8 || form == DW_FORM_sec_offset) {
|
||||||
form == DW_FORM_block4 ||
|
|
||||||
form == DW_FORM_block ||
|
|
||||||
form == DW_FORM_data4 ||
|
|
||||||
form == DW_FORM_data8 ||
|
|
||||||
form == DW_FORM_sec_offset) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -83,6 +106,7 @@ int regname_callback (void *arg, int regno, const char *setname, const char *pre
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
int reginfo_callback (void *arg, int regno, const char *setname, const char *prefix, const char *regname, int bits, int type)
|
int reginfo_callback (void *arg, int regno, const char *setname, const char *prefix, const char *regname, int bits, int type)
|
||||||
{
|
{
|
||||||
reginfo* info = (reginfo*)arg;
|
reginfo* info = (reginfo*)arg;
|
||||||
@@ -114,56 +138,9 @@ int reginfo_callback (void *arg, int regno, const char *setname, const char *pre
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void HandleType(Dwarf_Attribute* param, bool is_return = false)
|
/*
|
||||||
{
|
|
||||||
Dwarf_Attribute attr_mem;
|
|
||||||
Dwarf_Attribute* attr;
|
|
||||||
|
|
||||||
// get DIE of return type
|
|
||||||
Dwarf_Die ret_die;
|
|
||||||
|
|
||||||
if(dwarf_formref_die(param, &ret_die)) {
|
|
||||||
switch (dwarf_tag(&ret_die)) {
|
|
||||||
case DW_TAG_base_type: {
|
|
||||||
// get Size attribute and it's value
|
|
||||||
Dwarf_Word size = 0;
|
|
||||||
attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
|
|
||||||
if(attr) {
|
|
||||||
dwarf_formudata(attr, &size);
|
|
||||||
}
|
|
||||||
logger->Log(SEVERITY_INFO, "base type '%s'(%lu)", dwarf_diename(&ret_die), size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DW_TAG_array_type:
|
|
||||||
logger->Log(SEVERITY_INFO, "array type");
|
|
||||||
break;
|
|
||||||
case DW_TAG_pointer_type:
|
|
||||||
logger->Log(SEVERITY_INFO, "pointer type");
|
|
||||||
break;
|
|
||||||
case DW_TAG_enumeration_type:
|
|
||||||
logger->Log(SEVERITY_INFO, "enumeration type");
|
|
||||||
break;
|
|
||||||
case DW_TAG_const_type:
|
|
||||||
logger->Log(SEVERITY_INFO, "constant type");
|
|
||||||
break;
|
|
||||||
case DW_TAG_subroutine_type:
|
|
||||||
logger->Log(SEVERITY_INFO, "subroutine type");
|
|
||||||
break;
|
|
||||||
case DW_TAG_typedef:
|
|
||||||
logger->Log(SEVERITY_INFO, "typedef '%s' type", dwarf_diename(&ret_die));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger->Log(SEVERITY_INFO, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem);
|
|
||||||
if(attr) {
|
|
||||||
HandleType(attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_framereg(int regno)
|
void print_framereg(int regno)
|
||||||
{
|
{
|
||||||
Dwarf_Op ops_mem[3];
|
Dwarf_Op ops_mem[3];
|
||||||
@@ -187,31 +164,145 @@ void print_framereg(int regno)
|
|||||||
logger->Log(SEVERITY_DEBUG, "\t[%d] operation: 0x%hhX, operand1: 0x%lX, operand2: 0x%lx, offset: 0x%lX", i, ops[i].atom, ops[i].number, ops[i].number2, ops[i].offset);
|
logger->Log(SEVERITY_DEBUG, "\t[%d] operation: 0x%hhX, operand1: 0x%lX, operand2: 0x%lx, offset: 0x%lX", i, ops[i].atom, ops[i].number, ops[i].number2, ops[i].offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
void
|
uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr)
|
||||||
print_expr_block (Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size)
|
|
||||||
{
|
{
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
//printf ("%s", (i + 1 < len ? ", " : ""));
|
//printf ("%s", (i + 1 < len ? ", " : ""));
|
||||||
offset += snprintf(buff + offset, buff_size - offset, "0x%hhX(0x%lX, 0x%lx) ", exprs[i].atom, exprs[i].number, exprs[i].number2);
|
const dwarf_op_map* map = find_op_map(exprs[i].atom);
|
||||||
if(exprs[i].atom >= DW_OP_reg0 && exprs[i].atom <= DW_OP_bregx) {
|
if(map) {
|
||||||
print_framereg(exprs[i].atom);
|
if(map->op_num >= DW_OP_breg0 && map->op_num <= DW_OP_breg16) {
|
||||||
|
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number);
|
||||||
|
|
||||||
|
unw_word_t ptr = 0;
|
||||||
|
unw_get_reg(&cursor, map->regno, &ptr);
|
||||||
|
//ptr += off;
|
||||||
|
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s%s%d) reg_value: 0x%lX ", map->op_name, map->regname, off >=0 ? "+" : "", off, ptr);
|
||||||
|
} else if(map->op_num >= DW_OP_reg0 && map->op_num <= DW_OP_reg16) {
|
||||||
|
unw_word_t value = 0;
|
||||||
|
unw_get_reg(&cursor, map->regno, &value);
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s) value: 0x%lX", map->op_name, map->regname, value);
|
||||||
|
} else if(map->op_num == DW_OP_GNU_entry_value) {
|
||||||
|
uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number);
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s(%u, ", map->op_name, value);
|
||||||
|
Dwarf_Attribute attr_mem;
|
||||||
|
if(!dwarf_getlocation_attr(attr, exprs, &attr_mem)) {
|
||||||
|
Dwarf_Op *expr;
|
||||||
|
size_t exprlen;
|
||||||
|
if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) {
|
||||||
|
offset += print_expr_block (expr, exprlen, buff + offset, buff_size - offset, attr);
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, ") ");
|
||||||
|
} else {
|
||||||
|
log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr expression");
|
||||||
|
}
|
||||||
|
} else if(map->op_num == DW_OP_stack_value) {
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s", map->op_name);
|
||||||
|
} else if(map->op_num == DW_OP_plus_uconst) {
|
||||||
|
uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number);
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s(+%u) ", map->op_name, value);
|
||||||
|
} else if(map->op_num == DW_OP_bregx) {
|
||||||
|
uint32_t regno = decode_uleb128((unsigned char*)&exprs[i].number);
|
||||||
|
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number2);
|
||||||
|
|
||||||
|
unw_word_t ptr = 0;
|
||||||
|
unw_get_reg(&cursor, map->regno, &ptr);
|
||||||
|
//ptr += off;
|
||||||
|
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s(%s%s%d) reg_value = 0x%lX", map->op_name, unw_regname(regno), off >= 0 ? "+" : "", off, ptr);
|
||||||
|
} else {
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s(0x%lX, 0x%lx) ", map->op_name, exprs[i].number, exprs[i].number2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "0x%hhX(0x%lX, 0x%lx) ", exprs[i].atom, exprs[i].number, exprs[i].number2);
|
||||||
|
}
|
||||||
|
// if(exprs[i].atom >= DW_OP_reg0 && exprs[i].atom <= DW_OP_bregx) {
|
||||||
|
// print_framereg(exprs[i].atom);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
void HandleParameter(Dwarf_Die* result)
|
|
||||||
|
bool __pst_parameter::handle_type(Dwarf_Attribute* param, bool is_return)
|
||||||
{
|
{
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Attribute* attr;
|
Dwarf_Attribute* attr;
|
||||||
|
|
||||||
|
// get DIE of return type
|
||||||
|
Dwarf_Die ret_die;
|
||||||
|
|
||||||
|
if(!dwarf_formref_die(param, &ret_die)) {
|
||||||
|
function->ctx->log(SEVERITY_ERROR, "Failed to get parameter DIE");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dwarf_tag(&ret_die)) {
|
||||||
|
case DW_TAG_base_type: {
|
||||||
|
// get Size attribute and it's value
|
||||||
|
Dwarf_Word size = 0;
|
||||||
|
attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
dwarf_formudata(attr, &size);
|
||||||
|
}
|
||||||
|
function->ctx->log(SEVERITY_INFO, "base type '%s'(%lu)", dwarf_diename(&ret_die), size);
|
||||||
|
types.push_back(dwarf_diename(&ret_die));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_TAG_array_type:
|
||||||
|
logger->Log(SEVERITY_INFO, "array type");
|
||||||
|
types.push_back("[]");
|
||||||
|
break;
|
||||||
|
case DW_TAG_pointer_type:
|
||||||
|
logger->Log(SEVERITY_INFO, "pointer type");
|
||||||
|
types.push_back("*");
|
||||||
|
break;
|
||||||
|
case DW_TAG_enumeration_type:
|
||||||
|
logger->Log(SEVERITY_INFO, "enumeration type");
|
||||||
|
types.push_back("enum");
|
||||||
|
break;
|
||||||
|
case DW_TAG_const_type:
|
||||||
|
logger->Log(SEVERITY_INFO, "constant type");
|
||||||
|
types.push_back("const");
|
||||||
|
break;
|
||||||
|
case DW_TAG_subroutine_type:
|
||||||
|
logger->Log(SEVERITY_INFO, "subroutine type");
|
||||||
|
break;
|
||||||
|
case DW_TAG_typedef:
|
||||||
|
logger->Log(SEVERITY_INFO, "typedef '%s' type", dwarf_diename(&ret_die));
|
||||||
|
types.push_back(dwarf_diename(&ret_die));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger->Log(SEVERITY_INFO, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
return handle_type(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
||||||
|
{
|
||||||
|
die = result;
|
||||||
|
|
||||||
|
Dwarf_Attribute attr_mem;
|
||||||
|
Dwarf_Attribute* attr;
|
||||||
|
|
||||||
// Get reference to attribute type of the parameter/variable
|
// Get reference to attribute type of the parameter/variable
|
||||||
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
|
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
|
||||||
logger->Log(SEVERITY_INFO, "Handle '%s' %s", dwarf_diename(result), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
function->ctx->log(SEVERITY_INFO, "Handle '%s' %s", dwarf_diename(result), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
||||||
if(attr) {
|
if(attr) {
|
||||||
HandleType(attr);
|
handle_type(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine location of parameter in stack/heap or CPU registers
|
// determine location of parameter in stack/heap or CPU registers
|
||||||
@@ -222,146 +313,177 @@ void HandleParameter(Dwarf_Die* result)
|
|||||||
size_t exprlen;
|
size_t exprlen;
|
||||||
if (dwarf_getlocation(attr, &expr, &exprlen) == 0) {
|
if (dwarf_getlocation(attr, &expr, &exprlen) == 0) {
|
||||||
char str[1024]; str[0] = 0;
|
char str[1024]; str[0] = 0;
|
||||||
print_expr_block (expr, exprlen, str, sizeof(str));
|
function->ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
|
||||||
logger->Log(SEVERITY_DEBUG, "Found DW_AT_location expression: %s", str);
|
function->ctx->log(SEVERITY_DEBUG, "Found DW_AT_location expression: %s", str);
|
||||||
if(expr[0].atom >= DW_OP_reg0 && expr[0].atom <= DW_OP_bregx) {
|
// if(expr[0].atom >= DW_OP_reg0 && expr[0].atom <= DW_OP_bregx) {
|
||||||
print_framereg(expr[0].atom);
|
// print_framereg(expr[0].atom);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
} else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
|
} else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
|
||||||
Dwarf_Addr base, start, end;
|
Dwarf_Addr base, start, end;
|
||||||
ptrdiff_t off = 0;
|
ptrdiff_t off = 0;
|
||||||
Dwarf_Op *expr;
|
Dwarf_Op *expr;
|
||||||
size_t exprlen;
|
size_t exprlen;
|
||||||
Dwarf_Word value;
|
|
||||||
int ret = dwarf_formudata(attr, &value);
|
|
||||||
if(ret < 0) {
|
|
||||||
logger->Log(SEVERITY_ERROR, "Cannot get DW_AT_location offset");
|
|
||||||
}
|
|
||||||
for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) {
|
for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) {
|
||||||
char str[1024]; str[0] = 0;
|
char str[1024]; str[0] = 0;
|
||||||
print_expr_block (expr, exprlen, str, sizeof(str));
|
function->ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
|
||||||
logger->Log(SEVERITY_DEBUG, "[%d] low_offset: %" PRIx64 ", high_offset: %" PRIx64 ", .debug_locations section offset: 0x%lX ==> %s", i, start, end, value, str);
|
function->ctx->log(SEVERITY_DEBUG, "[%d] low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 " ==> %s", i, start, end, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger->Log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X, ", attr->form, attr->code);
|
function->ctx->log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X, ", attr->form, attr->code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleFunction(Dwarf_Die* func, const char* fname)
|
bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
||||||
{
|
{
|
||||||
if(!strcmp(fname, dwarf_diename(func))) {
|
die = d;
|
||||||
logger->Log(SEVERITY_INFO, "Found function in debug info. DWARF tag: 0x%X, name = %s(...)", dwarf_tag(func), dwarf_diename(func));
|
|
||||||
|
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Attribute* attr;
|
Dwarf_Attribute* attr;
|
||||||
|
|
||||||
|
// get offset to function in memory against base address where process executed
|
||||||
|
dwarf_lowpc(d, &lowpc);
|
||||||
|
Dwarf_Addr highpc;
|
||||||
|
dwarf_highpc(d, &highpc);
|
||||||
|
|
||||||
|
unw_proc_info_t info;
|
||||||
|
unw_get_proc_info(&ctx->cursor, &info);
|
||||||
|
|
||||||
|
logger->Log(SEVERITY_INFO, "Found function in debug info. name = %s(...), PC = 0x%lX, LOW_PC = 0x%lX, HIGH_PC = 0x%lX, offset from base address: 0x%lX, info start = 0x%lX, offset from info start: 0x%lX",
|
||||||
|
dwarf_diename(d), pc, lowpc, highpc, pc - ctx->base_addr, info.start_ip, info.start_ip - ctx->base_addr);
|
||||||
|
|
||||||
// determine function's stack frame base
|
// determine function's stack frame base
|
||||||
attr = dwarf_attr(func, DW_AT_frame_base, &attr_mem);
|
attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem);
|
||||||
if(attr) {
|
if(attr) {
|
||||||
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
|
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
|
||||||
Dwarf_Op *expr;
|
Dwarf_Op *expr;
|
||||||
size_t exprlen;
|
size_t exprlen;
|
||||||
if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
|
if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
|
||||||
char str[1024]; str[0] = 0;
|
char str[1024]; str[0] = 0;
|
||||||
print_expr_block (expr, exprlen, str, sizeof(str));
|
ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
|
||||||
logger->Log(SEVERITY_DEBUG, "Found DW_AT_framebase expression: %s", str);
|
ctx->log(SEVERITY_DEBUG, "Found DW_AT_framebase expression: %s", str);
|
||||||
//print_detail(0, expr, exprlen, 0, "\tLocation ");
|
|
||||||
} else {
|
} else {
|
||||||
logger->Log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
|
ctx->log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get reference to return attribute type of the function
|
// Get reference to return attribute type of the function
|
||||||
// may be to use dwfl_module_return_value_location() instead
|
// may be to use dwfl_module_return_value_location() instead
|
||||||
attr = dwarf_attr(func, DW_AT_type, &attr_mem);
|
pst_parameter ret_p(this); ret_p.is_return = true;
|
||||||
|
attr = dwarf_attr(die, DW_AT_type, &attr_mem);
|
||||||
if(attr) {
|
if(attr) {
|
||||||
logger->Log(SEVERITY_INFO, "Handle return parameter");
|
ctx->log(SEVERITY_INFO, "Handle return parameter");
|
||||||
HandleType(attr, true);
|
if(ret_p.handle_type(attr, true)) {
|
||||||
|
params.push_back(ret_p);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger->Log(SEVERITY_DEBUG, "return attr name = 'void(0)'");
|
ret_p.types.push_back("void");
|
||||||
|
params.push_back(ret_p);
|
||||||
|
ctx->log(SEVERITY_DEBUG, "return attr name = 'void(0)'");
|
||||||
}
|
}
|
||||||
|
|
||||||
Dwarf_Die result;
|
Dwarf_Die result;
|
||||||
if (dwarf_child(func, &result) != 0)
|
if(dwarf_child(die, &result) != 0)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// went through parameters and local variables of the function
|
// went through parameters and local variables of the function
|
||||||
do {
|
do {
|
||||||
|
pst_parameter param(this);
|
||||||
|
|
||||||
switch (dwarf_tag(&result)) {
|
switch (dwarf_tag(&result)) {
|
||||||
case DW_TAG_formal_parameter:
|
case DW_TAG_formal_parameter:
|
||||||
case DW_TAG_variable:
|
case DW_TAG_variable:
|
||||||
HandleParameter(&result);
|
if(param.handle_dwarf(&result)) {
|
||||||
|
params.push_back(param);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// case DW_TAG_inlined_subroutine:
|
// case DW_TAG_inlined_subroutine:
|
||||||
// /* Recurse further down */
|
// /* Recurse further down */
|
||||||
// HandleFunction(&result, dwarf_diename(&result));
|
// HandleFunction(&result, dwarf_diename(&result));
|
||||||
// break;
|
// break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(dwarf_siblingof(&result, &result) == 0);
|
} while(dwarf_siblingof(&result, &result) == 0);
|
||||||
}
|
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias, const char* prefix)
|
bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr)
|
||||||
{
|
{
|
||||||
printf("\t%s ", prefix);
|
pc = addr;
|
||||||
if (result < 0) {
|
|
||||||
printf("indeterminate (%s)\n", dwarf_errmsg (-1));
|
Dwfl_Line *line = dwfl_getsrc(dwfl, addr);
|
||||||
} else if (nops == 0) {
|
if(line != NULL) {
|
||||||
printf("%s\n", ops == NULL ? "same_value" : "undefined");
|
int nline;
|
||||||
|
Dwarf_Addr addr;
|
||||||
|
const char* filename = dwfl_lineinfo (line, &addr, &nline, NULL, NULL, NULL);
|
||||||
|
if(filename) {
|
||||||
|
const char* str = strrchr(filename, '/');
|
||||||
|
if(str && *str != 0) {
|
||||||
|
str++;
|
||||||
} else {
|
} else {
|
||||||
printf("%s expression:", result == 0 ? "location" : "value");
|
str = filename;
|
||||||
for (size_t i = 0; i < nops; ++i) {
|
|
||||||
printf (" 0x%X (offset: 0x%lX)", ops[i].atom, ops[i].offset);
|
|
||||||
if (ops[i].number2 == 0) {
|
|
||||||
if (ops[i].atom == DW_OP_addr) {
|
|
||||||
printf ("(%#" PRIx64 ")", ops[i].number + bias);
|
|
||||||
} else if (ops[i].number != 0) {
|
|
||||||
printf ("(%" PRIx64 ")", ops[i].number);
|
|
||||||
}
|
}
|
||||||
|
ctx->print("%s:%d", str, nline);
|
||||||
|
} else {
|
||||||
|
ctx->print("%p", (void*)addr);
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
printf ("(%" PRIx64 ",%" PRIx64 ")", ops[i].number, ops[i].number2);
|
ctx->print("%p", (void*)addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* addrname = dwfl_module_addrname(module, addr);
|
||||||
|
char* demangle_name = NULL;
|
||||||
|
if(addrname) {
|
||||||
|
int status;
|
||||||
|
demangle_name = abi::__cxa_demangle(addrname, NULL, NULL, &status);
|
||||||
|
char* function_name = NULL;
|
||||||
|
if(asprintf(&function_name, "%s%s", demangle_name ? demangle_name : addrname, demangle_name ? "" : "()") == -1) {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to allocate memory");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
puts("");
|
ctx->print(" --> %s", function_name);
|
||||||
|
|
||||||
|
char* str = strchr(function_name, '(');
|
||||||
|
if(str) {
|
||||||
|
*str = 0;
|
||||||
}
|
}
|
||||||
|
name = function_name;
|
||||||
|
free(function_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(demangle_name) {
|
||||||
|
free(demangle_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleCompilationUnit(Dwfl_Module* module, Dwarf_Addr addr, const char* fname)
|
|
||||||
{
|
|
||||||
Dwarf_Addr mod_cu = 0;
|
|
||||||
// get CU(Compilation Unit) debug definition
|
|
||||||
Dwarf_Die* cdie = dwfl_module_addrdie(module, addr, &mod_cu);
|
|
||||||
logger->Log(SEVERITY_DEBUG, "Function bias in module is 0x%lX", mod_cu);
|
|
||||||
//Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias);
|
|
||||||
if(!cdie) {
|
|
||||||
logger->Log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", addr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool __pst_context::get_frame()
|
||||||
|
{
|
||||||
// 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);
|
Dwarf_CFI* cfi = dwfl_module_eh_cfi(module, &mod_bias);
|
||||||
//Dwarf_CFI* cfi = dwfl_module_dwarf_cfi(module, &mod_bias);
|
//Dwarf_CFI* cfi = dwfl_module_dwarf_cfi(module, &mod_bias);
|
||||||
if(cfi) {
|
if(!cfi) {
|
||||||
// get frame of CFI for address
|
log(SEVERITY_INFO, "Cannot find CFI for module");
|
||||||
logger->Log(SEVERITY_INFO, "Found CFI for module %s", dwarf_diename(cdie));
|
return false;
|
||||||
if(frame) {
|
|
||||||
prev_frame = frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get frame of CFI for address
|
||||||
int result = dwarf_cfi_addrframe (cfi, addr - mod_bias, &frame);
|
int result = dwarf_cfi_addrframe (cfi, addr - mod_bias, &frame);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
// get frame information
|
// get frame information
|
||||||
logger->Log(SEVERITY_INFO, "Found CFI frame for module %s", dwarf_diename(cdie));
|
log(SEVERITY_INFO, "Found CFI frame for module");
|
||||||
Dwarf_Addr start = addr;
|
Dwarf_Addr start = addr;
|
||||||
Dwarf_Addr end = addr;
|
Dwarf_Addr end = addr;
|
||||||
bool signalp;
|
bool signalp;
|
||||||
@@ -370,13 +492,13 @@ void HandleCompilationUnit(Dwfl_Module* module, Dwarf_Addr addr, const char* fna
|
|||||||
start += mod_bias;
|
start += mod_bias;
|
||||||
end += mod_bias;
|
end += mod_bias;
|
||||||
}
|
}
|
||||||
logger->Log(SEVERITY_DEBUG, "Per '.eh_frame' info has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "] in_signal = %s", addr, start, end, signalp ? "true" : "false");
|
log(SEVERITY_DEBUG, "Per '.eh_frame' info has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "] in_signal = %s", addr, start, end, signalp ? "true" : "false");
|
||||||
if (ra_regno < 0)
|
if (ra_regno < 0)
|
||||||
logger->Log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg (0));
|
log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg(0));
|
||||||
else {
|
else {
|
||||||
reginfo info; info.regno = ra_regno;
|
reginfo info; info.regno = ra_regno;
|
||||||
dwfl_module_register_names(module, regname_callback, &info);
|
dwfl_module_register_names(module, regname_callback, &info);
|
||||||
logger->Log(SEVERITY_DEBUG, "return address in reg%u%s ==> %s", ra_regno, signalp ? " (signal frame)" : "", info.regname);
|
log(SEVERITY_DEBUG, "return address in reg%u%s ==> %s", ra_regno, signalp ? " (signal frame)" : "", info.regname);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally get CFA (Canonical Frame Address)
|
// finally get CFA (Canonical Frame Address)
|
||||||
@@ -388,43 +510,68 @@ void HandleCompilationUnit(Dwfl_Module* module, Dwarf_Addr addr, const char* fna
|
|||||||
result = dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops);
|
result = dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops);
|
||||||
char str[1024]; str[0] = 0;
|
char str[1024]; str[0] = 0;
|
||||||
print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
||||||
logger->Log(SEVERITY_INFO, "Found CFA expression: %s", str);
|
log(SEVERITY_INFO, "Found CFA expression: %s", str);
|
||||||
//print_detail (result, cfa_ops, cfa_nops, mod_bias, "\tCFA ");
|
//print_detail (result, cfa_ops, cfa_nops, mod_bias, "\tCFA ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __pst_context::get_dwarf_function(pst_function& fun)
|
||||||
|
{
|
||||||
|
Dwarf_Addr mod_cu = 0;
|
||||||
|
// get CU(Compilation Unit) debug definition
|
||||||
|
Dwarf_Die* cdie = dwfl_module_addrdie(module, addr, &mod_cu);
|
||||||
|
//Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias);
|
||||||
|
if(!cdie) {
|
||||||
|
logger->Log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", addr);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dwarf_tag(cdie) != DW_TAG_compile_unit) {
|
if(dwarf_tag(cdie) != DW_TAG_compile_unit) {
|
||||||
logger->Log(SEVERITY_DEBUG, "Skipping non-cu die. DWARF tag: 0x%X, name = %s", dwarf_tag(cdie), dwarf_diename(cdie));
|
logger->Log(SEVERITY_DEBUG, "Skipping non-cu die. DWARF tag: 0x%X, name = %s", dwarf_tag(cdie), dwarf_diename(cdie));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger->Log(SEVERITY_DEBUG, "Enumerating Compilation Unit '%s' to lookup for function %s()", dwarf_diename(cdie), fname);
|
|
||||||
Dwarf_Die result;
|
Dwarf_Die result;
|
||||||
if(dwarf_child(cdie, &result)) {
|
if(dwarf_child(cdie, &result)) {
|
||||||
logger->Log(SEVERITY_INFO, "No child DIE found for CU");
|
logger->Log(SEVERITY_ERROR, "No child DIE found for CU %s", dwarf_diename(cdie));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nret = false;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
switch (dwarf_tag(&result)) {
|
int tag = dwarf_tag(&result);
|
||||||
case DW_TAG_subprogram:
|
if(tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || tag == DW_TAG_inlined_subroutine) {
|
||||||
case DW_TAG_entry_point:
|
if(!strcmp(fun.name.c_str(), dwarf_diename(&result))) {
|
||||||
case DW_TAG_inlined_subroutine:
|
return fun.handle_dwarf(&result);
|
||||||
HandleFunction(&result, fname);
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
//logger->Log(SEVERITY_INFO, "Unknown tag 0x%X for die '%s'", dwarf_tag(&result), dwarf_diename(&result));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} while(dwarf_siblingof(&result, &result) == 0);
|
} while(dwarf_siblingof(&result, &result) == 0);
|
||||||
|
|
||||||
|
return nret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* LibdwTraceCallStack(ucontext_t* uctx)
|
void __pst_context::dwarf_print()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
char *debuginfo_path = NULL;
|
||||||
|
Dwfl_Callbacks callbacks = {
|
||||||
|
.find_elf = dwfl_linux_proc_find_elf,
|
||||||
|
.find_debuginfo = dwfl_standard_find_debuginfo,
|
||||||
|
.section_address = dwfl_offline_section_address,
|
||||||
|
.debuginfo_path = &debuginfo_path,
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
bool __pst_context::unwind()
|
||||||
{
|
{
|
||||||
void * caller_address = 0;
|
|
||||||
#ifdef REG_RIP // x86_64
|
#ifdef REG_RIP // x86_64
|
||||||
caller_address = (void *) uctx->uc_mcontext.gregs[REG_RIP];
|
caller = (void *) hcontext->uc_mcontext.gregs[REG_RIP];
|
||||||
#elif defined(REG_EIP) // x86_32
|
#elif defined(REG_EIP) // x86_32
|
||||||
caller_address = (void *) uctx->uc_mcontext.gregs[REG_EIP]);
|
caller_address = (void *) uctx->uc_mcontext.gregs[REG_EIP]);
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
@@ -440,84 +587,76 @@ const char* LibdwTraceCallStack(ucontext_t* uctx)
|
|||||||
#else
|
#else
|
||||||
# error "unknown architecture!"
|
# error "unknown architecture!"
|
||||||
#endif
|
#endif
|
||||||
void * array[50];
|
|
||||||
int size = backtrace(array, 50);
|
handle = dlopen(NULL, RTLD_NOW);
|
||||||
|
Dl_info info;
|
||||||
|
dladdr(caller, &info);
|
||||||
|
base_addr = (uint64_t)info.dli_fbase;
|
||||||
|
logger->Log(SEVERITY_INFO, "Process address information: dlopen handle: %p, base address: %p, object name: %s, symbol name: %s", handle, info.dli_fbase, info.dli_fname, info.dli_sname);
|
||||||
|
|
||||||
int skipped = 0;
|
int skipped = 0;
|
||||||
|
#ifndef USEI_LIBUNWIND
|
||||||
|
int size = 0;
|
||||||
|
void * array[50];
|
||||||
|
size = backtrace(array, 50);
|
||||||
for(int i = 0; i < size && array[i] != caller_address; ++i, ++skipped);
|
for(int i = 0; i < size && array[i] != caller_address; ++i, ++skipped);
|
||||||
__stack_trace[0] = 0; uint32_t offset = 0;
|
print("Stack trace(caller = %p. Total stack frames: %d, skipped: %d):\n", caller_address, size, skipped);
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Stack trace(caller = %p. Total stack frames: %d, skipped: %d):\n",
|
#else
|
||||||
caller_address, size, skipped);
|
unw_word_t pc;
|
||||||
|
|
||||||
char *debuginfo_path = NULL;
|
unw_getcontext(&context);
|
||||||
Dwfl_Callbacks callbacks = {
|
unw_init_local(&cursor, &context);
|
||||||
.find_elf = dwfl_linux_proc_find_elf,
|
while (unw_step(&cursor) > 0) {
|
||||||
.find_debuginfo = dwfl_standard_find_debuginfo,
|
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||||
.section_address = dwfl_offline_section_address,
|
if(pc == (uint64_t)caller) {
|
||||||
.debuginfo_path = &debuginfo_path,
|
break;
|
||||||
};
|
} else {
|
||||||
|
++skipped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print("Stack trace(caller = %p. Skipped stack frames: %d):\n", caller, skipped);
|
||||||
|
#endif
|
||||||
|
|
||||||
Dwfl* dwfl = dwfl_begin(&callbacks);
|
dwfl = dwfl_begin(&callbacks);
|
||||||
if(dwfl == NULL) {
|
if(dwfl == NULL) {
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Failed to initialize libdw session for parse stack frames");
|
print("Failed to initialize libdw session for parse stack frames");
|
||||||
return __stack_trace;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dwfl_linux_proc_report(dwfl, getpid()) != 0 || dwfl_report_end(dwfl, NULL, NULL) !=0) {
|
if(dwfl_linux_proc_report(dwfl, getpid()) != 0 || dwfl_report_end(dwfl, NULL, NULL) !=0) {
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Failed to parse debug section of executable");
|
print("Failed to parse debug section of executable");
|
||||||
return __stack_trace;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USEI_LIBUNWIND
|
||||||
for (int i = skipped, idx = 0; i < size ; ++i, ++idx) {
|
for (int i = skipped, idx = 0; i < size ; ++i, ++idx) {
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "[%-2d] ", idx);
|
print("[%-2d] ", idx);
|
||||||
|
|
||||||
Dwarf_Addr addr = (uintptr_t)array[i];
|
Dwarf_Addr addr = (uintptr_t)array[i];
|
||||||
Dwfl_Line *line = dwfl_getsrc(dwfl, addr);
|
#else
|
||||||
if(line != NULL) {
|
for (int i = skipped, idx = 0; true ; ++i, ++idx) {
|
||||||
int nline;
|
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||||
Dwarf_Addr addr;
|
addr = pc;
|
||||||
const char* filename = dwfl_lineinfo (line, &addr, &nline, NULL, NULL, NULL);
|
print("[%-2d] ", idx);
|
||||||
if(filename) {
|
#endif
|
||||||
const char* str = strrchr(filename, '/');
|
|
||||||
if(str && *str != 0) {
|
|
||||||
str++;
|
|
||||||
} else {
|
|
||||||
str = filename;
|
|
||||||
}
|
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%s:%d", str, nline);
|
|
||||||
} else {
|
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%p", array[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%p", array[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
module = dwfl_addrmodule(dwfl, addr);
|
module = dwfl_addrmodule(dwfl, addr);
|
||||||
const char* addrname = dwfl_module_addrname(module, addr);
|
get_frame();
|
||||||
char* demangle_name = NULL;
|
pst_function fun(this);
|
||||||
if(addrname) {
|
if(fun.unwind(dwfl, module, pc)) {
|
||||||
int status;
|
if(get_dwarf_function(fun)) {
|
||||||
demangle_name = abi::__cxa_demangle(addrname, NULL, NULL, &status);
|
functions.push_back(fun);
|
||||||
char* function_name = NULL;
|
|
||||||
if(asprintf(&function_name, "%s%s", demangle_name ? demangle_name : addrname, demangle_name ? "" : "()") == -1) {
|
|
||||||
logger->Log(SEVERITY_ERROR, "Failed to allocate memory");
|
|
||||||
return __stack_trace;
|
|
||||||
}
|
}
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, " --> %s", function_name);
|
|
||||||
|
|
||||||
char* str = strchr(function_name, '(');
|
|
||||||
if(str) {
|
|
||||||
*str = 0;
|
|
||||||
}
|
}
|
||||||
HandleCompilationUnit(module, addr, function_name);
|
print("\n");
|
||||||
free(function_name);
|
#ifdef USEI_LIBUNWIND
|
||||||
|
if(unw_step(&cursor) <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if(demangle_name) {
|
// for(int op = DW_OP_breg0; op <= DW_OP_breg16; op++ ) {
|
||||||
free(demangle_name);
|
// printf("{0x%X, 0x%X, \"%s\"},\n", op, op - DW_OP_breg0, unw_regname(op - DW_OP_breg0));
|
||||||
}
|
// }
|
||||||
|
|
||||||
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "\n");
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return __stack_trace;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+101
-8
@@ -14,17 +14,110 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <vector>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
|
#include <libunwind.h>
|
||||||
using std::string;
|
#include <elfutils/libdwfl.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
// stack trace string buffer
|
|
||||||
extern char __stack_trace[8192];
|
|
||||||
|
|
||||||
// libdw-based trace call stack implementation
|
|
||||||
const char* LibdwTraceCallStack(ucontext_t* uctx);
|
|
||||||
|
|
||||||
char* GetExecutableName(char* path, uint32_t size);
|
char* GetExecutableName(char* path, uint32_t size);
|
||||||
|
|
||||||
|
typedef struct __pst_function pst_function;
|
||||||
|
|
||||||
|
typedef struct __pst_parameter {
|
||||||
|
__pst_parameter(pst_function* fun) : function(fun)
|
||||||
|
{
|
||||||
|
die = NULL;
|
||||||
|
size = 0;
|
||||||
|
type = 0;
|
||||||
|
loc = NULL;
|
||||||
|
is_return = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_dwarf(Dwarf_Die* d);
|
||||||
|
bool handle_type(Dwarf_Attribute* param, bool is_return = false);
|
||||||
|
|
||||||
|
Dwarf_Die* die; // DWARF DIE containing parameter's definition
|
||||||
|
std::string name; // parameter's name
|
||||||
|
Dwarf_Word size; // size of parameter in bytes
|
||||||
|
int type; // base type of parameter in DW_TAG_XXX types enumeration
|
||||||
|
std::vector<std::string> types; // list of parameters definitions i.e. 'typedef', 'uint32_t'
|
||||||
|
void* loc; // pointer to location of parameter's value
|
||||||
|
bool is_return; // whether this parameter is return value of the function
|
||||||
|
pst_function* function;
|
||||||
|
} pst_parameter;
|
||||||
|
|
||||||
|
typedef struct __pst_context pst_context;
|
||||||
|
|
||||||
|
typedef struct __pst_function {
|
||||||
|
__pst_function(pst_context* ctx) : ctx(ctx)
|
||||||
|
{
|
||||||
|
pc = 0;
|
||||||
|
line = -1;
|
||||||
|
die = NULL;
|
||||||
|
lowpc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr);
|
||||||
|
bool handle_dwarf(Dwarf_Die* d);
|
||||||
|
|
||||||
|
Dwarf_Addr lowpc;
|
||||||
|
Dwarf_Die* die; // DWARF DIE containing definition of the function
|
||||||
|
std::string name; // function's name
|
||||||
|
std::vector<pst_parameter> params; // array of function's parameters
|
||||||
|
unw_word_t pc; // pointer to the start of the function
|
||||||
|
int line; // line in code where function is defined
|
||||||
|
std::string file; // file name (DWARF Compilation Unit) where is function defined
|
||||||
|
pst_context* ctx;
|
||||||
|
} pst_function;
|
||||||
|
|
||||||
|
typedef struct __pst_context {
|
||||||
|
__pst_context(ucontext_t* hctx) : hcontext(hctx)
|
||||||
|
{
|
||||||
|
caller = NULL;
|
||||||
|
module = NULL;
|
||||||
|
dwfl = NULL;
|
||||||
|
offset = 0;
|
||||||
|
buff[0] = 0;
|
||||||
|
frame = NULL;
|
||||||
|
addr = 0;
|
||||||
|
base_addr = 0;
|
||||||
|
handle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~__pst_context()
|
||||||
|
{
|
||||||
|
if(handle) {
|
||||||
|
dlclose(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool print(const char* fmt, ...);
|
||||||
|
void dwarf_print();
|
||||||
|
uint32_t print_expr_block(Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr = 0);
|
||||||
|
void log(SC_LogSeverity severity, const char*fmt, ...);
|
||||||
|
bool unwind();
|
||||||
|
bool get_frame();
|
||||||
|
bool get_dwarf_function(pst_function& fun);
|
||||||
|
|
||||||
|
ucontext_t* hcontext;// context of signal handler
|
||||||
|
unw_context_t context;// context of stack trace
|
||||||
|
unw_cursor_t cursor; // currently examined frame of context
|
||||||
|
void* handle; // process handle
|
||||||
|
Dwarf_Addr addr; // address of currently processed function
|
||||||
|
Dwarf_Addr base_addr;// base address where process loaded
|
||||||
|
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
|
||||||
|
std::vector<pst_function> functions;// array of functions in stack frame
|
||||||
|
char buff[8192]; // stack trace buffer
|
||||||
|
uint32_t offset; // offset in the 'buff'
|
||||||
|
} pst_context;
|
||||||
|
|
||||||
|
// libdw-based trace call stack implementation
|
||||||
|
bool LibdwTraceCallStack(pst_context& ctx);
|
||||||
|
|
||||||
#endif /* SC_SYSUTILS_H_ */
|
#endif /* SC_SYSUTILS_H_ */
|
||||||
|
|||||||
@@ -63,14 +63,15 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context)
|
|||||||
fatal_error_in_progress = 1;
|
fatal_error_in_progress = 1;
|
||||||
|
|
||||||
logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig));
|
logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig));
|
||||||
const char* trace = 0;
|
bool trace = false;
|
||||||
|
pst_context ctx((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))
|
||||||
{
|
{
|
||||||
trace = LibdwTraceCallStack((ucontext_t*)context);
|
trace = ctx.unwind();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(trace) {
|
if(trace) {
|
||||||
logger->Log(SEVERITY_DEBUG, "%s", trace);
|
logger->Log(SEVERITY_DEBUG, "%s", ctx.buff);
|
||||||
} else {
|
} else {
|
||||||
logger->Log(SEVERITY_ERROR, "No stack trace obtained");
|
logger->Log(SEVERITY_ERROR, "No stack trace obtained");
|
||||||
}
|
}
|
||||||
@@ -193,7 +194,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
SetSignalHandler(SigusrHandler);
|
SetSignalHandler(SigusrHandler);
|
||||||
|
|
||||||
Fun1(1, DEF_2, 3);
|
Fun1(1, DEF_2, 5);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user