summaryrefslogtreecommitdiffstats
path: root/e2fsck/sigcatcher.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--e2fsck/sigcatcher.c446
1 files changed, 446 insertions, 0 deletions
diff --git a/e2fsck/sigcatcher.c b/e2fsck/sigcatcher.c
new file mode 100644
index 0000000..a9d3b7f
--- /dev/null
+++ b/e2fsck/sigcatcher.c
@@ -0,0 +1,446 @@
+/*
+ * sigcatcher.c --- print a backtrace on a SIGSEGV, et. al
+ *
+ * Copyright (C) 2011 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#include "e2fsck.h"
+
+struct str_table {
+ int num;
+ const char *name;
+};
+
+#define DEFINE_ENTRY(SYM) { SYM, #SYM },
+#define END_TABLE { 0, 0 }
+
+static struct str_table sig_table[] = {
+#ifdef SIGHUP
+ DEFINE_ENTRY(SIGHUP)
+#endif
+#ifdef SIGINT
+ DEFINE_ENTRY(SIGINT)
+#endif
+#ifdef SIGQUIT
+ DEFINE_ENTRY(SIGQUIT)
+#endif
+#ifdef SIGILL
+ DEFINE_ENTRY(SIGILL)
+#endif
+#ifdef SIGTRAP
+ DEFINE_ENTRY(SIGTRAP)
+#endif
+#ifdef SIGABRT
+ DEFINE_ENTRY(SIGABRT)
+#endif
+#ifdef SIGIOT
+ DEFINE_ENTRY(SIGIOT)
+#endif
+#ifdef SIGBUS
+ DEFINE_ENTRY(SIGBUS)
+#endif
+#ifdef SIGFPE
+ DEFINE_ENTRY(SIGFPE)
+#endif
+#ifdef SIGKILL
+ DEFINE_ENTRY(SIGKILL)
+#endif
+#ifdef SIGUSR1
+ DEFINE_ENTRY(SIGUSR1)
+#endif
+#ifdef SIGSEGV
+ DEFINE_ENTRY(SIGSEGV)
+#endif
+#ifdef SIGUSR2
+ DEFINE_ENTRY(SIGUSR2)
+#endif
+#ifdef SIGPIPE
+ DEFINE_ENTRY(SIGPIPE)
+#endif
+#ifdef SIGALRM
+ DEFINE_ENTRY(SIGALRM)
+#endif
+#ifdef SIGTERM
+ DEFINE_ENTRY(SIGTERM)
+#endif
+#ifdef SIGSTKFLT
+ DEFINE_ENTRY(SIGSTKFLT)
+#endif
+#ifdef SIGCHLD
+ DEFINE_ENTRY(SIGCHLD)
+#endif
+#ifdef SIGCONT
+ DEFINE_ENTRY(SIGCONT)
+#endif
+#ifdef SIGSTOP
+ DEFINE_ENTRY(SIGSTOP)
+#endif
+#ifdef SIGTSTP
+ DEFINE_ENTRY(SIGTSTP)
+#endif
+#ifdef SIGTTIN
+ DEFINE_ENTRY(SIGTTIN)
+#endif
+#ifdef SIGTTOU
+ DEFINE_ENTRY(SIGTTOU)
+#endif
+#ifdef SIGURG
+ DEFINE_ENTRY(SIGURG)
+#endif
+#ifdef SIGXCPU
+ DEFINE_ENTRY(SIGXCPU)
+#endif
+#ifdef SIGXFSZ
+ DEFINE_ENTRY(SIGXFSZ)
+#endif
+#ifdef SIGVTALRM
+ DEFINE_ENTRY(SIGVTALRM)
+#endif
+#ifdef SIGPROF
+ DEFINE_ENTRY(SIGPROF)
+#endif
+#ifdef SIGWINCH
+ DEFINE_ENTRY(SIGWINCH)
+#endif
+#ifdef SIGIO
+ DEFINE_ENTRY(SIGIO)
+#endif
+#ifdef SIGPOLL
+ DEFINE_ENTRY(SIGPOLL)
+#endif
+#ifdef SIGPWR
+ DEFINE_ENTRY(SIGPWR)
+#endif
+#ifdef SIGSYS
+ DEFINE_ENTRY(SIGSYS)
+#endif
+ END_TABLE
+};
+
+static struct str_table generic_code_table[] = {
+#ifdef SI_ASYNCNL
+ DEFINE_ENTRY(SI_ASYNCNL)
+#endif
+#ifdef SI_TKILL
+ DEFINE_ENTRY(SI_TKILL)
+#endif
+#ifdef SI_SIGIO
+ DEFINE_ENTRY(SI_SIGIO)
+#endif
+#ifdef SI_ASYNCIO
+ DEFINE_ENTRY(SI_ASYNCIO)
+#endif
+#ifdef SI_MESGQ
+ DEFINE_ENTRY(SI_MESGQ)
+#endif
+#ifdef SI_TIMER
+ DEFINE_ENTRY(SI_TIMER)
+#endif
+#ifdef SI_QUEUE
+ DEFINE_ENTRY(SI_QUEUE)
+#endif
+#ifdef SI_USER
+ DEFINE_ENTRY(SI_USER)
+#endif
+#ifdef SI_KERNEL
+ DEFINE_ENTRY(SI_KERNEL)
+#endif
+ END_TABLE
+};
+
+static struct str_table sigill_code_table[] = {
+#ifdef ILL_ILLOPC
+ DEFINE_ENTRY(ILL_ILLOPC)
+#endif
+#ifdef ILL_ILLOPN
+ DEFINE_ENTRY(ILL_ILLOPN)
+#endif
+#ifdef ILL_ILLADR
+ DEFINE_ENTRY(ILL_ILLADR)
+#endif
+#ifdef ILL_ILLTRP
+ DEFINE_ENTRY(ILL_ILLTRP)
+#endif
+#ifdef ILL_PRVOPC
+ DEFINE_ENTRY(ILL_PRVOPC)
+#endif
+#ifdef ILL_PRVREG
+ DEFINE_ENTRY(ILL_PRVREG)
+#endif
+#ifdef ILL_COPROC
+ DEFINE_ENTRY(ILL_COPROC)
+#endif
+#ifdef ILL_BADSTK
+ DEFINE_ENTRY(ILL_BADSTK)
+#endif
+#ifdef BUS_ADRALN
+ DEFINE_ENTRY(BUS_ADRALN)
+#endif
+#ifdef BUS_ADRERR
+ DEFINE_ENTRY(BUS_ADRERR)
+#endif
+#ifdef BUS_OBJERR
+ DEFINE_ENTRY(BUS_OBJERR)
+#endif
+ END_TABLE
+};
+
+static struct str_table sigfpe_code_table[] = {
+#ifdef FPE_INTDIV
+ DEFINE_ENTRY(FPE_INTDIV)
+#endif
+#ifdef FPE_INTOVF
+ DEFINE_ENTRY(FPE_INTOVF)
+#endif
+#ifdef FPE_FLTDIV
+ DEFINE_ENTRY(FPE_FLTDIV)
+#endif
+#ifdef FPE_FLTOVF
+ DEFINE_ENTRY(FPE_FLTOVF)
+#endif
+#ifdef FPE_FLTUND
+ DEFINE_ENTRY(FPE_FLTUND)
+#endif
+#ifdef FPE_FLTRES
+ DEFINE_ENTRY(FPE_FLTRES)
+#endif
+#ifdef FPE_FLTINV
+ DEFINE_ENTRY(FPE_FLTINV)
+#endif
+#ifdef FPE_FLTSUB
+ DEFINE_ENTRY(FPE_FLTSUB)
+#endif
+ END_TABLE
+};
+
+static struct str_table sigsegv_code_table[] = {
+#ifdef SEGV_MAPERR
+ DEFINE_ENTRY(SEGV_MAPERR)
+#endif
+#ifdef SEGV_ACCERR
+ DEFINE_ENTRY(SEGV_ACCERR)
+#endif
+ END_TABLE
+};
+
+
+static struct str_table sigbus_code_table[] = {
+#ifdef BUS_ADRALN
+ DEFINE_ENTRY(BUS_ADRALN)
+#endif
+#ifdef BUS_ADRERR
+ DEFINE_ENTRY(BUS_ADRERR)
+#endif
+#ifdef BUS_OBJERR
+ DEFINE_ENTRY(BUS_OBJERR)
+#endif
+ END_TABLE
+};
+
+#if 0 /* should this be hooked in somewhere? */
+static struct str_table sigstrap_code_table[] = {
+#ifdef TRAP_BRKPT
+ DEFINE_ENTRY(TRAP_BRKPT)
+#endif
+#ifdef TRAP_TRACE
+ DEFINE_ENTRY(TRAP_TRACE)
+#endif
+ END_TABLE
+};
+#endif
+
+static struct str_table sigcld_code_table[] = {
+#ifdef CLD_EXITED
+ DEFINE_ENTRY(CLD_EXITED)
+#endif
+#ifdef CLD_KILLED
+ DEFINE_ENTRY(CLD_KILLED)
+#endif
+#ifdef CLD_DUMPED
+ DEFINE_ENTRY(CLD_DUMPED)
+#endif
+#ifdef CLD_TRAPPED
+ DEFINE_ENTRY(CLD_TRAPPED)
+#endif
+#ifdef CLD_STOPPED
+ DEFINE_ENTRY(CLD_STOPPED)
+#endif
+#ifdef CLD_CONTINUED
+ DEFINE_ENTRY(CLD_CONTINUED)
+#endif
+ END_TABLE
+};
+
+#if 0 /* should this be hooked in somewhere? */
+static struct str_table sigpoll_code_table[] = {
+#ifdef POLL_IN
+ DEFINE_ENTRY(POLL_IN)
+#endif
+#ifdef POLL_OUT
+ DEFINE_ENTRY(POLL_OUT)
+#endif
+#ifdef POLL_MSG
+ DEFINE_ENTRY(POLL_MSG)
+#endif
+#ifdef POLL_ERR
+ DEFINE_ENTRY(POLL_ERR)
+#endif
+#ifdef POLL_PRI
+ DEFINE_ENTRY(POLL_PRI)
+#endif
+#ifdef POLL_HUP
+ DEFINE_ENTRY(POLL_HUP)
+#endif
+ END_TABLE
+};
+#endif
+
+static const char *lookup_table(int num, struct str_table *table)
+{
+ struct str_table *p;
+
+ for (p=table; p->name; p++)
+ if (num == p->num)
+ return(p->name);
+ return NULL;
+}
+
+static const char *lookup_table_fallback(int num, struct str_table *table)
+{
+ static char buf[32];
+ const char *ret = lookup_table(num, table);
+
+ if (ret)
+ return ret;
+ snprintf(buf, sizeof(buf), "%d", num);
+ buf[sizeof(buf)-1] = 0;
+ return buf;
+}
+
+static void die_signal_handler(int signum, siginfo_t *siginfo,
+ void *context EXT2FS_ATTR((unused)))
+{
+ const char *cp;
+
+ fprintf(stderr, "Signal (%d) %s ", signum,
+ lookup_table_fallback(signum, sig_table));
+ if (siginfo->si_code == SI_USER)
+ fprintf(stderr, "(sent from pid %u) ", siginfo->si_pid);
+ cp = lookup_table(siginfo->si_code, generic_code_table);
+ if (cp)
+ fprintf(stderr, "si_code=%s ", cp);
+ else if (signum == SIGILL)
+ fprintf(stderr, "si_code=%s ",
+ lookup_table_fallback(siginfo->si_code,
+ sigill_code_table));
+ else if (signum == SIGFPE)
+ fprintf(stderr, "si_code=%s ",
+ lookup_table_fallback(siginfo->si_code,
+ sigfpe_code_table));
+ else if (signum == SIGSEGV)
+ fprintf(stderr, "si_code=%s ",
+ lookup_table_fallback(siginfo->si_code,
+ sigsegv_code_table));
+ else if (signum == SIGBUS)
+ fprintf(stderr, "si_code=%s ",
+ lookup_table_fallback(siginfo->si_code,
+ sigbus_code_table));
+ else if (signum == SIGCHLD)
+ fprintf(stderr, "si_code=%s ",
+ lookup_table_fallback(siginfo->si_code,
+ sigcld_code_table));
+ else
+ fprintf(stderr, "si code=%d ", siginfo->si_code);
+ if ((siginfo->si_code != SI_USER) &&
+ (signum == SIGILL || signum == SIGFPE ||
+ signum == SIGSEGV || signum == SIGBUS))
+ fprintf(stderr, "fault addr=%p", siginfo->si_addr);
+ fprintf(stderr, "\n");
+
+#if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE)
+ {
+ void *stack_syms[32];
+ int frames;
+
+ frames = backtrace(stack_syms, 32);
+ backtrace_symbols_fd(stack_syms, frames, 2);
+ }
+#endif
+ exit(FSCK_ERROR);
+}
+
+void sigcatcher_setup(void)
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_sigaction = die_signal_handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ sigaction(SIGFPE, &sa, 0);
+ sigaction(SIGILL, &sa, 0);
+ sigaction(SIGBUS, &sa, 0);
+ sigaction(SIGSEGV, &sa, 0);
+ sigaction(SIGABRT, &sa, 0);
+}
+
+
+#ifdef DEBUG
+#include <getopt.h>
+
+void usage(void)
+{
+ fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
+ exit(1);
+}
+
+int main(int argc, char** argv)
+{
+ struct sigaction sa;
+ char *p = 0;
+ int i, c;
+ volatile x=0;
+
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_sigaction = die_signal_handler;
+ sa.sa_flags = SA_SIGINFO;
+ for (i=1; i < 31; i++)
+ sigaction(i, &sa, 0);
+
+ while ((c = getopt (argc, argv, "afkn")) != EOF)
+ switch (c) {
+ case 'a':
+ abort();
+ break;
+ case 'f':
+ printf("%d\n", 42/x);
+ case 'k':
+ kill(getpid(), SIGTERM);
+ break;
+ case 'n':
+ *p = 42;
+ default:
+ usage ();
+ }
+
+ printf("Sleeping for 10 seconds, send kill signal to pid %u...\n",
+ getpid());
+ fflush(stdout);
+ sleep(10);
+ exit(0);
+}
+#endif