exprt next_function, next_parameter function_info, parameter_info to
external interface of the library
This commit is contained in:
@@ -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
@@ -15,7 +15,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
||||
+37
-37
@@ -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) {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <elfutils/libdw.h>
|
||||
#include <libunwind.h>
|
||||
|
||||
#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__ */
|
||||
|
||||
+15
-15
@@ -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) {
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
+34
-31
@@ -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 = <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 {
|
||||
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 = <undefined>", param->name);
|
||||
param->ctx->print(param->ctx, "%s = <undefined>", 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);
|
||||
|
||||
@@ -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);
|
||||
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
|
||||
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'
|
||||
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;
|
||||
|
||||
|
||||
+21
-1
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user