exprt next_function, next_parameter function_info, parameter_info to

external interface of the library
This commit is contained in:
2020-04-05 14:59:41 +04:00
parent e2e7535149
commit 3317cd212b
12 changed files with 193 additions and 117 deletions
+31
View File
@@ -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 <stdbool.h>
#include <libunwind.h>
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_ */
+35 -8
View File
@@ -15,7 +15,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include "libpst-types.h"
typedef struct pst_handler pst_handler; 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 * @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) * @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() * @param handler The handler obtained by pst_lib_init()
* @return 1 on success, 0 on failure * @return 1 on success, 0 on failure
*/ */
int pst_unwind_simple(pst_handler* handler); int pst_unwind_simple(pst_handler* handler);
/** /**
* @ingroup unwind_simple
* @brief Print unwound stack trace to internal buffer * @brief Print unwound stack trace to internal buffer
* @param handler The handler obtained by pst_lib_init() * @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); 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. // Advanced unwind routines.
// Additionally to pst_unwind_simple(...) provides types of parameters and variables in functions and their values if possible // Additionally to pst_unwind_simple(...) provides types of parameters and variables in functions and their values if possible
+1 -1
View File
@@ -37,7 +37,7 @@ VPATH = ./ ./dwarf ./arch ./utils
SRC = $(wildcard $(addsuffix /*.c,${VPATH})) SRC = $(wildcard $(addsuffix /*.c,${VPATH}))
OBJ = $(patsubst %.c,%.o,$(addprefix $(BUILD_DIR)/,$(notdir $(SRC)))) 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)" 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 .PHONY: all clean
+3 -3
View File
@@ -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 // 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 // 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 // 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_Die origin;
Dwarf_Attribute attr_mem; 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); attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem);
if(attr) { if(attr) {
pst_decl0(pst_dwarf_expr, expr); 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; target = expr.value;
pst_log(SEVERITY_DEBUG, "DW_AT_GNU_call_site_target: %#lX", target); 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; uint64_t start_pc = storage->ctx->base_addr + callee->lowpc;
pst_call_site* cs = storage_call_site_by_target(storage, start_pc); pst_call_site* cs = storage_call_site_by_target(storage, start_pc);
if(!cs) { if(!cs) {
cs = storage_call_site_by_origin(storage, callee->name); cs = storage_call_site_by_origin(storage, callee->info.name);
} }
return cs; return cs;
+1 -1
View File
@@ -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); 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); 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 // storage for all of function's call sites
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
+37 -37
View File
@@ -34,7 +34,7 @@ static bool get_frame(pst_function* fn)
} }
// get frame of CFI for address // 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) { if (result != 0) {
pst_log(SEVERITY_ERROR, "Failed to find CFI frame for module"); pst_log(SEVERITY_ERROR, "Failed to find CFI frame for module");
return false; return false;
@@ -44,8 +44,8 @@ static bool get_frame(pst_function* fn)
fn->ctx->frame = fn->frame; fn->ctx->frame = fn->frame;
// get return register and PC range for function // get return register and PC range for function
Dwarf_Addr start = fn->pc; Dwarf_Addr start = fn->info.pc;
Dwarf_Addr end = fn->pc; Dwarf_Addr end = fn->info.pc;
bool signalp; bool signalp;
int ra_regno = dwarf_frame_info (fn->frame, &start, &end, &signalp); int ra_regno = dwarf_frame_info (fn->frame, &start, &end, &signalp);
if(ra_regno >= 0) { if(ra_regno >= 0) {
@@ -54,7 +54,7 @@ static bool get_frame(pst_function* fn)
reginfo info; info.regno = ra_regno; reginfo info; info.regno = ra_regno;
dwfl_module_register_names(fn->ctx->module, regname_callback, &info); 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", 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 { } else {
pst_log(SEVERITY_WARNING, "Return address register info unavailable (%s)", dwarf_errmsg(0)); 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; bool nret = true;
pst_decl(pst_dwarf_stack, stack, fn->ctx); 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)) { 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 // setup context to match CFA for frame
fn->ctx->cfa = fn->cfa; fn->ctx->cfa = fn->cfa;
@@ -115,7 +115,7 @@ static void clear(pst_function* fn)
pst_call_site_storage_fini(&fn->call_sites); 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); 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) bool pst_function_print_dwarf(pst_function* fn)
{ {
char* at = NULL; char* at = NULL;
if(fn->file) { if(fn->info.file) {
if(!asprintf(&at, " at %s:%d, %p", fn->file, fn->line, (void*)fn->pc)) if(!asprintf(&at, " at %s:%d, %p", fn->info.file, fn->info.line, (void*)fn->info.pc))
return false; return false;
} else if(!asprintf(&at, " at %p", (void*)fn->pc)){ } else if(!asprintf(&at, " at %p", (void*)fn->info.pc)){
return false; return false;
} }
// 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(fn, NULL); pst_parameter* param = pst_function_next_parameter(fn, NULL);
if(param && param->is_return) { if(param && param->info.is_return) {
// print return value type, function name and start list of parameters // print return value type, function name and start list of parameters
pst_parameter_print_dwarf(param); pst_parameter_print_dwarf(param);
fn->ctx->print(fn->ctx, " %s(", fn->name); fn->ctx->print(fn->ctx, " %s(", fn->info.name);
param = next_param(fn, param); param = pst_function_next_parameter(fn, param);
} else { } 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; bool first = true; bool start_variable = false;
for(; param; param = next_param(fn, param)) { for(; param; param = pst_function_next_parameter(fn, param)) {
if(param->is_return) { if(param->info.is_return) {
// print return value type, function name and start list of parameters // print return value type, function name and start list of parameters
pst_parameter_print_dwarf(param); pst_parameter_print_dwarf(param);
fn->ctx->print(fn->ctx, " %s(", fn->name); fn->ctx->print(fn->ctx, " %s(", fn->info.name);
continue; continue;
} }
if(param->is_variable) { if(param->info.is_variable) {
if(!start_variable) { if(!start_variable) {
fn->ctx->print(fn->ctx, ")%s\n", at); fn->ctx->print(fn->ctx, ")%s\n", at);
fn->ctx->print(fn->ctx, "{\n"); fn->ctx->print(fn->ctx, "{\n");
start_variable = true; start_variable = true;
} }
if(param->line) { if(param->info.line) {
fn->ctx->print(fn->ctx, "%04u: ", param->line); fn->ctx->print(fn->ctx, "%04u: ", param->info.line);
} else { } else {
fn->ctx->print(fn->ctx, " "); 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); 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", 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); 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->sp : 0, fn->ctx->buff);
pst_log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), 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 // Get reference to return attribute type of the function
// may be to use dwfl_module_return_value_location() instead // 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); attr = dwarf_attr(fn->die, DW_AT_type, &attr_mem);
if(attr) { if(attr) {
if(!pst_parameter_handle_type(ret_p, 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); del_param(ret_p);
} }
} else { } else {
@@ -375,9 +375,9 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d)
bool pst_function_unwind(pst_function* fn) 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) { 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) { if(filename) {
const char* file = strrchr(filename, '/'); const char* file = strrchr(filename, '/');
if(file && *file != 0) { if(file && *file != 0) {
@@ -385,12 +385,12 @@ bool pst_function_unwind(pst_function* fn)
} else { } else {
file = filename; file = filename;
} }
fn->file = pst_strdup(file); fn->info.file = pst_strdup(file);
} }
} }
Dwfl_Module* module = dwfl_addrmodule(fn->ctx->dwfl, fn->pc); Dwfl_Module* module = dwfl_addrmodule(fn->ctx->dwfl, fn->info.pc);
const char* addrname = dwfl_module_addrname(module, fn->pc); const char* addrname = dwfl_module_addrname(module, fn->info.pc);
if(addrname) { if(addrname) {
char* demangle_name = cplus_demangle(addrname, 0); char* demangle_name = cplus_demangle(addrname, 0);
char* function_name = NULL; char* function_name = NULL;
@@ -403,7 +403,7 @@ bool pst_function_unwind(pst_function* fn)
if(str) { if(str) {
*str = 0; *str = 0;
} }
fn->name = pst_strdup(function_name); fn->info.name = pst_strdup(function_name);
free(function_name); free(function_name);
if(demangle_name) { if(demangle_name) {
@@ -421,17 +421,17 @@ void pst_function_init(pst_function* fn, pst_context* _ctx, pst_function* _paren
// fields // fields
fn->lowpc = 0; fn->lowpc = 0;
fn->highpc = 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->die = NULL;
fn->name = NULL;
list_head_init(&fn->params); list_head_init(&fn->params);
pst_call_site_storage_init(&fn->call_sites, _ctx); pst_call_site_storage_init(&fn->call_sites, _ctx);
fn->sp = 0; fn->sp = 0;
fn->cfa = 0; fn->cfa = 0;
memcpy(&fn->cursor, &_ctx->cursor, sizeof(fn->cursor)); memcpy(&fn->cursor, &_ctx->cursor, sizeof(fn->cursor));
fn->line = -1;
fn->file = NULL;
fn->parent = _parent; fn->parent = _parent;
fn->frame = NULL; fn->frame = NULL;
fn->ctx = _ctx; fn->ctx = _ctx;
@@ -458,12 +458,12 @@ void pst_function_fini(pst_function* fn)
free(fn->frame); free(fn->frame);
} }
if(fn->name) { if(fn->info.name) {
pst_free(fn->name); pst_free(fn->info.name);
} }
if(fn->file) { if(fn->info.file) {
pst_free(fn->file); pst_free(fn->info.file);
} }
if(fn->allocated) { if(fn->allocated) {
+5 -6
View File
@@ -11,6 +11,7 @@
#include <elfutils/libdw.h> #include <elfutils/libdw.h>
#include <libunwind.h> #include <libunwind.h>
#include "libpst-types.h"
#include "utils/list_head.h" #include "utils/list_head.h"
#include "context.h" #include "context.h"
#include "dwarf_call_site.h" #include "dwarf_call_site.h"
@@ -20,23 +21,20 @@
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
// pst_function // pst_function
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
typedef struct __pst_function { typedef struct pst_function {
list_node node; list_node node;
Dwarf_Addr lowpc; // offset to start of the function against base address 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 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 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 list_head params; // function's parameters
pst_call_site_storage call_sites; pst_call_site_storage call_sites;
unw_word_t sp; // SP register in function's frame unw_word_t sp; // SP register in function's frame
unw_word_t cfa; // CFA (Canonical Frame Address) of the function unw_word_t cfa; // CFA (Canonical Frame Address) of the function
unw_cursor_t cursor; // copy of stack state of the function unw_cursor_t cursor; // copy of stack state of the function
int line; // line in code where function is defined pst_function* parent; // parent function in call trace (caller)
char* file; // file name (DWARF Compilation Unit) where function is defined
struct __pst_function* parent; // parent function in call trace (caller)
Dwarf_Frame* frame; // function's stack frame Dwarf_Frame* frame; // function's stack frame
pst_context* ctx; // context of unwinding pst_context* ctx; // context of unwinding
bool allocated; // whether this object was allocated or not 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_unwind(pst_function* fn);
bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d); bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d);
bool pst_function_print_dwarf(pst_function* fn); 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__ */ #endif /* __PST_DWARF_FUNCTION_H__ */
+15 -15
View File
@@ -42,11 +42,11 @@ bool get_dwarf_function(pst_handler* h, pst_function* fun)
{ {
Dwarf_Addr mod_cu = 0; Dwarf_Addr mod_cu = 0;
// get CU(Compilation Unit) debug definition // get CU(Compilation Unit) debug definition
h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, fun->pc); h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, fun->info.pc);
Dwarf_Die* cdie = dwfl_module_addrdie(h->ctx.module, fun->pc, &mod_cu); Dwarf_Die* cdie = dwfl_module_addrdie(h->ctx.module, fun->info.pc, &mod_cu);
//Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias); //Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias);
if(!cdie) { 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; return false;
} }
@@ -67,7 +67,7 @@ bool get_dwarf_function(pst_handler* h, pst_function* fun)
int tag = dwarf_tag(&result); int tag = dwarf_tag(&result);
if(tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || tag == DW_TAG_inlined_subroutine) { 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)); //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); 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); list_node* n = (fn == NULL) ? list_first(&h->functions) : list_next(&fn->node);
pst_function* ret = NULL; 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 = next_function(NULL); fun; fun = next_function(fun)) {
for(pst_function* fun = last_function(h); fun; fun = prev_function(h, fun)) { for(pst_function* fun = last_function(h); fun; fun = prev_function(h, fun)) {
dladdr((void*)(fun->pc), &info); dladdr((void*)(fun->info.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); 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 // 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.base_addr = (uint64_t)info.dli_fbase;
h->ctx.curr_frame = &fun->cursor; h->ctx.curr_frame = &fun->cursor;
h->ctx.sp = fun->sp; 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.clean_print(&h->ctx);
h->ctx.print(&h->ctx, "DWARF-based stack trace information:\n"); h->ctx.print(&h->ctx, "DWARF-based stack trace information:\n");
uint32_t idx = 0; 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++; h->ctx.print(&h->ctx, "[%-2u] ", idx); idx++;
pst_function_print_dwarf(fn); pst_function_print_dwarf(fn);
h->ctx.print(&h->ctx, "\n"); 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.clean_print(&h->ctx);
h->ctx.print(&h->ctx, "Simple unwind-based stack trace:\n"); h->ctx.print(&h->ctx, "Simple unwind-based stack trace:\n");
uint32_t idx = 0; 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(&h->ctx, "[%-2d] ", idx);
h->ctx.print(fn->ctx, "%s() ", fn->name); h->ctx.print(fn->ctx, "%s() ", fn->info.name);
if(fn->file) { if(fn->info.file) {
h->ctx.print(fn->ctx, "at %s:%d, %p", fn->file, fn->line, (void*)fn->pc); h->ctx.print(fn->ctx, "at %s:%d, %p", fn->info.file, fn->info.line, (void*)fn->info.pc);
} else { } 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"); h->ctx.print(&h->ctx, "\n");
idx++; 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_log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, pc, sp);
pst_function* last = last_function(h); pst_function* last = last_function(h);
pst_function* fn = add_function(h, NULL); 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)) { if(!pst_function_unwind(fn)) {
del_function(fn); del_function(fn);
} else if(last) { } else if(last) {
+1
View File
@@ -28,5 +28,6 @@ void pst_handler_fini(pst_handler* h);
bool pst_handler_handle_dwarf(pst_handler* h); bool pst_handler_handle_dwarf(pst_handler* h);
bool pst_handler_unwind(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__ */ #endif /* __PST_DWARF_HANDLER_H__ */
+34 -31
View File
@@ -70,20 +70,20 @@ static pst_type* next_type(pst_parameter* param, pst_type* t)
bool pst_parameter_print_dwarf(pst_parameter* param) bool pst_parameter_print_dwarf(pst_parameter* param)
{ {
if(list_count(&param->types)) { if(list_count(&param->types)) {
if(!param->is_return) { if(!param->info.is_return) {
if(param->has_value) { if(param->info.has_value) {
param->ctx->print(param->ctx, "%s %s = 0x%lX", next_type(param, NULL)->name, param->name, param->location.value); param->ctx->print(param->ctx, "%s %s = 0x%lX", next_type(param, NULL)->name, param->info.name, param->info.value);
} else { } else {
param->ctx->print(param->ctx, "%s %s = <undefined>", next_type(param, NULL)->name, param->name); param->ctx->print(param->ctx, "%s %s = <undefined>", next_type(param, NULL)->name, param->info.name);
} }
} else { } else {
param->ctx->print(param->ctx, "%s", next_type(param, NULL)->name); param->ctx->print(param->ctx, "%s", next_type(param, NULL)->name);
} }
} else { } else {
if(param->has_value) { if(param->info.has_value) {
param->ctx->print(param->ctx, "%s = 0x%lX", param->name, param->location.value); param->ctx->print(param->ctx, "%s = 0x%lX", param->info.name, param->info.value);
} else { } else {
param->ctx->print(param->ctx, "%s = <undefined>", param->name); param->ctx->print(param->ctx, "%s = <undefined>", param->info.name);
} }
} }
return true; return true;
@@ -113,12 +113,12 @@ bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base)
switch (dwarf_tag(&ret_die)) { switch (dwarf_tag(&ret_die)) {
case DW_TAG_base_type: { case DW_TAG_base_type: {
// get Size attribute and it's value // 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); attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
if(attr) { if(attr) {
dwarf_formudata(attr, &param->size); dwarf_formudata(attr, &param->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); pst_parameter_add_type(param, dwarf_diename(&ret_die), DW_TAG_base_type);
param->type = 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_mem;
Dwarf_Attribute* attr; Dwarf_Attribute* attr;
param->name = pst_strdup(dwarf_diename(result)); param->info.name = pst_strdup(dwarf_diename(result));
param->is_variable = (dwarf_tag(result) == DW_TAG_variable); param->info.is_variable = (dwarf_tag(result) == DW_TAG_variable);
dwarf_decl_line(result, (int*)&param->line); dwarf_decl_line(result, (int*)&param->info.line);
// Get reference to attribute type of the parameter/variable // Get reference to attribute type of the parameter/variable
attr = dwarf_attr(result, DW_AT_type, &attr_mem); 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) { if(attr) {
pst_parameter_handle_type(param, 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); unw_get_reg(param->ctx->curr_frame, UNW_REG_IP, &pc);
if(handle_location(param->ctx, attr, &param->location, pc, fun)) { if(handle_location(param->ctx, attr, &param->location, pc, fun)) {
param->has_value = true; param->info.value = param->location.value;
param->info.has_value = true;
} else { } else {
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", param->ctx->buff); 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_data2:
case DW_FORM_data4: case DW_FORM_data4:
case DW_FORM_data8: case DW_FORM_data8:
dwarf_formudata(attr, &param->location.value); dwarf_formudata(attr, &param->info.value);
param->has_value = true; param->info.has_value = true;
break; break;
case DW_FORM_sdata: case DW_FORM_sdata:
dwarf_formsdata(attr, (int64_t*)&param->location.value); dwarf_formsdata(attr, (int64_t*)&param->info.value);
param->has_value = true; param->info.has_value = true;
break; break;
case DW_FORM_udata: case DW_FORM_udata:
dwarf_formudata(attr, &param->location.value); dwarf_formudata(attr, &param->info.value);
param->has_value = true; param->info.has_value = true;
break; break;
} }
if(param->has_value) { if(param->info.has_value) {
pst_log(SEVERITY_DEBUG, "Parameter constant value: 0x%lX", param->location.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(&param->node); list_node_init(&param->node);
param->die = NULL; param->die = NULL;
param->name = NULL; // info field
param->line = 0; param->info.name = NULL;
param->size = 0; 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->type = 0;
param->enc_type = 0; param->enc_type = 0;
list_head_init(&param->types); list_head_init(&param->types);
param->is_return = false;
param->is_variable = false;
param->has_value = false;
param->ctx = ctx; param->ctx = ctx;
pst_dwarf_expr_init(&param->location); pst_dwarf_expr_init(&param->location);
param->allocated = false; param->allocated = false;
@@ -287,8 +290,8 @@ pst_parameter* pst_parameter_new(pst_context* ctx)
void pst_parameter_fini(pst_parameter* param) void pst_parameter_fini(pst_parameter* param)
{ {
clear(param); clear(param);
if(param->name) { if(param->info.name) {
pst_free(param->name); pst_free(param->info.name);
} }
if(param->allocated) { if(param->allocated) {
pst_free(param); pst_free(param);
+2 -7
View File
@@ -26,22 +26,17 @@ void pst_type_init(pst_type* t, const char* name, uint32_t type);
pst_type* pst_type_new(const char* name, uint32_t type); pst_type* pst_type_new(const char* name, uint32_t type);
void pst_type_fini(pst_type* t); void pst_type_fini(pst_type* t);
typedef struct __pst_function pst_function; typedef struct pst_function pst_function;
typedef struct pst_parameter{ typedef struct pst_parameter{
list_node node; // uplink. !!! must be first !!! list_node node; // uplink. !!! must be first !!!
// fields // fields
Dwarf_Die* die; // DWARF DIE containing parameter's definition Dwarf_Die* die; // DWARF DIE containing parameter's definition
char* name; // parameter's name pst_parameter_info info;
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 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 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' 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_context* ctx;
pst_dwarf_expr location; pst_dwarf_expr location;
+21 -1
View File
@@ -11,7 +11,7 @@
#include "utils/allocator.h" #include "utils/allocator.h"
#include "dwarf/dwarf_handler.h" #include "dwarf/dwarf_handler.h"
#include "dwarf/dwarf_function.h" #include "dwarf/dwarf_parameter.h"
// allocate and initialize libpst library // allocate and initialize libpst library
pst_handler* pst_lib_init(ucontext_t* hctx, void* buff, uint32_t size) 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); return pst_handler_handle_dwarf(h);
} }
pst_parameter_info* pst_get_parameter_info(pst_parameter* parameter)
{
return &parameter->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);
}