all code except of pst_function & pst_handler rewritten on C language.

Logger nad Allocator decided to be a global for all library
This commit is contained in:
2020-02-01 15:19:55 +04:00
parent fcdb15ba95
commit 8251ba526f
30 changed files with 2073 additions and 2068 deletions
+2 -2
View File
@@ -16,7 +16,7 @@ NC=
COLOR= COLOR=
endif endif
CXX = g++ CXX = gcc
CC = gcc CC = gcc
RM = rm -f RM = rm -f
AR = ar rvs 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/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) -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 -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) .PHONY: all clean $(BIN)
+2 -2
View File
@@ -16,7 +16,7 @@ NC=
COLOR= COLOR=
endif endif
CXX = g++ CXX = gcc
CC = gcc CC = gcc
RM = rm -f RM = rm -f
AR = ar rvs AR = ar rvs
@@ -37,7 +37,7 @@ SRC = $(wildcard $(addsuffix /*.cpp,${VPATH}))
OBJ = $(patsubst %.cpp,%.o,$(addprefix $(BUILD_DIR)/,$(notdir $(SRC)))) 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" 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 .PHONY: all clean
+35 -19
View File
@@ -7,55 +7,71 @@
#include <stdlib.h> #include <stdlib.h>
#include <malloc.h> #include <malloc.h>
#include <string.h>
#include "common.h"
#include "allocator.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); free(buff);
} }
void* heap_alloc(pst_allocator& alloc, uint32_t size) void* heap_alloc(pst_allocator* alloc, uint32_t size)
{ {
void* buff = malloc(size); void* buff = malloc(size);
alloc.size += malloc_usable_size(buff); alloc->size += malloc_usable_size(buff);
return 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); void* new_buff = realloc(buff, new_size);
alloc.size += malloc_usable_size(new_buff); alloc->size += malloc_usable_size(new_buff);
return new_buff; return new_buff;
} }
void pst_alloc_init(pst_allocator& alloc) void pst_alloc_init(pst_allocator* alloc)
{ {
alloc.type = ALLOC_HEAP; alloc->type = ALLOC_HEAP;
alloc.base = NULL; alloc->base = NULL;
alloc.size = 0; alloc->size = 0;
alloc.alloc = heap_alloc; alloc->alloc = heap_alloc;
alloc.free = heap_free; alloc->free = heap_free;
alloc.realloc = heap_realloc; alloc->realloc = heap_realloc;
return; 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 // TBD to implement custom allocator
pst_alloc_init(alloc); pst_alloc_init(alloc);
return; return;
} }
void pst_alloc_fini(pst_allocator& alloc) void pst_alloc_fini(pst_allocator* alloc)
{ {
alloc.type = ALLOC_NONE; if(alloc->type == ALLOC_HEAP || alloc->type == ALLOC_CUSTOM) {
alloc.base = NULL; alloc->type = ALLOC_NONE;
alloc.size = 0; 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;
} }
+28 -10
View File
@@ -5,17 +5,33 @@
* Author: nnosov * Author: nnosov
*/ */
#ifndef FRAMEWORK_ALLOCATOR_H_ #ifndef PST_ALLOCATOR_H_
#define FRAMEWORK_ALLOCATOR_H_ #define PST_ALLOCATOR_H_
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <assert.h>
// 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 struct __pst_allocator pst_allocator;
typedef void* (*pst_alloc_def)(pst_allocator& alloc, uint32_t 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_free_def)(pst_allocator* alloc, void* buff);
typedef void* (*pst_realloc_def)(pst_allocator& alloc, void* buff, uint32_t new_size); typedef void* (*pst_realloc_def)(pst_allocator* alloc, void* buff, uint32_t new_size);
typedef enum { typedef enum {
ALLOC_NONE = 0, // not initialized ALLOC_NONE = 0, // not initialized
@@ -33,8 +49,10 @@ typedef struct __pst_allocator {
pst_realloc_def realloc; pst_realloc_def realloc;
} pst_allocator; } pst_allocator;
void pst_alloc_init(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_init_custom(pst_allocator* alloc, void* buff, uint32_t size);
void pst_alloc_fini(pst_allocator& alloc); void pst_alloc_fini(pst_allocator* alloc);
#endif /* FRAMEWORK_ALLOCATOR_H_ */ char* pst_dup(pst_allocator* alloc, const char* str);
#endif /* PST_ALLOCATOR_H_ */
-61
View File
@@ -19,67 +19,6 @@
#include "dwarf_operations.h" #include "dwarf_operations.h"
#include "registers.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) bool is_location_form(int form)
{ {
if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block || if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block ||
+11 -1
View File
@@ -1,8 +1,18 @@
#pragma once #ifndef __PST_COMMON_H__
#define __PST_COMMON_H__
#include <stdint.h>
#define USE_LIBUNWIND #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); int32_t decode_sleb128(uint8_t *sleb128);
uint32_t decode_uleb128(uint8_t *uleb128); uint32_t decode_uleb128(uint8_t *uleb128);
bool is_location_form(int form); bool is_location_form(int form);
#endif // __PST_COMMON_H__
+99 -55
View File
@@ -13,140 +13,184 @@
#include "dwarf_operations.h" #include "dwarf_operations.h"
extern SC_LogBase* logger;
extern dwarf_reg_map reg_map[]; extern dwarf_reg_map reg_map[];
extern int regnum; 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); ctx->log(SEVERITY_DEBUG, "CFA = %#lX, NEXT_CFA = %#lX, SP = %#lX", ctx->cfa, next_cfa, ctx->sp);
clean_print(); ctx->clean_print(ctx);
int i = 0; int i = 0;
if(cfa > sp) { if(ctx->cfa > ctx->sp) {
print("Args: "); ctx->print(ctx, "Args: ");
for(; i < max && (cfa - i) > sp; ++i) { for(; i < max && (ctx->cfa - i) > ctx->sp; ++i) {
print("#%d 0x%lX ", i, *(uint64_t*)(cfa - i)); ctx->print(ctx, "#%d 0x%lX ", i, *(uint64_t*)(ctx->cfa - i));
} }
} }
if((cfa - i) > next_cfa) { if((ctx->cfa - i) > next_cfa) {
print("Vars: "); ctx->print(ctx, "Vars: ");
for(; i < max && (cfa - i) > next_cfa; ++i) { for(; i < max && (ctx->cfa - i) > next_cfa; ++i) {
print("#%d 0x%lX ", i, *(uint64_t*)(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) { for(int i = from; i < regnum && i <= to; ++i) {
unw_word_t regval; unw_word_t regval;
if(!unw_get_reg(curr_frame, reg_map[i].regno, &regval)) { if(!unw_get_reg(ctx->curr_frame, reg_map[i].regno, &regval)) {
print("%s: %#lX ", reg_map[i].regname, regval); ctx->print(ctx, "%s: %#lX ", reg_map[i].regname, regval);
} else { } else {
print("%s: <undef>", reg_map[i].regname); ctx->print(ctx, "%s: <undef>", reg_map[i].regname);
} }
} }
} }
bool __pst_context::print(const char* fmt, ...) bool print(pst_context* ctx, const char* fmt, ...)
{ {
bool nret = true; bool nret = true;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
int size = sizeof(buff) - offset; int size = sizeof(ctx->buff) - ctx->offset;
int ret = vsnprintf(buff + offset, size, fmt, args); int ret = vsnprintf(ctx->buff + ctx->offset, size, fmt, args);
if(ret >= size || ret < 0) { if(ret >= size || ret < 0) {
nret = false; nret = false;
} }
offset += ret; ctx->offset += ret;
va_end(args); va_end(args);
return nret; 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; logger.log(&logger, severity, fmt);
char str[PATH_MAX]; str[0] = 0;
va_list args;
va_start(args, fmt);
str_len += vsnprintf(str + str_len, sizeof(str) - str_len, fmt, args);
va_end(args);
logger->Log(severity, "%s", str);
} }
uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr) bool print_expr_block (pst_context* ctx, Dwarf_Op *exprs, int exprlen, Dwarf_Attribute* attr)
{ {
uint32_t offset = 0; ctx->clean_print(ctx);
for (int i = 0; i < len; i++) { for (int i = 0; i < exprlen; i++) {
//printf ("%s", (i + 1 < len ? ", " : ""));
const dwarf_op_map* map = find_op_map(exprs[i].atom); const dwarf_op_map* map = find_op_map(exprs[i].atom);
if(map) { if(map) {
if(map->op_num >= DW_OP_breg0 && map->op_num <= DW_OP_breg16) { if(map->op_num >= DW_OP_breg0 && map->op_num <= DW_OP_breg16) {
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number); int32_t off = decode_sleb128((unsigned char*)&exprs[i].number);
int regno = map->op_num - DW_OP_breg0; int regno = map->op_num - DW_OP_breg0;
unw_word_t ptr = 0; unw_word_t ptr = 0;
unw_get_reg(curr_frame, regno, &ptr); unw_get_reg(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_reg0 && map->op_num <= DW_OP_reg16) { } else if(map->op_num >= DW_OP_reg0 && map->op_num <= DW_OP_reg16) {
unw_word_t value = 0; unw_word_t value = 0;
int regno = map->op_num - DW_OP_reg0; int regno = map->op_num - DW_OP_reg0;
unw_get_reg(curr_frame, regno, &value); unw_get_reg(ctx->curr_frame, regno, &value);
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s) value: 0x%lX", map->op_name, unw_regname(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) { } 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); 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; Dwarf_Attribute attr_mem;
if(!dwarf_getlocation_attr(attr, exprs, &attr_mem)) { if(!dwarf_getlocation_attr(attr, exprs, &attr_mem)) {
Dwarf_Op *expr; Dwarf_Op *expr;
size_t exprlen; size_t exprlen;
if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) { if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) {
offset += print_expr_block (expr, exprlen, buff + offset, buff_size - offset, &attr_mem); ctx->print_expr(ctx, expr, exprlen, &attr_mem);
offset += snprintf(buff + offset, buff_size - offset, ") "); ctx->print(ctx, ") ");
} else { } 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 { } 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) { } 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) { } else if(map->op_num == DW_OP_plus_uconst) {
uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number); 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) { } else if(map->op_num == DW_OP_bregx) {
uint32_t regno = decode_uleb128((unsigned char*)&exprs[i].number); uint32_t regno = decode_uleb128((unsigned char*)&exprs[i].number);
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number2); int32_t off = decode_sleb128((unsigned char*)&exprs[i].number2);
unw_word_t ptr = 0; unw_word_t ptr = 0;
unw_get_reg(curr_frame, regno, &ptr); unw_get_reg(ctx->curr_frame, regno, &ptr);
//ptr += off; //ptr += off;
offset += snprintf(buff + offset, buff_size - offset, "%s(%s%s%d) reg_value = 0x%lX", map->op_name, unw_regname(regno), off >= 0 ? "+" : "", off, ptr); 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) { } else if(map->op_num == DW_OP_regx) {
int32_t reg = decode_sleb128((unsigned char*)&exprs[i].number); int32_t reg = decode_sleb128((unsigned char*)&exprs[i].number);
unw_word_t value = 0; unw_word_t value = 0;
unw_get_reg(curr_frame, reg, &value); unw_get_reg(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) { } 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) { } else if(map->op_num == DW_OP_fbreg) {
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number); 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 { } 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 { } 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);
}
+17 -28
View File
@@ -15,51 +15,40 @@
#include <elfutils/libdwfl.h> #include <elfutils/libdwfl.h>
#include "logger/log.h" #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 { typedef struct __pst_context {
__pst_context(ucontext_t* hctx) : hcontext(hctx) // methods
{ void (*clean_print) (__pst_context* ctx);
clean_print(); bool (*print) (__pst_context* ctx, const char* fmt, ...);
base_addr = 0; void (*log) (SC_LogSeverity severity, const char*fmt, ...);
sp = 0; bool (*print_expr) (__pst_context* ctx, Dwarf_Op *exprs, int exprlen, Dwarf_Attribute* attr);
cfa = 0; void (*print_registers) (__pst_context* ctx, int from, int to);
curr_frame = NULL; void (*print_stack) (__pst_context* ctx, int max, uint64_t next_cfa);
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;
}
// fields
ucontext_t* hcontext; // context of signal handler ucontext_t* hcontext; // context of signal handler
unw_context_t context; // context of stack trace unw_context_t context; // context of stack trace
unw_cursor_t cursor; unw_cursor_t cursor; // libunwind stack frame storage
unw_cursor_t* curr_frame; // callee libunwind frame unw_cursor_t* curr_frame; // callee libunwind frame
Dwarf_Addr base_addr; // base address where process loaded Dwarf_Addr base_addr; // base address where process loaded
Dwarf_Addr sp; // stack pointer of currently processed stack frame 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 Dwarf_Frame* frame; // currently examined libdwfl frame
Dwfl* dwfl; // DWARF context Dwfl* dwfl; // DWARF context
Dwfl_Module* module; // currently processed CU Dwfl_Module* module; // currently processed CU
protected: // print buffer
char buff[8192]; // stack trace buffer char buff[8192]; // stack trace buffer
uint32_t offset; // offset in the 'buff' uint32_t offset; // offset in the 'buff'
} pst_context; } pst_context;
void pst_context_init(pst_context* ctx, ucontext_t* hctx);
void pst_context_fini(pst_context* ctx);
#endif /* FRAMEWORK_CONTEXT_H_ */ #endif /* FRAMEWORK_CONTEXT_H_ */
-36
View File
@@ -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 <stdint.h>
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_ */
-71
View File
@@ -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;
}
-275
View File
@@ -1,275 +0,0 @@
/*
* dictionary.h
*
* Created on: Aug 5, 2014
* Author: nnosov
*/
#ifndef DICTIONARY_H_
#define DICTIONARY_H_
//system
#include <stdint.h>
#include <string.h>
//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_ */
+174
View File
@@ -0,0 +1,174 @@
/*
* dwarf_expression.cpp
*
* Created on: Feb 1, 2020
* Author: nnosov
*/
#include <stdarg.h>
#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);
}
}
+55
View File
@@ -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 <inttypes.h>
#include <elfutils/libdwfl.h>
#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_ */
+169 -426
View File
@@ -10,19 +10,19 @@
#include "dwarf_operations.h" #include "dwarf_operations.h"
#include "common.h" #include "common.h"
#include "registers.h"
// not implemented operations // 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; return false;
} }
// The DW_OP_addr operation has a single operand that encodes a machine // 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. // 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; return true;
} }
@@ -32,12 +32,11 @@ 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 // retrieved is zero extended to the size of an address on the target machine
// before being pushed onto the expression stack. // 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) { if(value) {
uint64_t addr; uint64_t addr = value->value.uint64;
if(value->get_uint(addr)) {
uint64_t res = 0; uint64_t res = 0;
switch(op1) { switch(op1) {
case 1: case 1:
@@ -52,11 +51,13 @@ bool dw_op_deref_size(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op
case 8: case 8:
res = *((uint64_t*)addr); res = *((uint64_t*)addr);
break; break;
default:
return false;
break;
} }
stack->push(&res, sizeof(res), DWARF_TYPE_GENERIC); stack->push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC);
return true; return true;
} }
}
return false; 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 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 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. // 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); 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_const<n>u operation provides a 1, 2, 4, or 8-byte unsigned integer constant, respectively. // DW_OP_const1u, DW_OP_const2u, DW_OP_const4u, DW_OP_const8u. The single operand of a DW_OP_const<n>u operation provides a 1, 2, 4, or 8-byte unsigned integer constant, respectively.
// These operations push a value with the generic type // 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; uint8_t size = 0;
dwarf_value_type type = DWARF_TYPE_UNSIGNED; pst_dwarf_value_type type = DWARF_TYPE_UNSIGNED;
switch (map->op_num) { switch (map->op_num) {
case DW_OP_const1u: case DW_OP_const1u:
size = 1; 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; 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; return true;
} }
// DW_OP_const1s, DW_OP_const2s, DW_OP_const4s, DW_OP_const8s. The single operand of a DW_OP_const<n>s operation provides a 1, 2, 4, or 8-byte signed integer constant, respectively. // DW_OP_const1s, DW_OP_const2s, DW_OP_const4s, DW_OP_const8s. The single operand of a DW_OP_const<n>s operation provides a 1, 2, 4, or 8-byte signed integer constant, respectively.
// These operations push a value with the generic type // 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; 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) { switch (map->op_num) {
case DW_OP_const1s: case DW_OP_const1s:
v = (int8_t)op1; 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; 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; return true;
} }
// The single operand of the DW_OP_constu operation provides an unsigned LEB128 integer constant. // 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); 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; 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. // The single operand of the DW_OP_consts operation provides a signed LEB128 integer constant.
int64_t value = decode_sleb128((unsigned char*)&op1); 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; return true;
} }
// The DW_OP_dup operation duplicates the value (including its type identifier) at the top of the stack. // 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(); pst_dwarf_value* value = stack->get(stack, 0);
stack->push(value->value, value->size, value->type); stack->push(stack, &value->value, sizeof(value->value), value->type);
return true; return true;
} }
// The DW_OP_drop operation pops the value (including its type identifier) at the top of the stack. // 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(); pst_dwarf_value* value = stack->pop(stack);
free(value); pst_dwarf_value_fini(value);
return true; return true;
} }
// The DW_OP_over operation duplicates the entry currently second in the stack at the top of the stack. // 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. // 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); pst_dwarf_value* value = stack->get(stack, 1);
stack->push(value->value, value->size, value->type); stack->push(stack, &value->value, sizeof(value->value), value->type);
return true; return true;
} }
// The single operand of the DW_OP_pick operation provides a 1-byte index. // 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. // 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) { if(value) {
stack->push(value->value, value->size, value->type); stack->push(stack, &value->value, sizeof(value->value), value->type);
return true; 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 // 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. // 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(); pst_dwarf_value* value1 = stack->pop(stack);
dwarf_value* value2 = stack->pop(); pst_dwarf_value* value2 = stack->pop(stack);
if(value1 && value2) { if(value1 && value2) {
stack->push(value1); stack->push_value(stack, value1);
stack->push(value2); stack->push_value(stack, value2);
return true; return true;
} }
if(value1) { if(value1) {
delete(value1); pst_dwarf_value_fini(value1);
} }
if(value2) { if(value2) {
delete(value2); pst_dwarf_value_fini(value2);
} }
return false; 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 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, // 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 // 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(); pst_dwarf_value* value1 = stack->pop(stack);
dwarf_value* value2 = stack->pop(); pst_dwarf_value* value2 = stack->pop(stack);
dwarf_value* value3 = stack->pop(); pst_dwarf_value* value3 = stack->pop(stack);
if(value1 && value2 && value3) { if(value1 && value2 && value3) {
stack->push(value1); stack->push_value(stack, value1);
stack->push(value3); stack->push_value(stack, value3);
stack->push(value2); stack->push_value(stack, value2);
return true; return true;
} }
if(value1) { if(value1) {
free(value1); pst_dwarf_value_fini(value1);
} }
if(value2) { if(value2) {
free(value2); pst_dwarf_value_fini(value2);
} }
if(value3) { if(value3) {
free(value3); pst_dwarf_value_fini(value3);
} }
return false; 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. // 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. // 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) { if(value) {
int64_t v; uint64_t res = llabs(value->value.int64);
if(!value->get_int(v)) { value->set(value, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC | DWARF_TYPE_LONG);
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);
} }
return false; 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. // 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); pst_dwarf_value* value1 = stack->get(stack, 0);
dwarf_value* value2 = stack->get(1); pst_dwarf_value* value2 = stack->get(stack, 1);
if(value1 && value2) { if(value1 && value2) {
if(!(value1->type & value2->type)) { 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; return false;
} }
if(!value2->get_generic(v2)) { uint64_t res = value1->value.uint64 & value2->value.uint64;
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); stack->pop(stack); stack->pop(stack);
return false; stack->push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC);
}
uint64_t res = v1 & v2; pst_dwarf_value_fini(value1);
stack->pop(); stack->pop(); pst_dwarf_value_fini(value2);
stack->push(&res, value1->size, DWARF_TYPE_GENERIC);
return true; 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. // 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); pst_dwarf_value* value1 = stack->get(stack, 0);
dwarf_value* value2 = stack->get(1); pst_dwarf_value* value2 = stack->get(stack, 1);
if(value1 && value2) { if(value1 && value2) {
if(!(value1->type & value2->type)) { 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; return false;
} }
if(value2->type & DWARF_TYPE_SIGNED) { 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) { if(value1->type & DWARF_TYPE_SIGNED) {
int64_t sig1; if(value1->value.int64 == 0) {
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; return false;
} }
if(sig1 == 0) { uint64_t res = value2->value.int64 / value1->value.int64;
stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig2); stack->pop(stack); stack->pop(stack);
return false; stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
}
uint64_t res = sig2 / sig1;
stack->pop(); stack->pop();
stack->push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
return true; return true;
} else { } else {
uint64_t unsig1; if(value1->value.uint64 == 0) {
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; return false;
} }
if(unsig1 == 0) { int64_t res = value2->value.int64 / value1->value.uint64;
stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, sig2); stack->pop(stack); stack->pop(stack);
return false; stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
}
int64_t res = sig2 / unsig1;
stack->pop(); stack->pop();
stack->push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
return true; return true;
} }
} else { } 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) { if(value1->type & DWARF_TYPE_SIGNED) {
int64_t sig1; if(value1->value.int64 == 0) {
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; return false;
} }
if(sig1 == 0) { int64_t res = value2->value.uint64 / value1->value.int64;
stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig1); stack->pop(stack); stack->pop(stack);
return false; stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
}
int64_t res = unsig2 / sig1;
stack->pop(); stack->pop();
stack->push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
return true; return true;
} else { } else {
uint64_t unsig1; if(value1->value.uint64 == 0) {
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; return false;
} }
if(unsig1 == 0) { uint64_t res = value2->value.uint64 / value1->value.uint64;
stack->ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, unsig2); stack->pop(stack); stack->pop(stack);
return false; stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
}
uint64_t res = unsig2 / unsig1;
stack->pop(); stack->pop();
stack->push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
return true; 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. // 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); pst_dwarf_value* value1 = stack->get(stack, 0);
dwarf_value* value2 = stack->get(1); pst_dwarf_value* value2 = stack->get(stack, 1);
if(value1 && value2) { if(value1 && value2) {
if(!(value1->type & value2->type)) { 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; return false;
} }
int res_type = DWARF_TYPE_GENERIC; int res_type = DWARF_TYPE_GENERIC;
if(value2->type & DWARF_TYPE_MEMORY_LOC) { if(value2->type & DWARF_TYPE_MEMORY_LOC) {
res_type |= DWARF_TYPE_MEMORY_LOC; res_type |= DWARF_TYPE_MEMORY_LOC;
} }
uint64_t res = unsig2 - unsig1; // use arithmetic by modulo 1 plus
stack->pop(); stack->pop(); uint64_t res = value2->value.uint64 - value1->value.uint64;
stack->push(&res, sizeof(res), res_type); stack->pop(stack); stack->pop(stack);
stack->push(stack, &res, sizeof(res), res_type);
return true; 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. // 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); pst_dwarf_value* value1 = stack->get(stack, 0);
dwarf_value* value2 = stack->get(1); pst_dwarf_value* value2 = stack->get(stack, 1);
if(value1 && value2) { if(value1 && value2) {
if(!(value1->type & value2->type)) { 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; return false;
} }
if(v1 == 0) { if(value1->value.uint64 == 0) {
stack->ctx->log(SEVERITY_ERROR, "Division by zero requested, aborting.");
return false; return false;
} }
if(!value2->get_uint(v2)) { uint64_t res = value2->value.uint64 % value1->value.uint64;
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); stack->pop(stack); stack->pop(stack);
return false; 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; 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. // 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); pst_dwarf_value* value1 = stack->get(stack, 0);
dwarf_value* value2 = stack->get(1); pst_dwarf_value* value2 = stack->get(stack, 1);
if(value1 && value2) { if(value1 && value2) {
if(!(value1->type & value2->type)) { 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); 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) { 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) { if(value1->type & DWARF_TYPE_SIGNED) {
int64_t sig1; uint64_t res = value2->value.int64 * value1->value.int64;
if(!value1->get_int(sig1)) { stack->pop(stack); stack->pop(stack);
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
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);
return true; return true;
} else { } else {
uint64_t unsig1; int64_t res = value2->value.int64 * value1->value.uint64;
if(!value1->get_uint(unsig1)) { stack->pop(stack); stack->pop(stack);
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
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);
return true; return true;
} }
} else { } 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) { if(value1->type & DWARF_TYPE_SIGNED) {
int64_t sig1; int64_t res = value2->value.uint64 * value1->value.int64;
if(!value1->get_int(sig1)) { stack->pop(stack); stack->pop(stack);
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
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);
return true; return true;
} else { } else {
uint64_t unsig1; uint64_t res = value2->value.uint64 * value1->value.uint64;
if(!value1->get_uint(unsig1)) { stack->pop(stack); stack->pop(stack);
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
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);
return true; return true;
} }
} }
@@ -537,43 +429,19 @@ 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. // 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. // 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) { if(value) {
int64_t v = 0; if(value->type & DWARF_TYPE_CHAR) {
if(!value->get_int(v)) { value->value.int8 *= -1;
stack->ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size); } else if(value->type & DWARF_TYPE_SHORT) {
return false; value->value.int16 *= -1;
} else if(value->type & DWARF_TYPE_INT) {
value->value.int32 *= -1;
} else {
value->value.int64 *= -1;
} }
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; return true;
} }
@@ -581,18 +449,11 @@ bool dw_op_neg(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar
} }
// The DW_OP_not operation pops the top stack entry, and pushes its bitwise complement. // 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) { if(value) {
uint64_t v = 0; value->value.uint64 = ~value->value.uint64;
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);
return true; 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. // 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); pst_dwarf_value* value1 = stack->get(stack, 0);
dwarf_value* value2 = stack->get(1); pst_dwarf_value* value2 = stack->get(stack, 1);
if(value1 && value2) { if(value1 && value2) {
if(!(value1->type & value2->type)) { 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; return false;
} }
if(!value2->get_uint(v2)) { uint64_t res = value2->value.uint64 | value1->value.uint64;
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); stack->pop(stack); stack->pop(stack);
return false; 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; return true;
} }
@@ -631,29 +485,29 @@ 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 // 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); pst_dwarf_value* value1 = stack->get(stack, 0);
dwarf_value* value2 = stack->get(1); pst_dwarf_value* value2 = stack->get(stack, 1);
if(value1 && value2) { if(value1 && value2) {
if(!(value1->type & value2->type)) { 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; return false;
} }
if(!value2->get_int(v2)) { if((value1->type & DWARF_TYPE_SIGNED) && (value2->type & DWARF_TYPE_SIGNED)) {
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); int64_t res = value2->value.int64 + value1->value.int64;
return false; 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); stack->pop(stack);
stack->pop(); stack->pop(); pst_dwarf_value_fini(value1);
stack->push(&res, value1->size, value1->type); pst_dwarf_value_fini(value2);
return true; return true;
} }
@@ -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. // 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 // This operation is supplied specifically to be able to encode more field offsets in two
// bytes than can be done with “DW_OP_lit<n> DW_OP_plus.” // bytes than can be done with “DW_OP_lit<n> 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) { if(value) {
uint64_t op = decode_uleb128((unsigned char*)&op1); uint64_t op = decode_uleb128((unsigned char*)&op1);
uint64_t v = 0; value->value.uint64 += op;
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);
return true; 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. // 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. // 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 // 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)) { if(map->op_num != DW_OP_regx && (map->op_num < DW_OP_reg0 || map->op_num > DW_OP_reg31)) {
return false; 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; regno = map->op_num - DW_OP_reg0;
} }
stack->push(&regno, sizeof(regno), DWARF_TYPE_REGISTER_LOC); stack->push(stack, &regno, sizeof(regno), DWARF_TYPE_REGISTER_LOC);
return true; 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) // 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 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. // 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)) { if(map->op_num != DW_OP_bregx && (map->op_num < DW_OP_breg0 || map->op_num > DW_OP_breg31)) {
return false; 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; unw_word_t val = 0;
int ret = unw_get_reg(stack->ctx->curr_frame, regno, &val); int ret = unw_get_reg(stack->ctx->curr_frame, regno, &val);
if(ret) { if(ret) {
stack->ctx->log(SEVERITY_ERROR, "%s: Failed to get register 0x%X value. Error: %d", __PRETTY_FUNCTION__, regno, ret);
return false; return false;
} }
val += off; val += off;
stack->push(&val, sizeof(val), DWARF_TYPE_GENERIC); stack->push(stack, &val, sizeof(val), DWARF_TYPE_GENERIC);
return true; return true;
} }
// The DW_OP_lit<n> operations encode the unsigned literal values from 0 through 31, inclusive. // The DW_OP_lit<n> 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. // 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) { if(map->op_num < DW_OP_lit0 || map->op_num > DW_OP_lit31) {
return false; return false;
} }
uint64_t val = map->op_num - DW_OP_lit0; 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; 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 // 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. // 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. // 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) { if(v) {
v->type = DWARF_TYPE_GENERIC; v->type = DWARF_TYPE_GENERIC;
return true; 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). // 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 // since we are already know SP value, just push it to DWARF stack
// unw_word_t sp; // 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; // 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; 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 // 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 // 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 // since in signal handler we are know SP value, just use it as DW_AT_frame_base
unw_word_t sp; unw_word_t sp;
@@ -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); int64_t off = decode_sleb128((unsigned char*)&op1);
sp += off; 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; return true;
} }
@@ -989,107 +836,3 @@ const dwarf_op_map* find_op_map(int op)
return NULL; 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(&param->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;
}
+3 -113
View File
@@ -3,124 +3,15 @@
#include <elfutils/libdwfl.h> #include <elfutils/libdwfl.h>
#include "common.h" #include "common.h"
#include "linkedlist.h" #include "list_head.h"
#include "sysutils.h" #include "sysutils.h"
#include "context.h" #include "context.h"
typedef enum { #include "dwarf_stack.h"
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;
typedef struct __dwarf_op_map dwarf_op_map; 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 { typedef struct __dwarf_op_map {
int op_num; // DWARF Operation DW_OP_XXX int op_num; // DWARF Operation DW_OP_XXX
@@ -129,4 +20,3 @@ typedef struct __dwarf_op_map {
} dwarf_op_map; } dwarf_op_map;
const dwarf_op_map* find_op_map(int op); const dwarf_op_map* find_op_map(int op);
int find_regnum(uint32_t op);
+304
View File
@@ -0,0 +1,304 @@
/*
* dwarf_parameter.cpp
*
* Created on: Feb 1, 2020
* Author: nnosov
*/
#include <dwarf.h>
#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(&param->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 = <undefined>", 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 = <undefined>", 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, &param->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, &param->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(&param->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, &param->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(&param->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*)&param->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, &param->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, &param->location.value);
param->has_value = true;
break;
case DW_FORM_sdata:
dwarf_formsdata(attr, (int64_t*)&param->location.value);
param->has_value = true;
break;
case DW_FORM_udata:
dwarf_formudata(attr, &param->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(&param->node);
param->die = NULL;
param->name = NULL;
param->line = 0;
param->size = 0;
param->type = 0;
param->enc_type = 0;
list_head_init(&param->types);
param->is_return = false;
param->is_variable = false;
param->has_value = false;
param->ctx = ctx;
pst_dwarf_expr_init(&param->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);
}
}
+61
View File
@@ -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 <inttypes.h>
#include <elfutils/libdwfl.h>
#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_ */
+302
View File
@@ -0,0 +1,302 @@
/*
* dwarf_stack.cpp
*
* Created on: Jan 29, 2020
* Author: nnosov
*/
#include <string.h>
#include <stdlib.h>
#include <dwarf.h>
#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, &param->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;
}
}
+120
View File
@@ -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 <stdint.h>
#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_ */
-138
View File
@@ -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 <stdint.h>
typedef struct __SC_ListNode
{
__SC_ListNode()
{
pPrev = pNext = 0;
}
bool IsListed()
{
return (pNext || pPrev);
}
__SC_ListNode* pNext;
__SC_ListNode* pPrev;
} SC_ListNode;
class SC_ListHead
{
public:
SC_ListHead()
{
mHead.pPrev = mHead.pNext = &mHead;
size = 0;
}
virtual ~SC_ListHead()
{
Clear();
}
void Clear()
{
for(SC_ListNode* node = (SC_ListNode*)First(); node; node = (SC_ListNode*)First())
{
Remove(node);
}
}
bool IsEmpty() const
{
return (mHead.pNext == &mHead);
}
SC_ListNode* First()
{
return IsEmpty() ? 0 : mHead.pNext;
}
SC_ListNode* Last()
{
return IsEmpty() ? 0 : mHead.pPrev;
}
SC_ListNode* Next(SC_ListNode* node)
{
return (!node || node == Last() || !node->IsListed()) ? 0 : node->pNext;
}
SC_ListNode* Prev(SC_ListNode* node)
{
return (!node || node == First() || !node->IsListed()) ? 0 : node->pPrev;
}
void InsertFirst(SC_ListNode* node)
{
node->pNext = mHead.pNext;
mHead.pNext = node;
node->pNext->pPrev = node;
node->pPrev = &mHead;
size++;
}
void InsertLast(SC_ListNode* node)
{
node->pNext = &mHead;
node->pPrev = mHead.pPrev;
node->pPrev->pNext = node;
mHead.pPrev = node;
size++;
}
void InsertAfter(SC_ListNode* pPrev, SC_ListNode* p)
{
p->pNext = pPrev->pNext;
p->pPrev = p->pNext->pPrev;
p->pNext->pPrev = p;
p->pPrev->pNext = p;
size++;
}
void InsertBefore(SC_ListNode* pNext, SC_ListNode* p)
{
p->pNext = pNext;
p->pPrev = pNext->pPrev;
pNext->pPrev = p;
p->pPrev->pNext = p;
size++;
}
void Remove(SC_ListNode* node)
{
node->pPrev->pNext = node->pNext;
node->pNext->pPrev = node->pPrev;
node->pNext = node->pPrev = 0;
size--;
}
uint32_t Size()
{
return size;
}
protected:
SC_ListNode mHead; //previous element in list
uint32_t size; //total number of elements in list
};
#endif /* LINKEDLIST_H_ */
+338
View File
@@ -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 <stddef.h> /* 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__
+222 -31
View File
@@ -1,55 +1,246 @@
#include "log.h" #include "log.h"
#include <time.h> #include <time.h>
#include <stdlib.h>
#define LOG_BUFF_SIZE (1024*1024) const char * const severity_map[] = {
const char * const SC_LogBase::mSeverityStrings[] = {
" [DEBUG] : ", " [DEBUG] : ",
" [INFO] : ", " [INFO] : ",
" [WARNING]: ", " [WARNING]: ",
" [ERROR] : " " [ERROR] : "
}; };
char SC_LogBase::mString[LOG_BUFF_SIZE]; void format_string(pst_log* log, const char* fmt, va_list args)
uint32_t SC_LogBase::mStringSize = sizeof(SC_LogBase::mString);
SC_LogBase::SC_LogBase(uint32_t id, const char* source) : mID(id)
{ {
mStringLen = 0; log->mStringLen += vsnprintf(log->mString + log->mStringLen, log->mStringSize - log->mStringLen, fmt, args);
mCurrentSeverity = SEVERITY_DEBUG;
if(source) {
mSource = source;
}
} }
SC_LogBase::~SC_LogBase() void format_prefix(pst_log* log, SC_LogSeverity severity)
{
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)
{ {
time_t rawTime; time_t rawTime;
struct tm * timeinfo; struct tm * timeinfo;
time(&rawTime); time(&rawTime);
timeinfo = gmtime(&rawTime); timeinfo = gmtime(&rawTime);
mStringLen += strftime(mString, sizeof(mString), "%d-%m-%Y %H:%M:%S", timeinfo); log->mStringLen += strftime(log->mString, sizeof(log->mString), "%d-%m-%Y %H:%M:%S", timeinfo);
strncpy(mString + mStringLen, mSeverityStrings[(int)severity], strlen(mSeverityStrings[(int)severity])); strncpy(log->mString + log->mStringLen, severity_map[(int)severity], strlen(severity_map[(int)severity]));
mStringLen += strlen(mSeverityStrings[(int)severity]); log->mStringLen += strlen(severity_map[(int)severity]);
} }
void SC_LogBase::FormatPostfix() void format_postfix(pst_log* log)
{ {
if((mStringLen + 2) < mStringSize) { if((log->mStringLen + 2) < log->mStringSize) {
mString[mStringLen++] = '\n'; log->mString[log->mStringLen++] = '\n';
mString[mStringLen++] = 0; 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;
}
+27 -125
View File
@@ -1,15 +1,12 @@
#ifndef LOG_H_ #ifndef PST_LOG_H_
#define LOG_H_ #define PST_LOG_H_
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <string> #include <pthread.h>
#include <limits.h>
#include "mutex.h"
using std::string;
// Log message severity // Log message severity
enum SC_LogSeverity { enum SC_LogSeverity {
@@ -21,128 +18,33 @@ enum SC_LogSeverity {
SEVERITY_MAX SEVERITY_MAX
}; };
#define LOG_BUFF_SIZE (1024*1024)
class SC_LogBase typedef struct __pst_log pst_log;
{
protected:
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;
mLock.Lock();
if(!IsOpened())
{
//print header if present
if(Open() && mHeader.size())
{
SendMessage((char*)mHeader.c_str(), severity);
}
}
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 SC_LogSeverity mCurrentSeverity; // maximum severity value to be logged
static const char * const mSeverityStrings[]; pthread_mutex_t mLock;
SC_Mutex mLock;
};
#endif /* LOG_H_ */ void* child;
} pst_log;
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);
#endif /* PST_LOG_H_ */
-53
View File
@@ -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
-108
View File
@@ -1,108 +0,0 @@
#ifndef LOG_FILE_H_
#define LOG_FILE_H_
//framework
#include "log.h"
#include <stdio.h>
#include <sys/types.h>
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_ */
-40
View File
@@ -1,40 +0,0 @@
#ifndef MUTEX_H_
#define MUTEX_H_
#include <pthread.h>
#include <sys/time.h>
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_ */
+1
View File
@@ -84,6 +84,7 @@ dwarf_reg_map reg_map[] = {
{0x1d, "XMM12", DW_OP_breg29}, {0x1d, "XMM12", DW_OP_breg29},
{0x1e, "XMM13", DW_OP_breg30}, {0x1e, "XMM13", DW_OP_breg30},
{0x1f, "XMM14", DW_OP_breg31}, {0x1f, "XMM14", DW_OP_breg31},
{0x20, "XMM15", 0xff}, // no mapping to dwarf registers
}; };
int regnum = sizeof(reg_map) / sizeof(dwarf_reg_map); int regnum = sizeof(reg_map) / sizeof(dwarf_reg_map);
+68 -355
View File
@@ -27,6 +27,8 @@
#include "common.h" #include "common.h"
#include "dwarf_operations.h" #include "dwarf_operations.h"
#include "allocator.h"
#include "dwarf_stack.h"
// dwfl_addrsegment() possibly can be used to check address validity // dwfl_addrsegment() possibly can be used to check address validity
// dwarf_getattrs() allows to enumerate all DIE attributes // dwarf_getattrs() allows to enumerate all DIE attributes
@@ -51,24 +53,21 @@ int regname_callback (void *arg, int regno, const char *setname, const char *pre
return 0; 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_Addr offset = pc - ctx->base_addr;
dwarf_stack stack(ctx); pst_decl(pst_dwarf_stack, stack, ctx);
Dwarf_Op *expr; Dwarf_Op *expr;
size_t exprlen; size_t exprlen;
bool ret = false;
if(dwarf_hasform(attr, DW_FORM_exprloc)) { if(dwarf_hasform(attr, DW_FORM_exprloc)) {
// Location expression (exprloc class of location in DWARF terms) // Location expression (exprloc class of location in DWARF terms)
if(dwarf_getlocation(attr, &expr, &exprlen) == 0) { if(dwarf_getlocation(attr, &expr, &exprlen) == 0) {
loc.setup(expr, exprlen); loc->setup(expr, exprlen);
ctx->print_expr_block (expr, exprlen, str, strsize, attr); ctx->print_expr(ctx, expr, exprlen, attr);
if(stack.calc_expression(expr, exprlen, attr, fun) && stack.get_value(loc.value)) { ret = stack.calc(&stack, expr, exprlen, attr, fun);
return true;
} else {
return false;
}
} }
} else if(dwarf_hasform(attr, DW_FORM_sec_offset)) { } else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
// Location list (loclist class of location in DWARF terms) // 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 // handle list of possible locations of parameter
for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) { for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) {
ctx->print_expr_block (expr, exprlen, str, strsize, attr); ctx->print_expr(ctx, expr, exprlen, attr);
if(offset >= start && offset <= end) { if(offset >= start && offset <= end) {
loc.setup(expr, exprlen); loc->setup(expr, exprlen);
// actual location, try to calculate Location expression // actual location, try to calculate Location expression
if(stack.calc_expression(expr, exprlen, attr, fun) && stack.get_value(loc.value), fun) { ret = stack.calc(&stack, expr, exprlen, attr, 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;
}
} else { } else {
// Location skipped due to don't match current PC offset // 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); ctx->log(SEVERITY_WARNING, "Unknown location attribute form = 0x%X, code = 0x%X, ", attr->form, attr->code);
} }
pst_dwarf_stack_fini(&stack);
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);
}
return ret; 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 = <undefined>", 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 = <undefined>", 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) 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; Dwarf_Addr pc;
unw_get_reg(ctx->curr_frame, UNW_REG_IP, &pc); unw_get_reg(ctx->curr_frame, UNW_REG_IP, &pc);
char str[1024];
// expression represent where callee parameter will be stored // expression represent where callee parameter will be stored
pst_call_site_param* param = add_param(); pst_call_site_param* param = add_param();
if(dwarf_hasattr(child, DW_AT_location)) { if(dwarf_hasattr(child, DW_AT_location)) {
// handle location expression here // handle location expression here
// determine location of parameter in stack/heap or CPU registers // determine location of parameter in stack/heap or CPU registers
attr = dwarf_attr(child, DW_AT_location, &attr_mem); attr = dwarf_attr(child, DW_AT_location, &attr_mem);
if(!handle_location(ctx, attr, param->location, pc, str, sizeof(str))) { if(!handle_location(ctx, attr, param->location, pc, NULL)) {
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); del_param(param);
return false; 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)) { if(dwarf_hasattr(child, DW_AT_GNU_call_site_value)) {
// handle value expression here // handle value expression here
attr = dwarf_attr(child, DW_AT_GNU_call_site_value, &attr_mem); attr = dwarf_attr(child, DW_AT_GNU_call_site_value, &attr_mem);
dwarf_stack stack(ctx); pst_dwarf_expr loc(ctx->alloc);
pst_dwarf_expr loc; if(handle_location(ctx, attr, loc, pc, NULL)) {
if(handle_location(ctx, attr, loc, pc, str, sizeof(str))) {
param->value = loc.value; 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 { } 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); del_param(param);
return false; return false;
} }
@@ -592,17 +303,17 @@ bool __pst_function::print_dwarf()
return false; 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) // 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); pst_parameter* param = next_param(NULL);
if(param && param->is_return) { if(param && param->is_return) {
// print return value type, function name and start list of parameters // print return value type, function name and start list of parameters
param->print_dwarf(); param->print_dwarf();
ctx->print(" %s(", name.c_str()); ctx->print(ctx, " %s(", name.c_str());
param = next_param(param); param = next_param(param);
} else { } else {
ctx->print("%s(", name.c_str()); ctx->print(ctx, "%s(", name.c_str());
} }
bool first = true; bool start_variable = false; bool first = true; bool start_variable = false;
@@ -610,37 +321,37 @@ bool __pst_function::print_dwarf()
if(param->is_return) { if(param->is_return) {
// print return value type, function name and start list of parameters // print return value type, function name and start list of parameters
param->print_dwarf(); param->print_dwarf();
ctx->print(" %s(", name.c_str()); ctx->print(ctx, " %s(", name.c_str());
continue; continue;
} }
if(param->is_variable) { if(param->is_variable) {
if(!start_variable) { if(!start_variable) {
ctx->print(")%s\n", at); ctx->print(ctx, ")%s\n", at);
ctx->print("{\n"); ctx->print(ctx, "{\n");
start_variable = true; start_variable = true;
} }
if(param->line) { if(param->line) {
ctx->print("%04u: ", param->line); ctx->print(ctx, "%04u: ", param->line);
} else { } else {
ctx->print(" "); ctx->print(ctx, " ");
} }
param->print_dwarf(); param->print_dwarf();
ctx->print(";\n"); ctx->print(ctx, ";\n");
} else { } else {
if(first) { if(first) {
first = false; first = false;
} else { } else {
ctx->print(", "); ctx->print(ctx, ", ");
} }
param->print_dwarf(); param->print_dwarf();
} }
} }
if(!start_variable) { if(!start_variable) {
ctx->print(");%s\n", at); ctx->print(ctx, ");%s\n", at);
} else { } else {
ctx->print("}\n"); ctx->print(ctx, "}\n");
} }
free(at); 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)) { if(dwarf_hasattr (result, DW_AT_GNU_call_site_target)) {
attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem); attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem);
if(attr) { if(attr) {
char str[1024]; str[0] = 0; pst_dwarf_expr expr(ctx->alloc);
pst_dwarf_expr expr; if(handle_location(ctx, &attr_mem, expr, pc, this)) {
if(handle_location(ctx, &attr_mem, expr, pc, str, sizeof(str), this)) {
target = expr.value; target = expr.value;
ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_target: %#lX", target); 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_proc_info_t info;
unw_get_proc_info(&cursor, &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", 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); dwarf_diename(d), lowpc, highpc, pc - ctx->base_addr, info.start_ip, info.start_ip - ctx->base_addr);
ctx->print_registers(0x0, 0x10); ctx->print_registers(ctx, 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(...): CFA: %#lX %s", dwarf_diename(d), parent ? parent->sp : 0, ctx->buff);
ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->get_print()); ctx->log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), ctx->buff);
// determine function's stack frame base // determine function's stack frame base
attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem); attr = dwarf_attr(die, DW_AT_frame_base, &attr_mem);
@@ -797,19 +508,19 @@ bool __pst_function::handle_dwarf(Dwarf_Die* d)
Dwarf_Op *expr; Dwarf_Op *expr;
size_t exprlen; size_t exprlen;
if (dwarf_getlocation (attr, &expr, &exprlen) == 0) { if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
char str[1024]; str[0] = 0; ctx->print_expr(ctx, expr, exprlen, attr);
ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr); pst_decl(pst_dwarf_stack, stack, ctx);
dwarf_stack stack(ctx); if(stack.calc(&stack, expr, exprlen, attr, this)) {
if(stack.calc_expression(expr, exprlen, attr, this)) {
uint64_t value; uint64_t value;
if(stack.get_value(value)) { if(stack.get_value(&stack, &value)) {
ctx->log(SEVERITY_DEBUG, "DW_AT_framebase expression: \"%s\" ==> 0x%lX", str, value); ctx->log(SEVERITY_DEBUG, "DW_AT_framebase expression: \"%s\" ==> 0x%lX", ctx->buff, value);
} else { } 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 { } 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 { } else {
ctx->log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code); ctx->log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
} }
@@ -901,12 +612,12 @@ bool __pst_function::unwind(Dwarf_Addr addr)
str = filename; str = filename;
} }
file = str; file = str;
ctx->print("%s:%d", str, line); ctx->print(ctx, "%s:%d", str, line);
} else { } else {
ctx->print("%p", (void*)addr); ctx->print(ctx, "%p", (void*)addr);
} }
} else { } else {
ctx->print("%p", (void*)addr); ctx->print(ctx, "%p", (void*)addr);
} }
const char* addrname = dwfl_module_addrname(ctx->module, 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"); ctx->log(SEVERITY_ERROR, "Failed to allocate memory");
return false; return false;
} }
ctx->print(" --> %s", function_name); ctx->print(ctx, " --> %s", function_name);
char* str = strchr(function_name, '('); char* str = strchr(function_name, '(');
if(str) { if(str) {
@@ -986,12 +697,12 @@ bool __pst_function::get_frame()
ctx->log(SEVERITY_ERROR, "Failed to get CFA for frame"); ctx->log(SEVERITY_ERROR, "Failed to get CFA for frame");
return false; return false;
} }
char str[1024]; str[0] = 0;
ctx->print_expr_block (cfa_ops, cfa_nops, str, sizeof(str)); ctx->print_expr(ctx, cfa_ops, cfa_nops, NULL);
dwarf_stack st(ctx); pst_decl(pst_dwarf_stack, stack, ctx);
if(st.calc_expression(cfa_ops, cfa_nops, NULL) && st.get_value(cfa)) { if(stack.calc(&stack, cfa_ops, cfa_nops, NULL, this) && stack.get_value(&stack, &cfa)) {
//ctx.sp = v; //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 // setup context to match CFA for frame
ctx->cfa = cfa; ctx->cfa = cfa;
@@ -999,6 +710,8 @@ bool __pst_function::get_frame()
ctx->log(SEVERITY_ERROR, "Failed to calculate CFA expression"); ctx->log(SEVERITY_ERROR, "Failed to calculate CFA expression");
} }
pst_dwarf_stack_fini(&stack);
return true; return true;
} }
@@ -1081,7 +794,7 @@ pst_function* __pst_handler::last_function()
bool __pst_handler::handle_dwarf() bool __pst_handler::handle_dwarf()
{ {
ctx.clean_print(); ctx.clean_print(&ctx);
Dl_info info; Dl_info info;
//for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) { //for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) {
@@ -1103,13 +816,13 @@ bool __pst_handler::handle_dwarf()
void __pst_handler::print_dwarf() void __pst_handler::print_dwarf()
{ {
ctx.clean_print(); ctx.clean_print(&ctx);
ctx.print("DWARF-based stack trace information:\n"); ctx.print(&ctx, "DWARF-based stack trace information:\n");
uint32_t idx = 0; uint32_t idx = 0;
for(pst_function* function = next_function(NULL); function; function = next_function(function)) { 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(); function->print_dwarf();
ctx.print("\n"); ctx.print(&ctx, "\n");
} }
} }
@@ -1125,7 +838,7 @@ Dwfl_Callbacks callbacks = {
bool __pst_handler::unwind() bool __pst_handler::unwind()
{ {
ctx.clean_print(); ctx.clean_print(&ctx);
#ifdef REG_RIP // x86_64 #ifdef REG_RIP // x86_64
caller = (void *) ctx.hcontext->uc_mcontext.gregs[REG_RIP]; caller = (void *) ctx.hcontext->uc_mcontext.gregs[REG_RIP];
ctx.sp = ctx.hcontext->uc_mcontext.gregs[REG_RSP]; ctx.sp = ctx.hcontext->uc_mcontext.gregs[REG_RSP];
@@ -1154,16 +867,16 @@ bool __pst_handler::unwind()
ctx.dwfl = dwfl_begin(&callbacks); ctx.dwfl = dwfl_begin(&callbacks);
if(ctx.dwfl == NULL) { 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; return false;
} }
if(dwfl_linux_proc_report(ctx.dwfl, getpid()) != 0 || dwfl_report_end(ctx.dwfl, NULL, NULL) !=0) { 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; return false;
} }
ctx.print("Stack trace: caller = %p\n", caller); ctx.print(&ctx, "Stack trace: caller = %p\n", caller);
unw_getcontext(&ctx.context); unw_getcontext(&ctx.context);
unw_init_local(&ctx.cursor, &ctx.context); unw_init_local(&ctx.cursor, &ctx.context);
@@ -1186,7 +899,7 @@ bool __pst_handler::unwind()
continue; continue;
} }
ctx.print("[%-2d] ", i); ctx.print(&ctx, "[%-2d] ", i);
ctx.module = dwfl_addrmodule(ctx.dwfl, addr); ctx.module = dwfl_addrmodule(ctx.dwfl, addr);
pst_function* last = last_function(); pst_function* last = last_function();
pst_function* fun = add_function(NULL); pst_function* fun = add_function(NULL);
@@ -1200,7 +913,7 @@ bool __pst_handler::unwind()
} }
//get_frame(fun); //get_frame(fun);
} }
ctx.print("\n"); ctx.print(&ctx, "\n");
} }
return true; return true;
+9 -90
View File
@@ -22,103 +22,20 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <stdlib.h> #include <stdlib.h>
#include "allocator.h"
#include "common.h" #include "common.h"
#include "context.h" #include "context.h"
#include "dictionary.h" #include "allocator.h"
#include "data_entry.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 // DW_TAG_call_site_parameter
typedef struct __pst_call_site_param : public SC_ListNode { typedef struct __pst_call_site_param : public SC_ListNode {
__pst_call_site_param(pst_context* ctx) { __pst_call_site_param(pst_context* ctx) {
param = NULL; name = NULL; value = 0; param = NULL; name = NULL; value = 0;
pst_dwarf_expr_init(&location, ctx->alloc);
} }
~__pst_call_site_param() { ~__pst_call_site_param() {
@@ -233,8 +150,9 @@ typedef struct __pst_function : public SC_ListNode {
} pst_function; } pst_function;
typedef struct __pst_handler { typedef struct __pst_handler {
__pst_handler(ucontext_t* hctx) : ctx(hctx) __pst_handler(ucontext_t* hctx)
{ {
pst_context_init(&ctx, hctx);
caller = NULL; caller = NULL;
frame = NULL; frame = NULL;
addr = 0; addr = 0;
@@ -248,6 +166,7 @@ typedef struct __pst_handler {
} }
clear(); clear();
pst_context_fini(&ctx);
} }
void clear(); void clear();
+9 -12
View File
@@ -3,13 +3,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include "logger/log_console.h" #include "context.h"
#include "sysutils.h" #include "sysutils.h"
static SC_LogConsole log_local(0, "/tmp/unspecified.file");
SC_LogBase* logger = &log_local;
typedef enum { typedef enum {
DEF_1 = 1, DEF_1 = 1,
DEF_2, DEF_2,
@@ -64,7 +60,7 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context)
fatal_error_in_progress = 1; fatal_error_in_progress = 1;
logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig)); logger.log(&logger, SEVERITY_ERROR, "%s signal handled", strsignal(sig));
bool ret = false; bool ret = false;
pst_handler handler((ucontext_t*)context); pst_handler handler((ucontext_t*)context);
@@ -74,12 +70,12 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context)
} }
if(ret) { if(ret) {
logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print()); logger.log(&logger, SEVERITY_INFO, "%s", handler.ctx.buff);
handler.handle_dwarf(); handler.handle_dwarf();
handler.print_dwarf(); handler.print_dwarf();
logger->Log(SEVERITY_INFO, "%s", handler.ctx.get_print()); logger.log(&logger, SEVERITY_INFO, "%s", handler.ctx.buff);
} else { } 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 // comment out line below to prevent coredump
@@ -102,9 +98,9 @@ void SignalHandler(int sig)
// const char* str_sig = strsignal(sig); // const char* str_sig = strsignal(sig);
// logger->Log(SEVERITY_INFO, "%s received.", str_sig); // logger->Log(SEVERITY_INFO, "%s received.", str_sig);
if(sig == SIGUSR1) { if(sig == SIGUSR1) {
logger->Log(SEVERITY_INFO, "Maintenance mode enabled."); logger.log(&logger, SEVERITY_INFO, "Maintenance mode enabled.");
} else if(sig == SIGUSR2) { } else if(sig == SIGUSR2) {
logger->Log(SEVERITY_INFO, "Maintenance mode disabled."); logger.log(&logger, SEVERITY_INFO, "Maintenance mode disabled.");
} }
// signal (sig, SIG_DFL); // signal (sig, SIG_DFL);
// raise(sig); // raise(sig);
@@ -181,7 +177,7 @@ void SetSignalHandler(sig_handler_t handler)
limit.rlim_max = 1073741824; limit.rlim_max = 1073741824;
if (setrlimit(RLIMIT_CORE, &limit)) 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[]) int main(int argc, char* argv[])
{ {
pst_log_init_console(&logger);
//logger->SetCurrentSeverity(SEVERITY_INFO); //logger->SetCurrentSeverity(SEVERITY_INFO);
SetSignalHandler(SigusrHandler); SetSignalHandler(SigusrHandler);