From 8251ba526f22ca61e98c2ce35309b408c139c406 Mon Sep 17 00:00:00 2001 From: Nikolai Nosov Date: Sat, 1 Feb 2020 15:19:55 +0400 Subject: [PATCH] all code except of pst_function & pst_handler rewritten on C language. Logger nad Allocator decided to be a global for all library --- Makefile | 4 +- framework/Makefile | 4 +- framework/allocator.cpp | 54 ++- framework/allocator.h | 38 +- framework/common.cpp | 61 ---- framework/common.h | 12 +- framework/context.cpp | 154 +++++--- framework/context.h | 45 +-- framework/data_entry.h | 36 -- framework/dictionary.cpp | 71 ---- framework/dictionary.h | 275 -------------- framework/dwarf_expression.cpp | 174 +++++++++ framework/dwarf_expression.h | 55 +++ framework/dwarf_operations.cpp | 631 ++++++++++----------------------- framework/dwarf_operations.h | 116 +----- framework/dwarf_parameter.cpp | 304 ++++++++++++++++ framework/dwarf_parameter.h | 61 ++++ framework/dwarf_stack.cpp | 302 ++++++++++++++++ framework/dwarf_stack.h | 120 +++++++ framework/linkedlist.h | 138 ------- framework/list_head.h | 338 ++++++++++++++++++ framework/logger/log.cpp | 253 +++++++++++-- framework/logger/log.h | 150 ++------ framework/logger/log_console.h | 53 --- framework/logger/log_file.h | 108 ------ framework/mutex.h | 40 --- framework/registers.cpp | 1 + framework/sysutils.cpp | 423 ++++------------------ framework/sysutils.h | 99 +----- main.cpp | 21 +- 30 files changed, 2073 insertions(+), 2068 deletions(-) delete mode 100644 framework/data_entry.h delete mode 100644 framework/dictionary.cpp delete mode 100644 framework/dictionary.h create mode 100644 framework/dwarf_expression.cpp create mode 100644 framework/dwarf_expression.h create mode 100644 framework/dwarf_parameter.cpp create mode 100644 framework/dwarf_parameter.h create mode 100644 framework/dwarf_stack.cpp create mode 100644 framework/dwarf_stack.h delete mode 100644 framework/linkedlist.h create mode 100644 framework/list_head.h delete mode 100644 framework/logger/log_console.h delete mode 100644 framework/logger/log_file.h delete mode 100644 framework/mutex.h diff --git a/Makefile b/Makefile index a092b5e..e1593a9 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ NC= COLOR= endif -CXX = g++ +CXX = gcc CC = gcc RM = rm -f AR = ar rvs @@ -56,7 +56,7 @@ INCS = -I./ \ -I/usr/include/postgresql -I /usr/include/libxml2 -I./thirdparty -I/opt/swifttest/include -I/usr/include/GraphicsMagick \ -I./framework -I./framework/swi -I./framework/utils -I./framework/rmq -I./framework/logger -I$(BUILD_DIR) #FLAGS = -Wall -gdwarf-4 -fPIC -O3 -rdynamic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=c++11 -FLAGS = -Wall -ggdb -fPIC -O3 -rdynamic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=c++11 +FLAGS = -Wall -ggdb -fPIC -O3 -rdynamic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS .PHONY: all clean $(BIN) diff --git a/framework/Makefile b/framework/Makefile index b3eb1a1..bfeb573 100644 --- a/framework/Makefile +++ b/framework/Makefile @@ -16,7 +16,7 @@ NC= COLOR= endif -CXX = g++ +CXX = gcc CC = gcc RM = rm -f AR = ar rvs @@ -37,7 +37,7 @@ SRC = $(wildcard $(addsuffix /*.cpp,${VPATH})) OBJ = $(patsubst %.cpp,%.o,$(addprefix $(BUILD_DIR)/,$(notdir $(SRC)))) INCS = -I"../thirdparty" -I"./" -I"./utils" -I"./rmq" -I"/usr/include/json-c" -I"/usr/include/postgresql" -I /usr/include/libxml2 -I"/opt/swifttest/include" -I"../thirdparty/libswiftclient/src/lib" -FLAGS = -Wall -ggdb -fPIC -O3 -rdynamic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=c++11 -DSOFT_BUILD=$(SOFT_BUILD) -DUSER_BUILD=$(USER) -DDATE_BUILD="$(DATE_BUILD)" +FLAGS = -Wall -ggdb -fPIC -O3 -rdynamic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DSOFT_BUILD=$(SOFT_BUILD) -DUSER_BUILD=$(USER) -DDATE_BUILD="$(DATE_BUILD)" .PHONY: all clean diff --git a/framework/allocator.cpp b/framework/allocator.cpp index 15d498a..c5563b9 100644 --- a/framework/allocator.cpp +++ b/framework/allocator.cpp @@ -7,55 +7,71 @@ #include #include +#include +#include "common.h" #include "allocator.h" -void heap_free(pst_allocator& alloc, void* buff) +void heap_free(pst_allocator* alloc, void* buff) { - alloc.size -= malloc_usable_size(buff); + alloc->size -= malloc_usable_size(buff); free(buff); } -void* heap_alloc(pst_allocator& alloc, uint32_t size) +void* heap_alloc(pst_allocator* alloc, uint32_t size) { void* buff = malloc(size); - alloc.size += malloc_usable_size(buff); + alloc->size += malloc_usable_size(buff); return buff; } -void* heap_realloc(pst_allocator& alloc, void* buff, uint32_t new_size) +void* heap_realloc(pst_allocator* alloc, void* buff, uint32_t new_size) { - alloc.size -= malloc_usable_size(buff); + alloc->size -= malloc_usable_size(buff); void* new_buff = realloc(buff, new_size); - alloc.size += malloc_usable_size(new_buff); + alloc->size += malloc_usable_size(new_buff); return new_buff; } -void pst_alloc_init(pst_allocator& alloc) +void pst_alloc_init(pst_allocator* alloc) { - alloc.type = ALLOC_HEAP; - alloc.base = NULL; - alloc.size = 0; + alloc->type = ALLOC_HEAP; + alloc->base = NULL; + alloc->size = 0; - alloc.alloc = heap_alloc; - alloc.free = heap_free; - alloc.realloc = heap_realloc; + alloc->alloc = heap_alloc; + alloc->free = heap_free; + alloc->realloc = heap_realloc; return; } -void pst_alloc_init_custom(pst_allocator& alloc, void* buff, uint32_t size) +void pst_alloc_init_custom(pst_allocator* alloc, void* buff, uint32_t size) { // TBD to implement custom allocator pst_alloc_init(alloc); return; } -void pst_alloc_fini(pst_allocator& alloc) +void pst_alloc_fini(pst_allocator* alloc) { - alloc.type = ALLOC_NONE; - alloc.base = NULL; - alloc.size = 0; + if(alloc->type == ALLOC_HEAP || alloc->type == ALLOC_CUSTOM) { + alloc->type = ALLOC_NONE; + alloc->base = NULL; + alloc->size = 0; + } +} + +char* pst_dup(pst_allocator* alloc, const char* str) +{ + pst_assert(alloc && str); + + uint32_t len = strlen(str); + char* dst = (char*)alloc->alloc(len + 1); + memcpy(dst, str, len); + dst[len] = 0; + + return dst; } diff --git a/framework/allocator.h b/framework/allocator.h index afa4157..8020be2 100644 --- a/framework/allocator.h +++ b/framework/allocator.h @@ -5,17 +5,33 @@ * Author: nnosov */ -#ifndef FRAMEWORK_ALLOCATOR_H_ -#define FRAMEWORK_ALLOCATOR_H_ +#ifndef PST_ALLOCATOR_H_ +#define PST_ALLOCATOR_H_ -#include #include +#include + +// concatenation +#define CAT(a, ...) CAT2(a, __VA_ARGS__) +#define CAT2(a, ...) a ## __VA_ARGS__ + +// declaration with initialization +#define pst_decl(TYPE, NAME, ...) \ + TYPE NAME; CAT2(TYPE, _init) (&NAME, __VA_ARGS__); + +// allocation with initialization +#define pst_alloc(TYPE, NAME, ...) \ + TYPE* NAME; NAME = CAT2(TYPE, _new) (__VA_ARGS__); + +// de-initialization and deletion if was previously allocated +#define pst_free(TYPE, NAME) \ + CAT2(TYPE, _fini) (NAME); typedef struct __pst_allocator pst_allocator; -typedef void* (*pst_alloc_def)(pst_allocator& alloc, uint32_t size); -typedef void (*pst_free_def)(pst_allocator& alloc, void* buff); -typedef void* (*pst_realloc_def)(pst_allocator& alloc, void* buff, uint32_t new_size); +typedef void* (*pst_alloc_def)(pst_allocator* alloc, uint32_t size); +typedef void (*pst_free_def)(pst_allocator* alloc, void* buff); +typedef void* (*pst_realloc_def)(pst_allocator* alloc, void* buff, uint32_t new_size); typedef enum { ALLOC_NONE = 0, // not initialized @@ -33,8 +49,10 @@ typedef struct __pst_allocator { pst_realloc_def realloc; } pst_allocator; -void pst_alloc_init(pst_allocator& alloc); -void pst_alloc_init_custom(pst_allocator& alloc, void* buff, uint32_t size); -void pst_alloc_fini(pst_allocator& alloc); +void pst_alloc_init(pst_allocator* alloc); +void pst_alloc_init_custom(pst_allocator* alloc, void* buff, uint32_t size); +void pst_alloc_fini(pst_allocator* alloc); -#endif /* FRAMEWORK_ALLOCATOR_H_ */ +char* pst_dup(pst_allocator* alloc, const char* str); + +#endif /* PST_ALLOCATOR_H_ */ diff --git a/framework/common.cpp b/framework/common.cpp index 1707246..4a9970a 100644 --- a/framework/common.cpp +++ b/framework/common.cpp @@ -19,67 +19,6 @@ #include "dwarf_operations.h" #include "registers.h" -bool dwarf_value::get_int(int64_t& v) -{ - switch (size) { - case 1: - v = *((int8_t*)value); - break; - case 2: - v = *((int16_t*)value); - break; - case 4: - v = *((int32_t*)value); - break; - case 8: - v = *((int64_t*)value); - break; - default: - return false; - break; - } - - return true; -} - -bool dwarf_value::get_uint(uint64_t& v) -{ - if(type & DWARF_TYPE_SIGNED) { - int64_t sig; - if(!get_int(sig)) { - return false; - } - v = llabs(sig); - } else { - return get_generic(v); - } - - return true; -} - -bool dwarf_value::get_generic(uint64_t& v) -{ - switch (size) { - case 1: - v = *((uint8_t*)value); - break; - case 2: - v = *((uint16_t*)value); - break; - case 4: - v = *((uint32_t*)value); - break; - case 8: - v = *((uint64_t*)value); - break; - default: - return false; - break; - } - - return true; -} - bool is_location_form(int form) { if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block || diff --git a/framework/common.h b/framework/common.h index e4aa50d..97073b3 100644 --- a/framework/common.h +++ b/framework/common.h @@ -1,8 +1,18 @@ -#pragma once +#ifndef __PST_COMMON_H__ +#define __PST_COMMON_H__ + +#include #define USE_LIBUNWIND +// TBD custom assertion if needed +#define pst_assert(expr) assert(expr) + +// platform-dependent address size +#define PST_GENERIC_SIZE (8) // for x86_64 architecture int32_t decode_sleb128(uint8_t *sleb128); uint32_t decode_uleb128(uint8_t *uleb128); bool is_location_form(int form); + +#endif // __PST_COMMON_H__ diff --git a/framework/context.cpp b/framework/context.cpp index 57ddd20..27dd80e 100644 --- a/framework/context.cpp +++ b/framework/context.cpp @@ -13,140 +13,184 @@ #include "dwarf_operations.h" -extern SC_LogBase* logger; extern dwarf_reg_map reg_map[]; extern int regnum; -void __pst_context::print_stack(int max, uint64_t next_cfa) +pst_log logger; // logger for library + +void clean_print(pst_context* ctx) { + ctx->buff[0] = 0; + ctx->offset = 0; +} + +void print_stack(pst_context* ctx, int max, uint64_t next_cfa) { - log(SEVERITY_DEBUG, "CFA = %#lX, NEXT_CFA = %#lX, SP = %#lX", cfa, next_cfa, sp); - clean_print(); + ctx->log(SEVERITY_DEBUG, "CFA = %#lX, NEXT_CFA = %#lX, SP = %#lX", ctx->cfa, next_cfa, ctx->sp); + ctx->clean_print(ctx); int i = 0; - if(cfa > sp) { - print("Args: "); - for(; i < max && (cfa - i) > sp; ++i) { - print("#%d 0x%lX ", i, *(uint64_t*)(cfa - i)); + if(ctx->cfa > ctx->sp) { + ctx->print(ctx, "Args: "); + for(; i < max && (ctx->cfa - i) > ctx->sp; ++i) { + ctx->print(ctx, "#%d 0x%lX ", i, *(uint64_t*)(ctx->cfa - i)); } } - if((cfa - i) > next_cfa) { - print("Vars: "); - for(; i < max && (cfa - i) > next_cfa; ++i) { - print("#%d 0x%lX ", i, *(uint64_t*)(cfa - i)); + if((ctx->cfa - i) > next_cfa) { + ctx->print(ctx, "Vars: "); + for(; i < max && (ctx->cfa - i) > next_cfa; ++i) { + ctx->print(ctx, "#%d 0x%lX ", i, *(uint64_t*)(ctx->cfa - i)); } } } -void __pst_context::print_registers(int from, int to) +void print_registers(pst_context* ctx, int from, int to) { - clean_print(); + ctx->clean_print(ctx); for(int i = from; i < regnum && i <= to; ++i) { unw_word_t regval; - if(!unw_get_reg(curr_frame, reg_map[i].regno, ®val)) { - print("%s: %#lX ", reg_map[i].regname, regval); + if(!unw_get_reg(ctx->curr_frame, reg_map[i].regno, ®val)) { + ctx->print(ctx, "%s: %#lX ", reg_map[i].regname, regval); } else { - print("%s: ", reg_map[i].regname); + ctx->print(ctx, "%s: ", reg_map[i].regname); } } } -bool __pst_context::print(const char* fmt, ...) +bool print(pst_context* ctx, 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); + int size = sizeof(ctx->buff) - ctx->offset; + int ret = vsnprintf(ctx->buff + ctx->offset, size, fmt, args); if(ret >= size || ret < 0) { nret = false; } - offset += ret; + ctx->offset += ret; va_end(args); return nret; } -void __pst_context::log(SC_LogSeverity severity, const char* fmt, ...) +void 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); + logger.log(&logger, severity, fmt); } -uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr) +bool print_expr_block (pst_context* ctx, Dwarf_Op *exprs, int exprlen, Dwarf_Attribute* attr) { - uint32_t offset = 0; - for (int i = 0; i < len; i++) { - //printf ("%s", (i + 1 < len ? ", " : "")); + ctx->clean_print(ctx); + for (int i = 0; i < exprlen; 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); int regno = map->op_num - DW_OP_breg0; unw_word_t ptr = 0; - unw_get_reg(curr_frame, regno, &ptr); - //ptr += off; + unw_get_reg(ctx->curr_frame, regno, &ptr); - offset += snprintf(buff + offset, buff_size - offset, "%s(*%s%s%d) reg_value: 0x%lX", map->op_name, unw_regname(regno), off >=0 ? "+" : "", off, ptr); + ctx->print(ctx, "%s(*%s%s%d) reg_value: 0x%lX", map->op_name, unw_regname(regno), off >=0 ? "+" : "", off, ptr); } else if(map->op_num >= DW_OP_reg0 && map->op_num <= DW_OP_reg16) { unw_word_t value = 0; int regno = map->op_num - DW_OP_reg0; - unw_get_reg(curr_frame, regno, &value); - offset += snprintf(buff + offset, buff_size - offset, "%s(*%s) value: 0x%lX", map->op_name, unw_regname(regno), value); + unw_get_reg(ctx->curr_frame, regno, &value); + ctx->print(ctx, "%s(*%s) value: 0x%lX", map->op_name, unw_regname(regno), value); } else if(map->op_num == DW_OP_GNU_entry_value) { + if(!attr) { + ctx->log(SEVERITY_ERROR, "No attribute of DW_OP_GNU_entry_value provided"); + return false; + } uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number); - offset += snprintf(buff + offset, buff_size - offset, "%s(%u, ", map->op_name, value); + ctx->print(ctx, "%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_mem); - offset += snprintf(buff + offset, buff_size - offset, ") "); + ctx->print_expr(ctx, expr, exprlen, &attr_mem); + ctx->print(ctx, ") "); } else { - log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location"); + ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location"); + return false; } } else { - log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr expression"); + ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr expression"); + return false; } } else if(map->op_num == DW_OP_stack_value) { - offset += snprintf(buff + offset, buff_size - offset, "%s", map->op_name); + ctx->print(ctx, "%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); + ctx->print(ctx, "%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(curr_frame, regno, &ptr); + unw_get_reg(ctx->curr_frame, 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); + ctx->print(ctx, "%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(curr_frame, reg, &value); + unw_get_reg(ctx->curr_frame, reg, &value); - offset += snprintf(buff + offset, buff_size - offset, "%s(%s) value = 0x%lX", map->op_name, unw_regname(reg), value); + ctx->print(ctx, "%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 = %p", map->op_name, (void*)exprs[i].number); + ctx->print(ctx, "%s value = %p", map->op_name, (void*)exprs[i].number); } else if(map->op_num == DW_OP_fbreg) { int32_t off = decode_sleb128((unsigned char*)&exprs[i].number); - offset += snprintf(buff + offset, buff_size - offset, "%s(SP%s%d) ", map->op_name, off >=0 ? "+" : "", off); + ctx->print(ctx, "%s(SP%s%d) ", map->op_name, off >=0 ? "+" : "", off); } else { - offset += snprintf(buff + offset, buff_size - offset, "%s(0x%lX, 0x%lx) ", map->op_name, exprs[i].number, exprs[i].number2); + ctx->print(ctx, "%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); + ctx->print(ctx, "0x%hhX(0x%lX, 0x%lx)", exprs[i].atom, exprs[i].number, exprs[i].number2); } } - return offset; + return true; } +void pst_context_init(pst_context* ctx, pst_allocator* alloc, ucontext_t* hctx) +{ + // global + pst_alloc_init(&allocator); + pst_log_init_console(&logger); + // methods + ctx->clean_print = clean_print; + ctx->print = print; + ctx->log = log; + ctx->print_expr = print_expr_block; + ctx->print_registers = print_registers; + ctx->print_stack = print_stack; + + // fields + ctx->hcontext = hctx; + ctx->clean_print(ctx); + ctx->base_addr = 0; + ctx->sp = 0; + ctx->cfa = 0; + ctx->curr_frame = NULL; + ctx->frame = NULL; + ctx->dwfl = NULL; + ctx->module = NULL; +} + +void pst_context_fini(pst_context* ctx) +{ + ctx->hcontext = NULL; + ctx->clean_print(ctx); + ctx->base_addr = 0; + ctx->sp = 0; + ctx->cfa = 0; + ctx->curr_frame = NULL; + ctx->frame = NULL; + ctx->dwfl = NULL; + ctx->module = NULL; + + // global + pst_log_fini(&logger); + pst_alloc_fini(&allocator); +} diff --git a/framework/context.h b/framework/context.h index e07211f..44464ac 100644 --- a/framework/context.h +++ b/framework/context.h @@ -15,51 +15,40 @@ #include #include "logger/log.h" +#include "allocator.h" + +extern pst_log logger; // logger for whole PST library +extern pst_allocator allocator; // custom allocator for PS library typedef struct __pst_context { - __pst_context(ucontext_t* hctx) : hcontext(hctx) - { - clean_print(); - base_addr = 0; - sp = 0; - cfa = 0; - curr_frame = NULL; - frame = NULL; - dwfl = NULL; - module = NULL; - } - - 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); - void print_registers(int from, int to); - void print_stack(int max, uint64_t next_cfa); - void clean_print() { - buff[0] = 0; - offset = 0; - } - - const char* get_print() { - return buff; - } + // methods + void (*clean_print) (__pst_context* ctx); + bool (*print) (__pst_context* ctx, const char* fmt, ...); + void (*log) (SC_LogSeverity severity, const char*fmt, ...); + bool (*print_expr) (__pst_context* ctx, Dwarf_Op *exprs, int exprlen, Dwarf_Attribute* attr); + void (*print_registers) (__pst_context* ctx, int from, int to); + void (*print_stack) (__pst_context* ctx, int max, uint64_t next_cfa); + // fields ucontext_t* hcontext; // context of signal handler unw_context_t context; // context of stack trace - unw_cursor_t cursor; + unw_cursor_t cursor; // libunwind stack frame storage unw_cursor_t* curr_frame; // callee libunwind frame Dwarf_Addr base_addr; // base address where process loaded Dwarf_Addr sp; // stack pointer of currently processed stack frame - Dwarf_Addr cfa; // CFA (Canonical Frame Address) of currently processed stack + Dwarf_Addr cfa; // CFA (Canonical Frame Address) of currently processed stack frame Dwarf_Frame* frame; // currently examined libdwfl frame Dwfl* dwfl; // DWARF context Dwfl_Module* module; // currently processed CU -protected: + // print buffer char buff[8192]; // stack trace buffer uint32_t offset; // offset in the 'buff' } pst_context; +void pst_context_init(pst_context* ctx, ucontext_t* hctx); +void pst_context_fini(pst_context* ctx); #endif /* FRAMEWORK_CONTEXT_H_ */ diff --git a/framework/data_entry.h b/framework/data_entry.h deleted file mode 100644 index eb443d3..0000000 --- a/framework/data_entry.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * data_entry.h - * - * Created on: Oct 30, 2013 - * Author: nnosov - * - * Simple representation of data. Pointer to data and size of data. - */ - -#ifndef DATA_ENTRY_H_ -#define DATA_ENTRY_H_ - - -//system -#include - -typedef struct _SC_Data -{ - _SC_Data() - { - data = 0; - size =0; - } - - _SC_Data(const char* _data, uint32_t _size) - { - data = (char*)_data; - size = _size; - } - - char* data; - uint32_t size; -} SC_Data; - - -#endif /* DATA_ENTRY_H_ */ diff --git a/framework/dictionary.cpp b/framework/dictionary.cpp deleted file mode 100644 index 738efa5..0000000 --- a/framework/dictionary.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * dictionary.cpp - * - * Created on: Oct 28, 2014 - * Author: nnosov - */ -#include "dictionary.h" - -//framework -#include "logger/log.h" - -extern SC_LogBase* logger; - -typedef struct __key_value { - const char* key; - uint32_t keylen; - int value; -} key_value; - -#define KEY_VALUE(key, value) {key, sizeof(key), value} - -key_value utable[] = { - KEY_VALUE("key1", 1), - KEY_VALUE("key2", 2), - KEY_VALUE("key1", 3), -}; - - -bool SC_Dict::UnitTest() -{ - logger->Log(SEVERITY_DEBUG, "%s: starting ...", __PRETTY_FUNCTION__); - logger->Log(SEVERITY_DEBUG, "\t\tshift = %d, hash function = %p, number of buckets = %d, mask = 0x%X. count = %d", mShift, pHashFn, mSize, mMask, mCount); - logger->Log(SEVERITY_DEBUG, "... inserting values into the dictionary ..."); - for(uint32_t i = 0; i < sizeof(utable) / sizeof(key_value); i++) - { - logger->Log(SEVERITY_DEBUG, "\t\tKey = %s, Key size = %d, Key value = %d", utable[i].key, utable[i].keylen, utable[i].value); - Insert(utable[i].key, utable[i].keylen, &(utable[i].value)); - } - logger->Log(SEVERITY_DEBUG, "\t\tdictionary size = %d",mCount); - logger->Log(SEVERITY_DEBUG, "... went through the dictionary sequentially ..."); - for(void* data = First(); data; data = Next()) - { - logger->Log(SEVERITY_DEBUG, "\t\tvalue = %d", *((int*)data)); - } - - logger->Log(SEVERITY_DEBUG, "... went through the dictionary in key order ..."); - for(uint32_t i = 0; i < sizeof(utable) / sizeof(key_value); i++) - { - void* data = Lookup(utable[i].key, utable[i].keylen); - if(data) - logger->Log(SEVERITY_DEBUG, "\t\tKey = %s, Key size = %d, Key value = %d", utable[i].key, utable[i].keylen, *((int*)data)); - } - - void* data = Lookup(utable[0].key, utable[0].keylen); - if(data) - { - logger->Log(SEVERITY_DEBUG, "... removing first key[%s] ...", utable[0].key); - Remove(); - } - - logger->Log(SEVERITY_DEBUG, "... went through the dictionary in key order 2 ..."); - for(uint32_t i = 0; i < sizeof(utable) / sizeof(key_value); i++) - { - void* data = Lookup(utable[i].key, utable[i].keylen); - if(data) - logger->Log(SEVERITY_DEBUG, "\t\tKey = %s, Key size = %d, Key value = %d", utable[i].key, utable[i].keylen, *((int*)data)); - } - - logger->Log(SEVERITY_DEBUG, "%s: finished.", __PRETTY_FUNCTION__); - return true; -} diff --git a/framework/dictionary.h b/framework/dictionary.h deleted file mode 100644 index bbda9be..0000000 --- a/framework/dictionary.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - * dictionary.h - * - * Created on: Aug 5, 2014 - * Author: nnosov - */ - -#ifndef DICTIONARY_H_ -#define DICTIONARY_H_ - -//system -#include -#include - -//framework -#include "data_entry.h" -#include "linkedlist.h" - -#define HASH_MIN_SHIFT (8) -#define HASH_MAX_SHIFT (15) - -typedef uint32_t (* SC_HashFn)(const void *key, uint32_t key_size); - -inline uint32_t hash_bernstein(const void* key, uint32_t key_size) -{ - uint32_t hash = 0; - register unsigned char* p = (unsigned char*)key; - - for (unsigned int i = 0; i < key_size; i++) - { - hash = 33 * hash + p[i]; - } - - return hash; -} - -inline uint32_t hash_sdbm(const void *key, uint32_t key_size) -{ - uint32_t hash = 0; - register unsigned char* p = (unsigned char*)key; - - for (uint32_t i = 0; i < key_size; i++) - { - hash = p[i] + (hash << 6) + (hash << 16) - hash; - } - - return hash; -} - -inline uint32_t hash_fnv(const void *key, uint32_t key_size ) -{ - register unsigned char *p = (unsigned char*)key; - uint32_t hash = 2166136261U; - - for (uint32_t i = 0; i < key_size; i++ ) - { - hash = ( hash * 16777619 ) ^ p[i]; - } - - return hash; -} - -typedef struct __SC_DictItem : public SC_ListNode -{ - __SC_DictItem() - { - data = 0; - hash = 0; - } - - ~__SC_DictItem() - { - if(key.data) { - delete[] key.data; - } - key.data = 0; - key.size = 0; - } - - void* data; - SC_Data key; - uint32_t hash; -} SC_DictItem; - -class SC_Dict -{ -private: - SC_Dict(SC_Dict& other) : pHashFn(0), mCurIdx(0), pCurItem(0), mCount(0), mShift(0), mMask(0), mBuckets(0), mSize(0){(void) other;} - -public: - SC_Dict(uint16_t shift = 8, SC_HashFn fn = hash_bernstein) : pHashFn(fn), mCurIdx(0), pCurItem(0), mCount(0) - { - if(shift <= HASH_MIN_SHIFT) { - mShift = HASH_MIN_SHIFT; - } else if(shift >= HASH_MAX_SHIFT) { - mShift = HASH_MAX_SHIFT; - } else { - mShift = shift; - } - - mSize = 1UL << shift; - mMask = mSize -1; - - mBuckets = new SC_ListHead[mSize]; - } - - virtual ~SC_Dict() - { - Clean(); - delete[] mBuckets; - } - - void Clean() - { - First(); - while(mCount) Remove(); - mCurIdx = 0; - pCurItem = 0; - } - - - inline void Insert(const void* key, uint32_t size, void* data) - { - SC_DictItem* item = new SC_DictItem; - item->hash = pHashFn(key, size); - item->data = data; - - // save key - item->key.data = new char[size]; - memcpy(item->key.data, key, size); - item->key.size = size; - - mCurIdx = item->hash & mMask; - - for(pCurItem = (SC_DictItem*)mBuckets[mCurIdx].First(); pCurItem ; pCurItem = (SC_DictItem*)mBuckets[mCurIdx].Next(pCurItem)) - { - if(pCurItem->key.size == item->key.size) - { - if(!memcmp(pCurItem->key.data, item->key.data, size)) - { - pCurItem->data = data; - delete item; - return; - } - } - } - mBuckets[mCurIdx].InsertLast(item); - pCurItem = item; - mCount++; - } - - void Remove() - { - SC_DictItem* item = pCurItem; - if(item) - { - MoveNext(); - mBuckets[item->hash & mMask].Remove(item); - if(pCurItem == item) - pCurItem = 0; - delete item; - mCount--; - } - } - - //returns first data in dictionary - inline void* First() - { - if(!mCount) - { - return 0; - } - - mCurIdx = 0; - pCurItem = 0; - MoveNext(); - - return pCurItem ? pCurItem->data : 0; - } - - //returns next data in dictionary - inline void* Next() - { - MoveNext(); - return pCurItem ? pCurItem->data : 0; - } - - //looking up for the next data - inline void* LookupNext(const void* key, uint32_t size) - { - uint32_t hash = pHashFn(key, size); - - for(SC_DictItem* curr = (SC_DictItem*)mBuckets[mCurIdx].Next(pCurItem); curr; curr = (SC_DictItem*)mBuckets[mCurIdx].Next(curr)) - { - if(curr->hash == hash && curr->key.size == size) - { - if(!memcmp(key, curr->key.data, size)) - { - pCurItem = curr; - return curr->data; - } - } - } - - return 0; - } - - //looking up for the first data corresponds to the key value - inline void* Lookup(const void* key, uint32_t size) - { - uint32_t hash = pHashFn(key, size); - uint32_t idx = hash & mMask; - for(SC_DictItem* curr = (SC_DictItem*)mBuckets[idx].First(); curr; curr = (SC_DictItem*)mBuckets[idx].Next(curr)) - { - if(curr->hash == hash && curr->key.size == size) - { - if(!memcmp(key, curr->key.data, size)) - { - mCurIdx = idx; - pCurItem = curr; - return curr->data; - } - } - } - - return 0; - } - - uint32_t Size() - { - return mCount; - } - -protected: - inline SC_DictItem* MoveNext() - { - if(mCurIdx >= mSize) - { - return 0; - } - - if(pCurItem) - { - pCurItem = (SC_DictItem*)mBuckets[mCurIdx].Next(pCurItem); - if(!pCurItem) - mCurIdx++; - } - - while(!pCurItem && mCurIdx < mSize) - { - pCurItem = (SC_DictItem*)mBuckets[mCurIdx].First(); - if(pCurItem) - break; - mCurIdx++; - } - - return pCurItem; - } -public: - virtual bool UnitTest(); - -protected: - - SC_HashFn pHashFn; //hash function - uint32_t mCurIdx; //index of current bucket - SC_DictItem* pCurItem; //current item - uint32_t mCount; //number of elements in dictionary - uint32_t mShift; //shift of the hash - uint32_t mMask; //mask to be applied to the hash - SC_ListHead* mBuckets; //Buckets of hash table - uint32_t mSize; //size of array in buckets -}; - - -#endif /* DICTIONARY_H_ */ diff --git a/framework/dwarf_expression.cpp b/framework/dwarf_expression.cpp new file mode 100644 index 0000000..d04b285 --- /dev/null +++ b/framework/dwarf_expression.cpp @@ -0,0 +1,174 @@ +/* + * dwarf_expression.cpp + * + * Created on: Feb 1, 2020 + * Author: nnosov + */ + +#include + +#include "dwarf_expression.h" +#include "common.h" + +// +// DWARF operation +// +void pst_dwarf_op_init(pst_dwarf_op* dwop, uint8_t op, uint64_t a1, uint64_t a2) +{ + //pst_assert(dwop); + + list_node_init(&dwop->node); + dwop->operation = op; + dwop->arg1 = a1; + dwop->arg2 = a2; + dwop->allocated = false; +} + +pst_dwarf_op* pst_dwarf_op_new(pst_allocator* alloc, uint8_t op, uint64_t a1, uint64_t a2) +{ + pst_assert(alloc); + + pst_dwarf_op* nop = (pst_dwarf_op*)alloc->alloc(alloc, sizeof(pst_dwarf_op)); + if(nop) { + pst_dwarf_op_init(nop, op, a1, a2); + nop->allocated = true; + } + + return nop; +} + +void pst_dwarf_op_fini(pst_dwarf_op* dwop) +{ + assert(dwop); + + if(dwop->allocated) { + allocator.free(dwop); + } else { + dwop->operation = 0; + dwop->arg1 = 0; + dwop->arg2 = 0; + } +} + +// +// pst_dwarf_expr +// +bool expr_is_equal(pst_dwarf_expr* lhs, pst_dwarf_expr* rhs) +{ + if(list_count(&lhs->operations) != list_count(&rhs->operations)) { + return false; + } + + pst_dwarf_op* lop = lhs->next_op(NULL); + pst_dwarf_op* rop = rhs->next_op(NULL); + while(lop && rop) { + if(lop->operation == rop->operation && lop->arg1 == rop->arg1 && lop->arg2 == rop->arg2) { + return true; + } + lop = lhs->next_op(lop); + rop = rhs->next_op(rop); + } + + return false; +} + +pst_dwarf_op* expr_add_op(pst_dwarf_expr* expr, uint8_t operation, uint64_t arg1, uint64_t arg2) +{ + pst_alloc(pst_dwarf_op, op, operation, arg1, arg2); + list_add_bottom(&expr->operations, &op->node); + + return op; +} + +pst_dwarf_op* expr_next_op(pst_dwarf_expr* expr, pst_dwarf_op* op) +{ + struct list_node* n = (op == NULL) ? list_first(&expr->operations) : list_next(&op->node); + + pst_dwarf_op* ret = NULL; + if(n) { + ret = list_entry(n, pst_dwarf_op, node); + } + + return ret; +} + +bool expr_print_op(pst_dwarf_expr* expr, const char* fmt, ...) +{ + bool nret = true; + + va_list args; + va_start(args, fmt); + int size = sizeof(expr->buff) - expr->offset; + int ret = vsnprintf(expr->buff + expr->offset, size, fmt, args); + if(ret >= size || ret < 0) { + nret = false; + } + expr->offset += ret; + va_end(args); + + return nret; +} + +void expr_set_value(pst_dwarf_expr* expr, uint64_t v) +{ + expr->has_value = true; + expr->value = v; +} + +void expr_clean(pst_dwarf_expr* expr) +{ + pst_dwarf_op* op = NULL; + struct list_node *pos, *tn; + list_for_each_entry_safe(op, pos, tn, &expr->operations, node) { + list_del(&op->node); + pst_dwarf_op_fini(op); + } +} + +void expr_setup(pst_dwarf_expr* expr, Dwarf_Op* exprs, size_t exprlen) +{ + expr->clean(); + for(size_t i = 0; i < exprlen; ++i) { + expr->add_op(expr, exprs[i].atom, exprs[i].number, exprs[i].number2); + } +} + +void pst_dwarf_expr_init(pst_dwarf_expr* expr) +{ + // methods + expr->is_equal = expr_is_equal; + expr->add_op = expr_add_op; + expr->next_op = expr_next_op; + expr->clean = expr_clean; + expr->setup = expr_setup; + expr->set_value = expr_set_value; + expr->print_op = expr_print_op; + + // fields + list_head_init(&expr->operations); + expr->has_value = false; + expr->value = 0; + + expr->buff[0] = 0; + expr->offset = 0; + expr->allocated = false; +} + +pst_dwarf_expr* pst_dwarf_expr_new() +{ + pst_dwarf_expr* ne = allocator.alloc(sizeof(pst_dwarf_expr)); + if(ne) { + pst_dwarf_expr_init(ne); + ne->allocated = true; + } + + return ne; +} + +void pst_dwarf_expr_fini(pst_dwarf_expr* expr) +{ + expr->clean(); + if(expr->allocated) { + allocator.free(expr); + } +} diff --git a/framework/dwarf_expression.h b/framework/dwarf_expression.h new file mode 100644 index 0000000..9f438a4 --- /dev/null +++ b/framework/dwarf_expression.h @@ -0,0 +1,55 @@ +/* + * dwarf_expression.h + * + * Created on: Feb 1, 2020 + * Author: nnosov + */ + +#ifndef FRAMEWORK_DWARF_EXPRESSION_H_ +#define FRAMEWORK_DWARF_EXPRESSION_H_ + +#include +#include + +#include "list_head.h" +#include "allocator.h" + +// DWARF operation (represents our own DW_OP_XXX) +typedef struct { + list_node node; //uplink + + uint8_t operation; + uint64_t arg1; + uint64_t arg2; + bool allocated; +} pst_dwarf_op; +void pst_dwarf_op_init(pst_dwarf_op* dwop, uint8_t op, uint64_t a1, uint64_t a2); +pst_dwarf_op* pst_dwarf_op_new(uint8_t op, uint64_t a1, uint64_t a2); +void pst_dwarf_op_fini(pst_dwarf_op* dwop); + + +// DWARF expression +typedef struct pst_dwarf_expr { + // methods + bool (*is_equal)(pst_dwarf_expr* lhs, pst_dwarf_expr* rhs); + pst_dwarf_op* (*add_op) (pst_dwarf_expr* expr, uint8_t op, uint64_t arg1, uint64_t arg2); + pst_dwarf_op* (*next_op) (pst_dwarf_expr* expr, pst_dwarf_op* op); + void (*clean) (pst_dwarf_expr* expr); + void (*setup) (pst_dwarf_expr* expr, Dwarf_Op* exprs, size_t exprlen); + void (*set_value) (pst_dwarf_expr* expr, uint64_t v); + bool (*print_op) (pst_dwarf_expr* expr, const char* fmt, ...); + + // fields + list_head operations; + bool has_value; + uint64_t value; + char buff[512]; + uint16_t offset; + bool allocated; +} pst_dwarf_expr; +void pst_dwarf_expr_init(pst_dwarf_expr* expr); +pst_dwarf_expr* pst_dwarf_expr_new(); +void pst_dwarf_expr_fini(pst_dwarf_expr* expr); + + +#endif /* FRAMEWORK_DWARF_EXPRESSION_H_ */ diff --git a/framework/dwarf_operations.cpp b/framework/dwarf_operations.cpp index 44737df..a610c1a 100644 --- a/framework/dwarf_operations.cpp +++ b/framework/dwarf_operations.cpp @@ -10,19 +10,19 @@ #include "dwarf_operations.h" #include "common.h" +#include "registers.h" // not implemented operations -bool dw_op_notimpl(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_notimpl(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - stack->ctx->log(SEVERITY_ERROR, "%s(0x%lX, 0x%lX) operation is not implemented", map->op_name, op1, op2); return false; } // The DW_OP_addr operation has a single operand that encodes a machine // address and whose size is the size of an address on the target machine. -bool dw_op_addr(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_addr(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - stack->push(&op1, sizeof(op1), DWARF_TYPE_GENERIC); + stack->push(stack, &op1, sizeof(op1), DWARF_TYPE_GENERIC); return true; } @@ -32,30 +32,31 @@ bool dw_op_addr(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwa // retrieved is zero extended to the size of an address on the target machine // before being pushed onto the expression stack. -bool dw_op_deref_size(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_deref_size(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->pop(); + pst_dwarf_value* value = stack->pop(stack); if(value) { - uint64_t addr; - if(value->get_uint(addr)) { - uint64_t res = 0; - switch(op1) { - case 1: - res = *((uint8_t*)addr); - break; - case 2: - res = *((uint16_t*)addr); - break; - case 4: - res = *((uint32_t*)addr); - break; - case 8: - res = *((uint64_t*)addr); - break; - } - stack->push(&res, sizeof(res), DWARF_TYPE_GENERIC); - return true; + uint64_t addr = value->value.uint64; + uint64_t res = 0; + switch(op1) { + case 1: + res = *((uint8_t*)addr); + break; + case 2: + res = *((uint16_t*)addr); + break; + case 4: + res = *((uint32_t*)addr); + break; + case 8: + res = *((uint64_t*)addr); + break; + default: + return false; + break; } + stack->push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC); + return true; } return false; @@ -64,17 +65,17 @@ bool dw_op_deref_size(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op // The DW_ OP_deref operation pops the top stack entry and treats it as an address. // The popped value must have an integral type. The value retrieved from that address is pushed, and has the generic type. // The size of the data retrieved from the dereferenced address is the size of an address on the target machine. -bool dw_op_deref(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_deref(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { return dw_op_deref_size(stack, map, 8, op2); } // DW_OP_const1u, DW_OP_const2u, DW_OP_const4u, DW_OP_const8u. The single operand of a DW_OP_constu operation provides a 1, 2, 4, or 8-byte unsigned integer constant, respectively. // These operations push a value with the generic type -bool dw_op_const_x_u(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_const_x_u(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { uint8_t size = 0; - dwarf_value_type type = DWARF_TYPE_UNSIGNED; + pst_dwarf_value_type type = DWARF_TYPE_UNSIGNED; switch (map->op_num) { case DW_OP_const1u: size = 1; @@ -96,17 +97,17 @@ bool dw_op_const_x_u(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1 return false; } - stack->push(&op1, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); + stack->push(stack, &op1, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); return true; } // DW_OP_const1s, DW_OP_const2s, DW_OP_const4s, DW_OP_const8s. The single operand of a DW_OP_consts operation provides a 1, 2, 4, or 8-byte signed integer constant, respectively. // These operations push a value with the generic type -bool dw_op_const_x_s(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_const_x_s(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { uint8_t size; int64_t v; - dwarf_value_type type = DWARF_TYPE_SIGNED; + pst_dwarf_value_type type = DWARF_TYPE_SIGNED; switch (map->op_num) { case DW_OP_const1s: v = (int8_t)op1; @@ -132,62 +133,62 @@ bool dw_op_const_x_s(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1 return false; } - stack->push(&v, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); + stack->push(stack, &v, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); return true; } // The single operand of the DW_OP_constu operation provides an unsigned LEB128 integer constant. -bool dw_op_constu(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_constu(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { uint64_t value = decode_uleb128((unsigned char*)&op1); - stack->push(&value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_UNSIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); + stack->push(stack, &value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_UNSIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); return true; } -bool dw_op_consts(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_consts(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { // The single operand of the DW_OP_consts operation provides a signed LEB128 integer constant. int64_t value = decode_sleb128((unsigned char*)&op1); - stack->push(&value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_SIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); + stack->push(stack, &value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_SIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC); return true; } // The DW_OP_dup operation duplicates the value (including its type identifier) at the top of the stack. -bool dw_op_dup(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_dup(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->get(); - stack->push(value->value, value->size, value->type); + pst_dwarf_value* value = stack->get(stack, 0); + stack->push(stack, &value->value, sizeof(value->value), value->type); return true; } // The DW_OP_drop operation pops the value (including its type identifier) at the top of the stack. -bool dw_op_drop(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_drop(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->pop(); - free(value); + pst_dwarf_value* value = stack->pop(stack); + pst_dwarf_value_fini(value); return true; } // The DW_OP_over operation duplicates the entry currently second in the stack at the top of the stack. // This is equivalent to a DW_OP_pick operation, with index 1. -bool dw_op_over(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_over(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->get(1); - stack->push(value->value, value->size, value->type); + pst_dwarf_value* value = stack->get(stack, 1); + stack->push(stack, &value->value, sizeof(value->value), value->type); return true; } // The single operand of the DW_OP_pick operation provides a 1-byte index. // A copy of the stack entry (including its type identifier) with the specified index (0 through 255, inclusive) is pushed onto the stack. -bool dw_op_pick(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_pick(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->get(op1); + pst_dwarf_value* value = stack->get(stack, op1); if(value) { - stack->push(value->value, value->size, value->type); + stack->push(stack, &value->value, sizeof(value->value), value->type); return true; } @@ -196,21 +197,21 @@ bool dw_op_pick(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwa // The DW_OP_swap operation swaps the top two stack entries. The entry at the top of the stack (including its type identifier) becomes the second stack // entry, and the second entry (including its type identifier) becomes the top of the stack. -bool dw_op_swap(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_swap(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->pop(); - dwarf_value* value2 = stack->pop(); + pst_dwarf_value* value1 = stack->pop(stack); + pst_dwarf_value* value2 = stack->pop(stack); if(value1 && value2) { - stack->push(value1); - stack->push(value2); + stack->push_value(stack, value1); + stack->push_value(stack, value2); return true; } if(value1) { - delete(value1); + pst_dwarf_value_fini(value1); } if(value2) { - delete(value2); + pst_dwarf_value_fini(value2); } return false; @@ -220,26 +221,26 @@ bool dw_op_swap(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwa // The entry at the top of the stack (including its type identifier) becomes the third stack entry, // the second entry (including its type identifier) becomes the top of the stack, // and the third entry (including its type identifier) becomes the second entry -bool dw_op_rot(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_rot(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->pop(); - dwarf_value* value2 = stack->pop(); - dwarf_value* value3 = stack->pop(); + pst_dwarf_value* value1 = stack->pop(stack); + pst_dwarf_value* value2 = stack->pop(stack); + pst_dwarf_value* value3 = stack->pop(stack); if(value1 && value2 && value3) { - stack->push(value1); - stack->push(value3); - stack->push(value2); + stack->push_value(stack, value1); + stack->push_value(stack, value3); + stack->push_value(stack, value2); return true; } if(value1) { - free(value1); + pst_dwarf_value_fini(value1); } if(value2) { - free(value2); + pst_dwarf_value_fini(value2); } if(value3) { - free(value3); + pst_dwarf_value_fini(value3); } return false; @@ -247,45 +248,33 @@ bool dw_op_rot(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar // The DW_OP_abs operation pops the top stack entry, interprets it as a signed value and pushes its absolute value. // If the absolute value cannot be represented, the result is undefined. -bool dw_op_abs(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_abs(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->get(); + pst_dwarf_value* value = stack->get(stack, 0); if(value) { - int64_t v; - if(!value->get_int(v)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong %d size of stack value", value->size); - return false; - } - uint64_t res = llabs(v); - value->replace(&res, value->size, DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC | DWARF_TYPE_LONG); + uint64_t res = llabs(value->value.int64); + value->set(value, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC | DWARF_TYPE_LONG); } return false; } // The DW_OP_and operation pops the top two stack values, performs a bitwise and operation on the two, and pushes the result. -bool dw_op_and(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_and(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->get(0); - dwarf_value* value2 = stack->get(1); + pst_dwarf_value* value1 = stack->get(stack, 0); + pst_dwarf_value* value2 = stack->get(stack, 1); if(value1 && value2) { if(!(value1->type & value2->type)) { - stack->ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type); - return false; - } - uint64_t v1 = 0, v2 = 0; - if(!value1->get_generic(v1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); return false; } - if(!value2->get_generic(v2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } - uint64_t res = v1 & v2; - stack->pop(); stack->pop(); - stack->push(&res, value1->size, DWARF_TYPE_GENERIC); + uint64_t res = value1->value.uint64 & value2->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC); + + pst_dwarf_value_fini(value1); + pst_dwarf_value_fini(value2); return true; } @@ -293,84 +282,49 @@ bool dw_op_and(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar } // The DW_OP_div operation pops the top two stack values, divides the former second entry by the former top of the stack using signed division, and pushes the result. -bool dw_op_div(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_div(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->get(0); - dwarf_value* value2 = stack->get(1); + pst_dwarf_value* value1 = stack->get(stack, 0); + pst_dwarf_value* value2 = stack->get(stack, 1); if(value1 && value2) { if(!(value1->type & value2->type)) { - stack->ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type); return false; } if(value2->type & DWARF_TYPE_SIGNED) { - int64_t sig2; - if(!value2->get_int(sig2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } if(value1->type & DWARF_TYPE_SIGNED) { - int64_t sig1; - if(!value1->get_int(sig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); + if(value1->value.int64 == 0) { return false; } - if(sig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig2); - return false; - } - uint64_t res = sig2 / sig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); + uint64_t res = value2->value.int64 / value1->value.int64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); return true; } else { - uint64_t unsig1; - if(!value1->get_uint(unsig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); + if(value1->value.uint64 == 0) { return false; } - if(unsig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, sig2); - return false; - } - int64_t res = sig2 / unsig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); + int64_t res = value2->value.int64 / value1->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); return true; } } else { - uint64_t unsig2; - if(!value2->get_uint(unsig2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } if(value1->type & DWARF_TYPE_SIGNED) { - int64_t sig1; - if(!value1->get_int(sig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); + if(value1->value.int64 == 0) { return false; } - if(sig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig1); - return false; - } - int64_t res = unsig2 / sig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); + int64_t res = value2->value.uint64 / value1->value.int64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); return true; } else { - uint64_t unsig1; - if(!value1->get_uint(unsig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); + if(value1->value.uint64 == 0) { return false; } - if(unsig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, unsig2); - return false; - } - uint64_t res = unsig2 / unsig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); + uint64_t res = value2->value.uint64 / value1->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); return true; } } @@ -380,32 +334,23 @@ bool dw_op_div(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar } // The DW_OP_minus operation pops the top two stack values, subtracts the former top of the stack from the former second entry, and pushes the result. -bool dw_op_minus(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_minus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->get(0); - dwarf_value* value2 = stack->get(1); + pst_dwarf_value* value1 = stack->get(stack, 0); + pst_dwarf_value* value2 = stack->get(stack, 1); if(value1 && value2) { if(!(value1->type & value2->type)) { - stack->ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); return false; } - // use arithmetic by modulo 1 plus - uint64_t unsig1; uint64_t unsig2; - if(!value1->get_uint(unsig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } - if(!value2->get_uint(unsig2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value2->size); - return false; - } + int res_type = DWARF_TYPE_GENERIC; if(value2->type & DWARF_TYPE_MEMORY_LOC) { res_type |= DWARF_TYPE_MEMORY_LOC; } - uint64_t res = unsig2 - unsig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), res_type); + // use arithmetic by modulo 1 plus + uint64_t res = value2->value.uint64 - value1->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), res_type); return true; } @@ -414,34 +359,23 @@ bool dw_op_minus(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dw } // The DW_OP_mod operation pops the top two stack values and pushes the result of the calculation: former second stack entry modulo the former top of the stack. -bool dw_op_mod(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_mod(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->get(0); - dwarf_value* value2 = stack->get(1); + pst_dwarf_value* value1 = stack->get(stack, 0); + pst_dwarf_value* value2 = stack->get(stack, 1); if(value1 && value2) { if(!(value1->type & value2->type)) { - stack->ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); - return false; - } - uint64_t v1 = 0, v2 = 0; - if(!value1->get_uint(v1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); return false; } - if(v1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero requested, aborting."); + if(value1->value.uint64 == 0) { return false; } - if(!value2->get_uint(v2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } + uint64_t res = value2->value.uint64 % value1->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); - uint64_t res = v2 % v1; - stack->pop(); stack->pop(); - stack->push(&res, value1->size, DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); return true; } @@ -449,10 +383,10 @@ bool dw_op_mod(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar } // The DW_OP_mul operation pops the top two stack entries, multiplies them together, and pushes the result. -bool dw_op_mul(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_mul(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->get(0); - dwarf_value* value2 = stack->get(1); + pst_dwarf_value* value1 = stack->get(stack, 0); + pst_dwarf_value* value2 = stack->get(stack, 1); if(value1 && value2) { if(!(value1->type & value2->type)) { stack->ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type); @@ -460,73 +394,31 @@ bool dw_op_mul(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar } if(value2->type & DWARF_TYPE_SIGNED) { - int64_t sig2; - if(!value2->get_int(sig2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } if(value1->type & DWARF_TYPE_SIGNED) { - int64_t sig1; - if(!value1->get_int(sig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } - if(sig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig2); - return false; - } - uint64_t res = sig2 * sig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); + uint64_t res = value2->value.int64 * value1->value.int64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); + return true; } else { - uint64_t unsig1; - if(!value1->get_uint(unsig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } - if(unsig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, sig2); - return false; - } - int64_t res = sig2 * unsig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); + int64_t res = value2->value.int64 * value1->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); + return true; } } else { - uint64_t unsig2; - if(!value2->get_uint(unsig2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } if(value1->type & DWARF_TYPE_SIGNED) { - int64_t sig1; - if(!value1->get_int(sig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } - if(sig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig1); - return false; - } - int64_t res = unsig2 * sig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); + int64_t res = value2->value.uint64 * value1->value.int64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC); + return true; } else { - uint64_t unsig1; - if(!value1->get_uint(unsig1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } - if(unsig1 == 0) { - stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, unsig2); - return false; - } - uint64_t res = unsig2 * unsig1; - stack->pop(); stack->pop(); - stack->push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); + uint64_t res = value2->value.uint64 * value1->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC); + return true; } } @@ -537,62 +429,31 @@ bool dw_op_mul(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar // The DW_OP_neg operation pops the top stack entry, interprets it as a signed value and pushes its negation. // If the negation cannot be represented, the result is undefined. -bool dw_op_neg(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_neg(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->get(); + pst_dwarf_value* value = stack->get(stack, 0); if(value) { - int64_t v = 0; - if(!value->get_int(v)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size); - return false; - } - v *= -1; - - switch (value->size) { - case 1: { - int8_t vv = (int8_t)v; - value->replace(&vv, sizeof(vv), value->type); - break; - } - case 2: { - int16_t vv = (int16_t)v; - value->replace(&vv, sizeof(vv), value->type); - break; - } - case 4: { - int32_t vv = (int32_t)v; - value->replace(&vv, sizeof(vv), value->type); - break; - } - case 8: { - value->replace(&v, sizeof(v), value->type); - break; - } - default: - stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size); - return false; - break; - } - - return true; + if(value->type & DWARF_TYPE_CHAR) { + value->value.int8 *= -1; + } else if(value->type & DWARF_TYPE_SHORT) { + value->value.int16 *= -1; + } else if(value->type & DWARF_TYPE_INT) { + value->value.int32 *= -1; + } else { + value->value.int64 *= -1; + } + return true; } return false; } // The DW_OP_not operation pops the top stack entry, and pushes its bitwise complement. -bool dw_op_not(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_not(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->get(); + pst_dwarf_value* value = stack->get(stack, 0); if(value) { - uint64_t v = 0; - if(!value->get_uint(v)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size); - return false; - } - v = ~v; - - value->replace(&v, value->size, value->type); + value->value.uint64 = ~value->value.uint64; return true; } @@ -601,29 +462,22 @@ bool dw_op_not(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar } // The DW_OP_or operation pops the top two stack entries, performs a bitwise or operation on the two, and pushes the result. -bool dw_op_or(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_or(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->get(0); - dwarf_value* value2 = stack->get(1); + pst_dwarf_value* value1 = stack->get(stack, 0); + pst_dwarf_value* value2 = stack->get(stack, 1); if(value1 && value2) { if(!(value1->type & value2->type)) { - stack->ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); - return false; - } - uint64_t v1 = 0, v2 = 0; - if(!value1->get_uint(v1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); return false; } - if(!value2->get_uint(v2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; - } + uint64_t res = value2->value.uint64 | value1->value.uint64; + stack->pop(stack); stack->pop(stack); + stack->push(stack, &res, sizeof(res), value1->type); + + pst_dwarf_value_fini(value1); + pst_dwarf_value_fini(value2); - uint64_t res = v2 | v1; - stack->pop(); stack->pop(); - stack->push(&res, value1->size, value1->type); return true; } @@ -631,30 +485,30 @@ bool dw_op_or(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf } // The DW_OP_plus operation pops the top two stack entries, adds them together, and pushes the result -bool dw_op_plus(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_plus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value1 = stack->get(0); - dwarf_value* value2 = stack->get(1); + pst_dwarf_value* value1 = stack->get(stack, 0); + pst_dwarf_value* value2 = stack->get(stack, 1); if(value1 && value2) { if(!(value1->type & value2->type)) { - stack->ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); - return false; - } - int64_t v1 = 0, v2 = 0; - if(!value1->get_int(v1)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); return false; } - if(!value2->get_int(v2)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); - return false; + if((value1->type & DWARF_TYPE_SIGNED) && (value2->type & DWARF_TYPE_SIGNED)) { + int64_t res = value2->value.int64 + value1->value.int64; + stack->push(stack, &res, sizeof(res), value1->type); + } else { + // if in arithmetic expression even one operand is unsigned then result is unsigned as well + int type = (value1->type & (~DWARF_TYPE_SIGNED)) | DWARF_TYPE_UNSIGNED; + uint64_t res = value2->value.uint64 + value1->value.uint64; + stack->push(stack, &res, sizeof(res), type); } - uint64_t res = v2 + v1; - stack->pop(); stack->pop(); - stack->push(&res, value1->size, value1->type); - return true; + stack->pop(stack); stack->pop(stack); + pst_dwarf_value_fini(value1); + pst_dwarf_value_fini(value2); + + return true; } return false; @@ -664,18 +518,12 @@ bool dw_op_plus(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwa // operand popped from the top of the stack and pushes the result. // This operation is supplied specifically to be able to encode more field offsets in two // bytes than can be done with “DW_OP_lit DW_OP_plus.” -bool dw_op_plus_uconst(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_plus_uconst(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* value = stack->get(); + pst_dwarf_value* value = stack->get(stack, 0); if(value) { uint64_t op = decode_uleb128((unsigned char*)&op1); - uint64_t v = 0; - if(!value->get_generic(v)) { - stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size); - return false; - } - v += op; - value->replace(&v, sizeof(v), value->type); + value->value.uint64 += op; return true; } @@ -686,7 +534,7 @@ bool dw_op_plus_uconst(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word o // 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. // The DW_OP_regx operation has a single unsigned LEB128 literal operand that encodes the name of a register -bool dw_op_reg_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_reg_x(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { if(map->op_num != DW_OP_regx && (map->op_num < DW_OP_reg0 || map->op_num > DW_OP_reg31)) { return false; @@ -699,7 +547,7 @@ bool dw_op_reg_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dw regno = map->op_num - DW_OP_reg0; } - stack->push(®no, sizeof(regno), DWARF_TYPE_REGISTER_LOC); + stack->push(stack, ®no, sizeof(regno), DWARF_TYPE_REGISTER_LOC); return true; } @@ -707,7 +555,7 @@ bool dw_op_reg_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dw // 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) // 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. -bool dw_op_breg_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_breg_x(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { if(map->op_num != DW_OP_bregx && (map->op_num < DW_OP_breg0 || map->op_num > DW_OP_breg31)) { return false; @@ -725,26 +573,25 @@ bool dw_op_breg_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, D unw_word_t val = 0; int ret = unw_get_reg(stack->ctx->curr_frame, regno, &val); if(ret) { - stack->ctx->log(SEVERITY_ERROR, "%s: Failed to get register 0x%X value. Error: %d", __PRETTY_FUNCTION__, regno, ret); return false; } val += off; - stack->push(&val, sizeof(val), DWARF_TYPE_GENERIC); + stack->push(stack, &val, sizeof(val), DWARF_TYPE_GENERIC); return true; } // The DW_OP_lit operations encode the unsigned literal values from 0 through 31, inclusive. // Operations other than DW_OP_const_type push a value with the generic type. -bool dw_op_lit_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_lit_x(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { if(map->op_num < DW_OP_lit0 || map->op_num > DW_OP_lit31) { return false; } uint64_t val = map->op_num - DW_OP_lit0; - stack->push(&val, sizeof(val), DWARF_TYPE_GENERIC); + stack->push(stack, &val, sizeof(val), DWARF_TYPE_GENERIC); return true; } @@ -752,10 +599,10 @@ bool dw_op_lit_x(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dw // 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. -bool dw_op_stack_value(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_stack_value(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { - dwarf_value* v = stack->get(); + pst_dwarf_value* v = stack->get(stack, 0); if(v) { v->type = DWARF_TYPE_GENERIC; return true; @@ -765,7 +612,7 @@ bool dw_op_stack_value(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word o } // The DW_OP_call_frame_cfa operation pushes the value of the CFA, obtained from the Call Frame Information (see Section 6.4 on page 171). -bool dw_op_call_frame_cfa(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_call_frame_cfa(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { // since we are already know SP value, just push it to DWARF stack // unw_word_t sp; @@ -775,14 +622,14 @@ bool dw_op_call_frame_cfa(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Wor // return false; // } - stack->push(&stack->ctx->cfa, sizeof(stack->ctx->cfa), /*DWARF_TYPE_MEMORY_LOC | */DWARF_TYPE_GENERIC); + stack->push(stack, &stack->ctx->cfa, sizeof(stack->ctx->cfa), /*DWARF_TYPE_MEMORY_LOC | */DWARF_TYPE_GENERIC); return true; } // 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 -bool dw_op_fbreg(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) +bool dw_op_fbreg(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) { // since in signal handler we are know SP value, just use it as DW_AT_frame_base unw_word_t sp; @@ -796,7 +643,7 @@ bool dw_op_fbreg(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dw int64_t off = decode_sleb128((unsigned char*)&op1); sp += off; - stack->push(&sp, sizeof(sp), DWARF_TYPE_MEMORY_LOC | DWARF_TYPE_GENERIC); + stack->push(stack, &sp, sizeof(sp), DWARF_TYPE_MEMORY_LOC | DWARF_TYPE_GENERIC); return true; } @@ -989,107 +836,3 @@ const dwarf_op_map* find_op_map(int op) return NULL; } - -bool __dwarf_stack::get_value(uint64_t& value) -{ - if(!Size()) { - return false; - } - - value = 0; - dwarf_value* v = get(); - v->get_uint(value); - if(v->type & DWARF_TYPE_REGISTER_LOC) { - // dereference register location - uint64_t regno = value; - int ret = unw_get_reg(ctx->curr_frame, regno, &value); - if(ret) { - ctx->log(SEVERITY_ERROR, "Failed to get value of register 0x%X. Error: %d", regno, ret); - return false; - } - } else if(v->type & DWARF_TYPE_MEMORY_LOC) { - // dereference memory location - uint64_t addr = *(uint64_t*)v->value; - value = *((uint64_t*)addr); - } - - return true; -} - -bool __dwarf_stack::calc_expression(Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun) -{ - clear(); - for (int i = 0; i < expr_len; i++) { - const dwarf_op_map* map = find_op_map(exprs[i].atom); - if(!map) { - ctx->log(SEVERITY_ERROR, "Unknown operation type 0x%hhX(0x%lX, 0x%lX)", exprs[i].atom, exprs[i].number, exprs[i].number2); - return false; - } - - pst_dwarf_op* op = new pst_dwarf_op(exprs[i].atom, exprs[i].number, exprs[i].number2); - expr.InsertLast(op); - - dwarf_value* v = get(); - // dereference register location there if it is not last in stack - if(v && (v->type & DWARF_TYPE_REGISTER_LOC)) { - unw_word_t value = 0; - uint64_t regno = *((uint64_t*)v->value); - int ret = unw_get_reg(ctx->curr_frame, regno, &value); - if(ret) { - ctx->log(SEVERITY_ERROR, "Failed to ger value of register 0x%X. Error: %d", regno, ret); - return false; - } - v->replace(&value, sizeof(value), DWARF_TYPE_GENERIC); - } - - // handle there because it contains sub-expression of a Location in caller's frame - if(map->op_num == DW_OP_GNU_entry_value) { - if(!fun) { - ctx->log(SEVERITY_ERROR, "Cannot calculate DW_OP_GNU_entry_value expression while function is undefined"); - return false; - } - if(!fun->parent) { - ctx->log(SEVERITY_ERROR, "Function has not parent while calculate DW_OP_GNU_entry_value expression"); - return false; - } - // 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 - 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) { - pst_call_site* cs = fun->parent->find_call_site(fun); - if(!cs) { - ctx->log(SEVERITY_ERROR, "Failed to find call site while calculate DW_OP_GNU_entry_value expression"); - return false; - } - pst_dwarf_expr loc; loc.setup(expr, exprlen); - pst_call_site_param* param = cs->find_param(loc); - if(!param) { - ctx->log(SEVERITY_ERROR, "Failed to find call site parameter while calculate DW_OP_GNU_entry_value expression"); - return false; - } - - push(¶m->value, sizeof(param->value), DWARF_TYPE_GENERIC); - - continue; - } else { - ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location"); - return false; - } - } else { - ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr expression"); - return false; - } - } - - if(!map->operation(this, map, exprs[i].number, exprs[i].number2)) { - ctx->log(SEVERITY_ERROR, "Failed to calculate %s(0x%lX, 0x%lX) operation", map->op_name, exprs[i].number, exprs[i].number2); - return false; - } - - } - - return true; -} diff --git a/framework/dwarf_operations.h b/framework/dwarf_operations.h index 873508f..8f22385 100644 --- a/framework/dwarf_operations.h +++ b/framework/dwarf_operations.h @@ -3,124 +3,15 @@ #include #include "common.h" -#include "linkedlist.h" +#include "list_head.h" #include "sysutils.h" #include "context.h" -typedef enum { - DWARF_TYPE_INVALID = 0, // no type - DWARF_TYPE_SIGNED = 1, // signed type - DWARF_TYPE_UNSIGNED = 2, // unsigned type - DWARF_TYPE_CONST = 4, // constant signed/unsigned type - DWARF_TYPE_GENERIC = 8, // size of machine address type - DWARF_TYPE_CHAR = 16, // 1 byte size - DWARF_TYPE_FLOAT = 32, // machine-dependent floating point size - DWARF_TYPE_REGISTER_LOC = 64, // value located in register specified as 'value' - DWARF_TYPE_MEMORY_LOC = 128, // value located in memory address specified as 'value' - DWARF_TYPE_PIECE = 256, // piece of whole value located in current value - DWARF_TYPE_SHORT = 512, // 2 byte size - DWARF_TYPE_INT = 1024, // 4 byte size - DWARF_TYPE_LONG = 2048 // 8 byte size -} dwarf_value_type; - -typedef struct __dwarf_value : public SC_ListNode { - __dwarf_value(char*v, uint32_t s, int t) - { - size = s; - value = (char*)malloc(s); - memcpy(value, v, s); - type = t; - } - - ~__dwarf_value() - { - if(value) { - free(value); - value = NULL; - size = 0; - } - } - - void replace(void* v, uint32_t s, int t) - { - if(value) { - free(value); - size = 0; - type = DWARF_TYPE_INVALID; - } - - value = (char*)malloc(s); - memcpy(value, v, s); - size = s; - type = t; - } - - bool get_uint(uint64_t& v); - bool get_int(int64_t& v); - bool get_generic(uint64_t& v); - - char* value; - uint32_t size; // size in bytes except of 'DWARF_TYPE_PIECE', in such case in bits - int type; // bitmask of DWARF_TYPE_XXX -} dwarf_value; - -typedef struct __dwarf_stack : public SC_ListHead { - __dwarf_stack(pst_context* c) : ctx(c) { - attr = NULL; - } - - ~__dwarf_stack() { - for(pst_dwarf_op* op = (pst_dwarf_op*)expr.First(); op; op = (pst_dwarf_op*)expr.First()) { - expr.Remove(op); - delete op; - } - } - - void clear() { - for(dwarf_value* v = (dwarf_value*)First(); v; v = (dwarf_value*)First()) { - Remove(v); - delete v; - } - } - - void push(void* v, uint32_t s, int t) { - dwarf_value* value = new dwarf_value((char*)v, s, t); - 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_value* get(uint32_t idx = 0) { - dwarf_value* value = NULL; - for(value = (dwarf_value*)First(); value && idx; value = (dwarf_value*)Next(value)) { - idx--; - } - - return value; - } - - bool calc_expression(Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun = NULL); - bool get_value(uint64_t& value); - - Dwarf_Attribute* attr; // attribute which expression currently processed - SC_ListHead expr; // DWARF expression - pst_context* ctx; -} dwarf_stack; +#include "dwarf_stack.h" typedef struct __dwarf_op_map dwarf_op_map; -typedef bool (*dwarf_operation)(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2); +typedef bool (*dwarf_operation)(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2); typedef struct __dwarf_op_map { int op_num; // DWARF Operation DW_OP_XXX @@ -129,4 +20,3 @@ typedef struct __dwarf_op_map { } dwarf_op_map; const dwarf_op_map* find_op_map(int op); -int find_regnum(uint32_t op); diff --git a/framework/dwarf_parameter.cpp b/framework/dwarf_parameter.cpp new file mode 100644 index 0000000..3595f53 --- /dev/null +++ b/framework/dwarf_parameter.cpp @@ -0,0 +1,304 @@ +/* + * dwarf_parameter.cpp + * + * Created on: Feb 1, 2020 + * Author: nnosov + */ + +#include + +#include "dwarf_parameter.h" + +// +// pst_type +// +void pst_type_init(pst_type* t, const char* name, uint32_t type) +{ + list_node_init(&t->node); + t->name = pst_dup(&allocator, name); + t->type = type; + t->allocated = false; +} + +pst_type* pst_type_new(const char* name, uint32_t type) +{ + pst_type* nt = (pst_type*)allocator.alloc(&allocator, sizeof(pst_type)); + if(nt) { + pst_type_init(nt, name, type); + nt->allocated = true; + } + + return nt; +} + +void pst_type_fini(pst_type* t) +{ + allocator.free(&allocator, t->name); + if(t->allocated) { + allocator.free(&allocator, t); + } +} + +// +// pst_parameter +// +bool param_print_dwarf(pst_parameter* param) +{ + if(list_count(¶m->types)) { + if(!param->is_return) { + if(param->has_value) { + param->ctx->print(param->ctx, "%s %s = 0x%lX", param->next_type(NULL)->name, param->name, param->location.value); + } else { + param->ctx->print(param->ctx, "%s %s = ", param->next_type(NULL)->name, param->name); + } + } else { + param->ctx->print(param->ctx, "%s", param->next_type(NULL)->name); + } + } else { + if(param->has_value) { + param->ctx->print(param->ctx, "%s = 0x%lX", param->name, param->location.value); + } else { + param->ctx->print(param->ctx, "%s = ", param->name); + } + } + return true; +} + +bool param_handle_type(pst_parameter* param, Dwarf_Attribute* base) +{ + Dwarf_Attribute attr_mem; + Dwarf_Attribute* attr; + + // get DIE of return type + Dwarf_Die ret_die; + + if(!dwarf_formref_die(base, &ret_die)) { + logger.log(SEVERITY_ERROR, "Failed to get parameter DIE"); + return false; + } + + switch (dwarf_tag(&ret_die)) { + case DW_TAG_base_type: { + // get Size attribute and it's value + param->size = 0; + attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem); + if(attr) { + dwarf_formudata(attr, ¶m->size); + } + logger.log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->size); + param->add_type(dwarf_diename(&ret_die), DW_TAG_base_type); + param->type = DW_TAG_base_type; + + attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem); + if(attr) { + param->enc_type = 0; + dwarf_formudata(attr, ¶m->enc_type); + } + break; + } + case DW_TAG_array_type: + logger.log(SEVERITY_DEBUG, "array type"); + param->add_type("[]", DW_TAG_array_type); + break; + case DW_TAG_structure_type: + logger.log(SEVERITY_DEBUG, "structure type"); + param->add_type("struct", DW_TAG_structure_type); + break; + case DW_TAG_union_type: + logger.log(SEVERITY_DEBUG, "union type"); + param->add_type("union", DW_TAG_union_type); + break; + case DW_TAG_class_type: + logger.log(SEVERITY_DEBUG, "class type"); + param->add_type("class", DW_TAG_class_type); + break; + case DW_TAG_pointer_type: + logger.log(SEVERITY_DEBUG, "pointer type"); + param->add_type("*", DW_TAG_pointer_type); + break; + case DW_TAG_enumeration_type: + logger.log(SEVERITY_DEBUG, "enumeration type"); + param->add_type("enum", DW_TAG_enumeration_type); + break; + case DW_TAG_const_type: + logger.log(SEVERITY_DEBUG, "constant type"); + param->add_type("const", DW_TAG_const_type); + break; + case DW_TAG_subroutine_type: + logger.log(SEVERITY_DEBUG, "Skipping subroutine type"); + break; + case DW_TAG_typedef: + logger.log(SEVERITY_DEBUG, "typedef '%s' type", dwarf_diename(&ret_die)); + param->add_type(dwarf_diename(&ret_die), DW_TAG_typedef); + break; + default: + logger.log(SEVERITY_WARNING, "Unknown 0x%X tag type", dwarf_tag(&ret_die)); + break; + } + + attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem); + if(attr) { + return param->handle_type(attr); + } + + return true; +} + +pst_type* param_add_type(pst_parameter* param, const char* name, int type) +{ + pst_alloc(pst_type, t, name, type); + list_add_bottom(¶m->types, &t->node); + + return t; +} + +void param_clear(pst_parameter* param) +{ + pst_type* t = NULL; + struct list_node *pos, *tn; + list_for_each_entry_safe(t, pos, tn, ¶m->types, node) { + list_del(&t->node); + pst_type_fini(t); + } +} + +pst_type* param_next_type(pst_parameter* param, pst_type* t) +{ + list_node* n = (t == NULL) ? list_first(¶m->types) : list_next(&t->node); + pst_type* ret = NULL; + if(n) { + ret = list_entry(n, pst_type, node); + } + + return ret; +} + +bool param_handle_dwarf(pst_parameter* param, Dwarf_Die* result, __pst_function* fun) +{ + param->die = result; + + Dwarf_Attribute attr_mem; + Dwarf_Attribute* attr; + + param->name = pst_dup(&allocator, dwarf_diename(result)); + param->is_variable = (dwarf_tag(result) == DW_TAG_variable); + + dwarf_decl_line(result, (int*)¶m->line); + // Get reference to attribute type of the parameter/variable + attr = dwarf_attr(result, DW_AT_type, &attr_mem); + logger.log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable"); + if(attr) { + param->handle_type(param, attr); + } + + if(dwarf_hasattr(result, DW_AT_location)) { + // determine location of parameter in stack/heap or CPU registers + attr = dwarf_attr(result, DW_AT_location, &attr_mem); + Dwarf_Addr pc; + unw_get_reg(param->ctx->curr_frame, UNW_REG_IP, &pc); + + if(handle_location(param->ctx, attr, ¶m->location, pc, fun)) { + param->has_value = true; + } else { + logger.log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", param->ctx->buff); + return false; + } + } else if(dwarf_hasattr(result, DW_AT_const_value)) { + // no locations definitions, value is constant, known by DWARF directly + attr = dwarf_attr(result, DW_AT_const_value, &attr_mem); + switch (dwarf_whatform(attr)) { + case DW_FORM_string: + // do nothing for now + logger.log(SEVERITY_WARNING, "Const value form DW_FORM_string value = %s.", dwarf_formstring(attr)); + break; + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + dwarf_formudata(attr, ¶m->location.value); + param->has_value = true; + break; + case DW_FORM_sdata: + dwarf_formsdata(attr, (int64_t*)¶m->location.value); + param->has_value = true; + break; + case DW_FORM_udata: + dwarf_formudata(attr, ¶m->location.value); + param->has_value = true; + break; + } + if(param->has_value) { + logger.log(SEVERITY_DEBUG, "Parameter constant value: 0x%lX", param->location.value); + } + } + + // Additionally handle these attributes: + // 1. DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function + // A DW_AT_default_value attribute for a formal parameter entry. The value of + // this attribute may be a constant, or a reference to the debugging information + // entry for a variable, or a reference to a debugging information entry containing a DWARF procedure + + // 2. DW_AT_variable_parameter + // A DW_AT_variable_parameter attribute, which is a flag, if a formal + // parameter entry represents a parameter whose value in the calling function + // may be modified by the callee. The absence of this attribute implies that the + // parameter’s value in the calling function cannot be modified by the callee. + + // 3. DW_AT_abstract_origin + // In place of these omitted attributes, each concrete inlined instance entry has a DW_AT_abstract_origin attribute that may be used to obtain the + // missing information (indirectly) from the associated abstract instance entry. The value of the abstract origin attribute is a reference to the associated abstract + // instance entry. + + + return true; +} + +void pst_parameter_init(pst_parameter*param, pst_context* ctx) +{ + // methods + param->clear = param_clear; + param->add_type = param_add_type; + param->next_type = param_next_type; + param->handle_dwarf = param_handle_dwarf; + param->handle_type = param_handle_type; + param->print_dwarf = param_print_dwarf; + + // fields + list_node_init(¶m->node); + param->die = NULL; + param->name = NULL; + param->line = 0; + param->size = 0; + param->type = 0; + param->enc_type = 0; + list_head_init(¶m->types); + param->is_return = false; + param->is_variable = false; + param->has_value = false; + param->ctx = ctx; + pst_dwarf_expr_init(¶m->location); + param->allocated = false; +} + +pst_parameter* pst_parameter_new(pst_context* ctx) +{ + pst_parameter* param = (pst_parameter*)allocator.alloc(&allocator, sizeof(pst_parameter)); + if(param) { + pst_parameter_init(param, ctx); + param->allocated = true; + } + + return param; +} +void pst_parameter_fini(pst_parameter* param) +{ + param->clear(); + if(param->name) { + allocator.free(param->name); + } + if(param->allocated) { + allocator.free(&allocator, param); + } +} + + diff --git a/framework/dwarf_parameter.h b/framework/dwarf_parameter.h new file mode 100644 index 0000000..a5faa8d --- /dev/null +++ b/framework/dwarf_parameter.h @@ -0,0 +1,61 @@ +/* + * dwarf_parameter.h + * + * Created on: Feb 1, 2020 + * Author: nnosov + */ + +#ifndef FRAMEWORK_DWARF_PARAMETER_H_ +#define FRAMEWORK_DWARF_PARAMETER_H_ + +#include +#include + +#include "list_head.h" +#include "context.h" +#include "dwarf_expression.h" + +typedef struct __pst_type { + list_node node; // uplink + + char* name; // type name + uint32_t type; // DW_AT_XXX type + bool allocated; // whether this struct was allocated or not +} pst_type; +void pst_type_init(pst_type* t, const char* name, uint32_t type); +pst_type* pst_type_new(const char* name, uint32_t type); +void pst_type_fini(pst_type* t); + +typedef struct __pst_function pst_function; + +typedef struct pst_parameter{ + list_node node; // uplink. !!! must be first !!! + + // methods + void (*clear) (pst_parameter* param); + pst_type* (*add_type) (pst_parameter* param, const char* name, int type); + pst_type* (*next_type) (pst_parameter* param, pst_type* t); + bool (*handle_dwarf) (pst_parameter* param, Dwarf_Die* d, __pst_function* fun); + bool (*handle_type) (pst_parameter* param, Dwarf_Attribute* attr); + bool (*print_dwarf) (pst_parameter* param); + + // fields + Dwarf_Die* die; // DWARF DIE containing parameter's definition + char* name; // parameter's name + uint32_t line; // line of parameter definition + Dwarf_Word size; // size of parameter in bytes + int type; // type of parameter in DW_TAG_XXX types enumeration + Dwarf_Word enc_type; // if 'type' is DW_TAG_Base_type, then 'base_type' holds DW_AT_ATE_XXX base type encoding type + list_head types; // list of parameter's definitions i.e. 'typedef', 'uint32_t' + bool is_return; // whether this parameter is return value of the function + bool is_variable; // whether this parameter is function variable or argument of function + bool has_value; // whether we got value of parameter or not + pst_context* ctx; + pst_dwarf_expr location; + + bool allocated; +} pst_parameter; + + + +#endif /* FRAMEWORK_DWARF_PARAMETER_H_ */ diff --git a/framework/dwarf_stack.cpp b/framework/dwarf_stack.cpp new file mode 100644 index 0000000..abbd7dc --- /dev/null +++ b/framework/dwarf_stack.cpp @@ -0,0 +1,302 @@ +/* + * dwarf_stack.cpp + * + * Created on: Jan 29, 2020 + * Author: nnosov + */ + +#include +#include +#include + +#include "allocator.h" +#include "list_head.h" + +#include "dwarf_stack.h" +#include "sysutils.h" +#include "dwarf_operations.h" + +// ----------------------------------------------------------------------------------- +// DWARF Stack value +// ----------------------------------------------------------------------------------- +void value_set(pst_dwarf_value* value, void* v, uint32_t s, int t) +{ + pst_assert(value && v && s > 0 && s <= sizeof(value->value)); + + // clean-up all bits + value->value.uint64 = 0; + value->type = t; + + if(t & DWARF_TYPE_SIGNED) { + switch(s) { + case 1: + value->value.int8 = *(int8_t*)v; + break; + case 2: + value->value.int16 = *(int16_t*)v; + break; + case 4: + value->value.int32 = *(int32_t*)v; + break; + default: + value->value.int64 = *(int64_t*)v; + break; + + } + } else { + // GENERIC, SIGNED etc + switch(s) { + case 1: + value->value.uint8 = *(uint8_t*)v; + break; + case 2: + value->value.uint16 = *(uint16_t*)v; + break; + case 4: + value->value.uint32 = *(uint32_t*)v; + break; + default: + value->value.uint64 = *(uint64_t*)v; + break; + + } + } +} + +void pst_dwarf_value_init(pst_dwarf_value* dv, char* v, uint32_t s, int t) +{ + pst_assert(dv && s <= sizeof(dv->value)); + + list_node_init(&dv->node); + dv->type = t; + dv->allocated = false; + dv->set = value_set; + memcpy(&dv->value, v, s); +} + +pst_dwarf_value* pst_dwarf_value_new(char* v, uint32_t s, int t) +{ + pst_assert(v); + + pst_dwarf_value* nv = (pst_dwarf_value*)allocator.alloc(&allocator, sizeof(pst_dwarf_value)); + if(nv) { + pst_dwarf_value_init(nv, v, s, t); + nv->allocated = true; + } + + + return nv; +} + +void pst_dwarf_value_fini(pst_dwarf_value* value) +{ + pst_assert(value); + + if(value->allocated) { + allocator.free(&allocator, value); + } else { + value->type = DWARF_TYPE_INVALID; + value->value.uint64 = 0; + } +} + + +// ----------------------------------------------------------------------------------- +// DWARF stack +// ----------------------------------------------------------------------------------- +void stack_push(pst_dwarf_stack* st, void* v, uint32_t s, int t) { + pst_alloc(pst_dwarf_value, value, (char*)v, s, t); + list_add_head(&st->values, &value->node); +} + +void stack_push_value(pst_dwarf_stack* st, pst_dwarf_value* value) { + list_add_head(&st->values, &value->node); +} + +pst_dwarf_value* stack_pop(pst_dwarf_stack* st) { + pst_dwarf_value* value = (pst_dwarf_value*)list_first(&st->values); + if(value) { + list_del(&value->node); + } + + return value; +} + +pst_dwarf_value* stack_get(pst_dwarf_stack* st, uint32_t idx = 0) { + pst_dwarf_value* value = NULL; + struct list_node *pos; + list_for_each_entry(value, pos, &st->values, node) { + if(!idx) { + break; + } + idx--; + } + + return value; +} + +bool stack_get_value(pst_dwarf_stack* st, uint64_t* value) +{ + assert(st && value); + + if(!list_count(&st->values)) { + return false; + } + + pst_dwarf_value* v = st->get(st, 0); + if(v->type & DWARF_TYPE_REGISTER_LOC) { + // dereference register location + int ret = unw_get_reg(st->ctx->curr_frame, v->value.uint64, value); + if(ret) { + st->ctx->log(SEVERITY_ERROR, "Failed to get value of register 0x%X. Error: %d", v->value.uint64, ret); + return false; + } + } else if(v->type & DWARF_TYPE_MEMORY_LOC) { + // dereference memory location + *value = *((uint64_t*)v->value.uint64); + } + + return true; +} + +void stack_clear(pst_dwarf_stack* st) +{ + pst_dwarf_value* value = NULL; + struct list_node *pos, *tn; + list_for_each_entry_safe(value, pos, tn, &st->values, node) { + list_del(&value->node); + pst_dwarf_value_fini(value); + } + + pst_dwarf_op* op = NULL; + list_for_each_entry_safe(op, pos, tn, &st->expr, node) { + list_del(&op->node); + pst_dwarf_op_fini(op); + } +} + +bool stack_calc(pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun = NULL) +{ + st->clear(st); + bool nret = true; + + for (int i = 0; i < expr_len; i++) { + const dwarf_op_map* map = find_op_map(exprs[i].atom); + if(!map) { + st->ctx->log(SEVERITY_ERROR, "Unknown operation type 0x%hhX(0x%lX, 0x%lX)", exprs[i].atom, exprs[i].number, exprs[i].number2); + return false; + } + + pst_alloc(pst_dwarf_op, op, exprs[i].atom, exprs[i].number, exprs[i].number2); + list_add_bottom(&st->expr, &op->node); + + pst_dwarf_value* v = st->get(st, 0); + // dereference register location there if it is not last in stack + if(v && (v->type & DWARF_TYPE_REGISTER_LOC)) { + unw_word_t value = 0; + uint64_t regno = *((uint64_t*)v->value.uint64); + int ret = unw_get_reg(st->ctx->curr_frame, regno, &value); + if(ret) { + st->ctx->log(SEVERITY_ERROR, "Failed to ger value of register 0x%X. Error: %d", regno, ret); + return false; + } + v->set(v, &value, sizeof(value), DWARF_TYPE_GENERIC); + } + + // handle there because it contains sub-expression of a Location in caller's frame + if(map->op_num == DW_OP_GNU_entry_value) { + if(!fun) { + st->ctx->log(SEVERITY_ERROR, "Cannot calculate DW_OP_GNU_entry_value expression while function is undefined"); + return false; + } + if(!fun->parent) { + st->ctx->log(SEVERITY_ERROR, "Function has not parent while calculate DW_OP_GNU_entry_value expression"); + return false; + } + // 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 + 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) { + pst_call_site* cs = fun->parent->find_call_site(fun); + if(!cs) { + st->ctx->log(SEVERITY_ERROR, "Failed to find call site while calculate DW_OP_GNU_entry_value expression"); + return false; + } + pst_dwarf_expr loc; + pst_dwarf_expr_init(&loc); + loc.setup(&loc, expr, exprlen); + pst_call_site_param* param = cs->find_param(loc); + pst_dwarf_expr_fini(&loc); + if(!param) { + st->ctx->log(SEVERITY_ERROR, "Failed to find call site parameter while calculate DW_OP_GNU_entry_value expression"); + return false; + } + + st->push(st, ¶m->value, sizeof(param->value), DWARF_TYPE_GENERIC); + + continue; + } else { + st->ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location"); + nret = false; + break; + } + } else { + st->ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr expression"); + return false; + } + } + + if(!map->operation(st, map, exprs[i].number, exprs[i].number2)) { + st->ctx->log(SEVERITY_ERROR, "Failed to calculate %s(0x%lX, 0x%lX) operation", map->op_name, exprs[i].number, exprs[i].number2); + return false; + } + + } + + return true; +} + +void pst_dwarf_stack_init(pst_dwarf_stack* st, pst_context* ctx) +{ + pst_assert(st && ctx); + + list_head_init(&st->values); + st->push = stack_push; + st->push_value = stack_push_value; + st->pop = stack_pop; + st->get = stack_get; + st->get_value = stack_get_value; + st->calc = stack_calc; + st->clear = stack_clear; + + st->ctx = ctx; + st->allocated = false; +} + +pst_dwarf_stack* pst_dwarf_stack_new(pst_context* ctx) +{ + pst_assert(ctx); + + pst_alloc(pst_dwarf_stack, ns, ctx); + if(ns) { + pst_dwarf_stack_init(ns, ctx); + ns->allocated = true; + } + + return ns; +} + +void pst_dwarf_stack_fini(pst_dwarf_stack* st) +{ + pst_assert(st); + + st->clear(st); + if(st->allocated) { + allocator.free(&allocator, st); + } else { + st->ctx = NULL; + } +} diff --git a/framework/dwarf_stack.h b/framework/dwarf_stack.h new file mode 100644 index 0000000..9971983 --- /dev/null +++ b/framework/dwarf_stack.h @@ -0,0 +1,120 @@ +/* + * dwarf_stack.h + * + * Created on: Jan 29, 2020 + * Author: nnosov + */ + +#ifndef FRAMEWORK_DWARF_STACK_H_ +#define FRAMEWORK_DWARF_STACK_H_ + +#include + +#include "common.h" +#include "allocator.h" +#include "context.h" +#include "sysutils.h" + +// ----------------------------------------------------------------------------------- +// DWARF Stack value +// ----------------------------------------------------------------------------------- + +// DWARF Stack value types, bitmask +typedef enum { + DWARF_TYPE_INVALID = 0, // no type + DWARF_TYPE_SIGNED = 1, // signed type + DWARF_TYPE_UNSIGNED = 2, // unsigned type + DWARF_TYPE_CONST = 4, // constant signed/unsigned type + DWARF_TYPE_GENERIC = 8, // size of machine address type + DWARF_TYPE_CHAR = 16, // 1 byte size + DWARF_TYPE_FLOAT = 32, // machine-dependent floating point size + DWARF_TYPE_REGISTER_LOC = 64, // value located in register specified as 'value' + DWARF_TYPE_MEMORY_LOC = 128, // value located in memory address specified as 'value' + DWARF_TYPE_PIECE = 256, // piece of whole value located in current value + DWARF_TYPE_SHORT = 512, // 2 byte size + DWARF_TYPE_INT = 1024, // 4 byte size + DWARF_TYPE_LONG = 2048 // 8 byte size +} pst_dwarf_value_type; + +// DWARF Stack value storage +typedef union { + uint64_t uint64_v; +#define uint64 uint64_v + int64_t int64_v; +#define int64 int64_v + uint32_t uint32_v[2]; +#define uint32 uint32_v[0] + int32_t int32_v[2]; +#define int32 int32_v[0] + uint16_t uint16_v[4]; +#define uint16 uint16_v[0] + int16_t int16_v[4]; +#define int16 int16_v[0] + uint8_t uint8_v[8]; +#define uint8 uint8_v[0] + int8_t int8_v[8]; +#define int8 int8_v[0] + void* ptr; +} pst_sized_value; + +// forward declaration +typedef struct __pst_dwarf_value pst_dwarf_value; + +// typedefs for member function pointers +typedef void (*pst_dwarf_value_set) (pst_dwarf_value* value, void* v, uint32_t s, int t); + +typedef struct __pst_dwarf_value { + list_node node; // uplink, !!! must be 1st field in structure !!! + + // methods + pst_dwarf_value_set set; // replace value data + + // fields + pst_sized_value value; // value itself + int type; // value type. bitmask of DWARF_TYPE_XXX + bool allocated; +} pst_dwarf_value; + +void pst_dwarf_value_init(pst_dwarf_value* value, char* v, uint32_t s, int t); +pst_dwarf_value* pst_dwarf_value_new(char* v, uint32_t s, int t); +void pst_dwarf_value_fini(pst_dwarf_value* value); + + +// ----------------------------------------------------------------------------------- +// DWARF stack +// ----------------------------------------------------------------------------------- + +// forward declaration +typedef struct __pst_dwarf_stack pst_dwarf_stack; + +// typedefs for member function pointers +typedef void (*pst_dwarf_stack_push) (pst_dwarf_stack* st, void* v, uint32_t s, int t); +typedef void (*pst_dwarf_stack_push_val) (pst_dwarf_stack* st, pst_dwarf_value* value); +typedef pst_dwarf_value* (*pst_dwarf_stack_pop) (pst_dwarf_stack* st); +typedef pst_dwarf_value* (*pst_dwarf_stack_get) (pst_dwarf_stack* st, uint32_t idx); +typedef bool (*pst_dwarf_stack_calc) (pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun); +typedef bool (*pst_dwarf_stack_get_value) (pst_dwarf_stack* st, uint64_t* value); +typedef void (*pst_dwarf_stack_clear) (pst_dwarf_stack* st); + +typedef struct __pst_dwarf_stack { + // methods + pst_dwarf_stack_push push; // push new value on the top of the stack + pst_dwarf_stack_push_val push_value; // push an existing value on the top of the stack + pst_dwarf_stack_pop pop; // pop value from the top of the stack + pst_dwarf_stack_get get; // get value from top of the stack without popping + pst_dwarf_stack_calc calc; // calculate DWARF expression + pst_dwarf_stack_get_value get_value; // get result of calculation + pst_dwarf_stack_clear clear; // clean-up the stack + + // fields + list_head expr; // DWARF expression + list_head values; // list of values on the stack + pst_context* ctx; // context of execution + bool allocated; // whether this object was allocated or not +} pst_dwarf_stack; + +void pst_dwarf_stack_init(pst_dwarf_stack* st, pst_context* ctx); +pst_dwarf_stack* pst_dwarf_stack_new(pst_context* ctx); +void pst_dwarf_stack_fini(pst_dwarf_stack* st); + +#endif /* FRAMEWORK_DWARF_STACK_H_ */ diff --git a/framework/linkedlist.h b/framework/linkedlist.h deleted file mode 100644 index c2cf61d..0000000 --- a/framework/linkedlist.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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/list_head.h b/framework/list_head.h new file mode 100644 index 0000000..f793a58 --- /dev/null +++ b/framework/list_head.h @@ -0,0 +1,338 @@ +/******************************************************************************* +Copyright (c) 2006, Nikolay Nosov +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __LIST_HEAD_H__ +#define __LIST_HEAD_H__ + +/** +Double linked list for user space implementation +*/ + +#include /* for NULL declaration */ + +/** Get offset of a member +@param TYPE the type of the struct +@param MEMBER the name of the member, which offset to be computed +*/ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/** Casts a member of a structure out to the containing structure + @param ptr the pointer to the member. + @param type the type of the container struct this is embedded in + @param member the name of the member within the struct. +*/ + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type, member) );}) + +/** Get the struct for this entry + @param ptr the &struct list_head pointer. + @param type the type of the struct this is embedded in. + @param member the name of the list_struct within the struct +*/ + +#define list_entry(ptr, type, member) container_of(ptr, type, member) + +/** Iterate over a list + @param pos the &struct list_head to use as a loop counter. + @param head the head for your list. +*/ + +#define list_for_each(pos, head) \ + for (pos = (head)->first; pos; \ + pos = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define list_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ tpos = list_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + + +/** Iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct list_node to use as a loop cursor. + * @n: another &struct list_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_node within the struct. +*/ +#define list_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = list_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + + +/** Iterate over a list backwards + @param pos the &struct list_head to use as a loop counter. + @param head the head for your list. +*/ + +#define list_for_each_prev(pos, head) \ + for (pos = (head)->last; pos; \ + pos = pos->prev) + + +/** Iterate over a list safe against removal of list entry + @param pos the &struct list_head to use as a loop counter. + @param n another &struct list_head to use as temporary storage + @param head the head for your list. +*/ + +#if !defined(list_for_each_safe) +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) +#endif + +/* to compiler be happy */ + +struct list_head; + +/** Node of the list +@param next next node in the list +@param prev previous node in the list +@param head head of the list +*/ + +typedef struct list_node +{ + struct list_node *next, *prev; + struct list_head *head; +} list_node; + + + +/** Head of the list +@param first first node in the list +@param last last node in the list +@param count cont of the nodes +*/ + +typedef struct list_head +{ + struct list_node *first, *last; + int count; +} list_head; + +/** +Compile time initialization of the head struct +*/ + +#define LIST_HEAD_INIT { .first = NULL, .last = NULL, .count = 0 } + +/** +Compile time initialization of the node struct +*/ + +#define LIST_NODE_INIT { .prev = NULL, .next = NULL, .head = NULL } + +/** Runtime initialization of the head struct +(should be applied before first using of the list) +@param node head, which to be initialized. +*/ + +static inline void list_head_init(struct list_head *head) +{ + head->first = head->last = NULL; + head->count = 0; +} + + +/** Runtime initialization of the node struct +(should be applied before first using of the node) +@param node node, which to be initialized. +*/ + +static inline void list_node_init(struct list_node *node) +{ + node->next = node->prev = NULL; + node->head = NULL; +} + +/** Add node to begin of the list +@param head the head of the list +@param node node of the list, which to be added +*/ + +static inline void list_add_head(struct list_head *head, struct list_node *node) +{ + struct list_node *pfirst = head->first; + head->first = node; + node->next = pfirst; + node->prev = NULL; + node->head = head; + + if(pfirst) pfirst->prev = node; + else head->last = node; + + head->count++; +} + +/** Add node to the end of the list +@param head the head of the list; +@param node node of the list, which to be added +*/ + +static inline void list_add_bottom(struct list_head *head, struct list_node *node) +{ + struct list_node *plast = head->last; + + head->last = node; + node->next = NULL; + node->prev = plast; + node->head = head; + + if(plast) plast->next = node; + else head->first = node; + + head->count++; +} + +/** Add node in the list after given 'base' node +@param base the base node, after that node will be added +@param node node of the list, which to be added +*/ + +static inline void list_add_after(struct list_node *base, struct list_node *node) +{ + struct list_node *pnext = base->next; + + base->next = node; + node->next = pnext; + node->prev = base; + node->head = base->head; + + if(pnext) pnext->prev = node; + else base->head->last = node; + + base->head->count++; +} + +/** Adds node in the list before given 'base' node +@param base the base node, before that node will be added +@param node node of the list, which to be added +*/ + +static inline void list_add_before(struct list_node *base, struct list_node *node) +{ + struct list_node *pprev = base->prev; + + base->prev = node; + node->next = base; + node->prev = pprev; + node->head = base->head; + + if(pprev) pprev->next = node; + else base->head->first = node; + base->head->count++; +} + +/** Remove node from the list +@param node the node, which to be removed +*/ + +static inline void list_del(struct list_node *node) +{ + if(node->head) + { + if(node->prev) node->prev->next = node->next; + else node->head->first = node->next; + if(node->next) node->next->prev = node->prev; + else node->head->last = node->prev; + node->head->count--; + } + + node->prev = node->next = NULL; + node->head = NULL; +} + +static inline void list_del_init(struct list_node *node) +{ + list_del(node); + list_node_init(node); +} + +/** Count of the nodes in the list +@param head the head of the list +@return count of the nodes in the list +*/ + +static inline int list_count(struct list_head *head) +{ + return head->count; +} + +/** First element of the list +@param head the head of the list +@return pointer to first element of the list +*/ + +static inline struct list_node* list_first(struct list_head *head) +{ + return head->first; +} + +/** Last element of the list +@param head the head of the list +@return pointer to last element of the list +*/ + +static inline struct list_node* list_last(struct list_head *head) +{ + return head->last; +} + +/** Next element of the list +@param head current element of the list +@return pointer to next element relatively of current +*/ + +static inline struct list_node* list_next(struct list_node *node) +{ + return node->next; +} + +/** Previous element of the list +@param head current element of the list +@return pointer to previous element relatively of current +*/ + +static inline struct list_node* list_prev(struct list_node *node) +{ + return node->prev; +} + +#endif // __LIST_HEAD_H__ + diff --git a/framework/logger/log.cpp b/framework/logger/log.cpp index d043ab9..3ff4514 100644 --- a/framework/logger/log.cpp +++ b/framework/logger/log.cpp @@ -1,55 +1,246 @@ #include "log.h" #include +#include -#define LOG_BUFF_SIZE (1024*1024) - - -const char * const SC_LogBase::mSeverityStrings[] = { +const char * const severity_map[] = { " [DEBUG] : ", " [INFO] : ", " [WARNING]: ", " [ERROR] : " }; -char SC_LogBase::mString[LOG_BUFF_SIZE]; -uint32_t SC_LogBase::mStringSize = sizeof(SC_LogBase::mString); - -SC_LogBase::SC_LogBase(uint32_t id, const char* source) : mID(id) +void format_string(pst_log* log, const char* fmt, va_list args) { - mStringLen = 0; - mCurrentSeverity = SEVERITY_DEBUG; - if(source) { - mSource = source; - } + log->mStringLen += vsnprintf(log->mString + log->mStringLen, log->mStringSize - log->mStringLen, fmt, args); } -SC_LogBase::~SC_LogBase() -{ - Close(); -} - -void SC_LogBase::FormatString(const char* fmt, va_list args) -{ - mStringLen += vsnprintf(mString + mStringLen, mStringSize - mStringLen, fmt, args); -} - -void SC_LogBase::FormatPrefix(SC_LogSeverity severity) +void format_prefix(pst_log* log, SC_LogSeverity severity) { time_t rawTime; struct tm * timeinfo; time(&rawTime); timeinfo = gmtime(&rawTime); - mStringLen += strftime(mString, sizeof(mString), "%d-%m-%Y %H:%M:%S", timeinfo); - strncpy(mString + mStringLen, mSeverityStrings[(int)severity], strlen(mSeverityStrings[(int)severity])); - mStringLen += strlen(mSeverityStrings[(int)severity]); + log->mStringLen += strftime(log->mString, sizeof(log->mString), "%d-%m-%Y %H:%M:%S", timeinfo); + strncpy(log->mString + log->mStringLen, severity_map[(int)severity], strlen(severity_map[(int)severity])); + log->mStringLen += strlen(severity_map[(int)severity]); } -void SC_LogBase::FormatPostfix() +void format_postfix(pst_log* log) { - if((mStringLen + 2) < mStringSize) { - mString[mStringLen++] = '\n'; - mString[mStringLen++] = 0; + if((log->mStringLen + 2) < log->mStringSize) { + log->mString[log->mStringLen++] = '\n'; + log->mString[log->mStringLen++] = 0; } } + +//variable argument number logging +void log(pst_log* log, SC_LogSeverity severity, const char* fmt, ...) +{ + if (severity < log->mCurrentSeverity) + return; + + pthread_mutex_lock(&log->mLock); + + if(!log->is_opened(log)) { + log->open(log); + } + + log->mStringLen = 0; + format_prefix(log, severity); + va_list args; + va_start(args, fmt); + format_string(log, fmt, args); + va_end(args); + format_postfix(log); + log->send_message(log, severity); + + pthread_mutex_unlock(&log->mLock); +} + +void log_init_base(pst_log* plog, const char* source) +{ + // methods + plog->log = log; + + // fields + plog->mpSource = 0; + if(source) { + plog->mpSource = strdup(source); + } + plog->mString[0] = 0; + plog->mStringSize = sizeof(plog->mString); + plog->mStringLen = 0; + plog->mCurrentSeverity = SEVERITY_DEBUG; + pthread_mutex_init(&plog->mLock, NULL); + plog->child = 0; +} + +void log_fini(pst_log* log) +{ + pthread_mutex_destroy(&log->mLock); + log->close(log); + if(log->mpSource) { + free(log->mpSource); + log->mpSource = 0; + } +} + + +// +// Console logger implementation +// +#define RED "\e[0;31m" +#define GREEN "\e[0;32m" +#define YELLOW "\e[1;33m" +#define NC "\e[0m" // No Color + +//actually sends message to the source +void send_msg_console(pst_log* log, SC_LogSeverity severity) +{ + const char* color = NC; + switch(severity) { + case SEVERITY_DEBUG: + color = NC; + break; + case SEVERITY_ERROR: + color = RED; + break; + case SEVERITY_INFO: + color = GREEN; + break; + case SEVERITY_WARNING: + color = YELLOW; + break; + default: + color = NC; + break; + } + + fprintf(stderr, "%s%s%s", color, log->mString, NC); +} + +void close_console(pst_log* log) { + // do nothing +} + +bool open_console(pst_log* log) { + return true; +} + +bool is_opened_console(pst_log* log) { + return true; +} + +void pst_init_console(pst_log* log) +{ + log_init_base(log, NULL); + log->close = close_console; + log->open = open_console; + log->is_opened = is_opened_console; + log->send_message = send_msg_console; +} + +// +// Log to file +// + +typedef struct _file_spec { + FILE* fd; + uint64_t max_bytes; + uint64_t num_bytes; + char* dir; + char* fname; +} file_spec; + +//open file for writing +bool open_file(pst_log* log) +{ + file_spec* fsp = (file_spec*)log->child; + if(!fsp) { + fprintf(stderr, "Wrong initialization of File-based logger\n"); + return false; + } + + if(!fsp->fd) { + // extract log and path names + uint32_t namelen = strlen(log->mpSource); + if(namelen) { + const char* ptr = strrchr(log->mpSource, '/'); + uint32_t pathlen = 0; + if(ptr) { + pathlen = ptr - log->mpSource + 1; + namelen -= pathlen + 1; + } + + fsp->dir = strndup(log->mpSource, pathlen); + fsp->fname = strndup(log->mpSource + pathlen, namelen); + + //open the file finally + fsp->fd = fopen(log->mpSource, "a+"); + } + } + + return (fsp->fd != 0); +} + +void close_file(pst_log* log) +{ + file_spec* fsp = (file_spec*)log->child; + if(!fsp) { + fprintf(stderr, "Wrong initialization of File-based logger while close\n"); + return; + } + + if(fsp->fd) { + fclose(fsp->fd); + } + + fsp->fd = 0; + fsp->max_bytes = 0; +} + +bool is_file_opened(pst_log* log) +{ + file_spec* fsp = (file_spec*)log->child; + if(!fsp) { + fprintf(stderr, "Wrong initialization of File-based logger while check open\n"); + return false; + } + return (fsp->fd != 0); +} + +void send_msg_file(pst_log* log, SC_LogSeverity severity) +{ + file_spec* fsp = (file_spec*)log->child; + if(!fsp) { + fprintf(stderr, "Wrong initialization of File-based logger while check send message\n"); + return; + } + if(fsp->fd && fsp->num_bytes < fsp->max_bytes) { + if(fputs(log->mString, fsp->fd) >= 0) { + fflush(fsp->fd); + fsp->num_bytes += log->mStringLen; + } else { + fclose(fsp->fd); + fsp->fd = 0; + } + } +} + +void pst_log_init_file(pst_log* log, const char* path, uint64_t max_bytes) +{ + log_init_base(log, path); + file_spec* fsp = (file_spec*)malloc(sizeof(file_spec)); + fsp->fd = 0; + fsp->max_bytes = max_bytes; + fsp->num_bytes = 0; + log->child = fsp; + + log->close = close_file; + log->open = open_file; + log->is_opened = is_file_opened; + log->send_message = send_msg_file; + +} diff --git a/framework/logger/log.h b/framework/logger/log.h index 4409fb1..ce46118 100644 --- a/framework/logger/log.h +++ b/framework/logger/log.h @@ -1,15 +1,12 @@ -#ifndef LOG_H_ -#define LOG_H_ +#ifndef PST_LOG_H_ +#define PST_LOG_H_ #include #include #include #include -#include - -#include "mutex.h" - -using std::string; +#include +#include // Log message severity enum SC_LogSeverity { @@ -21,128 +18,33 @@ enum SC_LogSeverity { SEVERITY_MAX }; +#define LOG_BUFF_SIZE (1024*1024) -class SC_LogBase -{ -protected: +typedef struct __pst_log pst_log; - SC_LogBase(uint32_t id, const char* source); +typedef struct __pst_log { + // methods + void (*close) (pst_log* log); + bool (*open) (pst_log* log); + bool (*is_opened) (pst_log* log); + void (*log) (pst_log* log, SC_LogSeverity severity, const char* fmt, ...); + void (*send_message) (pst_log* log, SC_LogSeverity severity); -public: + // fields + char* mpSource; // source for store log messages (file, IP:port or something else) - virtual ~SC_LogBase(); + char mString[LOG_BUFF_SIZE]; // formatted string to be printed + uint32_t mStringSize; // size of the 'mString' buffer + uint32_t mStringLen; // length of the formatted string - //variable argument number logging - inline virtual void Log(SC_LogSeverity severity, const char* fmt, ...) - { - if (severity < mCurrentSeverity) - return; + SC_LogSeverity mCurrentSeverity; // maximum severity value to be logged + pthread_mutex_t mLock; - mLock.Lock(); + void* child; +} pst_log; - if(!IsOpened()) - { - //print header if present - if(Open() && mHeader.size()) - { - SendMessage((char*)mHeader.c_str(), severity); - } - } +void pst_log_init_console(pst_log* log); +void pst_log_init_file(pst_log* log, const char* path, uint64_t max_bytes = 64 * 1024 * 1024/* 64Mb */); +void pst_log_fini(pst_log* log); - mStringLen = 0; - FormatPrefix(severity); - va_list args; - va_start(args, fmt); - FormatString(fmt, args); - va_end(args); - FormatPostfix(); - SendMessage(mString, severity); - - mLock.Unlock(); - } - - //open source for send messages - virtual bool Open() = 0; - - //close source - virtual void Close(){} - - //whether source already opened - virtual bool IsOpened() = 0; - - //returns source path - string& GetSource() - { - return mSource; - } - - //assign source path - inline void SetSource(const char* source) - { - Close(); - mSource = source; - } - - void SetSource(string& source) - { - SetSource(source.c_str()); - } - - //assign Log header - inline void SetHeader(const char* header) - { - mHeader = string(header) + '\n'; - } - - //return Log ID - inline uint32_t GetID() const - { - return mID; - } - - //set Log ID - inline void SetID(uint32_t id) - { - mID = id; - } - - //return current severity threshold applied to the messages - inline SC_LogSeverity GetCurrentSeverity() const - { - return mCurrentSeverity; - } - - //set severity threshold to be applied to the messages - inline void SetCurrentSeverity(SC_LogSeverity severity) - { - mCurrentSeverity = severity; - } - -protected: - - //actually sends message to the source - virtual void SendMessage(const char* msg, SC_LogSeverity severity = SEVERITY_DEBUG) = 0; - - //format message prefix - virtual void FormatPrefix(SC_LogSeverity severity); - - //format message body - virtual void FormatString(const char* fmt, va_list args); - - //format message postfix - virtual void FormatPostfix(); - -protected: - - uint32_t mID; //log ID, associated with source - string mSource; //source for store log messages (file, IP address or sometsing else) - string mHeader; //header of the Log - static char mString[]; //formatted string to be printed - static uint32_t mStringSize; //size of the string buffer - uint32_t mStringLen; //length of the string - SC_LogSeverity mCurrentSeverity; //maximum severity value to be logged - static const char * const mSeverityStrings[]; - SC_Mutex mLock; -}; - -#endif /* LOG_H_ */ +#endif /* PST_LOG_H_ */ diff --git a/framework/logger/log_console.h b/framework/logger/log_console.h deleted file mode 100644 index eb2991c..0000000 --- a/framework/logger/log_console.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef SC_LOGCONSOLE_H -#define SC_LOGCONSOLE_H - -#include "log.h" - -#define RED "\e[0;31m" -#define GREEN "\e[0;32m" -#define YELLOW "\e[1;33m" -#define NC "\e[0m" // No Color - -class SC_LogConsole : public SC_LogBase { -public: - - SC_LogConsole(uint32_t id, const char* source) : SC_LogBase(id, source) { } - - //open file for writing - inline virtual bool Open() { - return true; - } - - //close file opened - inline virtual void Close() { } - - //whether file already opened or not - inline virtual bool IsOpened() { - return true; - } -protected: - inline virtual void SendMessage(const char* msg, SC_LogSeverity severity) { - const char* color = NC; - switch(severity) { - case SEVERITY_DEBUG: - color = NC; - break; - case SEVERITY_ERROR: - color = RED; - break; - case SEVERITY_INFO: - color = GREEN; - break; - case SEVERITY_WARNING: - color = YELLOW; - break; - default: - color = NC; - break; - } - - fprintf(stderr, "%s%s%s", color, msg, NC); - } -}; - -#endif // SC_LOGCONSOLE_H diff --git a/framework/logger/log_file.h b/framework/logger/log_file.h deleted file mode 100644 index f1ef869..0000000 --- a/framework/logger/log_file.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef LOG_FILE_H_ -#define LOG_FILE_H_ - -//framework -#include "log.h" -#include -#include - -using std::string; - -//============================================================================================= -// SWI Logger to file logging class declaration -//============================================================================================= -class SC_LogFile : public SC_LogBase -{ -public: - - SC_LogFile(uint32_t id, const char* source) : SC_LogBase(id, source) - { - mFile = 0; - //2GByte by default - mMaxFileSize = 0x0000000080000000ULL; - mBytesCount = 0; - } - - //open file for writing - inline virtual bool Open() - { - if(!mFile) { - // extract log and path names - uint32_t namelen = mSource.size(); - if(namelen) { - const char* ptr = strrchr(mSource.c_str(), '/'); - uint32_t pathlen = 0; - if(ptr) { - pathlen = ptr - mSource.c_str() + 1; - namelen -= pathlen + 1; - } - - mLogPath.append(mSource.c_str(), pathlen); - - mLogName.append((mSource.c_str() + pathlen), namelen); - - //open the file finally - mFile = fopen(mSource.c_str(), "a+"); - } - } - - return (mFile != 0); - } - - //close file opened - inline virtual void Close() - { - if(mFile) { - fclose(mFile); - } - - mFile = 0; - mBytesCount = 0; - } - - //whether file already opened or not - inline virtual bool IsOpened() - { - return (mFile != 0); - } - - inline void SetMaxFileSize(uint64_t size) - { - mMaxFileSize = size; - } - - inline uint64_t GetMaxFileSize() - { - return mMaxFileSize; - } - - inline FILE* GetLogFD() - { - return mFile; - } - -protected: - - inline virtual void SendMessage(const char* msg, SC_LogSeverity severity = SEVERITY_DEBUG) - { - if(mFile && mBytesCount < mMaxFileSize) { - if(fputs(msg, mFile) >= 0) { - fflush(mFile); - mBytesCount += mStringLen; - } else { - fclose(mFile); - mFile = 0; - } - } - } - -protected: - - string mLogPath; //path to the log file - string mLogName; //name of the log file - FILE* mFile; //log file descriptor - uint64_t mMaxFileSize; //maximum number bytes allowed to be written to the file - uint64_t mBytesCount; //number of bytes actually written -}; - -#endif /* LOG_FILE_H_ */ diff --git a/framework/mutex.h b/framework/mutex.h deleted file mode 100644 index ba42e80..0000000 --- a/framework/mutex.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef MUTEX_H_ -#define MUTEX_H_ - -#include -#include - -class SC_Mutex { -public: - SC_Mutex() { - pthread_mutex_init(&m, NULL); - } - SC_Mutex(SC_Mutex const&) { - pthread_mutex_init(&m, NULL); - } - SC_Mutex& operator=(SC_Mutex const& rhs) { - if (&rhs != this) { - pthread_mutex_init(&m, NULL); - } - return *this; - } - ~SC_Mutex() { - pthread_mutex_destroy(&m); - } - - void Lock() { - pthread_mutex_lock(&m); - } - - void Unlock() { - pthread_mutex_unlock(&m); - } - - bool Trylock() { - return (pthread_mutex_trylock(&m) == 0); - } -private: - pthread_mutex_t m; -}; - -#endif /* MUTEX_H_ */ diff --git a/framework/registers.cpp b/framework/registers.cpp index 6c029d5..02b7f0c 100644 --- a/framework/registers.cpp +++ b/framework/registers.cpp @@ -84,6 +84,7 @@ dwarf_reg_map reg_map[] = { {0x1d, "XMM12", DW_OP_breg29}, {0x1e, "XMM13", DW_OP_breg30}, {0x1f, "XMM14", DW_OP_breg31}, + {0x20, "XMM15", 0xff}, // no mapping to dwarf registers }; int regnum = sizeof(reg_map) / sizeof(dwarf_reg_map); diff --git a/framework/sysutils.cpp b/framework/sysutils.cpp index 02ddcad..495a513 100644 --- a/framework/sysutils.cpp +++ b/framework/sysutils.cpp @@ -27,6 +27,8 @@ #include "common.h" #include "dwarf_operations.h" +#include "allocator.h" +#include "dwarf_stack.h" // dwfl_addrsegment() possibly can be used to check address validity // dwarf_getattrs() allows to enumerate all DIE attributes @@ -51,24 +53,21 @@ int regname_callback (void *arg, int regno, const char *setname, const char *pre return 0; } -bool handle_location(pst_context* ctx, Dwarf_Attribute* attr, pst_dwarf_expr& loc, Dwarf_Addr pc, char* str, uint32_t strsize, __pst_function* fun = NULL) +bool handle_location(pst_context* ctx, Dwarf_Attribute* attr, pst_dwarf_expr* loc, Dwarf_Addr pc, __pst_function* fun = NULL) { - str[0] = 0; + ctx->clean_print(ctx); Dwarf_Addr offset = pc - ctx->base_addr; - dwarf_stack stack(ctx); + pst_decl(pst_dwarf_stack, stack, ctx); Dwarf_Op *expr; size_t exprlen; + bool ret = false; if(dwarf_hasform(attr, DW_FORM_exprloc)) { // Location expression (exprloc class of location in DWARF terms) if(dwarf_getlocation(attr, &expr, &exprlen) == 0) { - loc.setup(expr, exprlen); - ctx->print_expr_block (expr, exprlen, str, strsize, attr); - if(stack.calc_expression(expr, exprlen, attr, fun) && stack.get_value(loc.value)) { - return true; - } else { - return false; - } + loc->setup(expr, exprlen); + ctx->print_expr(ctx, expr, exprlen, attr); + ret = stack.calc(&stack, expr, exprlen, attr, fun); } } else if(dwarf_hasform(attr, DW_FORM_sec_offset)) { // Location list (loclist class of location in DWARF terms) @@ -77,19 +76,14 @@ bool handle_location(pst_context* ctx, Dwarf_Attribute* attr, pst_dwarf_expr& lo // handle list of possible locations of parameter for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) { - ctx->print_expr_block (expr, exprlen, str, strsize, attr); + ctx->print_expr(ctx, expr, exprlen, attr); if(offset >= start && offset <= end) { - loc.setup(expr, exprlen); + loc->setup(expr, exprlen); // actual location, try to calculate Location expression - if(stack.calc_expression(expr, exprlen, attr, fun) && stack.get_value(loc.value), fun) { - ctx->log(SEVERITY_DEBUG, "Location expression: (low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 "), \"%s\" ==> 0x%lX", start, end, str, loc.value); - return true; - } else { - return false; - } + ret = stack.calc(&stack, expr, exprlen, attr, fun); } else { // Location skipped due to don't match current PC offset - ctx->log(SEVERITY_DEBUG, "Skip Location list expression: [%d] (low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 "), \"%s\"", i, start, end, str); + ctx->log(SEVERITY_DEBUG, "Skip Location list expression: [%d] (low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 "), \"%s\"", i, start, end, ctx->buff); } } @@ -97,292 +91,11 @@ bool handle_location(pst_context* ctx, Dwarf_Attribute* attr, pst_dwarf_expr& lo ctx->log(SEVERITY_WARNING, "Unknown location attribute form = 0x%X, code = 0x%X, ", attr->form, attr->code); } - - return false; -} - -bool __pst_dwarf_expr::operator== (__pst_dwarf_expr &rhs) -{ - if(Size() != rhs.Size()) { - return false; - } - - pst_dwarf_op* lop = next_op(NULL); - pst_dwarf_op* rop = rhs.next_op(NULL); - while(lop && rop) { - if(lop->operation == rop->operation && lop->arg1 == rop->arg1 && lop->arg2 == rop->arg2) { - return true; - } - lop = next_op(lop); - rop = rhs.next_op(rop); - } - - return false; -} - -pst_dwarf_op* __pst_dwarf_expr::add_op(uint8_t operation, uint64_t arg1, uint64_t arg2) -{ - pst_dwarf_op* op = new pst_dwarf_op(operation, arg1, arg2); - InsertLast(op); - - return op; -} - -pst_dwarf_op* __pst_dwarf_expr::next_op(pst_dwarf_op* op) -{ - pst_dwarf_op* ret = NULL; - if(!op) { - ret = (pst_dwarf_op*)First(); - } else { - ret = (pst_dwarf_op*)Next(op); - } + pst_dwarf_stack_fini(&stack); return ret; } -bool __pst_dwarf_expr::print_op(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_dwarf_expr::clean() -{ - for(pst_dwarf_op* op = (pst_dwarf_op*)First(); op; op = (pst_dwarf_op*)First()) { - Remove(op); - delete op; - } -} - -void __pst_dwarf_expr::setup(Dwarf_Op* expr, size_t exprlen) -{ - clean(); - for(size_t i = 0; i < exprlen; ++i) { - add_op(expr[i].atom, expr[i].number, expr[i].number2); - } -} - -bool __pst_parameter::print_dwarf() -{ - if(types.Size()) { - if(!is_return) { - if(has_value) { - ctx->print("%s %s = 0x%lX", next_type(NULL)->name.c_str(), name.c_str(), location.value); - } else { - ctx->print("%s %s = ", next_type(NULL)->name.c_str(), name.c_str()); - } - } else { - ctx->print("%s", next_type(NULL)->name.c_str()); - } - } else { - if(has_value) { - ctx->print("%s = 0x%lX", name.c_str(), location.value); - } else { - ctx->print("%s = ", name.c_str()); - } - } - return true; -} - -bool __pst_parameter::handle_type(Dwarf_Attribute* param) -{ - Dwarf_Attribute attr_mem; - Dwarf_Attribute* attr; - - // get DIE of return type - Dwarf_Die ret_die; - - if(!dwarf_formref_die(param, &ret_die)) { - ctx->log(SEVERITY_ERROR, "Failed to get parameter DIE"); - return false; - } - - switch (dwarf_tag(&ret_die)) { - case DW_TAG_base_type: { - // get Size attribute and it's value - size = 0; - attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem); - if(attr) { - dwarf_formudata(attr, &size); - } - ctx->log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), size); - add_type(dwarf_diename(&ret_die), DW_TAG_base_type); - type = DW_TAG_base_type; - - attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem); - if(attr) { - enc_type = 0; - dwarf_formudata(attr, &enc_type); - } - break; - } - case DW_TAG_array_type: - ctx->log(SEVERITY_DEBUG, "array type"); - add_type("[]", DW_TAG_array_type); - break; - case DW_TAG_structure_type: - ctx->log(SEVERITY_DEBUG, "structure type"); - add_type("struct", DW_TAG_structure_type); - break; - case DW_TAG_union_type: - ctx->log(SEVERITY_DEBUG, "union type"); - add_type("union", DW_TAG_union_type); - break; - case DW_TAG_class_type: - ctx->log(SEVERITY_DEBUG, "class type"); - add_type("class", DW_TAG_class_type); - break; - case DW_TAG_pointer_type: - ctx->log(SEVERITY_DEBUG, "pointer type"); - add_type("*", DW_TAG_pointer_type); - break; - case DW_TAG_enumeration_type: - ctx->log(SEVERITY_DEBUG, "enumeration type"); - add_type("enum", DW_TAG_enumeration_type); - break; - case DW_TAG_const_type: - ctx->log(SEVERITY_DEBUG, "constant type"); - add_type("const", DW_TAG_const_type); - break; - case DW_TAG_subroutine_type: - ctx->log(SEVERITY_DEBUG, "Skipping subroutine type"); - break; - case DW_TAG_typedef: - ctx->log(SEVERITY_DEBUG, "typedef '%s' type", dwarf_diename(&ret_die)); - add_type(dwarf_diename(&ret_die), DW_TAG_typedef); - break; - default: - ctx->log(SEVERITY_WARNING, "Unknown 0x%X tag type", dwarf_tag(&ret_die)); - break; - } - - attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem); - if(attr) { - return handle_type(attr); - } - - return true; -} - -pst_type* __pst_parameter::add_type(const char* name, int type) -{ - pst_type* t = new pst_type(name, type); - types.InsertLast(t); - - return t; -} - -void __pst_parameter::clear() -{ - for(pst_type* t = (pst_type*)types.First(); t; t = (pst_type*)types.First()) { - types.Remove(t); - delete t; - } -} - -pst_type* __pst_parameter::next_type(pst_type* t) -{ - pst_type* next = NULL; - if(!t) { - next = (pst_type*)types.First(); - } else { - next = (pst_type*)types.Next(t); - } - - return next; -} - -bool __pst_parameter::handle_dwarf(Dwarf_Die* result, __pst_function* fun) -{ - die = result; - - Dwarf_Attribute attr_mem; - Dwarf_Attribute* attr; - - name = dwarf_diename(result); - is_variable = (dwarf_tag(result) == DW_TAG_variable); - - dwarf_decl_line(result, (int*)&line); - // Get reference to attribute type of the parameter/variable - attr = dwarf_attr(result, DW_AT_type, &attr_mem); - ctx->log(SEVERITY_DEBUG, "---> Handle '%s' %s", name.c_str(), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable"); - if(attr) { - handle_type(attr); - } - - if(dwarf_hasattr(result, DW_AT_location)) { - // determine location of parameter in stack/heap or CPU registers - attr = dwarf_attr(result, DW_AT_location, &attr_mem); - Dwarf_Addr pc; - unw_get_reg(ctx->curr_frame, UNW_REG_IP, &pc); - - dwarf_stack stack(ctx); - char str[1024]; str[0] = 0; - if(handle_location(ctx, attr, location, pc, str, sizeof(str), fun)) { - has_value = true; - } else { - ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str); - } - } else if(dwarf_hasattr(result, DW_AT_const_value)) { - // no locations definitions, value is constant, known by DWARF directly - attr = dwarf_attr(result, DW_AT_const_value, &attr_mem); - switch (dwarf_whatform(attr)) { - case DW_FORM_string: - // do nothing for now - ctx->log(SEVERITY_WARNING, "Const value form DW_FORM_string value = %s.", dwarf_formstring(attr)); - break; - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - dwarf_formudata(attr, &location.value); - has_value = true; - break; - case DW_FORM_sdata: - dwarf_formsdata(attr, (int64_t*)&location.value); - has_value = true; - break; - case DW_FORM_udata: - dwarf_formudata(attr, &location.value); - has_value = true; - break; - } - if(has_value) { - ctx->log(SEVERITY_DEBUG, "Parameter constant value: 0x%lX", location.value); - } - } - - // Additionally handle these attributes: - // 1. DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function - // A DW_AT_default_value attribute for a formal parameter entry. The value of - // this attribute may be a constant, or a reference to the debugging information - // entry for a variable, or a reference to a debugging information entry containing a DWARF procedure - - // 2. DW_AT_variable_parameter - // A DW_AT_variable_parameter attribute, which is a flag, if a formal - // parameter entry represents a parameter whose value in the calling function - // may be modified by the callee. The absence of this attribute implies that the - // parameter’s value in the calling function cannot be modified by the callee. - - // 3. DW_AT_abstract_origin - // In place of these omitted attributes, each concrete inlined instance entry has a DW_AT_abstract_origin attribute that may be used to obtain the - // missing information (indirectly) from the associated abstract instance entry. The value of the abstract origin attribute is a reference to the associated abstract - // instance entry. - - - return true; -} void __pst_call_site_param::set_location(Dwarf_Op* expr, size_t exprlen) { @@ -439,15 +152,14 @@ bool __pst_call_site::handle_dwarf(Dwarf_Die* child) Dwarf_Addr pc; unw_get_reg(ctx->curr_frame, UNW_REG_IP, &pc); - char str[1024]; // expression represent where callee parameter will be stored pst_call_site_param* param = add_param(); if(dwarf_hasattr(child, DW_AT_location)) { // handle location expression here // determine location of parameter in stack/heap or CPU registers attr = dwarf_attr(child, DW_AT_location, &attr_mem); - if(!handle_location(ctx, attr, param->location, pc, str, sizeof(str))) { - ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str); + if(!handle_location(ctx, attr, param->location, pc, NULL)) { + ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", ctx->buff); del_param(param); return false; } @@ -457,13 +169,12 @@ bool __pst_call_site::handle_dwarf(Dwarf_Die* child) if(dwarf_hasattr(child, DW_AT_GNU_call_site_value)) { // handle value expression here attr = dwarf_attr(child, DW_AT_GNU_call_site_value, &attr_mem); - dwarf_stack stack(ctx); - pst_dwarf_expr loc; - if(handle_location(ctx, attr, loc, pc, str, sizeof(str))) { + pst_dwarf_expr loc(ctx->alloc); + if(handle_location(ctx, attr, loc, pc, NULL)) { param->value = loc.value; - ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", str, param->value); + ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", ctx->buff, param->value); } else { - ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str); + ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", ctx->buff); del_param(param); return false; } @@ -592,17 +303,17 @@ bool __pst_function::print_dwarf() return false; } } - //ctx->print("%s:%d: ", file.c_str(), line); + //ctx->print(ctx, "%s:%d: ", file.c_str(), line); // handle return parameter and be safe if function haven't parameters (for example, dwar info for function is absent) pst_parameter* param = next_param(NULL); if(param && param->is_return) { // print return value type, function name and start list of parameters param->print_dwarf(); - ctx->print(" %s(", name.c_str()); + ctx->print(ctx, " %s(", name.c_str()); param = next_param(param); } else { - ctx->print("%s(", name.c_str()); + ctx->print(ctx, "%s(", name.c_str()); } bool first = true; bool start_variable = false; @@ -610,37 +321,37 @@ bool __pst_function::print_dwarf() if(param->is_return) { // print return value type, function name and start list of parameters param->print_dwarf(); - ctx->print(" %s(", name.c_str()); + ctx->print(ctx, " %s(", name.c_str()); continue; } if(param->is_variable) { if(!start_variable) { - ctx->print(")%s\n", at); - ctx->print("{\n"); + ctx->print(ctx, ")%s\n", at); + ctx->print(ctx, "{\n"); start_variable = true; } if(param->line) { - ctx->print("%04u: ", param->line); + ctx->print(ctx, "%04u: ", param->line); } else { - ctx->print(" "); + ctx->print(ctx, " "); } param->print_dwarf(); - ctx->print(";\n"); + ctx->print(ctx, ";\n"); } else { if(first) { first = false; } else { - ctx->print(", "); + ctx->print(ctx, ", "); } param->print_dwarf(); } } if(!start_variable) { - ctx->print(");%s\n", at); + ctx->print(ctx, ");%s\n", at); } else { - ctx->print("}\n"); + ctx->print(ctx, "}\n"); } free(at); @@ -738,9 +449,8 @@ bool __pst_function::handle_call_site(Dwarf_Die* result) if(dwarf_hasattr (result, DW_AT_GNU_call_site_target)) { attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem); if(attr) { - char str[1024]; str[0] = 0; - pst_dwarf_expr expr; - if(handle_location(ctx, &attr_mem, expr, pc, str, sizeof(str), this)) { + pst_dwarf_expr expr(ctx->alloc); + if(handle_location(ctx, &attr_mem, expr, pc, this)) { target = expr.value; ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_target: %#lX", target); } @@ -783,12 +493,13 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d) unw_proc_info_t info; unw_get_proc_info(&cursor, &info); + ctx->clean_print(ctx); ctx->log(SEVERITY_INFO, "Function %s(...): LOW_PC = %#lX, HIGH_PC = %#lX, offset from base address: 0x%lX, START_PC = 0x%lX, offset from start of function: 0x%lX", dwarf_diename(d), lowpc, highpc, pc - ctx->base_addr, info.start_ip, info.start_ip - ctx->base_addr); - ctx->print_registers(0x0, 0x10); - ctx->log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), parent ? parent->sp : 0, ctx->get_print()); - ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->get_print()); + ctx->print_registers(ctx, 0x0, 0x10); + ctx->log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), parent ? parent->sp : 0, ctx->buff); + ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->buff); // determine function's stack frame base attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem); @@ -797,19 +508,19 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d) Dwarf_Op *expr; size_t exprlen; if (dwarf_getlocation (attr, &expr, &exprlen) == 0) { - char str[1024]; str[0] = 0; - ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr); - dwarf_stack stack(ctx); - if(stack.calc_expression(expr, exprlen, attr, this)) { + ctx->print_expr(ctx, expr, exprlen, attr); + pst_decl(pst_dwarf_stack, stack, ctx); + if(stack.calc(&stack, expr, exprlen, attr, this)) { uint64_t value; - if(stack.get_value(value)) { - ctx->log(SEVERITY_DEBUG, "DW_AT_framebase expression: \"%s\" ==> 0x%lX", str, value); + if(stack.get_value(&stack, &value)) { + ctx->log(SEVERITY_DEBUG, "DW_AT_framebase expression: \"%s\" ==> 0x%lX", ctx->buff, value); } else { - ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_framebase expression: %s", str); + ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_framebase expression: %s", ctx->buff); } } else { - ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_framebase expression: %s", str); + ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_framebase expression: %s", ctx->buff); } + pst_dwarf_stack_fini(&stack); } else { ctx->log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code); } @@ -901,12 +612,12 @@ bool __pst_function::unwind(Dwarf_Addr addr) str = filename; } file = str; - ctx->print("%s:%d", str, line); + ctx->print(ctx, "%s:%d", str, line); } else { - ctx->print("%p", (void*)addr); + ctx->print(ctx, "%p", (void*)addr); } } else { - ctx->print("%p", (void*)addr); + ctx->print(ctx, "%p", (void*)addr); } const char* addrname = dwfl_module_addrname(ctx->module, addr); @@ -919,7 +630,7 @@ bool __pst_function::unwind(Dwarf_Addr addr) ctx->log(SEVERITY_ERROR, "Failed to allocate memory"); return false; } - ctx->print(" --> %s", function_name); + ctx->print(ctx, " --> %s", function_name); char* str = strchr(function_name, '('); if(str) { @@ -986,12 +697,12 @@ bool __pst_function::get_frame() ctx->log(SEVERITY_ERROR, "Failed to get CFA for frame"); return false; } - char str[1024]; str[0] = 0; - ctx->print_expr_block (cfa_ops, cfa_nops, str, sizeof(str)); - dwarf_stack st(ctx); - if(st.calc_expression(cfa_ops, cfa_nops, NULL) && st.get_value(cfa)) { + + ctx->print_expr(ctx, cfa_ops, cfa_nops, NULL); + pst_decl(pst_dwarf_stack, stack, ctx); + if(stack.calc(&stack, cfa_ops, cfa_nops, NULL, this) && stack.get_value(&stack, &cfa)) { //ctx.sp = v; - ctx->log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", name.c_str(), str, cfa); + ctx->log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", name.c_str(), ctx->buff, cfa); // setup context to match CFA for frame ctx->cfa = cfa; @@ -999,6 +710,8 @@ bool __pst_function::get_frame() ctx->log(SEVERITY_ERROR, "Failed to calculate CFA expression"); } + pst_dwarf_stack_fini(&stack); + return true; } @@ -1081,7 +794,7 @@ pst_function* __pst_handler::last_function() bool __pst_handler::handle_dwarf() { - ctx.clean_print(); + ctx.clean_print(&ctx); Dl_info info; //for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) { @@ -1103,13 +816,13 @@ bool __pst_handler::handle_dwarf() void __pst_handler::print_dwarf() { - ctx.clean_print(); - ctx.print("DWARF-based stack trace information:\n"); + ctx.clean_print(&ctx); + ctx.print(&ctx, "DWARF-based stack trace information:\n"); uint32_t idx = 0; for(pst_function* function = next_function(NULL); function; function = next_function(function)) { - ctx.print("[%-2u] ", idx); idx++; + ctx.print(&ctx, "[%-2u] ", idx); idx++; function->print_dwarf(); - ctx.print("\n"); + ctx.print(&ctx, "\n"); } } @@ -1125,7 +838,7 @@ Dwfl_Callbacks callbacks = { bool __pst_handler::unwind() { - ctx.clean_print(); + ctx.clean_print(&ctx); #ifdef REG_RIP // x86_64 caller = (void *) ctx.hcontext->uc_mcontext.gregs[REG_RIP]; ctx.sp = ctx.hcontext->uc_mcontext.gregs[REG_RSP]; @@ -1154,16 +867,16 @@ bool __pst_handler::unwind() ctx.dwfl = dwfl_begin(&callbacks); if(ctx.dwfl == NULL) { - ctx.print("Failed to initialize libdw session for parse stack frames"); + ctx.print(&ctx, "Failed to initialize libdw session for parse stack frames"); return false; } if(dwfl_linux_proc_report(ctx.dwfl, getpid()) != 0 || dwfl_report_end(ctx.dwfl, NULL, NULL) !=0) { - ctx.print("Failed to parse debug section of executable"); + ctx.print(&ctx, "Failed to parse debug section of executable"); return false; } - ctx.print("Stack trace: caller = %p\n", caller); + ctx.print(&ctx, "Stack trace: caller = %p\n", caller); unw_getcontext(&ctx.context); unw_init_local(&ctx.cursor, &ctx.context); @@ -1186,7 +899,7 @@ bool __pst_handler::unwind() continue; } - ctx.print("[%-2d] ", i); + ctx.print(&ctx, "[%-2d] ", i); ctx.module = dwfl_addrmodule(ctx.dwfl, addr); pst_function* last = last_function(); pst_function* fun = add_function(NULL); @@ -1200,7 +913,7 @@ bool __pst_handler::unwind() } //get_frame(fun); } - ctx.print("\n"); + ctx.print(&ctx, "\n"); } return true; diff --git a/framework/sysutils.h b/framework/sysutils.h index e3eb27a..5261e1c 100644 --- a/framework/sysutils.h +++ b/framework/sysutils.h @@ -22,103 +22,20 @@ #include #include +#include "allocator.h" #include "common.h" #include "context.h" -#include "dictionary.h" -#include "data_entry.h" +#include "allocator.h" +#include "list_head.h" +#include "dwarf_expression.h" +#include "dwarf_parameter.h" -// DWARF operation (represents our own DW_OP_XXX) -typedef struct __pst_dwarf_op : public SC_ListNode { - __pst_dwarf_op(uint8_t op, uint64_t a1, uint64_t a2) { - operation = op; arg1 = a1; arg2 = a2; - } - uint8_t operation; - uint64_t arg1; - uint64_t arg2; -} pst_dwarf_op; - -typedef struct __pst_dwarf_expr : public SC_ListHead { - __pst_dwarf_expr() { - has_value = false; value = 0; offset = 0; buff[0] = 0; - } - ~__pst_dwarf_expr() { - clean(); - } - pst_dwarf_op* add_op(uint8_t op, uint64_t arg1, uint64_t arg2); - pst_dwarf_op* next_op(pst_dwarf_op* op); - void clean(); - void setup(Dwarf_Op* expr, size_t exprlen); - void set_value(uint64_t v) { - has_value = true; - value = v; - } - bool print_op(const char* fmt, ...); - - bool operator== (__pst_dwarf_expr &rhs); - - bool has_value; - uint64_t value; - char buff[512]; - uint16_t offset; -} pst_dwarf_expr; - -typedef struct __pst_type : public SC_ListNode { - __pst_type(const char* n, uint32_t t) : type(t) { - if(n) { - name = n; - } - } - std::string name; // type name - uint32_t type; // DW_AT_XXX type -} pst_type; - -typedef struct __pst_function pst_function; - -typedef struct __pst_parameter : public SC_ListNode { - __pst_parameter(pst_context* c) : ctx(c) - { - die = NULL; - size = 0; - type = 0; - enc_type = 0; - is_return = false; - is_variable = false; - has_value = false; - line = 0; - } - - ~__pst_parameter() - { - clear(); - } - - void clear(); - pst_type* add_type(const char* name, int type); - pst_type* next_type(pst_type* t); - - bool handle_dwarf(Dwarf_Die* d, __pst_function* fun); - bool handle_type(Dwarf_Attribute* param); - bool print_dwarf(); - - Dwarf_Die* die; // DWARF DIE containing parameter's definition - std::string name; // parameter's name - uint32_t line; // line of parameter definition - Dwarf_Word size; // size of parameter in bytes - int type; // type of parameter in DW_TAG_XXX types enumeration - Dwarf_Word enc_type; // if 'type' is DW_TAG_Base_type, then 'base_type' holds DW_AT_ATE_XXX base type encoding type - SC_ListHead types; // list of parameter's definitions i.e. 'typedef', 'uint32_t' - bool is_return; // whether this parameter is return value of the function - bool is_variable;// whether this parameter is function variable or argument of function - bool has_value; // whether we got value of parameter or not - pst_dwarf_expr location; - pst_context* ctx; -} pst_parameter; - // DW_TAG_call_site_parameter typedef struct __pst_call_site_param : public SC_ListNode { __pst_call_site_param(pst_context* ctx) { param = NULL; name = NULL; value = 0; + pst_dwarf_expr_init(&location, ctx->alloc); } ~__pst_call_site_param() { @@ -233,8 +150,9 @@ typedef struct __pst_function : public SC_ListNode { } pst_function; typedef struct __pst_handler { - __pst_handler(ucontext_t* hctx) : ctx(hctx) + __pst_handler(ucontext_t* hctx) { + pst_context_init(&ctx, hctx); caller = NULL; frame = NULL; addr = 0; @@ -248,6 +166,7 @@ typedef struct __pst_handler { } clear(); + pst_context_fini(&ctx); } void clear(); diff --git a/main.cpp b/main.cpp index 7ccb4b6..b33fe99 100644 --- a/main.cpp +++ b/main.cpp @@ -3,13 +3,9 @@ #include #include -#include "logger/log_console.h" - +#include "context.h" #include "sysutils.h" -static SC_LogConsole log_local(0, "/tmp/unspecified.file"); -SC_LogBase* logger = &log_local; - typedef enum { DEF_1 = 1, DEF_2, @@ -64,7 +60,7 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context) fatal_error_in_progress = 1; - logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig)); + logger.log(&logger, SEVERITY_ERROR, "%s signal handled", strsignal(sig)); bool ret = false; pst_handler handler((ucontext_t*)context); @@ -74,12 +70,12 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context) } if(ret) { - logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print()); + logger.log(&logger, SEVERITY_INFO, "%s", handler.ctx.buff); handler.handle_dwarf(); handler.print_dwarf(); - logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print()); + logger.log(&logger, SEVERITY_INFO, "%s", handler.ctx.buff); } else { - logger->Log(SEVERITY_ERROR, "No stack trace obtained"); + logger.log(&logger, SEVERITY_ERROR, "No stack trace obtained"); } // comment out line below to prevent coredump @@ -102,9 +98,9 @@ void SignalHandler(int sig) // const char* str_sig = strsignal(sig); // logger->Log(SEVERITY_INFO, "%s received.", str_sig); if(sig == SIGUSR1) { - logger->Log(SEVERITY_INFO, "Maintenance mode enabled."); + logger.log(&logger, SEVERITY_INFO, "Maintenance mode enabled."); } else if(sig == SIGUSR2) { - logger->Log(SEVERITY_INFO, "Maintenance mode disabled."); + logger.log(&logger, SEVERITY_INFO, "Maintenance mode disabled."); } // signal (sig, SIG_DFL); // raise(sig); @@ -181,7 +177,7 @@ void SetSignalHandler(sig_handler_t handler) limit.rlim_max = 1073741824; if (setrlimit(RLIMIT_CORE, &limit)) { - logger->Log(SEVERITY_DEBUG, "Failed to set limit for core dump file size"); + logger.log(&logger, SEVERITY_DEBUG, "Failed to set limit for core dump file size"); } } @@ -197,6 +193,7 @@ void ResetSignalHandler() { int main(int argc, char* argv[]) { + pst_log_init_console(&logger); //logger->SetCurrentSeverity(SEVERITY_INFO); SetSignalHandler(SigusrHandler);