diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2018-06-18 17:41:47 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2018-06-18 17:41:47 +0100 |
commit | 04d3623c89afe60329dd1642cf4fc1b91311616b (patch) | |
tree | a0a434956d38ee1f104033e147f4326b17ffcaff /src | |
parent | 96acdaae8b1dc1839052df3b97526adfca8f64f5 (diff) | |
download | rspamd-04d3623c89afe60329dd1642cf4fc1b91311616b.tar.gz rspamd-04d3623c89afe60329dd1642cf4fc1b91311616b.zip |
[Feature] Print stack trace on crash
Diffstat (limited to 'src')
-rw-r--r-- | src/libserver/worker_util.c | 108 | ||||
-rw-r--r-- | src/libserver/worker_util.h | 5 | ||||
-rw-r--r-- | src/rspamd.c | 1 |
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; |