introduce separate print functions for 'simple' and 'pretty' variands of
unwinding
This commit is contained in:
+34
-16
@@ -17,33 +17,51 @@
|
||||
|
||||
typedef struct pst_handler pst_handler;
|
||||
|
||||
// allocate libpst handler and initialize the library
|
||||
pst_handler* pst_lib_init(ucontext_t* hctx);
|
||||
/**
|
||||
* @brief allocate libpst handler and initialize the library
|
||||
* @param context context of process given to signal handler of a program. If NULL, then we are not in signal handler
|
||||
* @param buff pointer to buffer by libpst custom allocator(i.e. no malloc() will beused). if NULL, then standard allocator will be used
|
||||
* @param size of 'buff'
|
||||
*
|
||||
* @return pointer to handler to be used for all other operations. NULL in case of error
|
||||
*/
|
||||
pst_handler* pst_lib_init(ucontext_t* context, void* buff, uint32_t size);
|
||||
|
||||
// deallocate libpst handler and deinitialize the library
|
||||
void pst_lib_fini(pst_handler* h);
|
||||
/**
|
||||
* @brief deallocate libpst handler and deinitialize the library
|
||||
* @param handler library handler previously initialized by 'pst_lib_init()'
|
||||
*/
|
||||
void pst_lib_fini(pst_handler* handler);
|
||||
|
||||
|
||||
//
|
||||
// Base unwind routines.
|
||||
// Unwinds current stack trace using base information about program (i.e. print out address, function name)
|
||||
//
|
||||
/**
|
||||
* @defgroup unwind_simple
|
||||
* @brief Unwinds current stack trace using base information about program (i.e. function address, function name and line)
|
||||
*/
|
||||
|
||||
// write stack trace information to provided file descriptor
|
||||
int pst_unwind_simple_fd(pst_handler* h, FILE* fd);
|
||||
/**
|
||||
* @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);
|
||||
|
||||
// save stack trace information to provided buffer in RAM
|
||||
int pst_unwind_simple(pst_handler* h, char* buff, uint32_t buff_size);
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
const char* pst_print_simple(pst_handler* handler);
|
||||
|
||||
//
|
||||
// Advanced unwind routines.
|
||||
// Additionally to pst_unwind_simple(...) provides types of parameters and variables in functions and their values if possible
|
||||
//
|
||||
|
||||
// write stack trace information to provided file descriptor
|
||||
int pst_unwind_pretty_fd(pst_handler* h, FILE* fd);
|
||||
|
||||
// save stack trace information to provided buffer in RAM
|
||||
int pst_unwind_pretty(pst_handler* h, char* buff, uint32_t buff_size);
|
||||
int pst_unwind_pretty(pst_handler* h);
|
||||
const char* pst_print_pretty(pst_handler* h);
|
||||
|
||||
#endif /* __LIBPST_EXTERNAL_H_ */
|
||||
|
||||
@@ -72,6 +72,7 @@ static bool get_frame(pst_function* fn)
|
||||
|
||||
fn->ctx->print_expr(fn->ctx, cfa_ops, cfa_nops, NULL);
|
||||
|
||||
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);
|
||||
@@ -79,12 +80,13 @@ static bool get_frame(pst_function* fn)
|
||||
// setup context to match CFA for frame
|
||||
fn->ctx->cfa = fn->cfa;
|
||||
} else {
|
||||
nret = false;
|
||||
pst_log(SEVERITY_ERROR, "Failed to calculate CFA expression");
|
||||
}
|
||||
|
||||
pst_dwarf_stack_fini(&stack);
|
||||
|
||||
return true;
|
||||
return nret;
|
||||
}
|
||||
|
||||
static pst_parameter* add_param(pst_function* fn)
|
||||
@@ -189,16 +191,12 @@ bool handle_lexical_block(pst_function* fn, Dwarf_Die* result)
|
||||
bool pst_function_print_dwarf(pst_function* fn)
|
||||
{
|
||||
char* at = NULL;
|
||||
if(!asprintf(&at, " at %s:%d, %p", fn->file, fn->line, (void*)fn->pc)) {
|
||||
if(fn->file) {
|
||||
if(!asprintf(&at, " at %s:%d, %p", fn->file, fn->line, (void*)fn->pc))
|
||||
return false;
|
||||
} else if(!asprintf(&at, " at %p", (void*)fn->pc)){
|
||||
return false;
|
||||
}
|
||||
if(at[4] == ':' && at[5] == '-') {
|
||||
free(at);
|
||||
if(!asprintf(&at, " at %p", (void*)fn->pc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//ctx->print(ctx, "%s:%d: ", file.c_str(), line);
|
||||
|
||||
// handle return parameter and be safe if function haven't parameters (for example, dwar info for function is absent)
|
||||
pst_parameter* param = next_param(fn, NULL);
|
||||
@@ -244,7 +242,7 @@ bool pst_function_print_dwarf(pst_function* fn)
|
||||
}
|
||||
|
||||
if(!start_variable) {
|
||||
fn->ctx->print(fn->ctx, ");%s\n", at);
|
||||
fn->ctx->print(fn->ctx, ")%s\n", at);
|
||||
} else {
|
||||
fn->ctx->print(fn->ctx, "}\n");
|
||||
}
|
||||
@@ -388,12 +386,7 @@ bool pst_function_unwind(pst_function* fn)
|
||||
file = filename;
|
||||
}
|
||||
fn->file = pst_strdup(file);
|
||||
fn->ctx->print(fn->ctx, "%s:%d", fn->file, fn->line);
|
||||
} else {
|
||||
fn->ctx->print(fn->ctx, "%p", (void*)fn->pc);
|
||||
}
|
||||
} else {
|
||||
fn->ctx->print(fn->ctx, "%p", (void*)fn->pc);
|
||||
}
|
||||
|
||||
Dwfl_Module* module = dwfl_addrmodule(fn->ctx->dwfl, fn->pc);
|
||||
@@ -405,7 +398,6 @@ bool pst_function_unwind(pst_function* fn)
|
||||
pst_log(SEVERITY_ERROR, "Failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
fn->ctx->print(fn->ctx, " --> %s", function_name);
|
||||
|
||||
char* str = strchr(function_name, '(');
|
||||
if(str) {
|
||||
|
||||
+61
-36
@@ -156,7 +156,7 @@ bool pst_handler_handle_dwarf(pst_handler* h)
|
||||
return true;
|
||||
}
|
||||
|
||||
void pst_handler_print_dwarf(pst_handler* h)
|
||||
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");
|
||||
@@ -166,6 +166,8 @@ void pst_handler_print_dwarf(pst_handler* h)
|
||||
pst_function_print_dwarf(fn);
|
||||
h->ctx.print(&h->ctx, "\n");
|
||||
}
|
||||
|
||||
return h->ctx.buff;
|
||||
}
|
||||
|
||||
char *debuginfo_path = NULL;
|
||||
@@ -177,53 +179,76 @@ Dwfl_Callbacks callbacks = {
|
||||
};
|
||||
|
||||
#include <dlfcn.h>
|
||||
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)) {
|
||||
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);
|
||||
} else {
|
||||
h->ctx.print(fn->ctx, "at %p", (void*)fn->pc);
|
||||
}
|
||||
h->ctx.print(&h->ctx, "\n");
|
||||
idx++;
|
||||
}
|
||||
|
||||
return h->ctx.buff;
|
||||
}
|
||||
|
||||
|
||||
bool pst_handler_unwind(pst_handler* h)
|
||||
{
|
||||
h->ctx.clean_print(&h->ctx);
|
||||
void* caller; // pointer to the function which requested to unwind stack
|
||||
void* caller = NULL; // pointer to the function which requested to unwind stack
|
||||
|
||||
#ifdef REG_RIP // x86_64
|
||||
caller = (void *) h->ctx.hcontext->uc_mcontext.gregs[REG_RIP];
|
||||
h->ctx.sp = h->ctx.hcontext->uc_mcontext.gregs[REG_RSP];
|
||||
pst_log(SEVERITY_DEBUG, "Original caller's SP: %#lX", h->ctx.sp);
|
||||
#elif defined(REG_EIP) // x86_32
|
||||
caller = (void *) uctx->uc_mcontext.gregs[REG_EIP]);
|
||||
#elif defined(__arm__)
|
||||
caller = (void *) uctx->uc_mcontext.arm_pc);
|
||||
#elif defined(__aarch64__)
|
||||
caller = (void *) uctx->uc_mcontext.pc);
|
||||
#elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__)
|
||||
caller = (void *) uctx->uc_mcontext.regs->nip);
|
||||
#elif defined(__s390x__)
|
||||
caller = (void *) uctx->uc_mcontext.psw.addr);
|
||||
#elif defined(__APPLE__) && defined(__x86_64__)
|
||||
caller = (void *) uctx->uc_mcontext->__ss.__rip);
|
||||
#else
|
||||
# error "unknown architecture!"
|
||||
#endif
|
||||
if(h->ctx.hcontext) {
|
||||
#ifdef REG_RIP // x86_64
|
||||
caller = (void *) h->ctx.hcontext->uc_mcontext.gregs[REG_RIP];
|
||||
h->ctx.sp = h->ctx.hcontext->uc_mcontext.gregs[REG_RSP];
|
||||
pst_log(SEVERITY_DEBUG, "Original caller's SP: %#lX", h->ctx.sp);
|
||||
#elif defined(REG_EIP) // x86_32
|
||||
caller = (void *) h->uc_mcontext.gregs[REG_EIP]);
|
||||
#elif defined(__arm__)
|
||||
caller = (void *) h->uc_mcontext.arm_pc);
|
||||
#elif defined(__aarch64__)
|
||||
caller = (void *) h->uc_mcontext.pc);
|
||||
#elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__)
|
||||
caller = (void *) h->uc_mcontext.regs->nip);
|
||||
#elif defined(__s390x__)
|
||||
caller = (void *) h->uc_mcontext.psw.addr);
|
||||
#elif defined(__APPLE__) && defined(__x86_64__)
|
||||
caller = (void *) h->uc_mcontext->__ss.__rip);
|
||||
#else
|
||||
# error "unknown architecture!"
|
||||
#endif
|
||||
}
|
||||
|
||||
//handle = dlopen(NULL, RTLD_NOW);
|
||||
Dl_info info;
|
||||
dladdr(caller, &info);
|
||||
h->ctx.base_addr = (uint64_t)info.dli_fbase;
|
||||
pst_log(SEVERITY_INFO, "Process address information: PC address: %p, base address: %p, object name: %s", caller, info.dli_fbase, info.dli_fname);
|
||||
if(caller) {
|
||||
Dl_info info;
|
||||
dladdr(caller, &info);
|
||||
h->ctx.base_addr = (uint64_t)info.dli_fbase;
|
||||
pst_log(SEVERITY_INFO, "Process address information: PC address: %p, base address: %p, object name: %s", caller, info.dli_fbase, info.dli_fname);
|
||||
}
|
||||
|
||||
if(!h->ctx.dwfl) {
|
||||
h->ctx.dwfl = dwfl_begin(&callbacks);
|
||||
if(h->ctx.dwfl == NULL) {
|
||||
h->ctx.print(&h->ctx, "Failed to initialize libdw session for parse stack frames");
|
||||
pst_log(SEVERITY_ERROR, "Failed to initialize libdw session to parse stack frames");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dwfl_linux_proc_report(h->ctx.dwfl, getpid()) != 0 || dwfl_report_end(h->ctx.dwfl, NULL, NULL) !=0) {
|
||||
h->ctx.print(&h->ctx, "Failed to parse debug section of executable");
|
||||
pst_log(SEVERITY_ERROR, "Failed to parse debug section of executable");
|
||||
dwfl_end(h->ctx.dwfl);
|
||||
h->ctx.dwfl = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
h->ctx.print(&h->ctx, "Stack trace: caller = %p\n", caller);
|
||||
pst_log(SEVERITY_INFO, "Stack trace: caller = %p\n", caller);
|
||||
|
||||
unw_getcontext(&h->ctx.context);
|
||||
unw_init_local(&h->ctx.cursor, &h->ctx.context);
|
||||
@@ -239,14 +264,15 @@ bool pst_handler_unwind(pst_handler* h)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(pc == (uint64_t)caller) {
|
||||
skip = 0;
|
||||
} else if(skip) {
|
||||
pst_log(SEVERITY_DEBUG, "Skipping frame #%d: PC = %#lX, SP = %#lX", i, pc, sp);
|
||||
continue;
|
||||
if(caller) {
|
||||
if(pc == (uint64_t)caller) {
|
||||
skip = 0;
|
||||
} else if(skip) {
|
||||
pst_log(SEVERITY_DEBUG, "Skipping frame #%d: PC = %#lX, SP = %#lX", i, pc, sp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
h->ctx.print(&h->ctx, "[%-2d] ", i);
|
||||
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);
|
||||
@@ -256,7 +282,6 @@ bool pst_handler_unwind(pst_handler* h)
|
||||
} else if(last) {
|
||||
last->parent = fn;
|
||||
}
|
||||
h->ctx.print(&h->ctx, "\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "utils/list_head.h"
|
||||
#include "common.h"
|
||||
#include "context.h"
|
||||
#include "dwarf_function.h"
|
||||
|
||||
typedef struct pst_handler {
|
||||
pst_context ctx; // context of unwinding
|
||||
@@ -26,7 +27,6 @@ pst_handler* pst_handler_new(ucontext_t* hctx);
|
||||
void pst_handler_fini(pst_handler* h);
|
||||
|
||||
bool pst_handler_handle_dwarf(pst_handler* h);
|
||||
void pst_handler_print_dwarf(pst_handler* h);
|
||||
bool pst_handler_unwind(pst_handler* h);
|
||||
|
||||
#endif /* __PST_DWARF_HANDLER_H__ */
|
||||
|
||||
+12
-52
@@ -11,12 +11,17 @@
|
||||
|
||||
#include "utils/allocator.h"
|
||||
#include "dwarf/dwarf_handler.h"
|
||||
#include "dwarf/dwarf_function.h"
|
||||
|
||||
// allocate and initialize libpst library
|
||||
pst_handler* pst_lib_init(ucontext_t* hctx)
|
||||
pst_handler* pst_lib_init(ucontext_t* hctx, void* buff, uint32_t size)
|
||||
{
|
||||
// global
|
||||
pst_alloc_init(&allocator);
|
||||
if(!buff || !size) {
|
||||
pst_alloc_init(&allocator);
|
||||
} else {
|
||||
pst_alloc_init_custom(&allocator, buff, size);
|
||||
}
|
||||
pst_log_init_console(&logger);
|
||||
|
||||
pst_new(pst_handler, handler, hctx);
|
||||
@@ -33,59 +38,14 @@ void pst_lib_fini(pst_handler* h)
|
||||
pst_alloc_fini(&allocator);
|
||||
}
|
||||
|
||||
// write stack trace information to provided file descriptor
|
||||
int pst_unwind_simple_fd(pst_handler* h, FILE* fd)
|
||||
// save stack trace information to provided buffer in RAM
|
||||
int pst_unwind_simple(pst_handler* h)
|
||||
{
|
||||
int ret = pst_handler_unwind(h);
|
||||
if(ret) {
|
||||
fwrite(h->ctx.buff, 1, strlen(h->ctx.buff), fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return pst_handler_unwind(h);
|
||||
}
|
||||
|
||||
// save stack trace information to provided buffer in RAM
|
||||
int pst_unwind_simple(pst_handler* h, char* buff, uint32_t buff_size)
|
||||
int pst_unwind_pretty(pst_handler* h)
|
||||
{
|
||||
int ret = pst_handler_unwind(h);
|
||||
if(ret) {
|
||||
uint32_t cnt = buff_size < sizeof(h->ctx.buff) ? buff_size : sizeof(h->ctx.buff);
|
||||
memcpy(buff, h->ctx.buff, cnt - 2);
|
||||
buff[cnt - 1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// write stack trace information to provided file descriptor
|
||||
int pst_unwind_pretty_fd(pst_handler* h, FILE* fd)
|
||||
{
|
||||
int ret = pst_handler_handle_dwarf(h);
|
||||
if(ret) {
|
||||
pst_handler_print_dwarf(h);
|
||||
fwrite(h->ctx.buff, 1, strlen(h->ctx.buff), fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// save stack trace information to provided buffer in RAM
|
||||
int pst_unwind_pretty(pst_handler* h, char* buff, uint32_t buff_size)
|
||||
{
|
||||
int ret = pst_handler_handle_dwarf(h);
|
||||
if(ret) {
|
||||
pst_handler_print_dwarf(h);
|
||||
uint32_t cnt = buff_size < sizeof(h->ctx.buff) ? buff_size : sizeof(h->ctx.buff);
|
||||
memcpy(buff, h->ctx.buff, cnt - 2);
|
||||
buff[cnt - 1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return pst_handler_handle_dwarf(h);
|
||||
}
|
||||
|
||||
+8
-4
@@ -62,15 +62,19 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context)
|
||||
printf("%s signal handled\n", strsignal(sig));
|
||||
if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE))
|
||||
{
|
||||
pst_handler* handler = pst_lib_init((ucontext_t*)context);
|
||||
pst_handler* handler = pst_lib_init((ucontext_t*)context, NULL, 0);
|
||||
if(!handler) {
|
||||
printf("Failed to allocate pst handler\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = pst_unwind_simple_fd(handler, stdout);
|
||||
if(!ret) {
|
||||
pst_unwind_pretty_fd(handler, stdout);
|
||||
if(pst_unwind_simple(handler)) {
|
||||
printf("%s", pst_print_simple(handler));
|
||||
if(pst_unwind_pretty(handler)) {
|
||||
printf("%s", pst_print_pretty(handler));
|
||||
} else {
|
||||
printf("Failed to use DWARF for unwind stack trace\n");
|
||||
}
|
||||
} else {
|
||||
printf("No stack trace obtained\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user