aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2018-06-18 17:41:47 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2018-06-18 17:41:47 +0100
commit04d3623c89afe60329dd1642cf4fc1b91311616b (patch)
treea0a434956d38ee1f104033e147f4326b17ffcaff /src
parent96acdaae8b1dc1839052df3b97526adfca8f64f5 (diff)
downloadrspamd-04d3623c89afe60329dd1642cf4fc1b91311616b.tar.gz
rspamd-04d3623c89afe60329dd1642cf4fc1b91311616b.zip
[Feature] Print stack trace on crash
Diffstat (limited to 'src')
-rw-r--r--src/libserver/worker_util.c108
-rw-r--r--src/libserver/worker_util.h5
-rw-r--r--src/rspamd.c1
3 files changed, 114 insertions, 0 deletions
diff --git a/src/libserver/worker_util.c b/src/libserver/worker_util.c
index c60273dea..a1fa4048c 100644
--- a/src/libserver/worker_util.c
+++ b/src/libserver/worker_util.c
@@ -44,6 +44,12 @@
#endif
#include "zlib.h"
+#ifdef WITH_LIBUNWIND
+#define UNW_LOCAL_ONLY 1
+#include <libunwind.h>
+#define UNWIND_BACKTRACE_DEPTH 256
+#endif
+
static void rspamd_worker_ignore_signal (int signo);
/**
* Return worker's control structure by its type
@@ -924,4 +930,106 @@ rspamd_worker_init_monitored (struct rspamd_worker *worker,
rspamd_monitored_ctx_config (worker->srv->cfg->monitored_ctx,
worker->srv->cfg, ev_base, resolver->r,
rspamd_worker_monitored_on_change, worker);
+}
+
+#ifdef HAVE_SA_SIGINFO
+
+#ifdef WITH_LIBUNWIND
+static void
+rspamd_print_crash (ucontext_t *uap)
+{
+ unw_cursor_t cursor;
+ unw_word_t ip, off;
+ guint level;
+ gint ret;
+
+ if ((ret = unw_init_local (&cursor, uap)) != 0) {
+ msg_err ("unw_init_local: %d", ret);
+
+ return;
+ }
+
+ level = 0;
+ ret = 0;
+
+ for (;;) {
+ char name[128];
+
+ if (level >= UNWIND_BACKTRACE_DEPTH) {
+ break;
+ }
+
+ unw_get_reg (&cursor, UNW_REG_IP, &ip);
+ ret = unw_get_proc_name(&cursor, name, sizeof (name), &off);
+
+ if (ret == 0) {
+ msg_err ("%d: %p: %s()+0x%xl",
+ level, ip, name, (uintptr_t)off);
+ } else {
+ msg_err ("%d: %p: <unknown>", level, ip);
+ }
+
+ level++;
+ ret = unw_step (&cursor);
+
+ if (ret <= 0) {
+ break;
+ }
+ }
+
+ if (ret < 0) {
+ msg_err ("unw_step_ptr: %d", ret);
+ }
+}
+#endif
+
+static void
+rspamd_crash_sig_handler (int sig, siginfo_t *info, void *ctx)
+{
+ struct sigaction sa;
+ ucontext_t *uap = ctx;
+
+ msg_err ("caught fatal signal %d(%s), "
+ "pid: %P, trace: ",
+ sig, strsignal (sig), getpid ());
+ (void)uap;
+#ifdef WITH_LIBUNWIND
+ rspamd_print_crash (uap);
+#endif
+
+ /*
+ * Invoke signal with the default handler
+ */
+ sigemptyset (&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sa.sa_flags = 0;
+ sigaction (sig, &sa, NULL);
+ kill (getpid (), sig);
+}
+#endif
+
+void
+rspamd_set_crash_handler (struct rspamd_main *main)
+{
+#ifdef HAVE_SA_SIGINFO
+ struct sigaction sa;
+
+#ifdef HAVE_SIGALTSTACK
+ stack_t ss;
+
+ /* Allocate special stack, NOT freed at the end so far */
+ ss.ss_size = MAX (SIGSTKSZ, 8192 * 4);
+ ss.ss_sp = g_malloc0 (ss.ss_size);
+ sigaltstack (&ss, NULL);
+#endif
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_sigaction = &rspamd_crash_sig_handler;
+ sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGFPE, &sa, NULL);
+ sigaction(SIGSYS, &sa, NULL);
+#endif
} \ No newline at end of file
diff --git a/src/libserver/worker_util.h b/src/libserver/worker_util.h
index 2e3fd4458..dbcc8f8a2 100644
--- a/src/libserver/worker_util.h
+++ b/src/libserver/worker_util.h
@@ -188,6 +188,11 @@ struct rspamd_worker *rspamd_fork_worker (struct rspamd_main *,
struct rspamd_worker_conf *, guint idx, struct event_base *ev_base);
/**
+ * Sets crash signals handlers if compiled with libunwind
+ */
+void rspamd_set_crash_handler (struct rspamd_main *);
+
+/**
* Initialise the main monitoring worker
* @param worker
* @param ev_base
diff --git a/src/rspamd.c b/src/rspamd.c
index d7543643e..7c5450521 100644
--- a/src/rspamd.c
+++ b/src/rspamd.c
@@ -1242,6 +1242,7 @@ main (gint argc, gchar **argv, gchar **env)
}
type = g_quark_from_static_string ("main");
+ rspamd_set_crash_handler (rspamd_main);
/* First set logger to console logger */
rspamd_main->cfg->log_type = RSPAMD_LOG_CONSOLE;