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