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