+/***********************************************
+* Handler for SIGSEGV *
+***********************************************/
+
+#define STACKDUMP_MAX 24
+void
+stackdump(void)
+{
+#ifndef NO_EXECINFO
+void * buf[STACKDUMP_MAX];
+char ** ss;
+int nptrs = backtrace(buf, STACKDUMP_MAX);
+
+log_write(0, LOG_MAIN|LOG_PANIC, "backtrace");
+log_write(0, LOG_MAIN|LOG_PANIC, "---");
+if ((ss = backtrace_symbols(buf, nptrs)))
+ {
+ for (int i = 0; i < nptrs; i++)
+ log_write(0, LOG_MAIN|LOG_PANIC, "\t%s", ss[i]);
+ free(ss);
+ }
+else
+ log_write(0, LOG_MAIN|LOG_PANIC, "backtrace_symbols: %s", strerror(errno));
+log_write(0, LOG_MAIN|LOG_PANIC, "---");
+#endif
+}
+#undef STACKDUMP_MAX
+
+
+static void
+#ifdef SA_SIGINFO
+segv_handler(int sig, siginfo_t * info, void * uctx)
+{
+log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr);
+# if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR)
+switch (info->si_code)
+ {
+ case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break;
+ case SEGV_ACCERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break;
+ case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break;
+ case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break;
+ }
+# endif
+if (US info->si_addr < US 4096)
+ log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (null pointer indirection)");
+else
+ log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)");
+if (process_info_len > 0)
+ log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%.*s)", process_info_len, process_info);
+stackdump();
+signal(SIGSEGV, SIG_DFL);
+kill(getpid(), sig);
+}
+
+#else
+segv_handler(int sig)
+{
+log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)");
+if (process_info_len > 0)
+ log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%.*s)", process_info_len, process_info);
+stackdump();
+signal(SIGSEGV, SIG_DFL);
+kill(getpid(), sig);
+}
+#endif
+
+