introduce separate print functions for 'simple' and 'pretty' variands of

unwinding
This commit is contained in:
2020-04-05 13:33:19 +04:00
parent 3adc8eb1ef
commit e2e7535149
6 changed files with 124 additions and 125 deletions
+34 -16
View File
@@ -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_ */
+8 -16
View File
@@ -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) {
+39 -14
View File
@@ -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
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 *) uctx->uc_mcontext.gregs[REG_EIP]);
caller = (void *) h->uc_mcontext.gregs[REG_EIP]);
#elif defined(__arm__)
caller = (void *) uctx->uc_mcontext.arm_pc);
caller = (void *) h->uc_mcontext.arm_pc);
#elif defined(__aarch64__)
caller = (void *) uctx->uc_mcontext.pc);
caller = (void *) h->uc_mcontext.pc);
#elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__)
caller = (void *) uctx->uc_mcontext.regs->nip);
caller = (void *) h->uc_mcontext.regs->nip);
#elif defined(__s390x__)
caller = (void *) uctx->uc_mcontext.psw.addr);
caller = (void *) h->uc_mcontext.psw.addr);
#elif defined(__APPLE__) && defined(__x86_64__)
caller = (void *) uctx->uc_mcontext->__ss.__rip);
caller = (void *) h->uc_mcontext->__ss.__rip);
#else
# error "unknown architecture!"
#endif
}
//handle = dlopen(NULL, RTLD_NOW);
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(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;
+1 -1
View File
@@ -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__ */
+11 -51
View File
@@ -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
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
View File
@@ -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");
}