sigcatcher.c revision 3df6014a3d216d19be7d2286de24e8ee106f18ad
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 23struct 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 31static 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 134static 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 165static 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 202static 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 230static 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 241static 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? */ 255static 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 266static 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? */ 289static 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 312static 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 322static 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 334static void die_signal_handler(int signum, siginfo_t *siginfo, 335 void *context EXT2FS_ATTR((unused))) 336{ 337 void *stack_syms[32]; 338 int frames; 339 const char *cp; 340 341 fprintf(stderr, "Signal (%d) %s ", signum, 342 lookup_table_fallback(signum, sig_table)); 343 if (siginfo->si_code == SI_USER) 344 fprintf(stderr, "(sent from pid %u) ", siginfo->si_pid); 345 cp = lookup_table(siginfo->si_code, generic_code_table); 346 if (cp) 347 fprintf(stderr, "si_code=%s ", cp); 348 else if (signum == SIGILL) 349 fprintf(stderr, "si_code=%s ", 350 lookup_table_fallback(siginfo->si_code, 351 sigill_code_table)); 352 else if (signum == SIGFPE) 353 fprintf(stderr, "si_code=%s ", 354 lookup_table_fallback(siginfo->si_code, 355 sigfpe_code_table)); 356 else if (signum == SIGSEGV) 357 fprintf(stderr, "si_code=%s ", 358 lookup_table_fallback(siginfo->si_code, 359 sigsegv_code_table)); 360 else if (signum == SIGBUS) 361 fprintf(stderr, "si_code=%s ", 362 lookup_table_fallback(siginfo->si_code, 363 sigbus_code_table)); 364 else if (signum == SIGCHLD) 365 fprintf(stderr, "si_code=%s ", 366 lookup_table_fallback(siginfo->si_code, 367 sigcld_code_table)); 368 else 369 fprintf(stderr, "si code=%d ", siginfo->si_code); 370 if ((siginfo->si_code != SI_USER) && 371 (signum == SIGILL || signum == SIGFPE || 372 signum == SIGSEGV || signum == SIGBUS)) 373 fprintf(stderr, "fault addr=%p", siginfo->si_addr); 374 fprintf(stderr, "\n"); 375 376#if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE) 377 frames = backtrace(stack_syms, 32); 378 backtrace_symbols_fd(stack_syms, frames, 2); 379#endif 380 exit(FSCK_ERROR); 381} 382 383void sigcatcher_setup(void) 384{ 385 struct sigaction sa; 386 387 memset(&sa, 0, sizeof(struct sigaction)); 388 sa.sa_sigaction = die_signal_handler; 389 sa.sa_flags = SA_SIGINFO; 390 391 sigaction(SIGFPE, &sa, 0); 392 sigaction(SIGILL, &sa, 0); 393 sigaction(SIGBUS, &sa, 0); 394 sigaction(SIGSEGV, &sa, 0); 395} 396 397 398#ifdef DEBUG 399#include <getopt.h> 400 401void usage(void) 402{ 403 fprintf(stderr, "tst_sigcatcher: [-akfn]\n"); 404 exit(1); 405} 406 407int main(int argc, char** argv) 408{ 409 struct sigaction sa; 410 char *p = 0; 411 int i, c; 412 volatile x=0; 413 414 memset(&sa, 0, sizeof(struct sigaction)); 415 sa.sa_sigaction = die_signal_handler; 416 sa.sa_flags = SA_SIGINFO; 417 for (i=1; i < 31; i++) 418 sigaction(i, &sa, 0); 419 420 while ((c = getopt (argc, argv, "afkn")) != EOF) 421 switch (c) { 422 case 'a': 423 abort(); 424 break; 425 case 'f': 426 printf("%d\n", 42/x); 427 case 'k': 428 kill(getpid(), SIGTERM); 429 break; 430 case 'n': 431 *p = 42; 432 default: 433 usage (); 434 } 435 436 printf("Sleeping for 10 seconds, send kill signal to pid %u...\n", 437 getpid()); 438 fflush(stdout); 439 sleep(10); 440 exit(0); 441} 442#endif 443