bunch of changes. mainly is: got right CFA from both libunwind & libdw
This commit is contained in:
@@ -121,14 +121,14 @@ uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff,
|
|||||||
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number);
|
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number);
|
||||||
int regno = map->op_num - DW_OP_breg0;
|
int regno = map->op_num - DW_OP_breg0;
|
||||||
unw_word_t ptr = 0;
|
unw_word_t ptr = 0;
|
||||||
unw_get_reg(&curr_frame, regno, &ptr);
|
unw_get_reg(curr_frame, regno, &ptr);
|
||||||
//ptr += off;
|
//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);
|
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 if(map->op_num >= DW_OP_reg0 && map->op_num <= DW_OP_reg16) {
|
} else if(map->op_num >= DW_OP_reg0 && map->op_num <= DW_OP_reg16) {
|
||||||
unw_word_t value = 0;
|
unw_word_t value = 0;
|
||||||
int regno = map->op_num - DW_OP_reg0;
|
int regno = map->op_num - DW_OP_reg0;
|
||||||
unw_get_reg(&curr_frame, regno, &value);
|
unw_get_reg(curr_frame, regno, &value);
|
||||||
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s) value: 0x%lX", map->op_name, unw_regname(regno), value);
|
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s) value: 0x%lX", map->op_name, unw_regname(regno), value);
|
||||||
} else if(map->op_num == DW_OP_GNU_entry_value) {
|
} else if(map->op_num == DW_OP_GNU_entry_value) {
|
||||||
uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number);
|
uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number);
|
||||||
@@ -155,20 +155,23 @@ uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff,
|
|||||||
uint32_t regno = decode_uleb128((unsigned char*)&exprs[i].number);
|
uint32_t regno = decode_uleb128((unsigned char*)&exprs[i].number);
|
||||||
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number2);
|
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number2);
|
||||||
unw_word_t ptr = 0;
|
unw_word_t ptr = 0;
|
||||||
unw_get_reg(&curr_frame, regno, &ptr);
|
unw_get_reg(curr_frame, regno, &ptr);
|
||||||
//ptr += off;
|
//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);
|
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 if(map->op_num == DW_OP_regx) {
|
} else if(map->op_num == DW_OP_regx) {
|
||||||
int32_t reg = decode_sleb128((unsigned char*)&exprs[i].number);
|
int32_t reg = decode_sleb128((unsigned char*)&exprs[i].number);
|
||||||
|
|
||||||
unw_word_t value = 0;
|
unw_word_t value = 0;
|
||||||
unw_get_reg(&curr_frame, reg, &value);
|
unw_get_reg(curr_frame, reg, &value);
|
||||||
|
|
||||||
offset += snprintf(buff + offset, buff_size - offset, "%s(%s) value = 0x%lX", map->op_name, unw_regname(reg), value);
|
offset += snprintf(buff + offset, buff_size - offset, "%s(%s) value = 0x%lX", map->op_name, unw_regname(reg), value);
|
||||||
} else if(map->op_num == DW_OP_addr) {
|
} else if(map->op_num == DW_OP_addr) {
|
||||||
offset += snprintf(buff + offset, buff_size - offset, "%s value = %p", map->op_name, (void*)exprs[i].number);
|
offset += snprintf(buff + offset, buff_size - offset, "%s value = %p", map->op_name, (void*)exprs[i].number);
|
||||||
|
} else if(map->op_num == DW_OP_fbreg) {
|
||||||
|
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number);
|
||||||
|
offset += snprintf(buff + offset, buff_size - offset, "%s(SP%s%d) ", map->op_name, off >=0 ? "+" : "", off);
|
||||||
} else {
|
} else {
|
||||||
offset += snprintf(buff + offset, buff_size - offset, "%s(0x%lX, 0x%lx)", map->op_name, exprs[i].number, exprs[i].number2);
|
offset += snprintf(buff + offset, buff_size - offset, "%s(0x%lX, 0x%lx) ", map->op_name, exprs[i].number, exprs[i].number2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
offset += snprintf(buff + offset, buff_size - offset, "0x%hhX(0x%lX, 0x%lx)", exprs[i].atom, exprs[i].number, exprs[i].number2);
|
offset += snprintf(buff + offset, buff_size - offset, "0x%hhX(0x%lX, 0x%lx)", exprs[i].atom, exprs[i].number, exprs[i].number2);
|
||||||
|
|||||||
+9
-4
@@ -14,7 +14,10 @@ typedef struct __pst_context {
|
|||||||
offset = 0;
|
offset = 0;
|
||||||
buff[0] = 0;
|
buff[0] = 0;
|
||||||
base_addr = 0;
|
base_addr = 0;
|
||||||
has_nframe = false;
|
sp = 0;
|
||||||
|
cfa = 0;
|
||||||
|
curr_frame = NULL;
|
||||||
|
next_frame = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool print(const char* fmt, ...);
|
bool print(const char* fmt, ...);
|
||||||
@@ -23,13 +26,15 @@ typedef struct __pst_context {
|
|||||||
|
|
||||||
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 curr_frame; // currently examined frame of context
|
unw_cursor_t cursor;
|
||||||
unw_cursor_t next_frame; // caller frame
|
unw_cursor_t* curr_frame; // currently examined frame of context
|
||||||
bool has_nframe; // has next frame or not
|
unw_cursor_t* next_frame; // caller 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
|
char buff[8192]; // stack trace buffer
|
||||||
uint32_t offset; // offset in the 'buff'
|
uint32_t offset; // offset in the 'buff'
|
||||||
|
Dwarf_Addr sp;
|
||||||
|
Dwarf_Addr cfa;
|
||||||
} pst_context;
|
} pst_context;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -742,29 +742,14 @@ bool dw_op_plus_uconst(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word o
|
|||||||
{
|
{
|
||||||
dwarf_value* value = stack->get();
|
dwarf_value* value = stack->get();
|
||||||
if(value) {
|
if(value) {
|
||||||
if(value->type != DWARF_TYPE_SIGNED && value->type != DWARF_TYPE_UNSIGNED) {
|
|
||||||
stack->ctx->log(SEVERITY_ERROR, "Invalid type for operation %s(%d)", map->op_name, value->type);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t op = decode_uleb128((unsigned char*)&op1);
|
uint64_t op = decode_uleb128((unsigned char*)&op1);
|
||||||
if(value->type == DWARF_TYPE_SIGNED) {
|
|
||||||
int64_t v = 0;
|
|
||||||
if(!value->get_int(v)) {
|
|
||||||
stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
v += op;
|
|
||||||
value->replace(&v, sizeof(v), value->type);
|
|
||||||
} else {
|
|
||||||
uint64_t v = 0;
|
uint64_t v = 0;
|
||||||
if(!value->get_uint(v)) {
|
if(!value->get_generic(v)) {
|
||||||
stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size);
|
stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
v += op;
|
v += op;
|
||||||
value->replace(&v, sizeof(v), value->type);
|
value->replace(&v, sizeof(v), value->type);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -812,7 +797,9 @@ bool dw_op_breg_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, D
|
|||||||
}
|
}
|
||||||
|
|
||||||
unw_word_t val = 0;
|
unw_word_t val = 0;
|
||||||
if(unw_get_reg(&stack->ctx->curr_frame, regno, &val)) {
|
int ret = unw_get_reg(stack->ctx->curr_frame, regno, &val);
|
||||||
|
if(ret) {
|
||||||
|
stack->ctx->log(SEVERITY_ERROR, "%s: Failed to get register 0x%X value. Error: %d", __PRETTY_FUNCTION__, regno, ret);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,13 +841,15 @@ bool dw_op_stack_value(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word o
|
|||||||
// The DW_OP_call_frame_cfa operation pushes the value of the CFA, obtained from the Call Frame Information (see Section 6.4 on page 171).
|
// The DW_OP_call_frame_cfa operation pushes the value of the CFA, obtained from the Call Frame Information (see Section 6.4 on page 171).
|
||||||
bool dw_op_call_frame_cfa(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_call_frame_cfa(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
// since in signal handler we are know SP value, just push it to DWARF stack
|
// since we are already know SP value, just push it to DWARF stack
|
||||||
unw_word_t sp;
|
// unw_word_t sp;
|
||||||
if(unw_get_reg(&stack->ctx->curr_frame, UNW_REG_SP, &sp)) {
|
// int ret = unw_get_reg(stack->ctx->curr_frame, UNW_REG_SP, &sp);
|
||||||
return false;
|
// if(ret) {
|
||||||
}
|
// stack->ctx->log(SEVERITY_ERROR, "%s: failed to get register 0x%X value. Error: %d", __PRETTY_FUNCTION__, UNW_REG_SP, ret);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
stack->push(&sp, sizeof(sp), DWARF_TYPE_MEMORY_LOC | DWARF_TYPE_GENERIC);
|
stack->push(&stack->ctx->cfa, sizeof(stack->ctx->cfa), /*DWARF_TYPE_MEMORY_LOC | */DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -871,10 +860,13 @@ bool dw_op_fbreg(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dw
|
|||||||
{
|
{
|
||||||
// since in signal handler we are know SP value, just use it as DW_AT_frame_base
|
// since in signal handler we are know SP value, just use it as DW_AT_frame_base
|
||||||
unw_word_t sp;
|
unw_word_t sp;
|
||||||
if(unw_get_reg(&stack->ctx->curr_frame, UNW_REG_SP, &sp)) {
|
// int ret = unw_get_reg(stack->ctx->curr_frame, UNW_REG_SP, &sp);
|
||||||
return false;
|
// if(ret) {
|
||||||
}
|
// stack->ctx->log(SEVERITY_ERROR, "Failed to get register 0x%X value. Error: %d", __PRETTY_FUNCTION__, UNW_REG_SP, ret);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
sp = stack->ctx->cfa;
|
||||||
int64_t off = decode_sleb128((unsigned char*)&op1);
|
int64_t off = decode_sleb128((unsigned char*)&op1);
|
||||||
sp += off;
|
sp += off;
|
||||||
|
|
||||||
@@ -1055,8 +1047,10 @@ dwarf_op_map op_map[] = {
|
|||||||
{DW_OP_bit_piece, "DW_OP_bit_piece", dw_op_notimpl},
|
{DW_OP_bit_piece, "DW_OP_bit_piece", dw_op_notimpl},
|
||||||
{DW_OP_implicit_value, "DW_OP_implicit_value", dw_op_notimpl},
|
{DW_OP_implicit_value, "DW_OP_implicit_value", dw_op_notimpl},
|
||||||
{DW_OP_stack_value, "DW_OP_stack_value", dw_op_stack_value},
|
{DW_OP_stack_value, "DW_OP_stack_value", dw_op_stack_value},
|
||||||
|
|
||||||
|
// GNU extensions
|
||||||
// in fact, implementation is at upper layer since this operation contains sub-expression
|
// in fact, implementation is at upper layer since this operation contains sub-expression
|
||||||
{DW_OP_GNU_entry_value, "DW_OP_GNU_entry_value", dw_op_notimpl}, // seems that it's equal to DW_OP_entry_value
|
{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)
|
int find_regnum(uint32_t op)
|
||||||
@@ -1094,16 +1088,14 @@ bool __dwarf_stack::get_value(uint64_t& value)
|
|||||||
if(v->type & DWARF_TYPE_REGISTER_LOC) {
|
if(v->type & DWARF_TYPE_REGISTER_LOC) {
|
||||||
// dereference register location
|
// dereference register location
|
||||||
uint64_t regno = value;
|
uint64_t regno = value;
|
||||||
if(unw_get_reg(&ctx->curr_frame, regno, &value)) {
|
int ret = unw_get_reg(ctx->curr_frame, regno, &value);
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get value of register 0x%lX", regno);
|
if(ret) {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to get value of register 0x%X. Error: %d", __PRETTY_FUNCTION__, regno, ret);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if(v->type & DWARF_TYPE_MEMORY_LOC) {
|
} else if(v->type & DWARF_TYPE_MEMORY_LOC) {
|
||||||
// dereference memory location
|
// dereference memory location
|
||||||
uint64_t addr;
|
uint64_t addr = *(uint64_t*)v->value;
|
||||||
if(!v->get_uint(addr)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = *((uint64_t*)addr);
|
value = *((uint64_t*)addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1125,8 +1117,9 @@ bool __dwarf_stack::calc_expression(Dwarf_Op *exprs, int expr_len, Dwarf_Attribu
|
|||||||
if(v && (v->type & DWARF_TYPE_REGISTER_LOC)) {
|
if(v && (v->type & DWARF_TYPE_REGISTER_LOC)) {
|
||||||
unw_word_t value = 0;
|
unw_word_t value = 0;
|
||||||
uint64_t regno = *((uint64_t*)v->value);
|
uint64_t regno = *((uint64_t*)v->value);
|
||||||
if(unw_get_reg(&ctx->curr_frame, regno, &value)) {
|
int ret = unw_get_reg(ctx->curr_frame, regno, &value);
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to ger value of register 0x%lX", regno);
|
if(ret) {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to ger value of register 0x%X. Error: %d", __PRETTY_FUNCTION__, regno, ret);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
v->replace(&value, sizeof(value), DWARF_TYPE_GENERIC);
|
v->replace(&value, sizeof(value), DWARF_TYPE_GENERIC);
|
||||||
@@ -1142,13 +1135,13 @@ bool __dwarf_stack::calc_expression(Dwarf_Op *exprs, int expr_len, Dwarf_Attribu
|
|||||||
size_t exprlen;
|
size_t exprlen;
|
||||||
if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) {
|
if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) {
|
||||||
// save current frame cursor
|
// save current frame cursor
|
||||||
unw_cursor_t cursor = ctx->curr_frame; ctx->curr_frame = ctx->next_frame;
|
unw_cursor_t* cursor = ctx->curr_frame; ctx->curr_frame = ctx->next_frame;
|
||||||
dwarf_stack st(ctx);
|
dwarf_stack st(ctx);
|
||||||
char str[1024]; str[0]= 0;
|
char str[1024]; str[0]= 0;
|
||||||
ctx->print_expr_block (expr, exprlen, str, sizeof(str), &attr_mem);
|
ctx->print_expr_block (expr, exprlen, str, sizeof(str), &attr_mem);
|
||||||
ctx->log(SEVERITY_DEBUG, "Parent frame expression: %s", str);
|
ctx->log(SEVERITY_DEBUG, "Parent frame expression: %s", str);
|
||||||
bool eret = st.calc_expression(expr, exprlen, &attr_mem);
|
bool eret = st.calc_expression(expr, exprlen, &attr_mem);
|
||||||
uint64_t val;
|
uint64_t val = 0;
|
||||||
bool gret = false;
|
bool gret = false;
|
||||||
if(eret) {
|
if(eret) {
|
||||||
gret = st.get_value(val);
|
gret = st.get_value(val);
|
||||||
|
|||||||
+180
-72
@@ -192,7 +192,7 @@ bool __pst_parameter::handle_type(Dwarf_Attribute* param)
|
|||||||
switch (dwarf_tag(&ret_die)) {
|
switch (dwarf_tag(&ret_die)) {
|
||||||
case DW_TAG_base_type: {
|
case DW_TAG_base_type: {
|
||||||
// get Size attribute and it's value
|
// get Size attribute and it's value
|
||||||
Dwarf_Word size = 0;
|
size = 0;
|
||||||
attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
|
attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
|
||||||
if(attr) {
|
if(attr) {
|
||||||
dwarf_formudata(attr, &size);
|
dwarf_formudata(attr, &size);
|
||||||
@@ -200,6 +200,12 @@ bool __pst_parameter::handle_type(Dwarf_Attribute* param)
|
|||||||
ctx->log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), size);
|
ctx->log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), size);
|
||||||
add_type(dwarf_diename(&ret_die), DW_TAG_base_type);
|
add_type(dwarf_diename(&ret_die), DW_TAG_base_type);
|
||||||
type = DW_TAG_base_type;
|
type = DW_TAG_base_type;
|
||||||
|
|
||||||
|
attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
enc_type = 0;
|
||||||
|
dwarf_formudata(attr, &enc_type);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DW_TAG_array_type:
|
case DW_TAG_array_type:
|
||||||
@@ -291,7 +297,7 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
|||||||
dwarf_decl_line(result, (int*)&line);
|
dwarf_decl_line(result, (int*)&line);
|
||||||
// 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);
|
||||||
ctx->log(SEVERITY_DEBUG, "Handle '%s' %s", name.c_str(), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
ctx->log(SEVERITY_DEBUG, "---> Handle '%s' %s", name.c_str(), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
||||||
if(attr) {
|
if(attr) {
|
||||||
handle_type(attr);
|
handle_type(attr);
|
||||||
}
|
}
|
||||||
@@ -300,7 +306,7 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
|||||||
// determine location of parameter in stack/heap or CPU registers
|
// determine location of parameter in stack/heap or CPU registers
|
||||||
attr = dwarf_attr(result, DW_AT_location, &attr_mem);
|
attr = dwarf_attr(result, DW_AT_location, &attr_mem);
|
||||||
Dwarf_Addr pc;
|
Dwarf_Addr pc;
|
||||||
unw_get_reg(&ctx->curr_frame, UNW_REG_IP, &pc);
|
unw_get_reg(ctx->curr_frame, UNW_REG_IP, &pc);
|
||||||
|
|
||||||
dwarf_stack stack(ctx);
|
dwarf_stack stack(ctx);
|
||||||
char str[1024]; str[0] = 0;
|
char str[1024]; str[0] = 0;
|
||||||
@@ -320,7 +326,7 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
|||||||
switch (dwarf_whatform(attr)) {
|
switch (dwarf_whatform(attr)) {
|
||||||
case DW_FORM_string:
|
case DW_FORM_string:
|
||||||
// do nothing for now
|
// do nothing for now
|
||||||
ctx->log(SEVERITY_WARNING, "Const value form DW_FORM_string is not implemented.");
|
ctx->log(SEVERITY_WARNING, "Const value form DW_FORM_string value = %s.", dwarf_formstring(attr));
|
||||||
break;
|
break;
|
||||||
case DW_FORM_data1:
|
case DW_FORM_data1:
|
||||||
case DW_FORM_data2:
|
case DW_FORM_data2:
|
||||||
@@ -343,7 +349,23 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function
|
// Additionally handle these attributes:
|
||||||
|
// 1. DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function
|
||||||
|
// A DW_AT_default_value attribute for a formal parameter entry. The value of
|
||||||
|
// this attribute may be a constant, or a reference to the debugging information
|
||||||
|
// entry for a variable, or a reference to a debugging information entry containing a DWARF procedure
|
||||||
|
|
||||||
|
// 2. DW_AT_variable_parameter
|
||||||
|
// A DW_AT_variable_parameter attribute, which is a flag, if a formal
|
||||||
|
// parameter entry represents a parameter whose value in the calling function
|
||||||
|
// may be modified by the callee. The absence of this attribute implies that the
|
||||||
|
// parameter’s value in the calling function cannot be modified by the callee.
|
||||||
|
|
||||||
|
// 3. DW_AT_abstract_origin
|
||||||
|
// In place of these omitted attributes, each concrete inlined instance entry has a DW_AT_abstract_origin attribute that may be used to obtain the
|
||||||
|
// missing information (indirectly) from the associated abstract instance entry. The value of the abstract origin attribute is a reference to the associated abstract
|
||||||
|
// instance entry.
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -468,6 +490,7 @@ bool __pst_function::handle_lexical_block(Dwarf_Die* result)
|
|||||||
case DW_TAG_formal_parameter:
|
case DW_TAG_formal_parameter:
|
||||||
ctx->log(SEVERITY_DEBUG, "Abstract origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
|
ctx->log(SEVERITY_DEBUG, "Abstract origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
|
||||||
break;
|
break;
|
||||||
|
// Also handle DW_TAG_unspecified_parameters (unknown number of arguments i.e. fun(arg1, ...);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -525,6 +548,8 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
|
|||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Attribute* attr;
|
Dwarf_Attribute* attr;
|
||||||
|
|
||||||
|
ctx->log(SEVERITY_DEBUG, "***** DW_TAG_GNU_call_site contents:");
|
||||||
|
// reference to DIE which represents callee's parameter if compiler knows where it is at compile time
|
||||||
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
|
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
|
||||||
Dwarf_Die child;
|
Dwarf_Die child;
|
||||||
if(dwarf_child (&origin, &child) == 0) {
|
if(dwarf_child (&origin, &child) == 0) {
|
||||||
@@ -533,7 +558,7 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
|
|||||||
{
|
{
|
||||||
case DW_TAG_variable:
|
case DW_TAG_variable:
|
||||||
case DW_TAG_formal_parameter:
|
case DW_TAG_formal_parameter:
|
||||||
ctx->log(SEVERITY_DEBUG, "Abstract origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
|
ctx->log(SEVERITY_DEBUG, "\tDW_AT_abstract_origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -541,6 +566,26 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
|
|||||||
} while (dwarf_siblingof (&child, &child) == 0);
|
} while (dwarf_siblingof (&child, &child) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The call site may have a DW_AT_call_site_target attribute which is a DWARF expression. For indirect calls or jumps where it is unknown at
|
||||||
|
// compile time which subprogram will be called the expression computes the address of the subprogram that will be called.
|
||||||
|
if(dwarf_hasattr (result, DW_AT_GNU_call_site_target)) {
|
||||||
|
attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
dwarf_stack stack(ctx);
|
||||||
|
char str[1024]; str[0] = 0;
|
||||||
|
uint64_t value;
|
||||||
|
if(handle_location(ctx, &attr_mem, stack, pc, str, sizeof(str))) {
|
||||||
|
if(stack.get_value(value)) {
|
||||||
|
ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_target: %s ==> %#lX", str, (void*)value);
|
||||||
|
} else {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_GNU_call_site_target expression: %s", str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_GNU_call_site_target expression: %s", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Dwarf_Die child;
|
Dwarf_Die child;
|
||||||
if(dwarf_child (result, &child) == 0) {
|
if(dwarf_child (result, &child) == 0) {
|
||||||
do {
|
do {
|
||||||
@@ -551,13 +596,14 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
|
|||||||
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||||
|
|
||||||
dwarf_stack stack(ctx); char str[1024]; uint64_t value;
|
dwarf_stack stack(ctx); char str[1024]; uint64_t value;
|
||||||
|
// expression represent where calle parameter vill be stored
|
||||||
if(dwarf_hasattr(&child, DW_AT_location)) {
|
if(dwarf_hasattr(&child, DW_AT_location)) {
|
||||||
// handle location expression here
|
// handle location expression here
|
||||||
// determine location of parameter in stack/heap or CPU registers
|
// determine location of parameter in stack/heap or CPU registers
|
||||||
attr = dwarf_attr(&child, DW_AT_location, &attr_mem);
|
attr = dwarf_attr(&child, DW_AT_location, &attr_mem);
|
||||||
if(handle_location(ctx, attr, stack, pc, str, sizeof(str))) {
|
if(handle_location(ctx, attr, stack, pc, str, sizeof(str))) {
|
||||||
if(stack.get_value(value)) {
|
if(stack.get_value(value)) {
|
||||||
ctx->log(SEVERITY_DEBUG, "DW_TAG_GNU_call_site_parameter Location: \"%s\" ==> 0x%lX", str, value);
|
ctx->log(SEVERITY_DEBUG, "\tDW_TAG_GNU_call_site_parameter: \"%s\" ==> 0x%lX", str, value);
|
||||||
} else {
|
} else {
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
||||||
}
|
}
|
||||||
@@ -565,12 +611,13 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
|
|||||||
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str);
|
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// expression represents call parameter's value
|
||||||
if(dwarf_hasattr(&child, DW_AT_GNU_call_site_value)) {
|
if(dwarf_hasattr(&child, DW_AT_GNU_call_site_value)) {
|
||||||
// handle value expression here
|
// handle value expression here
|
||||||
attr = dwarf_attr(&child, DW_AT_GNU_call_site_value, &attr_mem);
|
attr = dwarf_attr(&child, DW_AT_GNU_call_site_value, &attr_mem);
|
||||||
if(handle_location(ctx, attr, stack, pc, str, sizeof(str))) {
|
if(handle_location(ctx, attr, stack, pc, str, sizeof(str))) {
|
||||||
if(stack.get_value(value)) {
|
if(stack.get_value(value)) {
|
||||||
ctx->log(SEVERITY_DEBUG, "DW_AT_GNU_call_site_value Location:\"%s\" ==> 0x%lX", str, value);
|
ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", str, value);
|
||||||
} else {
|
} else {
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
||||||
}
|
}
|
||||||
@@ -592,7 +639,6 @@ 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;
|
||||||
ctx->curr_frame = cursor;
|
|
||||||
|
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Attribute* attr;
|
Dwarf_Attribute* attr;
|
||||||
@@ -611,8 +657,9 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
|||||||
unw_word_t sp;
|
unw_word_t sp;
|
||||||
unw_get_reg(&cursor, UNW_REG_SP, &sp);
|
unw_get_reg(&cursor, UNW_REG_SP, &sp);
|
||||||
|
|
||||||
ctx->log(SEVERITY_DEBUG, "=====> %s(...), PC = 0x%lX, LOW_PC = 0x%lX, HIGH_PC = 0x%lX, offset from base address: 0x%lX, BASE_PC = 0x%lX, offset from start of function: 0x%lX, stack address: 0x%lX",
|
|
||||||
dwarf_diename(d), pc, lowpc, highpc, pc - ctx->base_addr, info.start_ip, info.start_ip - ctx->base_addr, sp);
|
ctx->log(SEVERITY_DEBUG, "=====> %s(...) parent '%s', PC = 0x%lX, LOW_PC = 0x%lX, HIGH_PC = 0x%lX, offset from base address: 0x%lX, BASE_PC = 0x%lX, offset from start of function: 0x%lX, SP: 0x%lX, CFA: %#lX",
|
||||||
|
dwarf_diename(d), parent?parent->name.c_str() : "none", pc, lowpc, highpc, pc - ctx->base_addr, info.start_ip, info.start_ip - ctx->base_addr, sp, parent ? parent->sp : 0);
|
||||||
|
|
||||||
// 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);
|
||||||
@@ -646,20 +693,35 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
|||||||
attr = dwarf_attr(die, DW_AT_type, &attr_mem);
|
attr = dwarf_attr(die, DW_AT_type, &attr_mem);
|
||||||
if(attr) {
|
if(attr) {
|
||||||
if(!ret_p->handle_type(attr)) {
|
if(!ret_p->handle_type(attr)) {
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to handle return parameter type");
|
ctx->log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", name.c_str());
|
||||||
del_param(ret_p);
|
del_param(ret_p);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret_p->add_type("void", 0);
|
ret_p->add_type("void", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle and save additionally these attributes:
|
||||||
|
// 1. string of DW_AT_linkage_name (mangled name of program if any)
|
||||||
|
// A debugging information entry may have a DW_AT_linkage_name attribute
|
||||||
|
// whose value is a null-terminated string containing the object file linkage name
|
||||||
|
// associated with the corresponding entity.
|
||||||
|
|
||||||
|
// 2. flag DW_AT_external attribute
|
||||||
|
// A DW_AT_external attribute, which is a flag, if the name of a variable is
|
||||||
|
// visible outside of its enclosing compilation unit.
|
||||||
|
|
||||||
|
// 3. A subroutine entry may contain a DW_AT_main_subprogram attribute which is
|
||||||
|
// a flag whose presence indicates that the subroutine has been identified as the
|
||||||
|
// starting function of the program. If more than one subprogram contains this flag,
|
||||||
|
// any one of them may be the starting subroutine of the program.
|
||||||
|
|
||||||
|
|
||||||
Dwarf_Die result;
|
Dwarf_Die result;
|
||||||
if(dwarf_child(die, &result) != 0)
|
if(dwarf_child(die, &result) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// went through parameters and local variables of the function
|
// went through parameters and local variables of the function
|
||||||
do {
|
do {
|
||||||
|
|
||||||
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: {
|
||||||
@@ -682,6 +744,9 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
|||||||
handle_lexical_block(&result);
|
handle_lexical_block(&result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Also handle:
|
||||||
|
// DW_TAG_unspecified_parameters (unknown number of arguments i.e. fun(arg1, ...);
|
||||||
|
// DW_AT_inline
|
||||||
default:
|
default:
|
||||||
ctx->log(SEVERITY_DEBUG, "Unknown TAG of function: 0x%X", dwarf_tag(&result));
|
ctx->log(SEVERITY_DEBUG, "Unknown TAG of function: 0x%X", dwarf_tag(&result));
|
||||||
break;
|
break;
|
||||||
@@ -743,7 +808,7 @@ bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool __pst_handler::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()
|
||||||
@@ -756,19 +821,23 @@ bool __pst_handler::get_frame()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get frame of CFI for address
|
// get frame of CFI for address
|
||||||
int result = dwarf_cfi_addrframe (cfi, addr - mod_bias, &frame);
|
int result = dwarf_cfi_addrframe (cfi, fun->pc - mod_bias, &frame);
|
||||||
if (result == 0) {
|
if (result != 0) {
|
||||||
|
ctx.log(SEVERITY_DEBUG, "Failed to find CFI frame for module");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// get frame information
|
// get frame information
|
||||||
ctx.log(SEVERITY_DEBUG, "Found CFI frame for module");
|
ctx.log(SEVERITY_DEBUG, "Found CFI frame for module");
|
||||||
Dwarf_Addr start = addr;
|
Dwarf_Addr start = fun->pc;
|
||||||
Dwarf_Addr end = addr;
|
Dwarf_Addr end = fun->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;
|
||||||
}
|
}
|
||||||
ctx.log(SEVERITY_DEBUG, "Per '.eh_frame' info has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "] in_signal = %s", addr, start, end, signalp ? "true" : "false");
|
ctx.log(SEVERITY_DEBUG, "Per '.eh_frame' info has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "] in_signal = %s", fun->pc, start, end, signalp ? "true" : "false");
|
||||||
if (ra_regno < 0)
|
if (ra_regno < 0)
|
||||||
ctx.log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg(0));
|
ctx.log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg(0));
|
||||||
else {
|
else {
|
||||||
@@ -786,8 +855,41 @@ bool __pst_handler::get_frame()
|
|||||||
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;
|
||||||
ctx.print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
ctx.print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
||||||
ctx.log(SEVERITY_INFO, "CFA expression: \"%s\"", str);
|
// ctx.log(SEVERITY_INFO, "CFA expression: \"%s\"", str);
|
||||||
//print_detail (result, cfa_ops, cfa_nops, mod_bias, "\tCFA ");
|
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, "CFA expression for function %s(...): %s ==> %#lX", fun->name.c_str(), str, v);
|
||||||
|
} else {
|
||||||
|
ctx.log(SEVERITY_ERROR, "Failed to calculate CFA expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
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_DEBUG, "CFI register 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 {
|
||||||
|
ctx.log(SEVERITY_DEBUG, "Failed to get CFI expression for register 0x%X", regno);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -831,9 +933,9 @@ bool __pst_handler::get_dwarf_function(pst_function* fun)
|
|||||||
return nret;
|
return nret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_function* __pst_handler::add_function(__pst_function* fun)
|
pst_function* __pst_handler::add_function(__pst_function* parent)
|
||||||
{
|
{
|
||||||
pst_function* f = new pst_function(&ctx, fun);
|
pst_function* f = new pst_function(&ctx, parent);
|
||||||
functions.InsertLast(f);
|
functions.InsertLast(f);
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
@@ -865,21 +967,34 @@ pst_function* __pst_handler::next_function(pst_function* f)
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pst_function* __pst_handler::last_function()
|
||||||
|
{
|
||||||
|
return (pst_function*)functions.Last();
|
||||||
|
}
|
||||||
|
|
||||||
bool __pst_handler::handle_dwarf()
|
bool __pst_handler::handle_dwarf()
|
||||||
{
|
{
|
||||||
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)) {
|
||||||
dladdr((void*)(fun->pc), &info);
|
dladdr((void*)(fun->pc), &info);
|
||||||
|
module = dwfl_addrmodule(dwfl, fun->pc);
|
||||||
ctx.base_addr = (uint64_t)info.dli_fbase;
|
ctx.base_addr = (uint64_t)info.dli_fbase;
|
||||||
ctx.log(SEVERITY_DEBUG, "Function %s(...): module name: %s, base address: %p", fun->name.c_str(), info.dli_fname, info.dli_fbase);
|
ctx.log(SEVERITY_DEBUG, "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;
|
ctx.sp = fun->sp;
|
||||||
|
ctx.cfa = fun->parent ? fun->parent->sp : 0;
|
||||||
if(fun->parent) {
|
if(fun->parent) {
|
||||||
ctx.next_frame = fun->parent->cursor;
|
ctx.next_frame = &fun->parent->cursor;
|
||||||
ctx.has_nframe = true;
|
|
||||||
} else {
|
} else {
|
||||||
ctx.has_nframe = false;
|
ctx.next_frame = 0;
|
||||||
|
}
|
||||||
|
get_frame(fun);
|
||||||
|
|
||||||
|
ctx.curr_frame = &fun->cursor;
|
||||||
|
ctx.next_frame = NULL;
|
||||||
|
if(fun->parent) {
|
||||||
|
ctx.next_frame = &fun->parent->cursor;
|
||||||
}
|
}
|
||||||
get_dwarf_function(fun);
|
get_dwarf_function(fun);
|
||||||
}
|
}
|
||||||
@@ -913,6 +1028,8 @@ bool __pst_handler::unwind()
|
|||||||
{
|
{
|
||||||
#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.log(SEVERITY_DEBUG, "Original caller's SP: %#lX", ctx.sp);
|
||||||
#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__)
|
||||||
@@ -936,29 +1053,6 @@ 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);
|
||||||
|
|
||||||
int skipped = 0;
|
|
||||||
#ifndef USE_LIBUNWIND
|
|
||||||
int size = 0;
|
|
||||||
void * array[50];
|
|
||||||
size = backtrace(array, 50);
|
|
||||||
for(int i = 0; i < size && array[i] != caller; ++i, ++skipped);
|
|
||||||
ctx.print("Stack trace(caller = %p. Total stack frames: %d, skipped: %d):\n", caller, size, skipped);
|
|
||||||
#else
|
|
||||||
unw_word_t pc;
|
|
||||||
|
|
||||||
unw_getcontext(&ctx.context);
|
|
||||||
unw_init_local(&ctx.curr_frame, &ctx.context);
|
|
||||||
while (unw_step(&ctx.curr_frame) > 0) {
|
|
||||||
unw_get_reg(&ctx.curr_frame, UNW_REG_IP, &pc);
|
|
||||||
if(pc == (uint64_t)caller) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
++skipped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.print("Stack trace(caller = %p. Skipped stack frames: %d):\n", caller, skipped);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dwfl = dwfl_begin(&callbacks);
|
dwfl = dwfl_begin(&callbacks);
|
||||||
if(dwfl == NULL) {
|
if(dwfl == NULL) {
|
||||||
ctx.print("Failed to initialize libdw session for parse stack frames");
|
ctx.print("Failed to initialize libdw session for parse stack frames");
|
||||||
@@ -970,30 +1064,44 @@ bool __pst_handler::unwind()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USE_LIBUNWIND
|
ctx.print("Stack trace: caller = %p\n", caller);
|
||||||
for (int i = skipped, idx = 0; i < size ; ++i, ++idx) {
|
|
||||||
uint64_t pc = (uint64_t)array[i];
|
unw_getcontext(&ctx.context);
|
||||||
ctx.print("[%-2d] ", idx);
|
unw_init_local(&ctx.cursor, &ctx.context);
|
||||||
Dwarf_Addr addr = (uintptr_t)array[i];
|
ctx.curr_frame = &ctx.cursor;
|
||||||
#else
|
for(int i = 0, skip = 1; unw_step(ctx.curr_frame) > 0; ++i) {
|
||||||
ctx.has_nframe = false;
|
if(unw_get_reg(ctx.curr_frame, UNW_REG_IP, &addr)) {
|
||||||
for (int i = skipped, idx = 0; true ; ++i, ++idx) {
|
ctx.log(SEVERITY_DEBUG, "Failed to get IP value");
|
||||||
unw_get_reg(&ctx.curr_frame, UNW_REG_IP, &pc);
|
continue;
|
||||||
addr = pc;
|
}
|
||||||
ctx.print("[%-2d] ", idx);
|
unw_word_t sp;
|
||||||
#endif
|
if(unw_get_reg(ctx.curr_frame, UNW_REG_SP, &sp)) {
|
||||||
|
ctx.log(SEVERITY_DEBUG, "Failed to get SP value");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == (uint64_t)caller) {
|
||||||
|
skip = 0;
|
||||||
|
} else if(skip) {
|
||||||
|
ctx.log(SEVERITY_DEBUG, "Skipping frame #%d: PC = %#lX, SP = %#lX", i, addr, sp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.print("[%-2d] ", i);
|
||||||
module = dwfl_addrmodule(dwfl, addr);
|
module = dwfl_addrmodule(dwfl, addr);
|
||||||
get_frame();
|
pst_function* last = last_function();
|
||||||
pst_function* fun = add_function(next_function(NULL)/* first element */);
|
pst_function* fun = add_function(NULL);
|
||||||
if(!fun->unwind(dwfl, module, pc)) {
|
fun->sp = sp;
|
||||||
|
ctx.log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, addr, sp);
|
||||||
|
if(!fun->unwind(dwfl, module, addr)) {
|
||||||
del_function(fun);
|
del_function(fun);
|
||||||
|
} else {
|
||||||
|
if(last) {
|
||||||
|
last->parent = fun;
|
||||||
|
}
|
||||||
|
//get_frame(fun);
|
||||||
}
|
}
|
||||||
ctx.print("\n");
|
ctx.print("\n");
|
||||||
#ifdef USE_LIBUNWIND
|
|
||||||
if(unw_step(&ctx.curr_frame) <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -23,8 +23,6 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
char* GetExecutableName(char* path, uint32_t size);
|
|
||||||
|
|
||||||
typedef struct __pst_function pst_function;
|
typedef struct __pst_function pst_function;
|
||||||
|
|
||||||
typedef struct __pst_type : public SC_ListNode {
|
typedef struct __pst_type : public SC_ListNode {
|
||||||
@@ -43,7 +41,7 @@ typedef struct __pst_parameter : public SC_ListNode {
|
|||||||
die = NULL;
|
die = NULL;
|
||||||
size = 0;
|
size = 0;
|
||||||
type = 0;
|
type = 0;
|
||||||
loc = NULL;
|
enc_type = 0;
|
||||||
is_return = false;
|
is_return = false;
|
||||||
is_variable = false;
|
is_variable = false;
|
||||||
has_value = false;
|
has_value = false;
|
||||||
@@ -68,9 +66,9 @@ typedef struct __pst_parameter : public SC_ListNode {
|
|||||||
std::string name; // parameter's name
|
std::string name; // parameter's name
|
||||||
uint32_t line; // line of parameter definition
|
uint32_t line; // line of parameter definition
|
||||||
Dwarf_Word size; // size of parameter in bytes
|
Dwarf_Word size; // size of parameter in bytes
|
||||||
int type; // base type of parameter in DW_TAG_XXX types enumeration
|
int type; // type of parameter in DW_TAG_XXX types enumeration
|
||||||
|
Dwarf_Word enc_type; // if 'type' is DW_TAG_Base_type, then 'base_type' holds DW_AT_ATE_XXX base type encoding type
|
||||||
SC_ListHead types; // list of parameter's definitions i.e. 'typedef', 'uint32_t'
|
SC_ListHead types; // list of parameter's 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
|
bool is_return; // whether this parameter is return value of the function
|
||||||
bool is_variable;// whether this parameter is function variable or argument of function
|
bool is_variable;// whether this parameter is function variable or argument of function
|
||||||
bool has_value; // whether we got value of parameter or not
|
bool has_value; // whether we got value of parameter or not
|
||||||
@@ -87,9 +85,9 @@ typedef struct __pst_function : public SC_ListNode {
|
|||||||
die = NULL;
|
die = NULL;
|
||||||
lowpc = 0;
|
lowpc = 0;
|
||||||
highpc = 0;
|
highpc = 0;
|
||||||
parent = NULL;
|
memcpy(&cursor, _ctx->curr_frame, sizeof(cursor));
|
||||||
cursor = _ctx->curr_frame;
|
|
||||||
parent = _parent;
|
parent = _parent;
|
||||||
|
sp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
~__pst_function() {
|
~__pst_function() {
|
||||||
@@ -113,6 +111,7 @@ typedef struct __pst_function : public SC_ListNode {
|
|||||||
std::string name; // function's name
|
std::string name; // function's name
|
||||||
SC_ListHead params; // function's parameters
|
SC_ListHead params; // function's parameters
|
||||||
unw_word_t pc; // address between lowpc & highpc (plus base address offset). actually, currently executed command
|
unw_word_t pc; // address between lowpc & highpc (plus base address offset). actually, currently executed command
|
||||||
|
unw_word_t sp; // SP register in function's frame
|
||||||
unw_cursor_t cursor; // copy of stack state of the function
|
unw_cursor_t cursor; // copy of stack state of the function
|
||||||
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
|
||||||
@@ -144,11 +143,12 @@ typedef struct __pst_handler {
|
|||||||
pst_function* add_function(__pst_function* fun);
|
pst_function* add_function(__pst_function* fun);
|
||||||
void del_function(pst_function* f);
|
void del_function(pst_function* f);
|
||||||
pst_function* next_function(pst_function* f);
|
pst_function* next_function(pst_function* f);
|
||||||
|
pst_function* last_function();
|
||||||
|
|
||||||
bool handle_dwarf();
|
bool handle_dwarf();
|
||||||
void print_dwarf();
|
void print_dwarf();
|
||||||
bool unwind();
|
bool unwind();
|
||||||
bool get_frame();
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user