Home | History | Annotate | Download | only in e2fsck
      1 /*
      2  * sigcatcher.c --- print a backtrace on a SIGSEGV, et. al
      3  *
      4  * Copyright (C) 2011 Theodore Ts'o.
      5  *
      6  * %Begin-Header%
      7  * This file may be redistributed under the terms of the GNU Public
      8  * License.
      9  * %End-Header%
     10  */
     11 
     12 #include "config.h"
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <signal.h>
     16 #include <string.h>
     17 #ifdef HAVE_EXECINFO_H
     18 #include <execinfo.h>
     19 #endif
     20 
     21 #include "e2fsck.h"
     22 
     23 struct str_table {
     24 	int	num;
     25 	const char	*name;
     26 };
     27 
     28 #define DEFINE_ENTRY(SYM)	{ SYM, #SYM },
     29 #define END_TABLE		{ 0, 0 }
     30 
     31 static struct str_table sig_table[] = {
     32 #ifdef SIGHUP
     33 	DEFINE_ENTRY(SIGHUP)
     34 #endif
     35 #ifdef SIGINT
     36 	DEFINE_ENTRY(SIGINT)
     37 #endif
     38 #ifdef SIGQUIT
     39 	DEFINE_ENTRY(SIGQUIT)
     40 #endif
     41 #ifdef SIGILL
     42 	DEFINE_ENTRY(SIGILL)
     43 #endif
     44 #ifdef SIGTRAP
     45 	DEFINE_ENTRY(SIGTRAP)
     46 #endif
     47 #ifdef SIGABRT
     48 	DEFINE_ENTRY(SIGABRT)
     49 #endif
     50 #ifdef SIGIOT
     51 	DEFINE_ENTRY(SIGIOT)
     52 #endif
     53 #ifdef SIGBUS
     54 	DEFINE_ENTRY(SIGBUS)
     55 #endif
     56 #ifdef SIGFPE
     57 	DEFINE_ENTRY(SIGFPE)
     58 #endif
     59 #ifdef SIGKILL
     60 	DEFINE_ENTRY(SIGKILL)
     61 #endif
     62 #ifdef SIGUSR1
     63 	DEFINE_ENTRY(SIGUSR1)
     64 #endif
     65 #ifdef SIGSEGV
     66 	DEFINE_ENTRY(SIGSEGV)
     67 #endif
     68 #ifdef SIGUSR2
     69 	DEFINE_ENTRY(SIGUSR2)
     70 #endif
     71 #ifdef SIGPIPE
     72 	DEFINE_ENTRY(SIGPIPE)
     73 #endif
     74 #ifdef SIGALRM
     75 	DEFINE_ENTRY(SIGALRM)
     76 #endif
     77 #ifdef SIGTERM
     78 	DEFINE_ENTRY(SIGTERM)
     79 #endif
     80 #ifdef SIGSTKFLT
     81 	DEFINE_ENTRY(SIGSTKFLT)
     82 #endif
     83 #ifdef SIGCHLD
     84 	DEFINE_ENTRY(SIGCHLD)
     85 #endif
     86 #ifdef SIGCONT
     87 	DEFINE_ENTRY(SIGCONT)
     88 #endif
     89 #ifdef SIGSTOP
     90 	DEFINE_ENTRY(SIGSTOP)
     91 #endif
     92 #ifdef SIGTSTP
     93 	DEFINE_ENTRY(SIGTSTP)
     94 #endif
     95 #ifdef SIGTTIN
     96 	DEFINE_ENTRY(SIGTTIN)
     97 #endif
     98 #ifdef SIGTTOU
     99 	DEFINE_ENTRY(SIGTTOU)
    100 #endif
    101 #ifdef SIGURG
    102 	DEFINE_ENTRY(SIGURG)
    103 #endif
    104 #ifdef SIGXCPU
    105 	DEFINE_ENTRY(SIGXCPU)
    106 #endif
    107 #ifdef SIGXFSZ
    108 	DEFINE_ENTRY(SIGXFSZ)
    109 #endif
    110 #ifdef SIGVTALRM
    111 	DEFINE_ENTRY(SIGVTALRM)
    112 #endif
    113 #ifdef SIGPROF
    114 	DEFINE_ENTRY(SIGPROF)
    115 #endif
    116 #ifdef SIGWINCH
    117 	DEFINE_ENTRY(SIGWINCH)
    118 #endif
    119 #ifdef SIGIO
    120 	DEFINE_ENTRY(SIGIO)
    121 #endif
    122 #ifdef SIGPOLL
    123 	DEFINE_ENTRY(SIGPOLL)
    124 #endif
    125 #ifdef SIGPWR
    126 	DEFINE_ENTRY(SIGPWR)
    127 #endif
    128 #ifdef SIGSYS
    129 	DEFINE_ENTRY(SIGSYS)
    130 #endif
    131 	END_TABLE
    132 };
    133 
    134 static struct str_table generic_code_table[] = {
    135 #ifdef SI_ASYNCNL
    136 	DEFINE_ENTRY(SI_ASYNCNL)
    137 #endif
    138 #ifdef SI_TKILL
    139 	DEFINE_ENTRY(SI_TKILL)
    140 #endif
    141 #ifdef SI_SIGIO
    142 	DEFINE_ENTRY(SI_SIGIO)
    143 #endif
    144 #ifdef SI_ASYNCIO
    145 	DEFINE_ENTRY(SI_ASYNCIO)
    146 #endif
    147 #ifdef SI_MESGQ
    148 	DEFINE_ENTRY(SI_MESGQ)
    149 #endif
    150 #ifdef SI_TIMER
    151 	DEFINE_ENTRY(SI_TIMER)
    152 #endif
    153 #ifdef SI_QUEUE
    154 	DEFINE_ENTRY(SI_QUEUE)
    155 #endif
    156 #ifdef SI_USER
    157 	DEFINE_ENTRY(SI_USER)
    158 #endif
    159 #ifdef SI_KERNEL
    160 	DEFINE_ENTRY(SI_KERNEL)
    161 #endif
    162 	END_TABLE
    163 };
    164 
    165 static struct str_table sigill_code_table[] = {
    166 #ifdef ILL_ILLOPC
    167 	DEFINE_ENTRY(ILL_ILLOPC)
    168 #endif
    169 #ifdef ILL_ILLOPN
    170 	DEFINE_ENTRY(ILL_ILLOPN)
    171 #endif
    172 #ifdef ILL_ILLADR
    173 	DEFINE_ENTRY(ILL_ILLADR)
    174 #endif
    175 #ifdef ILL_ILLTRP
    176 	DEFINE_ENTRY(ILL_ILLTRP)
    177 #endif
    178 #ifdef ILL_PRVOPC
    179 	DEFINE_ENTRY(ILL_PRVOPC)
    180 #endif
    181 #ifdef ILL_PRVREG
    182 	DEFINE_ENTRY(ILL_PRVREG)
    183 #endif
    184 #ifdef ILL_COPROC
    185 	DEFINE_ENTRY(ILL_COPROC)
    186 #endif
    187 #ifdef ILL_BADSTK
    188 	DEFINE_ENTRY(ILL_BADSTK)
    189 #endif
    190 #ifdef BUS_ADRALN
    191 	DEFINE_ENTRY(BUS_ADRALN)
    192 #endif
    193 #ifdef BUS_ADRERR
    194 	DEFINE_ENTRY(BUS_ADRERR)
    195 #endif
    196 #ifdef BUS_OBJERR
    197 	DEFINE_ENTRY(BUS_OBJERR)
    198 #endif
    199 	END_TABLE
    200 };
    201 
    202 static struct str_table sigfpe_code_table[] = {
    203 #ifdef FPE_INTDIV
    204 	DEFINE_ENTRY(FPE_INTDIV)
    205 #endif
    206 #ifdef FPE_INTOVF
    207 	DEFINE_ENTRY(FPE_INTOVF)
    208 #endif
    209 #ifdef FPE_FLTDIV
    210 	DEFINE_ENTRY(FPE_FLTDIV)
    211 #endif
    212 #ifdef FPE_FLTOVF
    213 	DEFINE_ENTRY(FPE_FLTOVF)
    214 #endif
    215 #ifdef FPE_FLTUND
    216 	DEFINE_ENTRY(FPE_FLTUND)
    217 #endif
    218 #ifdef FPE_FLTRES
    219 	DEFINE_ENTRY(FPE_FLTRES)
    220 #endif
    221 #ifdef FPE_FLTINV
    222 	DEFINE_ENTRY(FPE_FLTINV)
    223 #endif
    224 #ifdef FPE_FLTSUB
    225 	DEFINE_ENTRY(FPE_FLTSUB)
    226 #endif
    227 	END_TABLE
    228 };
    229 
    230 static struct str_table sigsegv_code_table[] = {
    231 #ifdef SEGV_MAPERR
    232 	DEFINE_ENTRY(SEGV_MAPERR)
    233 #endif
    234 #ifdef SEGV_ACCERR
    235 	DEFINE_ENTRY(SEGV_ACCERR)
    236 #endif
    237 	END_TABLE
    238 };
    239 
    240 
    241 static struct str_table sigbus_code_table[] = {
    242 #ifdef BUS_ADRALN
    243 	DEFINE_ENTRY(BUS_ADRALN)
    244 #endif
    245 #ifdef BUS_ADRERR
    246 	DEFINE_ENTRY(BUS_ADRERR)
    247 #endif
    248 #ifdef BUS_OBJERR
    249 	DEFINE_ENTRY(BUS_OBJERR)
    250 #endif
    251 	END_TABLE
    252 };
    253 
    254 #if 0 /* should this be hooked in somewhere? */
    255 static struct str_table sigstrap_code_table[] = {
    256 #ifdef TRAP_BRKPT
    257 	DEFINE_ENTRY(TRAP_BRKPT)
    258 #endif
    259 #ifdef TRAP_TRACE
    260 	DEFINE_ENTRY(TRAP_TRACE)
    261 #endif
    262 	END_TABLE
    263 };
    264 #endif
    265 
    266 static struct str_table sigcld_code_table[] = {
    267 #ifdef CLD_EXITED
    268 	DEFINE_ENTRY(CLD_EXITED)
    269 #endif
    270 #ifdef CLD_KILLED
    271 	DEFINE_ENTRY(CLD_KILLED)
    272 #endif
    273 #ifdef CLD_DUMPED
    274 	DEFINE_ENTRY(CLD_DUMPED)
    275 #endif
    276 #ifdef CLD_TRAPPED
    277 	DEFINE_ENTRY(CLD_TRAPPED)
    278 #endif
    279 #ifdef CLD_STOPPED
    280 	DEFINE_ENTRY(CLD_STOPPED)
    281 #endif
    282 #ifdef CLD_CONTINUED
    283 	DEFINE_ENTRY(CLD_CONTINUED)
    284 #endif
    285 	END_TABLE
    286 };
    287 
    288 #if 0 /* should this be hooked in somewhere? */
    289 static struct str_table sigpoll_code_table[] = {
    290 #ifdef POLL_IN
    291 	DEFINE_ENTRY(POLL_IN)
    292 #endif
    293 #ifdef POLL_OUT
    294 	DEFINE_ENTRY(POLL_OUT)
    295 #endif
    296 #ifdef POLL_MSG
    297 	DEFINE_ENTRY(POLL_MSG)
    298 #endif
    299 #ifdef POLL_ERR
    300 	DEFINE_ENTRY(POLL_ERR)
    301 #endif
    302 #ifdef POLL_PRI
    303 	DEFINE_ENTRY(POLL_PRI)
    304 #endif
    305 #ifdef POLL_HUP
    306 	DEFINE_ENTRY(POLL_HUP)
    307 #endif
    308 	END_TABLE
    309 };
    310 #endif
    311 
    312 static const char *lookup_table(int num, struct str_table *table)
    313 {
    314 	struct str_table *p;
    315 
    316 	for (p=table; p->name; p++)
    317 		if (num == p->num)
    318 			return(p->name);
    319 	return NULL;
    320 }
    321 
    322 static const char *lookup_table_fallback(int num, struct str_table *table)
    323 {
    324 	static char buf[32];
    325 	const char *ret = lookup_table(num, table);
    326 
    327 	if (ret)
    328 		return ret;
    329 	snprintf(buf, sizeof(buf), "%d", num);
    330 	buf[sizeof(buf)-1] = 0;
    331 	return buf;
    332 }
    333 
    334 static void die_signal_handler(int signum, siginfo_t *siginfo,
    335 			       void *context EXT2FS_ATTR((unused)))
    336 {
    337        const char *cp;
    338 
    339        fprintf(stderr, "Signal (%d) %s ", signum,
    340 	       lookup_table_fallback(signum, sig_table));
    341        if (siginfo->si_code == SI_USER)
    342 	       fprintf(stderr, "(sent from pid %u) ", siginfo->si_pid);
    343        cp = lookup_table(siginfo->si_code, generic_code_table);
    344        if (cp)
    345 	       fprintf(stderr, "si_code=%s ", cp);
    346        else if (signum == SIGILL)
    347 	       fprintf(stderr, "si_code=%s ",
    348 		       lookup_table_fallback(siginfo->si_code,
    349 					     sigill_code_table));
    350        else if (signum == SIGFPE)
    351 	       fprintf(stderr, "si_code=%s ",
    352 		       lookup_table_fallback(siginfo->si_code,
    353 					     sigfpe_code_table));
    354        else if (signum == SIGSEGV)
    355 	       fprintf(stderr, "si_code=%s ",
    356 		       lookup_table_fallback(siginfo->si_code,
    357 					     sigsegv_code_table));
    358        else if (signum == SIGBUS)
    359 	       fprintf(stderr, "si_code=%s ",
    360 		       lookup_table_fallback(siginfo->si_code,
    361 					     sigbus_code_table));
    362        else if (signum == SIGCHLD)
    363 	       fprintf(stderr, "si_code=%s ",
    364 		       lookup_table_fallback(siginfo->si_code,
    365 					     sigcld_code_table));
    366        else
    367 	       fprintf(stderr, "si code=%d ", siginfo->si_code);
    368        if ((siginfo->si_code != SI_USER) &&
    369 	   (signum == SIGILL || signum == SIGFPE ||
    370 	    signum == SIGSEGV || signum == SIGBUS))
    371 	       fprintf(stderr, "fault addr=%p", siginfo->si_addr);
    372        fprintf(stderr, "\n");
    373 
    374 #if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE)
    375        {
    376 	       void *stack_syms[32];
    377 	       int frames;
    378 
    379 	       frames = backtrace(stack_syms, 32);
    380 	       backtrace_symbols_fd(stack_syms, frames, 2);
    381        }
    382 #endif
    383        exit(FSCK_ERROR);
    384 }
    385 
    386 void sigcatcher_setup(void)
    387 {
    388 	struct sigaction	sa;
    389 
    390 	memset(&sa, 0, sizeof(struct sigaction));
    391 	sa.sa_sigaction = die_signal_handler;
    392 	sa.sa_flags = SA_SIGINFO;
    393 
    394 	sigaction(SIGFPE, &sa, 0);
    395 	sigaction(SIGILL, &sa, 0);
    396 	sigaction(SIGBUS, &sa, 0);
    397 	sigaction(SIGSEGV, &sa, 0);
    398 	sigaction(SIGABRT, &sa, 0);
    399 }
    400 
    401 
    402 #ifdef DEBUG
    403 #include <getopt.h>
    404 
    405 void usage(void)
    406 {
    407 	fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
    408 	exit(1);
    409 }
    410 
    411 int main(int argc, char** argv)
    412 {
    413 	struct sigaction	sa;
    414 	char			*p = 0;
    415 	int 			i, c;
    416 	volatile		x=0;
    417 
    418 	memset(&sa, 0, sizeof(struct sigaction));
    419 	sa.sa_sigaction = die_signal_handler;
    420 	sa.sa_flags = SA_SIGINFO;
    421 	for (i=1; i < 31; i++)
    422 		sigaction(i, &sa, 0);
    423 
    424 	while ((c = getopt (argc, argv, "afkn")) != EOF)
    425 		switch (c) {
    426 		case 'a':
    427 			abort();
    428 			break;
    429 		case 'f':
    430 			printf("%d\n", 42/x);
    431 		case 'k':
    432 			kill(getpid(), SIGTERM);
    433 			break;
    434 		case 'n':
    435 			*p = 42;
    436 		default:
    437 			usage ();
    438 		}
    439 
    440 	printf("Sleeping for 10 seconds, send kill signal to pid %u...\n",
    441 	       getpid());
    442 	fflush(stdout);
    443 	sleep(10);
    444 	exit(0);
    445 }
    446 #endif
    447