summaryrefslogtreecommitdiff
path: root/dbus/sigsegv.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbus/sigsegv.c')
-rw-r--r--dbus/sigsegv.c192
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