From 58f14a695dfe7d164a67f4cba29dd146a7b16124 Mon Sep 17 00:00:00 2001 From: Nikolai Nosov Date: Sat, 11 Jan 2020 14:56:45 +0400 Subject: [PATCH] extract context from handler and move it to common. define functions to use in calculation of DWARF expressions --- framework/.gitignore | 6 + framework/common.cpp | 258 +++++++++++++++++++++++++-------- framework/common.h | 97 ++++++++++++- framework/dwarf_operations.cpp | 127 ++++++++++++++++ framework/dwarf_operations.h | 19 +++ framework/linkedlist.h | 138 ++++++++++++++++++ framework/sysutils.cpp | 251 +++++++++++--------------------- framework/sysutils.h | 53 +++---- main.cpp | 6 +- 9 files changed, 688 insertions(+), 267 deletions(-) create mode 100644 framework/.gitignore create mode 100644 framework/dwarf_operations.cpp create mode 100644 framework/dwarf_operations.h create mode 100644 framework/linkedlist.h diff --git a/framework/.gitignore b/framework/.gitignore new file mode 100644 index 0000000..eecffaf --- /dev/null +++ b/framework/.gitignore @@ -0,0 +1,6 @@ +/CMakeFiles/ +/CMakeCache.txt +/install_manifest.txt +/cmake_install.cmake +/libframework.a +/Makefile diff --git a/framework/common.cpp b/framework/common.cpp index 7c1e58d..8580fcf 100644 --- a/framework/common.cpp +++ b/framework/common.cpp @@ -7,78 +7,130 @@ #include #include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/framework/common.h b/framework/common.h index 05895e5..ab87b16 100644 --- a/framework/common.h +++ b/framework/common.h @@ -1,13 +1,96 @@ #pragma once +#include +#include +#include +#include + +#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); diff --git a/framework/dwarf_operations.cpp b/framework/dwarf_operations.cpp new file mode 100644 index 0000000..f233fa6 --- /dev/null +++ b/framework/dwarf_operations.cpp @@ -0,0 +1,127 @@ +/* + * dwarf_operations.cpp + * + * Created on: Jan 11, 2020 + * Author: nnosov + */ + +#include +#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; +} diff --git a/framework/dwarf_operations.h b/framework/dwarf_operations.h new file mode 100644 index 0000000..983cc26 --- /dev/null +++ b/framework/dwarf_operations.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#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); diff --git a/framework/linkedlist.h b/framework/linkedlist.h new file mode 100644 index 0000000..c2cf61d --- /dev/null +++ b/framework/linkedlist.h @@ -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 + +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_ */ diff --git a/framework/sysutils.cpp b/framework/sysutils.cpp index 6209b3c..becabcb 100644 --- a/framework/sysutils.cpp +++ b/framework/sysutils.cpp @@ -14,11 +14,10 @@ #include #include #include +#include -#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 - 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 -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 diff --git a/framework/sysutils.h b/framework/sysutils.h index 84df3c7..dc09560 100644 --- a/framework/sysutils.h +++ b/framework/sysutils.h @@ -21,18 +21,21 @@ #include #include +#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 types; // list of parameters definitions i.e. 'typedef', 'uint32_t' + std::vector 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 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 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 functions; // array of functions in stack frame +} pst_handler; #endif /* SC_SYSUTILS_H_ */ diff --git a/main.cpp b/main.cpp index d170265..bd8d017 100644 --- a/main.cpp +++ b/main.cpp @@ -64,14 +64,14 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context) logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig)); bool trace = false; - pst_context ctx((ucontext_t*)context); + pst_handler handler((ucontext_t*)context); if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE)) { - trace = ctx.unwind(); + trace = handler.unwind(); } if(trace) { - logger->Log(SEVERITY_DEBUG, "%s", ctx.buff); + logger->Log(SEVERITY_DEBUG, "%s", handler.ctx.buff); } else { logger->Log(SEVERITY_ERROR, "No stack trace obtained"); }