diff options
Diffstat (limited to 'dbus/sigsegv.c')
-rw-r--r-- | dbus/sigsegv.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/dbus/sigsegv.c b/dbus/sigsegv.c new file mode 100644 index 00000000..46645408 --- /dev/null +++ b/dbus/sigsegv.c @@ -0,0 +1,192 @@ +/** + * This source file is used to print out a stack-trace when your program + * segfaults. It is relatively reliable and spot-on accurate. + * + * This code is in the public domain. Use it as you see fit, some credit + * would be appreciated, but is not a prerequisite for usage. Feedback + * on it's use would encourage further development and maintenance. + * + * Author: Jaco Kroon <jaco@kroon.co.za> + * + * Copyright (C) 2005 - 2008 Jaco Kroon + */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +//#define NO_CPP_DEMANGLE +#define SIGSEGV_NO_AUTO_INIT + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <memory.h> +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <ucontext.h> +#include <dlfcn.h> +#include <execinfo.h> +#include <errno.h> +#ifndef NO_CPP_DEMANGLE +//#include <cxxabi.h> +char * __cxa_demangle(const char * __mangled_name, char * __output_buffer, size_t * __length, int * __status); +#endif + +#include "JackError.h" + +#if defined(REG_RIP) +# define SIGSEGV_STACK_IA64 +# define REGFORMAT "%016lx" +#elif defined(REG_EIP) +# define SIGSEGV_STACK_X86 +# define REGFORMAT "%08x" +#else +# define SIGSEGV_STACK_GENERIC +# define REGFORMAT "%x" +#endif + +#ifdef __APPLE__ + +// TODO : does not compile yet on OSX +static void signal_segv(int signum, siginfo_t* info, void*ptr) +{} + +#else + +static void signal_segv(int signum, siginfo_t* info, void*ptr) { + static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"}; + + size_t i; + ucontext_t *ucontext = (ucontext_t*)ptr; + +#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) + int f = 0; + Dl_info dlinfo; + void **bp = 0; + void *ip = 0; +#else + void *bt[20]; + char **strings; + size_t sz; +#endif + + if (signum == SIGSEGV) + { + jack_error("Segmentation Fault!"); + } + else if (signum == SIGABRT) + { + jack_error("Abort!"); + } + else if (signum == SIGILL) + { + jack_error("Illegal instruction!"); + } + else if (signum == SIGFPE) + { + jack_error("Floating point exception!"); + } + else + { + jack_error("Unknown bad signal catched!"); + } + + jack_error("info.si_signo = %d", signum); + jack_error("info.si_errno = %d", info->si_errno); + jack_error("info.si_code = %d (%s)", info->si_code, si_codes[info->si_code]); + jack_error("info.si_addr = %p", info->si_addr); + for(i = 0; i < NGREG; i++) + jack_error("reg[%02d] = 0x" REGFORMAT, i, ucontext->uc_mcontext.gregs[i]); + +#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) +# if defined(SIGSEGV_STACK_IA64) + ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP]; + bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP]; +# elif defined(SIGSEGV_STACK_X86) + ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP]; + bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP]; +# endif + + jack_error("Stack trace:"); + while(bp && ip) { + if(!dladdr(ip, &dlinfo)) + break; + + const char *symname = dlinfo.dli_sname; +#ifndef NO_CPP_DEMANGLE + int status; + char *tmp = __cxa_demangle(symname, NULL, 0, &status); + + if(status == 0 && tmp) + symname = tmp; +#endif + + jack_error("% 2d: %p <%s+%u> (%s)", + ++f, + ip, + symname, + (unsigned)(ip - dlinfo.dli_saddr), + dlinfo.dli_fname); + +#ifndef NO_CPP_DEMANGLE + if(tmp) + free(tmp); +#endif + + if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main")) + break; + + ip = bp[1]; + bp = (void**)bp[0]; + } +#else + jack_error("Stack trace (non-dedicated):"); + sz = backtrace(bt, 20); + strings = backtrace_symbols(bt, sz); + + for(i = 0; i < sz; ++i) + jack_error("%s", strings[i]); +#endif + jack_error("End of stack trace"); + exit (-1); +} + +#endif + +int setup_sigsegv() { + struct sigaction action; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = signal_segv; + action.sa_flags = SA_SIGINFO; + if(sigaction(SIGSEGV, &action, NULL) < 0) { + jack_error("sigaction failed. errno is %d (%s)", errno, strerror(errno)); + return 0; + } + + if(sigaction(SIGILL, &action, NULL) < 0) { + jack_error("sigaction failed. errno is %d (%s)", errno, strerror(errno)); + return 0; + } + + if(sigaction(SIGABRT, &action, NULL) < 0) { + jack_error("sigaction failed. errno is %d (%s)", errno, strerror(errno)); + return 0; + } + + if(sigaction(SIGFPE, &action, NULL) < 0) { + jack_error("sigaction failed. errno is %d (%s)", errno, strerror(errno)); + return 0; + } + + return 1; +} + +#ifndef SIGSEGV_NO_AUTO_INIT +static void __attribute((constructor)) init(void) { + setup_sigsegv(); +} +#endif |