/* Neutrino-GUI - DBoxII-Project Copyright (C) 2015 CoolStream International Ltd print_stacktrace function taken from: stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/ published under the WTFPL v2.0 License: GPLv2 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define __USE_GNU #include #include #include #include #include #ifdef HAVE_BACKTRACE #include /** Print a demangled stack backtrace of the caller function to FILE* out. */ void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63) { fprintf(out, "stack trace:\n"); // storage array for stack trace address data void* addrlist[max_frames+1]; // retrieve current stack addresses int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*)); if (addrlen == 0) { fprintf(out, " \n"); return; } // resolve addresses into strings containing "filename(function+address)", // this array must be free()-ed char** symbollist = backtrace_symbols(addrlist, addrlen); // allocate string which will be filled with the demangled function name size_t funcnamesize = 256; char* funcname = (char*)malloc(funcnamesize); // iterate over the returned symbol lines. skip the first, it is the // address of this function. for (int i = 1; i < addrlen; i++) { char *begin_name = 0, *begin_offset = 0, *end_offset = 0; // find parentheses and +address offset surrounding the mangled name: // ./module(function+0x15c) [0x8048a6d] for (char *p = symbollist[i]; *p; ++p) { if (*p == '(') begin_name = p; else if (*p == '+') begin_offset = p; else if (*p == ')' && begin_offset) { end_offset = p; break; } } if (begin_name && begin_offset && end_offset && begin_name < begin_offset) { *begin_name++ = '\0'; *begin_offset++ = '\0'; *end_offset = '\0'; // mangled name is now in [begin_name, begin_offset) and caller // offset in [begin_offset, end_offset). now apply // __cxa_demangle(): int status; char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status); if (status == 0) { funcname = ret; // use possibly realloc()-ed string fprintf(out, " %s : %s+%s [%p]\n", symbollist[i], funcname, begin_offset, addrlist[i]); } else { // demangling failed. Output function name as a C function with // no arguments. fprintf(out, " %s : %s()+%s [%p]\n", symbollist[i], begin_name, begin_offset, addrlist[i]); } } else { // couldn't parse the line? print the whole line. fprintf(out, " %s\n", symbollist[i]); } } free(funcname); free(symbollist); } static void crash_handler(int signum, siginfo_t * si, void *ctx) { void *trace[16]; int trace_size = 0; ucontext_t *ct = (ucontext_t *) ctx; if (si) {} #if 0 printf("signal %d, siginfo->si_addr is %p\n", signum, si->si_addr); printf("reg[%02d] = 0x%lx\n",0 , ct->uc_mcontext.arm_r0); printf("reg[%02d] = 0x%lx\n",1 , ct->uc_mcontext.arm_r1); printf("reg[%02d] = 0x%lx\n",2 , ct->uc_mcontext.arm_r2); printf("reg[%02d] = 0x%lx\n",3 , ct->uc_mcontext.arm_r3); printf("reg[%02d] = 0x%lx\n",4 , ct->uc_mcontext.arm_r4); printf("reg[%02d] = 0x%lx\n",5 , ct->uc_mcontext.arm_r5); printf("reg[%02d] = 0x%lx\n",6 , ct->uc_mcontext.arm_r6); printf("reg[%02d] = 0x%lx\n",7 , ct->uc_mcontext.arm_r7); printf("reg[%02d] = 0x%lx\n",8 , ct->uc_mcontext.arm_r8); printf("reg[%02d] = 0x%lx\n",9 , ct->uc_mcontext.arm_r9); printf("reg[%02d] = 0x%lx\n",10 , ct->uc_mcontext.arm_r10); printf("FP = 0x%lx\n", ct->uc_mcontext.arm_fp); printf("IP = 0x%lx\n", ct->uc_mcontext.arm_ip); printf("SP = 0x%lx\n", ct->uc_mcontext.arm_sp); printf("LR = 0x%lx\n", ct->uc_mcontext.arm_lr); printf("PC = 0x%lx\n", ct->uc_mcontext.arm_pc); printf("CPSR = 0x%lx\n", ct->uc_mcontext.arm_cpsr); printf("Fault Address = 0x%lx\n", ct->uc_mcontext.fault_address); printf("Trap no = 0x%lx\n", ct->uc_mcontext.trap_no); printf("Err Code = 0x%lx\n", ct->uc_mcontext.error_code); printf("Old Mask = 0x%lx\n", ct->uc_mcontext.oldmask); #endif trace_size = backtrace(trace, 16); trace[1] = (void *) ct->uc_mcontext.arm_pc; #if 0 char **messages = backtrace_symbols(trace, trace_size); /* skip first stack frame (points here) */ printf("Execution path: (%d)\n", trace_size); for (int i = 0; i < trace_size; ++i) printf("[#%d] %s\n", i, messages[i]); #endif backtrace_symbols_fd(trace, trace_size, fileno(stdout)); if (signum != SIGUSR1) abort(); } void install_crash_handler() { struct sigaction sa; sa.sa_sigaction = crash_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &sa, NULL); sigaction(SIGFPE, &sa, NULL); sigaction(SIGBUS, &sa, NULL); /* for testing */ sigaction(SIGUSR1, &sa, NULL); void *trace[16]; backtrace(trace, 16); } #endif