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 22struct 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 30static 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 133static 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 164static 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 201static 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 229static 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 240static 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? */ 254static 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 265static 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? */ 288static 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 311static 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 321static 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 333static 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 382void 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 400void usage(void) 401{ 402 fprintf(stderr, "tst_sigcatcher: [-akfn]\n"); 403 exit(1); 404} 405 406int 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