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:
@@ -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
@@ -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
@@ -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
@@ -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_ */
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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, ®val)) {
|
if(!unw_get_reg(ctx->curr_frame, reg_map[i].regno, ®val)) {
|
||||||
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
@@ -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_ */
|
||||||
|
|||||||
@@ -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_ */
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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_ */
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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_ */
|
||||||
+187
-444
@@ -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,30 +32,31 @@ bool dw_op_addr(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwa
|
|||||||
// retrieved is zero extended to the size of an address on the target machine
|
// 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:
|
res = *((uint8_t*)addr);
|
||||||
res = *((uint8_t*)addr);
|
break;
|
||||||
break;
|
case 2:
|
||||||
case 2:
|
res = *((uint16_t*)addr);
|
||||||
res = *((uint16_t*)addr);
|
break;
|
||||||
break;
|
case 4:
|
||||||
case 4:
|
res = *((uint32_t*)addr);
|
||||||
res = *((uint32_t*)addr);
|
break;
|
||||||
break;
|
case 8:
|
||||||
case 8:
|
res = *((uint64_t*)addr);
|
||||||
res = *((uint64_t*)addr);
|
break;
|
||||||
break;
|
default:
|
||||||
}
|
return false;
|
||||||
stack->push(&res, sizeof(res), DWARF_TYPE_GENERIC);
|
break;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
stack->push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC);
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
// use arithmetic by modulo 1 plus
|
|
||||||
uint64_t unsig1; uint64_t unsig2;
|
|
||||||
if(!value1->get_uint(unsig1)) {
|
|
||||||
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!value2->get_uint(unsig2)) {
|
|
||||||
stack->ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value2->size);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int res_type = DWARF_TYPE_GENERIC;
|
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,62 +429,31 @@ bool dw_op_mul(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwar
|
|||||||
|
|
||||||
// The DW_OP_neg operation pops the top stack entry, interprets it as a signed value and pushes its negation.
|
// 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) {
|
||||||
v *= -1;
|
value->value.int32 *= -1;
|
||||||
|
} else {
|
||||||
switch (value->size) {
|
value->value.int64 *= -1;
|
||||||
case 1: {
|
}
|
||||||
int8_t vv = (int8_t)v;
|
return true;
|
||||||
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 false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,30 +485,30 @@ bool dw_op_or(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The DW_OP_plus operation pops the top two stack entries, adds them together, and pushes the result
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -664,18 +518,12 @@ bool dw_op_plus(dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwa
|
|||||||
// operand popped from the top of the stack and pushes the result.
|
// 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(®no, sizeof(regno), DWARF_TYPE_REGISTER_LOC);
|
stack->push(stack, ®no, 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(¶m->value, sizeof(param->value), DWARF_TYPE_GENERIC);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr expression");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!map->operation(this, map, exprs[i].number, exprs[i].number2)) {
|
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to calculate %s(0x%lX, 0x%lX) operation", map->op_name, exprs[i].number, exprs[i].number2);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
|
|||||||
@@ -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(¶m->types)) {
|
||||||
|
if(!param->is_return) {
|
||||||
|
if(param->has_value) {
|
||||||
|
param->ctx->print(param->ctx, "%s %s = 0x%lX", param->next_type(NULL)->name, param->name, param->location.value);
|
||||||
|
} else {
|
||||||
|
param->ctx->print(param->ctx, "%s %s = <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, ¶m->size);
|
||||||
|
}
|
||||||
|
logger.log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->size);
|
||||||
|
param->add_type(dwarf_diename(&ret_die), DW_TAG_base_type);
|
||||||
|
param->type = DW_TAG_base_type;
|
||||||
|
|
||||||
|
attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
param->enc_type = 0;
|
||||||
|
dwarf_formudata(attr, ¶m->enc_type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_TAG_array_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "array type");
|
||||||
|
param->add_type("[]", DW_TAG_array_type);
|
||||||
|
break;
|
||||||
|
case DW_TAG_structure_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "structure type");
|
||||||
|
param->add_type("struct", DW_TAG_structure_type);
|
||||||
|
break;
|
||||||
|
case DW_TAG_union_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "union type");
|
||||||
|
param->add_type("union", DW_TAG_union_type);
|
||||||
|
break;
|
||||||
|
case DW_TAG_class_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "class type");
|
||||||
|
param->add_type("class", DW_TAG_class_type);
|
||||||
|
break;
|
||||||
|
case DW_TAG_pointer_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "pointer type");
|
||||||
|
param->add_type("*", DW_TAG_pointer_type);
|
||||||
|
break;
|
||||||
|
case DW_TAG_enumeration_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "enumeration type");
|
||||||
|
param->add_type("enum", DW_TAG_enumeration_type);
|
||||||
|
break;
|
||||||
|
case DW_TAG_const_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "constant type");
|
||||||
|
param->add_type("const", DW_TAG_const_type);
|
||||||
|
break;
|
||||||
|
case DW_TAG_subroutine_type:
|
||||||
|
logger.log(SEVERITY_DEBUG, "Skipping subroutine type");
|
||||||
|
break;
|
||||||
|
case DW_TAG_typedef:
|
||||||
|
logger.log(SEVERITY_DEBUG, "typedef '%s' type", dwarf_diename(&ret_die));
|
||||||
|
param->add_type(dwarf_diename(&ret_die), DW_TAG_typedef);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.log(SEVERITY_WARNING, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
return param->handle_type(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_type* param_add_type(pst_parameter* param, const char* name, int type)
|
||||||
|
{
|
||||||
|
pst_alloc(pst_type, t, name, type);
|
||||||
|
list_add_bottom(¶m->types, &t->node);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void param_clear(pst_parameter* param)
|
||||||
|
{
|
||||||
|
pst_type* t = NULL;
|
||||||
|
struct list_node *pos, *tn;
|
||||||
|
list_for_each_entry_safe(t, pos, tn, ¶m->types, node) {
|
||||||
|
list_del(&t->node);
|
||||||
|
pst_type_fini(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_type* param_next_type(pst_parameter* param, pst_type* t)
|
||||||
|
{
|
||||||
|
list_node* n = (t == NULL) ? list_first(¶m->types) : list_next(&t->node);
|
||||||
|
pst_type* ret = NULL;
|
||||||
|
if(n) {
|
||||||
|
ret = list_entry(n, pst_type, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool param_handle_dwarf(pst_parameter* param, Dwarf_Die* result, __pst_function* fun)
|
||||||
|
{
|
||||||
|
param->die = result;
|
||||||
|
|
||||||
|
Dwarf_Attribute attr_mem;
|
||||||
|
Dwarf_Attribute* attr;
|
||||||
|
|
||||||
|
param->name = pst_dup(&allocator, dwarf_diename(result));
|
||||||
|
param->is_variable = (dwarf_tag(result) == DW_TAG_variable);
|
||||||
|
|
||||||
|
dwarf_decl_line(result, (int*)¶m->line);
|
||||||
|
// Get reference to attribute type of the parameter/variable
|
||||||
|
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
|
||||||
|
logger.log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
||||||
|
if(attr) {
|
||||||
|
param->handle_type(param, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dwarf_hasattr(result, DW_AT_location)) {
|
||||||
|
// determine location of parameter in stack/heap or CPU registers
|
||||||
|
attr = dwarf_attr(result, DW_AT_location, &attr_mem);
|
||||||
|
Dwarf_Addr pc;
|
||||||
|
unw_get_reg(param->ctx->curr_frame, UNW_REG_IP, &pc);
|
||||||
|
|
||||||
|
if(handle_location(param->ctx, attr, ¶m->location, pc, fun)) {
|
||||||
|
param->has_value = true;
|
||||||
|
} else {
|
||||||
|
logger.log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", param->ctx->buff);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if(dwarf_hasattr(result, DW_AT_const_value)) {
|
||||||
|
// no locations definitions, value is constant, known by DWARF directly
|
||||||
|
attr = dwarf_attr(result, DW_AT_const_value, &attr_mem);
|
||||||
|
switch (dwarf_whatform(attr)) {
|
||||||
|
case DW_FORM_string:
|
||||||
|
// do nothing for now
|
||||||
|
logger.log(SEVERITY_WARNING, "Const value form DW_FORM_string value = %s.", dwarf_formstring(attr));
|
||||||
|
break;
|
||||||
|
case DW_FORM_data1:
|
||||||
|
case DW_FORM_data2:
|
||||||
|
case DW_FORM_data4:
|
||||||
|
case DW_FORM_data8:
|
||||||
|
dwarf_formudata(attr, ¶m->location.value);
|
||||||
|
param->has_value = true;
|
||||||
|
break;
|
||||||
|
case DW_FORM_sdata:
|
||||||
|
dwarf_formsdata(attr, (int64_t*)¶m->location.value);
|
||||||
|
param->has_value = true;
|
||||||
|
break;
|
||||||
|
case DW_FORM_udata:
|
||||||
|
dwarf_formudata(attr, ¶m->location.value);
|
||||||
|
param->has_value = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(param->has_value) {
|
||||||
|
logger.log(SEVERITY_DEBUG, "Parameter constant value: 0x%lX", param->location.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additionally handle these attributes:
|
||||||
|
// 1. DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function
|
||||||
|
// A DW_AT_default_value attribute for a formal parameter entry. The value of
|
||||||
|
// this attribute may be a constant, or a reference to the debugging information
|
||||||
|
// entry for a variable, or a reference to a debugging information entry containing a DWARF procedure
|
||||||
|
|
||||||
|
// 2. DW_AT_variable_parameter
|
||||||
|
// A DW_AT_variable_parameter attribute, which is a flag, if a formal
|
||||||
|
// parameter entry represents a parameter whose value in the calling function
|
||||||
|
// may be modified by the callee. The absence of this attribute implies that the
|
||||||
|
// parameter’s value in the calling function cannot be modified by the callee.
|
||||||
|
|
||||||
|
// 3. DW_AT_abstract_origin
|
||||||
|
// In place of these omitted attributes, each concrete inlined instance entry has a DW_AT_abstract_origin attribute that may be used to obtain the
|
||||||
|
// missing information (indirectly) from the associated abstract instance entry. The value of the abstract origin attribute is a reference to the associated abstract
|
||||||
|
// instance entry.
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pst_parameter_init(pst_parameter*param, pst_context* ctx)
|
||||||
|
{
|
||||||
|
// methods
|
||||||
|
param->clear = param_clear;
|
||||||
|
param->add_type = param_add_type;
|
||||||
|
param->next_type = param_next_type;
|
||||||
|
param->handle_dwarf = param_handle_dwarf;
|
||||||
|
param->handle_type = param_handle_type;
|
||||||
|
param->print_dwarf = param_print_dwarf;
|
||||||
|
|
||||||
|
// fields
|
||||||
|
list_node_init(¶m->node);
|
||||||
|
param->die = NULL;
|
||||||
|
param->name = NULL;
|
||||||
|
param->line = 0;
|
||||||
|
param->size = 0;
|
||||||
|
param->type = 0;
|
||||||
|
param->enc_type = 0;
|
||||||
|
list_head_init(¶m->types);
|
||||||
|
param->is_return = false;
|
||||||
|
param->is_variable = false;
|
||||||
|
param->has_value = false;
|
||||||
|
param->ctx = ctx;
|
||||||
|
pst_dwarf_expr_init(¶m->location);
|
||||||
|
param->allocated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_parameter* pst_parameter_new(pst_context* ctx)
|
||||||
|
{
|
||||||
|
pst_parameter* param = (pst_parameter*)allocator.alloc(&allocator, sizeof(pst_parameter));
|
||||||
|
if(param) {
|
||||||
|
pst_parameter_init(param, ctx);
|
||||||
|
param->allocated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
void pst_parameter_fini(pst_parameter* param)
|
||||||
|
{
|
||||||
|
param->clear();
|
||||||
|
if(param->name) {
|
||||||
|
allocator.free(param->name);
|
||||||
|
}
|
||||||
|
if(param->allocated) {
|
||||||
|
allocator.free(&allocator, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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_ */
|
||||||
@@ -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, ¶m->value, sizeof(param->value), DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
st->ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location");
|
||||||
|
nret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
st->ctx->log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr expression");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!map->operation(st, map, exprs[i].number, exprs[i].number2)) {
|
||||||
|
st->ctx->log(SEVERITY_ERROR, "Failed to calculate %s(0x%lX, 0x%lX) operation", map->op_name, exprs[i].number, exprs[i].number2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pst_dwarf_stack_init(pst_dwarf_stack* st, pst_context* ctx)
|
||||||
|
{
|
||||||
|
pst_assert(st && ctx);
|
||||||
|
|
||||||
|
list_head_init(&st->values);
|
||||||
|
st->push = stack_push;
|
||||||
|
st->push_value = stack_push_value;
|
||||||
|
st->pop = stack_pop;
|
||||||
|
st->get = stack_get;
|
||||||
|
st->get_value = stack_get_value;
|
||||||
|
st->calc = stack_calc;
|
||||||
|
st->clear = stack_clear;
|
||||||
|
|
||||||
|
st->ctx = ctx;
|
||||||
|
st->allocated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_dwarf_stack* pst_dwarf_stack_new(pst_context* ctx)
|
||||||
|
{
|
||||||
|
pst_assert(ctx);
|
||||||
|
|
||||||
|
pst_alloc(pst_dwarf_stack, ns, ctx);
|
||||||
|
if(ns) {
|
||||||
|
pst_dwarf_stack_init(ns, ctx);
|
||||||
|
ns->allocated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pst_dwarf_stack_fini(pst_dwarf_stack* st)
|
||||||
|
{
|
||||||
|
pst_assert(st);
|
||||||
|
|
||||||
|
st->clear(st);
|
||||||
|
if(st->allocated) {
|
||||||
|
allocator.free(&allocator, st);
|
||||||
|
} else {
|
||||||
|
st->ctx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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_ */
|
||||||
@@ -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_ */
|
|
||||||
@@ -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
@@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
+26
-124
@@ -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
|
SC_LogSeverity mCurrentSeverity; // maximum severity value to be logged
|
||||||
inline virtual void Log(SC_LogSeverity severity, const char* fmt, ...)
|
pthread_mutex_t mLock;
|
||||||
{
|
|
||||||
if (severity < mCurrentSeverity)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mLock.Lock();
|
void* child;
|
||||||
|
} pst_log;
|
||||||
|
|
||||||
if(!IsOpened())
|
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 */);
|
||||||
//print header if present
|
void pst_log_fini(pst_log* log);
|
||||||
if(Open() && mHeader.size())
|
|
||||||
{
|
|
||||||
SendMessage((char*)mHeader.c_str(), severity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mStringLen = 0;
|
#endif /* PST_LOG_H_ */
|
||||||
FormatPrefix(severity);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
FormatString(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
FormatPostfix();
|
|
||||||
SendMessage(mString, severity);
|
|
||||||
|
|
||||||
mLock.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
//open source for send messages
|
|
||||||
virtual bool Open() = 0;
|
|
||||||
|
|
||||||
//close source
|
|
||||||
virtual void Close(){}
|
|
||||||
|
|
||||||
//whether source already opened
|
|
||||||
virtual bool IsOpened() = 0;
|
|
||||||
|
|
||||||
//returns source path
|
|
||||||
string& GetSource()
|
|
||||||
{
|
|
||||||
return mSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
//assign source path
|
|
||||||
inline void SetSource(const char* source)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
mSource = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSource(string& source)
|
|
||||||
{
|
|
||||||
SetSource(source.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
//assign Log header
|
|
||||||
inline void SetHeader(const char* header)
|
|
||||||
{
|
|
||||||
mHeader = string(header) + '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
//return Log ID
|
|
||||||
inline uint32_t GetID() const
|
|
||||||
{
|
|
||||||
return mID;
|
|
||||||
}
|
|
||||||
|
|
||||||
//set Log ID
|
|
||||||
inline void SetID(uint32_t id)
|
|
||||||
{
|
|
||||||
mID = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
//return current severity threshold applied to the messages
|
|
||||||
inline SC_LogSeverity GetCurrentSeverity() const
|
|
||||||
{
|
|
||||||
return mCurrentSeverity;
|
|
||||||
}
|
|
||||||
|
|
||||||
//set severity threshold to be applied to the messages
|
|
||||||
inline void SetCurrentSeverity(SC_LogSeverity severity)
|
|
||||||
{
|
|
||||||
mCurrentSeverity = severity;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
//actually sends message to the source
|
|
||||||
virtual void SendMessage(const char* msg, SC_LogSeverity severity = SEVERITY_DEBUG) = 0;
|
|
||||||
|
|
||||||
//format message prefix
|
|
||||||
virtual void FormatPrefix(SC_LogSeverity severity);
|
|
||||||
|
|
||||||
//format message body
|
|
||||||
virtual void FormatString(const char* fmt, va_list args);
|
|
||||||
|
|
||||||
//format message postfix
|
|
||||||
virtual void FormatPostfix();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
uint32_t mID; //log ID, associated with source
|
|
||||||
string mSource; //source for store log messages (file, IP address or sometsing else)
|
|
||||||
string mHeader; //header of the Log
|
|
||||||
static char mString[]; //formatted string to be printed
|
|
||||||
static uint32_t mStringSize; //size of the string buffer
|
|
||||||
uint32_t mStringLen; //length of the string
|
|
||||||
SC_LogSeverity mCurrentSeverity; //maximum severity value to be logged
|
|
||||||
static const char * const mSeverityStrings[];
|
|
||||||
SC_Mutex mLock;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* LOG_H_ */
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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_ */
|
|
||||||
@@ -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_ */
|
|
||||||
@@ -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
@@ -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
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user