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