From 3317cd212be8c4e6a0bc1c0f4f401d37cf19667e Mon Sep 17 00:00:00 2001 From: Nikolai Nosov Date: Sun, 5 Apr 2020 14:59:41 +0400 Subject: [PATCH] exprt next_function, next_parameter function_info, parameter_info to external interface of the library --- include/libpst-types.h | 31 ++++++++++++++++ include/libpst.h | 43 +++++++++++++++++---- src/Makefile | 2 +- src/dwarf/dwarf_call_site.c | 6 +-- src/dwarf/dwarf_call_site.h | 2 +- src/dwarf/dwarf_function.c | 74 ++++++++++++++++++------------------- src/dwarf/dwarf_function.h | 11 +++--- src/dwarf/dwarf_handler.c | 30 +++++++-------- src/dwarf/dwarf_handler.h | 1 + src/dwarf/dwarf_parameter.c | 65 ++++++++++++++++---------------- src/dwarf/dwarf_parameter.h | 23 +++++------- src/libpst.c | 22 ++++++++++- 12 files changed, 193 insertions(+), 117 deletions(-) create mode 100644 include/libpst-types.h diff --git a/include/libpst-types.h b/include/libpst-types.h new file mode 100644 index 0000000..bf81b35 --- /dev/null +++ b/include/libpst-types.h @@ -0,0 +1,31 @@ +/* + * libpst-types.h + * + * Created on: Apr 5, 2020 + * Author: nnosov + */ + +#ifndef INCLUDE_LIBPST_TYPES_H_ +#define INCLUDE_LIBPST_TYPES_H_ + +#include +#include + +typedef struct pst_function_info { + char* name; ///< demangled name of the function + char* file; ///< file name where the function is defined + int line; ///< line of definition of the function + unw_word_t pc; ///< address between LowPC & HighPC (plus base address offset). actually, address of currently executed command in function +} pst_function_info; + +typedef struct pst_parameter_info { + char* name; ///< parameter's name + uint32_t line; ///< line of parameter definition + unw_word_t size; ///< size of parameter in bytes + unw_word_t value; ///< value of parameter. currently only base types supported. use 'size' to determine number of actual bytes of value + 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_parameter_info; + +#endif /* INCLUDE_LIBPST_TYPES_H_ */ diff --git a/include/libpst.h b/include/libpst.h index d861505..6588682 100644 --- a/include/libpst.h +++ b/include/libpst.h @@ -15,7 +15,11 @@ #include #include +#include "libpst-types.h" + typedef struct pst_handler pst_handler; +typedef struct pst_function pst_function; +typedef struct pst_parameter pst_parameter; /** * @brief allocate libpst handler and initialize the library @@ -35,26 +39,49 @@ void pst_lib_fini(pst_handler* handler); /** - * @defgroup unwind_simple * @brief Unwinds current stack trace using base information about program (i.e. function address, function name and line) - */ - -/** - * @ingroup unwind_simple - * @brief Save stack trace information to provided buffer in RAM * @param handler The handler obtained by pst_lib_init() * @return 1 on success, 0 on failure */ int pst_unwind_simple(pst_handler* handler); /** - * @ingroup unwind_simple * @brief Print unwound stack trace to internal buffer * @param handler The handler obtained by pst_lib_init() - * @return pointer on zero terminated C string, NULL on failure + * @return pointer to zero terminated C string, NULL on failure */ const char* pst_print_simple(pst_handler* handler); +/** + * @brief Get next function handle in stack trace + * @param handler The handler obtained by pst_lib_init() + * @param current pointer to current function. NULL to get first + * @return pointer to next function's handle, NULL in case of end of list + */ +const pst_function* pst_get_next_function(pst_handler* handler, pst_function* current); + +/** + * @brief Get function's information (name, address, line) + * @param function Function's handle obtained by pst_get_next_function() + * @return pointer to function's info + */ +const pst_function_info* pst_get_function_info(pst_function* function); + +/** + * @brief Get next parameter's handle in function + * @param function Function's handler obtained by pst_get_next_function() + * @param current pointer to current parameter. NULL to get first + * @return pointer to next parameter's handle, NULL in case of end of list + */ +const pst_parameter* pst_get_next_parameter(pst_function* function, pst_parameter* current); + +/** + * @brief Get parameter's information (name, type, line etc) + * @param parameter Parameter's handle obtained by pst_get_next_parameter() + * @return pointer to parameter's info + */ +const pst_parameter_info* pst_get_parameter_info(pst_parameter* parameter); + // // Advanced unwind routines. // Additionally to pst_unwind_simple(...) provides types of parameters and variables in functions and their values if possible diff --git a/src/Makefile b/src/Makefile index fccc839..e2c6d02 100644 --- a/src/Makefile +++ b/src/Makefile @@ -37,7 +37,7 @@ VPATH = ./ ./dwarf ./arch ./utils SRC = $(wildcard $(addsuffix /*.c,${VPATH})) OBJ = $(patsubst %.c,%.o,$(addprefix $(BUILD_DIR)/,$(notdir $(SRC)))) -INCS = -I"./dwarf" -I"./" -I"./utils" -I"./arch" +INCS = -I"./dwarf" -I"./" -I"./utils" -I"./arch" -I"../include" FLAGS = -Wall -ggdb -fPIC -O3 -rdynamic -D_GNU_SOURCE -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DSOFT_BUILD=$(SOFT_BUILD) -DUSER_BUILD=$(USER) -DDATE_BUILD="$(DATE_BUILD)" .PHONY: all clean diff --git a/src/dwarf/dwarf_call_site.c b/src/dwarf/dwarf_call_site.c index 7a7cbd7..411d772 100644 --- a/src/dwarf/dwarf_call_site.c +++ b/src/dwarf/dwarf_call_site.c @@ -195,7 +195,7 @@ void pst_call_site_fini(pst_call_site* site) // DW_TAG_GNU_call_site_parameter is defined under child DIE of DW_TAG_GNU_call_site and defines value of subroutine before calling it // relates to DW_OP_GNU_entry_value() handling in callee function to determine the value of an argument/variable of the callee // get DIE of return type -bool pst_call_site_storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Die* result, pst_function* info) +bool pst_call_site_storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Die* result, pst_function* fn) { Dwarf_Die origin; Dwarf_Attribute attr_mem; @@ -216,7 +216,7 @@ bool pst_call_site_storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Di attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem); if(attr) { pst_decl0(pst_dwarf_expr, expr); - if(handle_location(storage->ctx, &attr_mem, &expr, info->pc, info)) { + if(handle_location(storage->ctx, &attr_mem, &expr, fn->info.pc, fn)) { target = expr.value; pst_log(SEVERITY_DEBUG, "DW_AT_GNU_call_site_target: %#lX", target); } @@ -310,7 +310,7 @@ pst_call_site* pst_call_site_storage_find(pst_call_site_storage* storage, pst_fu uint64_t start_pc = storage->ctx->base_addr + callee->lowpc; pst_call_site* cs = storage_call_site_by_target(storage, start_pc); if(!cs) { - cs = storage_call_site_by_origin(storage, callee->name); + cs = storage_call_site_by_origin(storage, callee->info.name); } return cs; diff --git a/src/dwarf/dwarf_call_site.h b/src/dwarf/dwarf_call_site.h index e14547c..1460b11 100644 --- a/src/dwarf/dwarf_call_site.h +++ b/src/dwarf/dwarf_call_site.h @@ -64,7 +64,7 @@ void pst_call_site_fini(pst_call_site* site); pst_call_site_param* pst_call_site_find(pst_call_site* site, pst_dwarf_expr* expr); bool pst_call_site_handle_dwarf(pst_call_site* site, Dwarf_Die* child); -typedef struct __pst_function pst_function; +typedef struct pst_function pst_function; // ----------------------------------------------------------------------------------- // storage for all of function's call sites // ----------------------------------------------------------------------------------- diff --git a/src/dwarf/dwarf_function.c b/src/dwarf/dwarf_function.c index 5b95597..9fb5249 100644 --- a/src/dwarf/dwarf_function.c +++ b/src/dwarf/dwarf_function.c @@ -34,7 +34,7 @@ static bool get_frame(pst_function* fn) } // get frame of CFI for address - int result = dwarf_cfi_addrframe (cfi, fn->pc - mod_bias, &fn->frame); + int result = dwarf_cfi_addrframe (cfi, fn->info.pc - mod_bias, &fn->frame); if (result != 0) { pst_log(SEVERITY_ERROR, "Failed to find CFI frame for module"); return false; @@ -44,8 +44,8 @@ static bool get_frame(pst_function* fn) fn->ctx->frame = fn->frame; // get return register and PC range for function - Dwarf_Addr start = fn->pc; - Dwarf_Addr end = fn->pc; + Dwarf_Addr start = fn->info.pc; + Dwarf_Addr end = fn->info.pc; bool signalp; int ra_regno = dwarf_frame_info (fn->frame, &start, &end, &signalp); if(ra_regno >= 0) { @@ -54,7 +54,7 @@ static bool get_frame(pst_function* fn) reginfo info; info.regno = ra_regno; dwfl_module_register_names(fn->ctx->module, regname_callback, &info); pst_log(SEVERITY_INFO, "Function %s(...): '.eh/debug frame' info: PC range: => [%#" PRIx64 ", %#" PRIx64 "], return register: %s, in_signal = %s", - fn->name, start, end, info.regname, signalp ? "true" : "false"); + fn->info.name, start, end, info.regname, signalp ? "true" : "false"); } else { pst_log(SEVERITY_WARNING, "Return address register info unavailable (%s)", dwarf_errmsg(0)); } @@ -75,7 +75,7 @@ static bool get_frame(pst_function* fn) bool nret = true; pst_decl(pst_dwarf_stack, stack, fn->ctx); if(pst_dwarf_stack_calc(&stack, cfa_ops, cfa_nops, NULL, NULL) && pst_dwarf_stack_get_value(&stack, &fn->cfa)) { - pst_log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fn->name, fn->ctx->buff, fn->cfa); + pst_log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fn->info.name, fn->ctx->buff, fn->cfa); // setup context to match CFA for frame fn->ctx->cfa = fn->cfa; @@ -115,7 +115,7 @@ static void clear(pst_function* fn) pst_call_site_storage_fini(&fn->call_sites); } -static pst_parameter* next_param(pst_function* fn, pst_parameter* p) +pst_parameter* pst_function_next_parameter(pst_function* fn, pst_parameter* p) { struct list_node* n = (p == NULL) ? list_first(&fn->params) : list_next(&p->node); @@ -191,41 +191,41 @@ bool handle_lexical_block(pst_function* fn, Dwarf_Die* result) bool pst_function_print_dwarf(pst_function* fn) { char* at = NULL; - if(fn->file) { - if(!asprintf(&at, " at %s:%d, %p", fn->file, fn->line, (void*)fn->pc)) + if(fn->info.file) { + if(!asprintf(&at, " at %s:%d, %p", fn->info.file, fn->info.line, (void*)fn->info.pc)) return false; - } else if(!asprintf(&at, " at %p", (void*)fn->pc)){ + } else if(!asprintf(&at, " at %p", (void*)fn->info.pc)){ return false; } // handle return parameter and be safe if function haven't parameters (for example, dwar info for function is absent) - pst_parameter* param = next_param(fn, NULL); - if(param && param->is_return) { + pst_parameter* param = pst_function_next_parameter(fn, NULL); + if(param && param->info.is_return) { // print return value type, function name and start list of parameters pst_parameter_print_dwarf(param); - fn->ctx->print(fn->ctx, " %s(", fn->name); - param = next_param(fn, param); + fn->ctx->print(fn->ctx, " %s(", fn->info.name); + param = pst_function_next_parameter(fn, param); } else { - fn->ctx->print(fn->ctx, "%s(", fn->name); + fn->ctx->print(fn->ctx, "%s(", fn->info.name); } bool first = true; bool start_variable = false; - for(; param; param = next_param(fn, param)) { - if(param->is_return) { + for(; param; param = pst_function_next_parameter(fn, param)) { + if(param->info.is_return) { // print return value type, function name and start list of parameters pst_parameter_print_dwarf(param); - fn->ctx->print(fn->ctx, " %s(", fn->name); + fn->ctx->print(fn->ctx, " %s(", fn->info.name); continue; } - if(param->is_variable) { + if(param->info.is_variable) { if(!start_variable) { fn->ctx->print(fn->ctx, ")%s\n", at); fn->ctx->print(fn->ctx, "{\n"); start_variable = true; } - if(param->line) { - fn->ctx->print(fn->ctx, "%04u: ", param->line); + if(param->info.line) { + fn->ctx->print(fn->ctx, "%04u: ", param->info.line); } else { fn->ctx->print(fn->ctx, " "); } @@ -273,7 +273,7 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d) fn->ctx->clean_print(fn->ctx); pst_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), fn->lowpc, fn->highpc, fn->pc - fn->ctx->base_addr, info.start_ip, info.start_ip - fn->ctx->base_addr); + dwarf_diename(d), fn->lowpc, fn->highpc, fn->info.pc - fn->ctx->base_addr, info.start_ip, info.start_ip - fn->ctx->base_addr); fn->ctx->print_registers(fn->ctx, 0x0, 0x10); pst_log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), fn->parent ? fn->parent->sp : 0, fn->ctx->buff); pst_log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), fn->ctx->buff); @@ -306,11 +306,11 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d) // Get reference to return attribute type of the function // may be to use dwfl_module_return_value_location() instead - pst_parameter* ret_p = add_param(fn); ret_p->is_return = true; + pst_parameter* ret_p = add_param(fn); ret_p->info.is_return = true; attr = dwarf_attr(fn->die, DW_AT_type, &attr_mem); if(attr) { if(!pst_parameter_handle_type(ret_p, attr)) { - pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->name); + pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->info.name); del_param(ret_p); } } else { @@ -375,9 +375,9 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d) bool pst_function_unwind(pst_function* fn) { - Dwfl_Line *dwline = dwfl_getsrc(fn->ctx->dwfl, fn->pc); + Dwfl_Line *dwline = dwfl_getsrc(fn->ctx->dwfl, fn->info.pc); if(dwline != NULL) { - const char* filename = dwfl_lineinfo (dwline, &fn->pc, &fn->line, NULL, NULL, NULL); + const char* filename = dwfl_lineinfo (dwline, &fn->info.pc, &fn->info.line, NULL, NULL, NULL); if(filename) { const char* file = strrchr(filename, '/'); if(file && *file != 0) { @@ -385,12 +385,12 @@ bool pst_function_unwind(pst_function* fn) } else { file = filename; } - fn->file = pst_strdup(file); + fn->info.file = pst_strdup(file); } } - Dwfl_Module* module = dwfl_addrmodule(fn->ctx->dwfl, fn->pc); - const char* addrname = dwfl_module_addrname(module, fn->pc); + Dwfl_Module* module = dwfl_addrmodule(fn->ctx->dwfl, fn->info.pc); + const char* addrname = dwfl_module_addrname(module, fn->info.pc); if(addrname) { char* demangle_name = cplus_demangle(addrname, 0); char* function_name = NULL; @@ -403,7 +403,7 @@ bool pst_function_unwind(pst_function* fn) if(str) { *str = 0; } - fn->name = pst_strdup(function_name); + fn->info.name = pst_strdup(function_name); free(function_name); if(demangle_name) { @@ -421,17 +421,17 @@ void pst_function_init(pst_function* fn, pst_context* _ctx, pst_function* _paren // fields fn->lowpc = 0; fn->highpc = 0; - fn->pc = 0; + fn->info.pc = 0; + fn->info.name = NULL; + fn->info.line = -1; + fn->info.file = NULL; fn->die = NULL; - fn->name = NULL; list_head_init(&fn->params); pst_call_site_storage_init(&fn->call_sites, _ctx); fn->sp = 0; fn->cfa = 0; memcpy(&fn->cursor, &_ctx->cursor, sizeof(fn->cursor)); - fn->line = -1; - fn->file = NULL; fn->parent = _parent; fn->frame = NULL; fn->ctx = _ctx; @@ -458,12 +458,12 @@ void pst_function_fini(pst_function* fn) free(fn->frame); } - if(fn->name) { - pst_free(fn->name); + if(fn->info.name) { + pst_free(fn->info.name); } - if(fn->file) { - pst_free(fn->file); + if(fn->info.file) { + pst_free(fn->info.file); } if(fn->allocated) { diff --git a/src/dwarf/dwarf_function.h b/src/dwarf/dwarf_function.h index 98b60cd..2654bc8 100644 --- a/src/dwarf/dwarf_function.h +++ b/src/dwarf/dwarf_function.h @@ -11,6 +11,7 @@ #include #include +#include "libpst-types.h" #include "utils/list_head.h" #include "context.h" #include "dwarf_call_site.h" @@ -20,23 +21,20 @@ // ----------------------------------------------------------------------------------- // pst_function // ----------------------------------------------------------------------------------- -typedef struct __pst_function { +typedef struct pst_function { list_node node; Dwarf_Addr lowpc; // offset to start of the function against base address Dwarf_Addr highpc; // offset to the next address after the end of the function against base address - unw_word_t pc; // address between LowPC & HighPC (plus base address offset). actually, currently executed command Dwarf_Die* die; // DWARF DIE containing definition of the function - char* name; // function's name + pst_function_info info; list_head params; // function's parameters pst_call_site_storage call_sites; unw_word_t sp; // SP register in function's frame unw_word_t cfa; // CFA (Canonical Frame Address) of the function unw_cursor_t cursor; // copy of stack state of the function - int line; // line in code where function is defined - char* file; // file name (DWARF Compilation Unit) where function is defined - struct __pst_function* parent; // parent function in call trace (caller) + pst_function* parent; // parent function in call trace (caller) Dwarf_Frame* frame; // function's stack frame pst_context* ctx; // context of unwinding bool allocated; // whether this object was allocated or not @@ -48,5 +46,6 @@ void pst_function_fini(pst_function* fn); bool pst_function_unwind(pst_function* fn); bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d); bool pst_function_print_dwarf(pst_function* fn); +pst_parameter* pst_function_next_parameter(pst_function* fn, pst_parameter* p); #endif /* __PST_DWARF_FUNCTION_H__ */ diff --git a/src/dwarf/dwarf_handler.c b/src/dwarf/dwarf_handler.c index ecbd57f..8c72c87 100644 --- a/src/dwarf/dwarf_handler.c +++ b/src/dwarf/dwarf_handler.c @@ -42,11 +42,11 @@ bool get_dwarf_function(pst_handler* h, pst_function* fun) { Dwarf_Addr mod_cu = 0; // get CU(Compilation Unit) debug definition - h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, fun->pc); - Dwarf_Die* cdie = dwfl_module_addrdie(h->ctx.module, fun->pc, &mod_cu); + h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, fun->info.pc); + Dwarf_Die* cdie = dwfl_module_addrdie(h->ctx.module, fun->info.pc, &mod_cu); //Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias); if(!cdie) { - pst_log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", fun->pc); + pst_log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", fun->info.pc); return false; } @@ -67,7 +67,7 @@ bool get_dwarf_function(pst_handler* h, pst_function* fun) int tag = dwarf_tag(&result); if(tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || tag == DW_TAG_inlined_subroutine) { //ctx.log(SEVERITY_DEBUG, "function die name %s", dwarf_diename(&result)); - if(!strcmp(fun->name, dwarf_diename(&result))) { + if(!strcmp(fun->info.name, dwarf_diename(&result))) { return pst_function_handle_dwarf(fun, &result); } } @@ -100,7 +100,7 @@ static void clear(pst_handler* h) } } -static pst_function* next_function(pst_handler* h, pst_function* fn) +pst_function* pst_handler_next_function(pst_handler* h, pst_function* fn) { list_node* n = (fn == NULL) ? list_first(&h->functions) : list_next(&fn->node); pst_function* ret = NULL; @@ -139,11 +139,11 @@ bool pst_handler_handle_dwarf(pst_handler* h) //for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) { for(pst_function* fun = last_function(h); fun; fun = prev_function(h, fun)) { - dladdr((void*)(fun->pc), &info); - pst_log(SEVERITY_INFO, "Function %s(...): module name: %s, base address: %p, CFA: %#lX", fun->name, info.dli_fname, info.dli_fbase, fun->parent ? fun->parent->sp : 0); + dladdr((void*)(fun->info.pc), &info); + pst_log(SEVERITY_INFO, "Function %s(...): module name: %s, base address: %p, CFA: %#lX", fun->info.name, info.dli_fname, info.dli_fbase, fun->parent ? fun->parent->sp : 0); // setup context - h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, fun->pc); + h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, fun->info.pc); h->ctx.base_addr = (uint64_t)info.dli_fbase; h->ctx.curr_frame = &fun->cursor; h->ctx.sp = fun->sp; @@ -161,7 +161,7 @@ const char* pst_print_pretty(pst_handler* h) h->ctx.clean_print(&h->ctx); h->ctx.print(&h->ctx, "DWARF-based stack trace information:\n"); uint32_t idx = 0; - for(pst_function* fn = next_function(h, NULL); fn; fn = next_function(h, fn)) { + for(pst_function* fn = pst_handler_next_function(h, NULL); fn; fn = pst_handler_next_function(h, fn)) { h->ctx.print(&h->ctx, "[%-2u] ", idx); idx++; pst_function_print_dwarf(fn); h->ctx.print(&h->ctx, "\n"); @@ -184,13 +184,13 @@ const char* pst_print_simple(pst_handler* h) h->ctx.clean_print(&h->ctx); h->ctx.print(&h->ctx, "Simple unwind-based stack trace:\n"); uint32_t idx = 0; - for(pst_function* fn = next_function(h, NULL); fn; fn = next_function(h, fn)) { + for(pst_function* fn = pst_handler_next_function(h, NULL); fn; fn = pst_handler_next_function(h, fn)) { h->ctx.print(&h->ctx, "[%-2d] ", idx); - h->ctx.print(fn->ctx, "%s() ", fn->name); - if(fn->file) { - h->ctx.print(fn->ctx, "at %s:%d, %p", fn->file, fn->line, (void*)fn->pc); + h->ctx.print(fn->ctx, "%s() ", fn->info.name); + if(fn->info.file) { + h->ctx.print(fn->ctx, "at %s:%d, %p", fn->info.file, fn->info.line, (void*)fn->info.pc); } else { - h->ctx.print(fn->ctx, "at %p", (void*)fn->pc); + h->ctx.print(fn->ctx, "at %p", (void*)fn->info.pc); } h->ctx.print(&h->ctx, "\n"); idx++; @@ -276,7 +276,7 @@ bool pst_handler_unwind(pst_handler* h) pst_log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, pc, sp); pst_function* last = last_function(h); pst_function* fn = add_function(h, NULL); - fn->pc = pc; fn->sp = sp; + fn->info.pc = pc; fn->sp = sp; if(!pst_function_unwind(fn)) { del_function(fn); } else if(last) { diff --git a/src/dwarf/dwarf_handler.h b/src/dwarf/dwarf_handler.h index a387620..8a4dc0b 100644 --- a/src/dwarf/dwarf_handler.h +++ b/src/dwarf/dwarf_handler.h @@ -28,5 +28,6 @@ void pst_handler_fini(pst_handler* h); bool pst_handler_handle_dwarf(pst_handler* h); bool pst_handler_unwind(pst_handler* h); +pst_function* pst_handler_next_function(pst_handler* h, pst_function* fn); #endif /* __PST_DWARF_HANDLER_H__ */ diff --git a/src/dwarf/dwarf_parameter.c b/src/dwarf/dwarf_parameter.c index a39c530..37bc818 100644 --- a/src/dwarf/dwarf_parameter.c +++ b/src/dwarf/dwarf_parameter.c @@ -70,20 +70,20 @@ static pst_type* next_type(pst_parameter* param, pst_type* t) bool pst_parameter_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", next_type(param, NULL)->name, param->name, param->location.value); + if(!param->info.is_return) { + if(param->info.has_value) { + param->ctx->print(param->ctx, "%s %s = 0x%lX", next_type(param, NULL)->name, param->info.name, param->info.value); } else { - param->ctx->print(param->ctx, "%s %s = ", next_type(param, NULL)->name, param->name); + param->ctx->print(param->ctx, "%s %s = ", next_type(param, NULL)->name, param->info.name); } } else { param->ctx->print(param->ctx, "%s", next_type(param, NULL)->name); } } else { - if(param->has_value) { - param->ctx->print(param->ctx, "%s = 0x%lX", param->name, param->location.value); + if(param->info.has_value) { + param->ctx->print(param->ctx, "%s = 0x%lX", param->info.name, param->info.value); } else { - param->ctx->print(param->ctx, "%s = ", param->name); + param->ctx->print(param->ctx, "%s = ", param->info.name); } } return true; @@ -113,12 +113,12 @@ bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base) switch (dwarf_tag(&ret_die)) { case DW_TAG_base_type: { // get Size attribute and it's value - param->size = 0; + param->info.size = 0; attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem); if(attr) { - dwarf_formudata(attr, ¶m->size); + dwarf_formudata(attr, ¶m->info.size); } - pst_log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->size); + pst_log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->info.size); pst_parameter_add_type(param, dwarf_diename(&ret_die), DW_TAG_base_type); param->type = DW_TAG_base_type; @@ -184,13 +184,13 @@ bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_fun Dwarf_Attribute attr_mem; Dwarf_Attribute* attr; - param->name = pst_strdup(dwarf_diename(result)); - param->is_variable = (dwarf_tag(result) == DW_TAG_variable); + param->info.name = pst_strdup(dwarf_diename(result)); + param->info.is_variable = (dwarf_tag(result) == DW_TAG_variable); - dwarf_decl_line(result, (int*)¶m->line); + dwarf_decl_line(result, (int*)¶m->info.line); // Get reference to attribute type of the parameter/variable attr = dwarf_attr(result, DW_AT_type, &attr_mem); - pst_log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable"); + pst_log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->info.name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable"); if(attr) { pst_parameter_handle_type(param, attr); } @@ -202,7 +202,8 @@ bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_fun 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; + param->info.value = param->location.value; + param->info.has_value = true; } else { pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", param->ctx->buff); } @@ -218,20 +219,20 @@ bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_fun case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: - dwarf_formudata(attr, ¶m->location.value); - param->has_value = true; + dwarf_formudata(attr, ¶m->info.value); + param->info.has_value = true; break; case DW_FORM_sdata: - dwarf_formsdata(attr, (int64_t*)¶m->location.value); - param->has_value = true; + dwarf_formsdata(attr, (int64_t*)¶m->info.value); + param->info.has_value = true; break; case DW_FORM_udata: - dwarf_formudata(attr, ¶m->location.value); - param->has_value = true; + dwarf_formudata(attr, ¶m->info.value); + param->info.has_value = true; break; } - if(param->has_value) { - pst_log(SEVERITY_DEBUG, "Parameter constant value: 0x%lX", param->location.value); + if(param->info.has_value) { + pst_log(SEVERITY_DEBUG, "Parameter constant value: 0x%lX", param->info.value); } } @@ -260,15 +261,17 @@ void pst_parameter_init(pst_parameter* param, pst_context* ctx) { list_node_init(¶m->node); param->die = NULL; - param->name = NULL; - param->line = 0; - param->size = 0; + // info field + param->info.name = NULL; + param->info.line = 0; + param->info.size = 0; + param->info.is_return = false; + param->info.is_variable = false; + param->info.has_value = false; + 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; @@ -287,8 +290,8 @@ pst_parameter* pst_parameter_new(pst_context* ctx) void pst_parameter_fini(pst_parameter* param) { clear(param); - if(param->name) { - pst_free(param->name); + if(param->info.name) { + pst_free(param->info.name); } if(param->allocated) { pst_free(param); diff --git a/src/dwarf/dwarf_parameter.h b/src/dwarf/dwarf_parameter.h index 702b6b3..78565bf 100644 --- a/src/dwarf/dwarf_parameter.h +++ b/src/dwarf/dwarf_parameter.h @@ -26,26 +26,21 @@ 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_function pst_function; typedef struct pst_parameter{ list_node node; // uplink. !!! must be first !!! // 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; + Dwarf_Die* die; // DWARF DIE containing parameter's definition + pst_parameter_info info; + 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' + pst_context* ctx; + pst_dwarf_expr location; - bool allocated; + bool allocated; } pst_parameter; void pst_parameter_init(pst_parameter* param, pst_context* ctx); pst_parameter* pst_parameter_new(pst_context* ctx); diff --git a/src/libpst.c b/src/libpst.c index 0004129..06b38d2 100644 --- a/src/libpst.c +++ b/src/libpst.c @@ -11,7 +11,7 @@ #include "utils/allocator.h" #include "dwarf/dwarf_handler.h" -#include "dwarf/dwarf_function.h" +#include "dwarf/dwarf_parameter.h" // allocate and initialize libpst library pst_handler* pst_lib_init(ucontext_t* hctx, void* buff, uint32_t size) @@ -49,3 +49,23 @@ int pst_unwind_pretty(pst_handler* h) { return pst_handler_handle_dwarf(h); } + +pst_parameter_info* pst_get_parameter_info(pst_parameter* parameter) +{ + return ¶meter->info; +} + +pst_function_info* pst_get_function_info(pst_function* function) +{ + return &function->info; +} + +pst_function* pst_get_next_function(pst_handler* handler, pst_function* current) +{ + return pst_handler_next_function(handler, current); +} + +pst_parameter* pst_get_next_parameter(pst_function* function, pst_parameter* current) +{ + return pst_function_next_parameter(function, current); +}