mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2024-11-28 12:34:13 +08:00
3df6014a3d
Add a test to see if the backtrace() function requires linking in a library in /usr/lib. Addresses-Debian-Bug: #708307 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
443 lines
8.1 KiB
C
443 lines
8.1 KiB
C
/*
|
|
* 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)))
|
|
{
|
|
void *stack_syms[32];
|
|
int frames;
|
|
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)
|
|
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);
|
|
}
|
|
|
|
|
|
#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
|