diff --git a/include/libpst-types.h b/include/libpst-types.h index c4b7613..1ab5323 100644 --- a/include/libpst-types.h +++ b/include/libpst-types.h @@ -12,13 +12,18 @@ #include typedef struct { - char* name; ///< demangled name of the function. NULL if function name resolution failed - char* file; ///< file name where the function is defined. NULL if library failed to get file name - int line; ///< line of definition of the function. -1 if library failed to get file line - unw_word_t pc; ///< address between LowPC & HighPC (plus base address offset). actually, address of currently executed command in function + char* name; ///< demangled name of the function. NULL if function name resolution failed + char* file; ///< file name where the function is defined. NULL if library failed to get file name + int line; ///< line of definition of the function. -1 if library failed to get file line + unw_word_t pc; ///< address between LowPC & HighPC (plus base address offset). actually, address of currently executed command in function + unw_word_t lowpc; ///< offset to start of the function against base address + unw_word_t highpc; ///< offset to the next address after the end of the function against base address + unw_word_t sp; ///< SP register in function's frame + unw_word_t cfa; ///< CFA (Canonical Frame Address) of the function. !!! Don't use CFA provided by libunwind, it's not valid !!! + unw_cursor_t context;///< Function's frame including register's values } pst_function_info; -/// @brief bitmask of parameter options +/// @brief bitmask of parameter's options typedef enum { // scope & access PARAM_CONST = 0x00000001, ///< constant access diff --git a/src/dwarf/dwarf_call_site.c b/src/dwarf/dwarf_call_site.c index 411d772..918e71a 100644 --- a/src/dwarf/dwarf_call_site.c +++ b/src/dwarf/dwarf_call_site.c @@ -307,7 +307,7 @@ void pst_call_site_storage_del(pst_call_site_storage* storage, pst_call_site* st pst_call_site* pst_call_site_storage_find(pst_call_site_storage* storage, pst_function* callee) { - uint64_t start_pc = storage->ctx->base_addr + callee->lowpc; + uint64_t start_pc = storage->ctx->base_addr + callee->info.lowpc; pst_call_site* cs = storage_call_site_by_target(storage, start_pc); if(!cs) { cs = storage_call_site_by_origin(storage, callee->info.name); diff --git a/src/dwarf/dwarf_function.c b/src/dwarf/dwarf_function.c index a1d20ce..77f1913 100644 --- a/src/dwarf/dwarf_function.c +++ b/src/dwarf/dwarf_function.c @@ -74,11 +74,11 @@ 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->info.name, fn->ctx->buff, fn->cfa); + if(pst_dwarf_stack_calc(&stack, cfa_ops, cfa_nops, NULL, NULL) && pst_dwarf_stack_get_value(&stack, &fn->info.cfa)) { + pst_log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fn->info.name, fn->ctx->buff, fn->info.cfa); // setup context to match CFA for frame - fn->ctx->cfa = fn->cfa; + fn->ctx->cfa = fn->info.cfa; } else { nret = false; pst_log(SEVERITY_ERROR, "Failed to calculate CFA expression"); @@ -261,21 +261,21 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d) // get list of offsets from process base address of continuous memory ranges where function's code resides // if(dwarf_haspc(d, pc)) { - dwarf_lowpc(d, &fn->lowpc); - dwarf_highpc(d, &fn->highpc); + dwarf_lowpc(d, &fn->info.lowpc); + dwarf_highpc(d, &fn->info.highpc); // } else { // pst_log(SEVERITY_ERROR, "Function's '%s' DIE hasn't definitions of memory offsets of function's code", dwarf_diename(d)); // return false; // } unw_proc_info_t info; - unw_get_proc_info(&fn->cursor, &info); + unw_get_proc_info(&fn->info.context, &info); 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->info.pc - fn->ctx->base_addr, info.start_ip, info.start_ip - fn->ctx->base_addr); + dwarf_diename(d), fn->info.lowpc, fn->info.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(...): CFA: %#lX %s", dwarf_diename(d), fn->parent ? fn->parent->info.sp : 0, fn->ctx->buff); pst_log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), fn->ctx->buff); // determine function's stack frame base @@ -418,20 +418,22 @@ void pst_function_init(pst_function* fn, pst_context* _ctx, pst_function* _paren { list_node_init(&fn->node); - // fields - fn->lowpc = 0; - fn->highpc = 0; + // user visible fields fn->info.pc = 0; + fn->info.lowpc = 0; + fn->info.highpc = 0; + bzero(&fn->info.context, sizeof(fn->info.context)); fn->info.name = NULL; fn->info.line = -1; fn->info.file = NULL; + fn->info.sp = 0; + + // internal fields fn->die = 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)); + memcpy(&fn->info.context, &_ctx->cursor, sizeof(fn->info.context)); fn->parent = _parent; fn->frame = NULL; fn->ctx = _ctx; diff --git a/src/dwarf/dwarf_function.h b/src/dwarf/dwarf_function.h index 2654bc8..c5f5983 100644 --- a/src/dwarf/dwarf_function.h +++ b/src/dwarf/dwarf_function.h @@ -22,18 +22,11 @@ // 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 + list_node node; // uplink Dwarf_Die* die; // DWARF DIE containing definition of the function - 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 + pst_function_info info; // information about the function itself + list_head params; // parameters of the function + pst_call_site_storage call_sites; // call-sites of the function pst_function* parent; // parent function in call trace (caller) Dwarf_Frame* frame; // function's stack frame pst_context* ctx; // context of unwinding diff --git a/src/dwarf/dwarf_handler.c b/src/dwarf/dwarf_handler.c index b7dd942..2b134fc 100644 --- a/src/dwarf/dwarf_handler.c +++ b/src/dwarf/dwarf_handler.c @@ -146,15 +146,15 @@ 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->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); + 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->info.sp : 0); // setup context 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; - h->ctx.cfa = fun->cfa; - h->ctx.curr_frame = &fun->cursor; + h->ctx.curr_frame = &fun->info.context; + h->ctx.sp = fun->info.sp; + h->ctx.cfa = fun->info.cfa; get_dwarf_function(h, fun); } @@ -282,7 +282,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->info.pc = pc; fn->sp = sp; + fn->info.pc = pc; fn->info.sp = sp; if(!pst_function_unwind(fn)) { del_function(fn); } else if(last) {