diff options
Diffstat (limited to '')
-rw-r--r-- | e2fsck/sigcatcher.c | 446 |
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 |