extract context from handler and move it to common. define functions to
use in calculation of DWARF expressions
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
/CMakeFiles/
|
||||
/CMakeCache.txt
|
||||
/install_manifest.txt
|
||||
/cmake_install.cmake
|
||||
/libframework.a
|
||||
/Makefile
|
||||
+196
-62
@@ -7,78 +7,130 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <dwarf.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include <libunwind.h>
|
||||
|
||||
#include "logger/log.h"
|
||||
#include "common.h"
|
||||
#include "dwarf_operations.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"},
|
||||
extern SC_LogBase* logger;
|
||||
|
||||
// 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)
|
||||
bool __pst_context::print(const char* fmt, ...)
|
||||
{
|
||||
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];
|
||||
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);
|
||||
}
|
||||
|
||||
uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
//printf ("%s", (i + 1 < len ? ", " : ""));
|
||||
const dwarf_op_map* map = find_op_map(exprs[i].atom);
|
||||
if(map) {
|
||||
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 if(map->op_num == DW_OP_regx) {
|
||||
int32_t reg = decode_sleb128((unsigned char*)&exprs[i].number);
|
||||
|
||||
unw_word_t value = 0;
|
||||
unw_get_reg(&cursor, 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) {
|
||||
offset += snprintf(buff + offset, buff_size - offset, "%s value = 0x%X", map->op_name, *((uint32_t*)exprs[i].number));
|
||||
} 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);
|
||||
// }DW_OP_addr
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool is_location_form(int form)
|
||||
{
|
||||
if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block ||
|
||||
form == DW_FORM_data4 || form == DW_FORM_data8 || form == DW_FORM_sec_offset) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int32_t decode_sleb128(uint8_t *sleb128)
|
||||
{
|
||||
int32_t num = 0, shift = 0, size = 0;
|
||||
@@ -103,3 +155,85 @@ uint32_t decode_uleb128(uint8_t *uleb128)
|
||||
return num;
|
||||
}
|
||||
|
||||
// Utility function to encode a ULEB128 value to a buffer. Returns
|
||||
// the length in bytes of the encoded value.
|
||||
inline unsigned encodeULEB128(uint64_t Value, uint8_t *p, unsigned PadTo = 0)
|
||||
{
|
||||
uint8_t *orig_p = p;
|
||||
unsigned Count = 0;
|
||||
do {
|
||||
uint8_t Byte = Value & 0x7f;
|
||||
Value >>= 7;
|
||||
Count++;
|
||||
if (Value != 0 || Count < PadTo)
|
||||
Byte |= 0x80; // Mark this byte to show that more bytes will follow.
|
||||
*p++ = Byte;
|
||||
} while (Value != 0);
|
||||
|
||||
// Pad with 0x80 and emit a null byte at the end.
|
||||
if (Count < PadTo) {
|
||||
for (; Count < PadTo - 1; ++Count)
|
||||
*p++ = '\x80';
|
||||
*p++ = '\x00';
|
||||
}
|
||||
|
||||
return (unsigned)(p - orig_p);
|
||||
}
|
||||
|
||||
// Utility function to encode a SLEB128 value to a buffer. Returns
|
||||
// the length in bytes of the encoded value.
|
||||
inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0)
|
||||
{
|
||||
uint8_t *orig_p = p;
|
||||
unsigned Count = 0;
|
||||
bool More;
|
||||
do {
|
||||
uint8_t Byte = Value & 0x7f;
|
||||
// NOTE: this assumes that this signed shift is an arithmetic right shift.
|
||||
Value >>= 7;
|
||||
More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
|
||||
((Value == -1) && ((Byte & 0x40) != 0))));
|
||||
Count++;
|
||||
if (More || Count < PadTo)
|
||||
Byte |= 0x80; // Mark this byte to show that more bytes will follow.
|
||||
*p++ = Byte;
|
||||
} while (More);
|
||||
|
||||
// Pad with 0x80 and emit a terminating byte at the end.
|
||||
if (Count < PadTo) {
|
||||
uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
|
||||
for (; Count < PadTo - 1; ++Count)
|
||||
*p++ = (PadValue | 0x80);
|
||||
*p++ = PadValue;
|
||||
}
|
||||
return (unsigned)(p - orig_p);
|
||||
}
|
||||
|
||||
// Utility function to get the size of the ULEB128-encoded value.
|
||||
unsigned getULEB128Size(uint64_t Value)
|
||||
{
|
||||
unsigned Size = 0;
|
||||
do {
|
||||
Value >>= 7;
|
||||
Size += sizeof(int8_t);
|
||||
} while (Value);
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
// Utility function to get the size of the SLEB128-encoded value.
|
||||
unsigned getSLEB128Size(int64_t Value)
|
||||
{
|
||||
unsigned Size = 0;
|
||||
int Sign = Value >> (8 * sizeof(Value) - 1);
|
||||
bool IsMore;
|
||||
|
||||
do {
|
||||
unsigned Byte = Value & 0x7f;
|
||||
Value >>= 7;
|
||||
IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
|
||||
Size += sizeof(int8_t);
|
||||
} while (IsMore);
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
+90
-7
@@ -1,13 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <execinfo.h>
|
||||
#include <libunwind.h>
|
||||
|
||||
#include "logger/log.h"
|
||||
#include "linkedlist.h"
|
||||
|
||||
typedef struct __dwarf_value : public SC_ListNode {
|
||||
__dwarf_value(uint32_t s)
|
||||
{
|
||||
size = s;
|
||||
value = (char*)malloc(s);
|
||||
}
|
||||
|
||||
__dwarf_value(char*v, uint32_t s)
|
||||
{
|
||||
size = s;
|
||||
value = (char*)malloc(s);
|
||||
memcpy(value, v, s);
|
||||
}
|
||||
|
||||
__dwarf_value()
|
||||
{
|
||||
value = NULL;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
~__dwarf_value()
|
||||
{
|
||||
if(value) {
|
||||
free(value);
|
||||
value = NULL;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
char* value;
|
||||
uint32_t size;
|
||||
} dwarf_value;
|
||||
|
||||
typedef struct __dwarf_stack : public SC_ListHead {
|
||||
void clear() {
|
||||
for(dwarf_value* v = (dwarf_value*)First(); v; v = (dwarf_value*)First()) {
|
||||
Remove(v);
|
||||
delete v;
|
||||
}
|
||||
}
|
||||
|
||||
void push(char* v, uint32_t s) {
|
||||
dwarf_value* value = new dwarf_value(v, s);
|
||||
InsertFirst(value);
|
||||
}
|
||||
|
||||
void push(dwarf_value* value) {
|
||||
InsertFirst(value);
|
||||
}
|
||||
|
||||
dwarf_value* pop() {
|
||||
dwarf_value* value = (dwarf_value*)First();
|
||||
if(value) {
|
||||
Remove(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
} dwarf_stack;
|
||||
|
||||
typedef struct __pst_context {
|
||||
__pst_context(ucontext_t* hctx) : hcontext(hctx)
|
||||
{
|
||||
offset = 0;
|
||||
buff[0] = 0;
|
||||
base_addr = 0;
|
||||
}
|
||||
|
||||
bool print(const char* fmt, ...);
|
||||
void log(SC_LogSeverity severity, const char*fmt, ...);
|
||||
uint32_t print_expr_block(Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr = 0);
|
||||
|
||||
ucontext_t* hcontext; // context of signal handler
|
||||
unw_context_t context; // context of stack trace
|
||||
unw_cursor_t cursor; // currently examined frame of context
|
||||
dwarf_stack stack;
|
||||
Dwarf_Addr base_addr; // base address where process loaded
|
||||
|
||||
char buff[8192]; // stack trace buffer
|
||||
uint32_t offset; // offset in the 'buff'
|
||||
} pst_context;
|
||||
|
||||
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);
|
||||
bool is_location_form(int form);
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* dwarf_operations.cpp
|
||||
*
|
||||
* Created on: Jan 11, 2020
|
||||
* Author: nnosov
|
||||
*/
|
||||
|
||||
#include <dwarf.h>
|
||||
#include "dwarf_operations.h"
|
||||
|
||||
bool dw_op_addr(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
dwarf_op_map dw_op[] = {
|
||||
{0x03, -1, 0, "DW_OP_addr", dw_op_addr},
|
||||
{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.
|
||||
|
||||
// GP Registers
|
||||
{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"},
|
||||
// Extended GP Registers
|
||||
{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"}, // Return Address (RA) mapped to RIP
|
||||
// SSE Vector Registers
|
||||
{0x61, 0x11, "XMM0", "DW_OP_reg17"},
|
||||
{0x62, 0x12, "XMM1", "DW_OP_reg18"},
|
||||
{0x63, 0x13, "XMM2", "DW_OP_reg19"},
|
||||
{0x64, 0x14, "XMM3", "DW_OP_reg20"},
|
||||
{0x65, 0x15, "XMM4", "DW_OP_reg21"},
|
||||
{0x66, 0x16, "XMM5", "DW_OP_reg22"},
|
||||
{0x67, 0x17, "XMM6", "DW_OP_reg23"},
|
||||
{0x68, 0x18, "XMM7", "DW_OP_reg24"},
|
||||
{0x69, 0x19, "XMM8", "DW_OP_reg25"},
|
||||
{0x6a, 0x1a, "XMM9", "DW_OP_reg26"},
|
||||
{0x6b, 0x1b, "XMM10", "DW_OP_reg27"},
|
||||
{0x6c, 0x1c, "XMM11", "DW_OP_reg28"},
|
||||
{0x6d, 0x1d, "XMM12", "DW_OP_reg29"},
|
||||
{0x6e, 0x1e, "XMM13", "DW_OP_reg30"},
|
||||
{0x6f, 0x1f, "XMM14", "DW_OP_reg31"},
|
||||
|
||||
// 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)
|
||||
|
||||
// GP Registers
|
||||
{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"},
|
||||
// Extended GP Registers
|
||||
{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"}, // Return Address (RA) mapped to RIP
|
||||
// SSE Vector Registers
|
||||
{0x81, 0x11, "XMM0", "DW_OP_breg17"},
|
||||
{0x82, 0x12, "XMM1", "DW_OP_breg18"},
|
||||
{0x83, 0x13, "XMM2", "DW_OP_breg19"},
|
||||
{0x84, 0x14, "XMM3", "DW_OP_breg20"},
|
||||
{0x85, 0x15, "XMM4", "DW_OP_breg21"},
|
||||
{0x86, 0x16, "XMM5", "DW_OP_breg22"},
|
||||
{0x87, 0x17, "XMM6", "DW_OP_breg23"},
|
||||
{0x88, 0x18, "XMM7", "DW_OP_breg24"},
|
||||
{0x89, 0x19, "XMM8", "DW_OP_breg25"},
|
||||
{0x8a, 0x1a, "XMM9", "DW_OP_breg26"},
|
||||
{0x8b, 0x1b, "XMM10", "DW_OP_breg27"},
|
||||
{0x8c, 0x1c, "XMM11", "DW_OP_breg28"},
|
||||
{0x8d, 0x1d, "XMM12", "DW_OP_breg29"},
|
||||
{0x8e, 0x1e, "XMM13", "DW_OP_breg30"},
|
||||
{0x8f, 0x1f, "XMM14", "DW_OP_breg31"},
|
||||
|
||||
// The DW_OP_regx operation has a single unsigned LEB128 literal operand that encodes the name of a register
|
||||
{0x90, -1, 0, "DW_OP_regx"},
|
||||
// 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, 0, "DW_OP_fbreg"},
|
||||
// The DW_OP_bregx operation provides the sum of two values specified by its two operands.
|
||||
// The first operand is a register number which is specified by an unsigned LEB128 number. The second operand is a signed LEB128 offset.
|
||||
{0x92, -1, 0, "DW_OP_bregx"},
|
||||
{0x9C, -1, 0, "DW_OP_call_frame_cfa"},
|
||||
// DWARF5, Section 2.6.1.1.4:
|
||||
// The 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, 0, "DW_OP_stack_value"},
|
||||
// This opcode has two operands, the first one is uleb128 length and the second is block of that length, containing either a
|
||||
// simple register or DWARF expression
|
||||
{0xF3, -1, 0, "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;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct __dwarf_op_map dwarf_op_map;
|
||||
|
||||
typedef bool (*dwarf_operation)(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2);
|
||||
|
||||
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_operation operation; // function which handles operation
|
||||
} dwarf_op_map;
|
||||
|
||||
const dwarf_op_map* find_op_map(int op);
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* linkedlist.h
|
||||
*
|
||||
* Created on: Oct 24, 2013
|
||||
* Author: nnosov
|
||||
*
|
||||
* Simple double linked list implementation. Base class.
|
||||
*/
|
||||
|
||||
#ifndef LINKEDLIST_H_
|
||||
#define LINKEDLIST_H_
|
||||
|
||||
//system
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct __SC_ListNode
|
||||
{
|
||||
__SC_ListNode()
|
||||
{
|
||||
pPrev = pNext = 0;
|
||||
}
|
||||
|
||||
bool IsListed()
|
||||
{
|
||||
return (pNext || pPrev);
|
||||
}
|
||||
|
||||
__SC_ListNode* pNext;
|
||||
__SC_ListNode* pPrev;
|
||||
} SC_ListNode;
|
||||
|
||||
|
||||
class SC_ListHead
|
||||
{
|
||||
|
||||
public:
|
||||
SC_ListHead()
|
||||
{
|
||||
mHead.pPrev = mHead.pNext = &mHead;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
virtual ~SC_ListHead()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for(SC_ListNode* node = (SC_ListNode*)First(); node; node = (SC_ListNode*)First())
|
||||
{
|
||||
Remove(node);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return (mHead.pNext == &mHead);
|
||||
}
|
||||
|
||||
SC_ListNode* First()
|
||||
{
|
||||
return IsEmpty() ? 0 : mHead.pNext;
|
||||
}
|
||||
|
||||
SC_ListNode* Last()
|
||||
{
|
||||
return IsEmpty() ? 0 : mHead.pPrev;
|
||||
}
|
||||
|
||||
SC_ListNode* Next(SC_ListNode* node)
|
||||
{
|
||||
return (!node || node == Last() || !node->IsListed()) ? 0 : node->pNext;
|
||||
}
|
||||
|
||||
SC_ListNode* Prev(SC_ListNode* node)
|
||||
{
|
||||
return (!node || node == First() || !node->IsListed()) ? 0 : node->pPrev;
|
||||
}
|
||||
|
||||
void InsertFirst(SC_ListNode* node)
|
||||
{
|
||||
node->pNext = mHead.pNext;
|
||||
mHead.pNext = node;
|
||||
node->pNext->pPrev = node;
|
||||
node->pPrev = &mHead;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
void InsertLast(SC_ListNode* node)
|
||||
{
|
||||
node->pNext = &mHead;
|
||||
node->pPrev = mHead.pPrev;
|
||||
node->pPrev->pNext = node;
|
||||
mHead.pPrev = node;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
void InsertAfter(SC_ListNode* pPrev, SC_ListNode* p)
|
||||
{
|
||||
p->pNext = pPrev->pNext;
|
||||
p->pPrev = p->pNext->pPrev;
|
||||
p->pNext->pPrev = p;
|
||||
p->pPrev->pNext = p;
|
||||
size++;
|
||||
}
|
||||
|
||||
void InsertBefore(SC_ListNode* pNext, SC_ListNode* p)
|
||||
{
|
||||
p->pNext = pNext;
|
||||
p->pPrev = pNext->pPrev;
|
||||
pNext->pPrev = p;
|
||||
p->pPrev->pNext = p;
|
||||
size++;
|
||||
}
|
||||
|
||||
void Remove(SC_ListNode* node)
|
||||
{
|
||||
node->pPrev->pNext = node->pNext;
|
||||
node->pNext->pPrev = node->pPrev;
|
||||
node->pNext = node->pPrev = 0;
|
||||
|
||||
size--;
|
||||
}
|
||||
|
||||
uint32_t Size()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
protected:
|
||||
SC_ListNode mHead; //previous element in list
|
||||
uint32_t size; //total number of elements in list
|
||||
};
|
||||
|
||||
#endif /* LINKEDLIST_H_ */
|
||||
+86
-165
@@ -14,11 +14,10 @@
|
||||
#include <cxxabi.h>
|
||||
#include <execinfo.h>
|
||||
#include <dwarf.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "logger/log.h"
|
||||
#include "sysutils.h"
|
||||
|
||||
extern SC_LogBase* logger;
|
||||
#include "logger/log.h"
|
||||
|
||||
#define USEI_LIBUNWIND
|
||||
|
||||
@@ -27,66 +26,12 @@ extern SC_LogBase* logger;
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
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);
|
||||
}
|
||||
#include "dwarf_operations.h"
|
||||
|
||||
// dwfl_addrsegment() possibly can be used to check address validity
|
||||
// dwarf_getattrs() allows to enumerate all DIE attributes
|
||||
// dwarf_getfuncs() allows to enumerate functions within CU
|
||||
|
||||
bool is_location_form(int form)
|
||||
{
|
||||
if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block ||
|
||||
form == DW_FORM_data4 || form == DW_FORM_data8 || form == DW_FORM_sec_offset) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char* GetExecutableName(char* path, uint32_t size)
|
||||
{
|
||||
char link[PATH_MAX];
|
||||
snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
|
||||
int nret = readlink(link, path, size);
|
||||
if (nret == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// trailing zero
|
||||
path[nret] = 0;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef struct __reginfo {
|
||||
__reginfo() {
|
||||
regname[0] = 0;
|
||||
@@ -166,70 +111,28 @@ void print_framereg(int regno)
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr)
|
||||
bool __pst_handler::calc_expr_block(Dwarf_Op *exprs, int expr_len, dwarf_stack* stack, Dwarf_Attribute* attr)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
//printf ("%s", (i + 1 < len ? ", " : ""));
|
||||
for (int i = 0; i < expr_len; i++) {
|
||||
const dwarf_op_map* map = find_op_map(exprs[i].atom);
|
||||
if(map) {
|
||||
if(map->op_num >= DW_OP_breg0 && map->op_num <= DW_OP_breg16) {
|
||||
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number);
|
||||
if(!map) {
|
||||
ctx.log(SEVERITY_ERROR, "Unknown operation type 0x%hhX", exprs[i].atom);
|
||||
return false;
|
||||
}
|
||||
|
||||
unw_word_t ptr = 0;
|
||||
unw_get_reg(&cursor, map->regno, &ptr);
|
||||
//ptr += off;
|
||||
if(map->op_num == DW_OP_stack_value && stack->Size() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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(!map->operation(&ctx, map, exprs[i].number, exprs[i].number2)) {
|
||||
return false;
|
||||
}
|
||||
// if(exprs[i].atom >= DW_OP_reg0 && exprs[i].atom <= DW_OP_bregx) {
|
||||
// print_framereg(exprs[i].atom);
|
||||
// }
|
||||
}
|
||||
|
||||
return offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool __pst_parameter::handle_type(Dwarf_Attribute* param, bool is_return)
|
||||
{
|
||||
Dwarf_Attribute attr_mem;
|
||||
@@ -239,7 +142,7 @@ bool __pst_parameter::handle_type(Dwarf_Attribute* param, bool is_return)
|
||||
Dwarf_Die ret_die;
|
||||
|
||||
if(!dwarf_formref_die(param, &ret_die)) {
|
||||
function->ctx->log(SEVERITY_ERROR, "Failed to get parameter DIE");
|
||||
ctx->log(SEVERITY_ERROR, "Failed to get parameter DIE");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -251,35 +154,47 @@ bool __pst_parameter::handle_type(Dwarf_Attribute* param, bool is_return)
|
||||
if(attr) {
|
||||
dwarf_formudata(attr, &size);
|
||||
}
|
||||
function->ctx->log(SEVERITY_INFO, "base type '%s'(%lu)", dwarf_diename(&ret_die), size);
|
||||
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");
|
||||
ctx->log(SEVERITY_INFO, "array type");
|
||||
types.push_back("[]");
|
||||
break;
|
||||
case DW_TAG_structure_type:
|
||||
ctx->log(SEVERITY_INFO, "structure type");
|
||||
types.push_back("struct");
|
||||
break;
|
||||
case DW_TAG_union_type:
|
||||
ctx->log(SEVERITY_INFO, "union type");
|
||||
types.push_back("union");
|
||||
break;
|
||||
case DW_TAG_class_type:
|
||||
ctx->log(SEVERITY_INFO, "class type");
|
||||
types.push_back("class");
|
||||
break;
|
||||
case DW_TAG_pointer_type:
|
||||
logger->Log(SEVERITY_INFO, "pointer type");
|
||||
ctx->log(SEVERITY_INFO, "pointer type");
|
||||
types.push_back("*");
|
||||
break;
|
||||
case DW_TAG_enumeration_type:
|
||||
logger->Log(SEVERITY_INFO, "enumeration type");
|
||||
ctx->log(SEVERITY_INFO, "enumeration type");
|
||||
types.push_back("enum");
|
||||
break;
|
||||
case DW_TAG_const_type:
|
||||
logger->Log(SEVERITY_INFO, "constant type");
|
||||
ctx->log(SEVERITY_INFO, "constant type");
|
||||
types.push_back("const");
|
||||
break;
|
||||
case DW_TAG_subroutine_type:
|
||||
logger->Log(SEVERITY_INFO, "subroutine type");
|
||||
ctx->log(SEVERITY_INFO, "subroutine type");
|
||||
break;
|
||||
case DW_TAG_typedef:
|
||||
logger->Log(SEVERITY_INFO, "typedef '%s' type", dwarf_diename(&ret_die));
|
||||
ctx->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));
|
||||
ctx->log(SEVERITY_INFO, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -300,7 +215,7 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
||||
|
||||
// Get reference to attribute type of the parameter/variable
|
||||
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
|
||||
function->ctx->log(SEVERITY_INFO, "Handle '%s' %s", dwarf_diename(result), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
||||
ctx->log(SEVERITY_INFO, "Handle '%s' %s", dwarf_diename(result), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
||||
if(attr) {
|
||||
handle_type(attr);
|
||||
}
|
||||
@@ -313,8 +228,8 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
||||
size_t exprlen;
|
||||
if (dwarf_getlocation(attr, &expr, &exprlen) == 0) {
|
||||
char str[1024]; str[0] = 0;
|
||||
function->ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
|
||||
function->ctx->log(SEVERITY_DEBUG, "Found DW_AT_location expression: %s", str);
|
||||
ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
|
||||
ctx->log(SEVERITY_DEBUG, "Found DW_AT_location expression: %s", str);
|
||||
// if(expr[0].atom >= DW_OP_reg0 && expr[0].atom <= DW_OP_bregx) {
|
||||
// print_framereg(expr[0].atom);
|
||||
// }
|
||||
@@ -327,12 +242,12 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
||||
|
||||
for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) {
|
||||
char str[1024]; str[0] = 0;
|
||||
function->ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
|
||||
function->ctx->log(SEVERITY_DEBUG, "[%d] low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 " ==> %s", i, start, end, str);
|
||||
ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
|
||||
ctx->log(SEVERITY_DEBUG, "[%d] low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 " ==> %s", i, start, end, str);
|
||||
}
|
||||
|
||||
} else {
|
||||
function->ctx->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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,16 +261,22 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
||||
Dwarf_Attribute attr_mem;
|
||||
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);
|
||||
// get list of offsets from process base address of continuous memory ranges where function's code resides
|
||||
// if(dwarf_haspc(d, pc)) {
|
||||
dwarf_lowpc(d, &lowpc);
|
||||
dwarf_highpc(d, &highpc);
|
||||
// } else {
|
||||
// ctx->log(SEVERITY_ERROR, "Function's '%s' DIE hasn't definitions of memory offsets of function's code", dwarf_diename(d));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
unw_proc_info_t info;
|
||||
unw_get_proc_info(&ctx->cursor, &info);
|
||||
unw_word_t sp;
|
||||
unw_get_reg(&ctx->cursor, UNW_REG_SP, &sp);
|
||||
|
||||
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);
|
||||
ctx->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, 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);
|
||||
|
||||
// determine function's stack frame base
|
||||
attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem);
|
||||
@@ -375,7 +296,7 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
||||
|
||||
// Get reference to return attribute type of the function
|
||||
// may be to use dwfl_module_return_value_location() instead
|
||||
pst_parameter ret_p(this); ret_p.is_return = true;
|
||||
pst_parameter ret_p(ctx); ret_p.is_return = true;
|
||||
attr = dwarf_attr(die, DW_AT_type, &attr_mem);
|
||||
if(attr) {
|
||||
ctx->log(SEVERITY_INFO, "Handle return parameter");
|
||||
@@ -394,7 +315,7 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
|
||||
|
||||
// went through parameters and local variables of the function
|
||||
do {
|
||||
pst_parameter param(this);
|
||||
pst_parameter param(ctx);
|
||||
|
||||
switch (dwarf_tag(&result)) {
|
||||
case DW_TAG_formal_parameter:
|
||||
@@ -467,7 +388,7 @@ bool __pst_function::unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr)
|
||||
}
|
||||
|
||||
|
||||
bool __pst_context::get_frame()
|
||||
bool __pst_handler::get_frame()
|
||||
{
|
||||
// get CFI (Call Frame Information) for current module
|
||||
// from handle_cfi()
|
||||
@@ -475,7 +396,7 @@ bool __pst_context::get_frame()
|
||||
Dwarf_CFI* cfi = dwfl_module_eh_cfi(module, &mod_bias);
|
||||
//Dwarf_CFI* cfi = dwfl_module_dwarf_cfi(module, &mod_bias);
|
||||
if(!cfi) {
|
||||
log(SEVERITY_INFO, "Cannot find CFI for module");
|
||||
ctx.log(SEVERITY_INFO, "Cannot find CFI for module");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -483,7 +404,7 @@ bool __pst_context::get_frame()
|
||||
int result = dwarf_cfi_addrframe (cfi, addr - mod_bias, &frame);
|
||||
if (result == 0) {
|
||||
// get frame information
|
||||
log(SEVERITY_INFO, "Found CFI frame for module");
|
||||
ctx.log(SEVERITY_INFO, "Found CFI frame for module");
|
||||
Dwarf_Addr start = addr;
|
||||
Dwarf_Addr end = addr;
|
||||
bool signalp;
|
||||
@@ -492,13 +413,13 @@ bool __pst_context::get_frame()
|
||||
start += mod_bias;
|
||||
end += mod_bias;
|
||||
}
|
||||
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", addr, start, end, signalp ? "true" : "false");
|
||||
if (ra_regno < 0)
|
||||
log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg(0));
|
||||
ctx.log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg(0));
|
||||
else {
|
||||
reginfo info; info.regno = ra_regno;
|
||||
dwfl_module_register_names(module, regname_callback, &info);
|
||||
log(SEVERITY_DEBUG, "return address in reg%u%s ==> %s", ra_regno, signalp ? " (signal frame)" : "", info.regname);
|
||||
ctx.log(SEVERITY_DEBUG, "return address in reg%u%s ==> %s", ra_regno, signalp ? " (signal frame)" : "", info.regname);
|
||||
}
|
||||
|
||||
// finally get CFA (Canonical Frame Address)
|
||||
@@ -509,33 +430,33 @@ bool __pst_context::get_frame()
|
||||
size_t cfa_nops;
|
||||
result = dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops);
|
||||
char str[1024]; str[0] = 0;
|
||||
print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
||||
log(SEVERITY_INFO, "Found CFA expression: %s", str);
|
||||
ctx.print_expr_block (cfa_ops, cfa_nops, str, sizeof(str));
|
||||
ctx.log(SEVERITY_INFO, "Found CFA expression: %s", str);
|
||||
//print_detail (result, cfa_ops, cfa_nops, mod_bias, "\tCFA ");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __pst_context::get_dwarf_function(pst_function& fun)
|
||||
bool __pst_handler::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);
|
||||
ctx.log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
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));
|
||||
ctx.log(SEVERITY_DEBUG, "Skipping non-cu die. DWARF tag: 0x%X, name = %s", dwarf_tag(cdie), dwarf_diename(cdie));
|
||||
return false;
|
||||
}
|
||||
|
||||
Dwarf_Die result;
|
||||
if(dwarf_child(cdie, &result)) {
|
||||
logger->Log(SEVERITY_ERROR, "No child DIE found for CU %s", dwarf_diename(cdie));
|
||||
ctx.log(SEVERITY_ERROR, "No child DIE found for CU %s", dwarf_diename(cdie));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -553,7 +474,7 @@ bool __pst_context::get_dwarf_function(pst_function& fun)
|
||||
return nret;
|
||||
}
|
||||
|
||||
void __pst_context::dwarf_print()
|
||||
void __pst_handler::dwarf_print()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -568,10 +489,10 @@ Dwfl_Callbacks callbacks = {
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
bool __pst_context::unwind()
|
||||
bool __pst_handler::unwind()
|
||||
{
|
||||
#ifdef REG_RIP // x86_64
|
||||
caller = (void *) hcontext->uc_mcontext.gregs[REG_RIP];
|
||||
caller = (void *) ctx.hcontext->uc_mcontext.gregs[REG_RIP];
|
||||
#elif defined(REG_EIP) // x86_32
|
||||
caller_address = (void *) uctx->uc_mcontext.gregs[REG_EIP]);
|
||||
#elif defined(__arm__)
|
||||
@@ -591,8 +512,8 @@ bool __pst_context::unwind()
|
||||
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);
|
||||
ctx.base_addr = (uint64_t)info.dli_fbase;
|
||||
ctx.log(SEVERITY_INFO, "Process address information: base address: %p, object name: %s", info.dli_fbase, info.dli_fname);
|
||||
|
||||
int skipped = 0;
|
||||
#ifndef USEI_LIBUNWIND
|
||||
@@ -604,27 +525,27 @@ bool __pst_context::unwind()
|
||||
#else
|
||||
unw_word_t pc;
|
||||
|
||||
unw_getcontext(&context);
|
||||
unw_init_local(&cursor, &context);
|
||||
while (unw_step(&cursor) > 0) {
|
||||
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||
unw_getcontext(&ctx.context);
|
||||
unw_init_local(&ctx.cursor, &ctx.context);
|
||||
while (unw_step(&ctx.cursor) > 0) {
|
||||
unw_get_reg(&ctx.cursor, UNW_REG_IP, &pc);
|
||||
if(pc == (uint64_t)caller) {
|
||||
break;
|
||||
} else {
|
||||
++skipped;
|
||||
}
|
||||
}
|
||||
print("Stack trace(caller = %p. Skipped stack frames: %d):\n", caller, skipped);
|
||||
ctx.print("Stack trace(caller = %p. Skipped stack frames: %d):\n", caller, skipped);
|
||||
#endif
|
||||
|
||||
dwfl = dwfl_begin(&callbacks);
|
||||
if(dwfl == NULL) {
|
||||
print("Failed to initialize libdw session for parse stack frames");
|
||||
ctx.print("Failed to initialize libdw session for parse stack frames");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dwfl_linux_proc_report(dwfl, getpid()) != 0 || dwfl_report_end(dwfl, NULL, NULL) !=0) {
|
||||
print("Failed to parse debug section of executable");
|
||||
ctx.print("Failed to parse debug section of executable");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -634,21 +555,21 @@ bool __pst_context::unwind()
|
||||
Dwarf_Addr addr = (uintptr_t)array[i];
|
||||
#else
|
||||
for (int i = skipped, idx = 0; true ; ++i, ++idx) {
|
||||
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||
unw_get_reg(&ctx.cursor, UNW_REG_IP, &pc);
|
||||
addr = pc;
|
||||
print("[%-2d] ", idx);
|
||||
ctx.print("[%-2d] ", idx);
|
||||
#endif
|
||||
module = dwfl_addrmodule(dwfl, addr);
|
||||
get_frame();
|
||||
pst_function fun(this);
|
||||
pst_function fun(&ctx);
|
||||
if(fun.unwind(dwfl, module, pc)) {
|
||||
if(get_dwarf_function(fun)) {
|
||||
functions.push_back(fun);
|
||||
}
|
||||
}
|
||||
print("\n");
|
||||
ctx.print("\n");
|
||||
#ifdef USEI_LIBUNWIND
|
||||
if(unw_step(&cursor) <= 0) {
|
||||
if(unw_step(&ctx.cursor) <= 0) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
+23
-30
@@ -21,18 +21,21 @@
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
char* GetExecutableName(char* path, uint32_t size);
|
||||
|
||||
typedef struct __pst_function pst_function;
|
||||
|
||||
typedef struct __pst_parameter {
|
||||
__pst_parameter(pst_function* fun) : function(fun)
|
||||
__pst_parameter(pst_context* c) : ctx(c)
|
||||
{
|
||||
die = NULL;
|
||||
size = 0;
|
||||
type = 0;
|
||||
loc = NULL;
|
||||
is_return = false;
|
||||
value = 0;
|
||||
}
|
||||
|
||||
bool handle_dwarf(Dwarf_Die* d);
|
||||
@@ -42,13 +45,14 @@ typedef struct __pst_parameter {
|
||||
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'
|
||||
std::vector<std::string> 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
|
||||
pst_function* function;
|
||||
uint64_t value; // value of parameter
|
||||
pst_context* ctx;
|
||||
} pst_parameter;
|
||||
|
||||
typedef struct __pst_context pst_context;
|
||||
typedef struct __pst_handler pst_handler;
|
||||
|
||||
typedef struct __pst_function {
|
||||
__pst_function(pst_context* ctx) : ctx(ctx)
|
||||
@@ -57,12 +61,14 @@ typedef struct __pst_function {
|
||||
line = -1;
|
||||
die = NULL;
|
||||
lowpc = 0;
|
||||
highpc = 0;
|
||||
}
|
||||
|
||||
bool unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr);
|
||||
bool handle_dwarf(Dwarf_Die* d);
|
||||
|
||||
Dwarf_Addr lowpc;
|
||||
Dwarf_Addr highpc;
|
||||
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
|
||||
@@ -72,21 +78,18 @@ typedef struct __pst_function {
|
||||
pst_context* ctx;
|
||||
} pst_function;
|
||||
|
||||
typedef struct __pst_context {
|
||||
__pst_context(ucontext_t* hctx) : hcontext(hctx)
|
||||
typedef struct __pst_handler {
|
||||
__pst_handler(ucontext_t* hctx) : ctx(hctx)
|
||||
{
|
||||
caller = NULL;
|
||||
module = NULL;
|
||||
dwfl = NULL;
|
||||
offset = 0;
|
||||
buff[0] = 0;
|
||||
frame = NULL;
|
||||
addr = 0;
|
||||
base_addr = 0;
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
~__pst_context()
|
||||
~__pst_handler()
|
||||
{
|
||||
if(handle) {
|
||||
dlclose(handle);
|
||||
@@ -94,30 +97,20 @@ typedef struct __pst_context {
|
||||
}
|
||||
|
||||
|
||||
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 calc_expr_block(Dwarf_Op *exprs, int exp_len, dwarf_stack* stack, Dwarf_Attribute* attr = 0);
|
||||
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);
|
||||
pst_context ctx; // context of unwinding
|
||||
void* handle; // process handle
|
||||
Dwarf_Addr addr; // address of currently processed function
|
||||
Dwfl* dwfl; // DWARF context
|
||||
Dwfl_Module* module; // currently processed CU
|
||||
Dwarf_Frame* frame; // currently processed stack frame
|
||||
void* caller; // pointer to the function which requested to unwind stack
|
||||
std::vector<pst_function> functions; // array of functions in stack frame
|
||||
} pst_handler;
|
||||
|
||||
#endif /* SC_SYSUTILS_H_ */
|
||||
|
||||
Reference in New Issue
Block a user