2 * sigcatcher.c --- print a backtrace on a SIGSEGV, et. al
4 * Copyright (C) 2011 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
16 #ifdef HAVE_EXECINFO_H
27 #define DEFINE_ENTRY(SYM) { SYM, #SYM },
28 #define END_TABLE { 0, 0 }
30 static struct str_table sig_table[] = {
80 DEFINE_ENTRY(SIGSTKFLT)
104 DEFINE_ENTRY(SIGXCPU)
107 DEFINE_ENTRY(SIGXFSZ)
110 DEFINE_ENTRY(SIGVTALRM)
113 DEFINE_ENTRY(SIGPROF)
116 DEFINE_ENTRY(SIGWINCH)
122 DEFINE_ENTRY(SIGPOLL)
133 static struct str_table generic_code_table[] = {
135 DEFINE_ENTRY(SI_ASYNCNL)
138 DEFINE_ENTRY(SI_TKILL)
141 DEFINE_ENTRY(SI_SIGIO)
144 DEFINE_ENTRY(SI_ASYNCIO)
147 DEFINE_ENTRY(SI_MESGQ)
150 DEFINE_ENTRY(SI_TIMER)
153 DEFINE_ENTRY(SI_QUEUE)
156 DEFINE_ENTRY(SI_USER)
159 DEFINE_ENTRY(SI_KERNEL)
164 static struct str_table sigill_code_table[] = {
166 DEFINE_ENTRY(ILL_ILLOPC)
169 DEFINE_ENTRY(ILL_ILLOPN)
172 DEFINE_ENTRY(ILL_ILLADR)
175 DEFINE_ENTRY(ILL_ILLTRP)
178 DEFINE_ENTRY(ILL_PRVOPC)
181 DEFINE_ENTRY(ILL_PRVREG)
184 DEFINE_ENTRY(ILL_COPROC)
187 DEFINE_ENTRY(ILL_BADSTK)
190 DEFINE_ENTRY(BUS_ADRALN)
193 DEFINE_ENTRY(BUS_ADRERR)
196 DEFINE_ENTRY(BUS_OBJERR)
201 static struct str_table sigfpe_code_table[] = {
203 DEFINE_ENTRY(FPE_INTDIV)
206 DEFINE_ENTRY(FPE_INTOVF)
209 DEFINE_ENTRY(FPE_FLTDIV)
212 DEFINE_ENTRY(FPE_FLTOVF)
215 DEFINE_ENTRY(FPE_FLTUND)
218 DEFINE_ENTRY(FPE_FLTRES)
221 DEFINE_ENTRY(FPE_FLTINV)
224 DEFINE_ENTRY(FPE_FLTSUB)
229 static struct str_table sigsegv_code_table[] = {
231 DEFINE_ENTRY(SEGV_MAPERR)
234 DEFINE_ENTRY(SEGV_ACCERR)
240 static struct str_table sigbus_code_table[] = {
242 DEFINE_ENTRY(BUS_ADRALN)
245 DEFINE_ENTRY(BUS_ADRERR)
248 DEFINE_ENTRY(BUS_OBJERR)
253 #if 0 /* should this be hooked in somewhere? */
254 static struct str_table sigstrap_code_table[] = {
256 DEFINE_ENTRY(TRAP_BRKPT)
259 DEFINE_ENTRY(TRAP_TRACE)
265 static struct str_table sigcld_code_table[] = {
267 DEFINE_ENTRY(CLD_EXITED)
270 DEFINE_ENTRY(CLD_KILLED)
273 DEFINE_ENTRY(CLD_DUMPED)
276 DEFINE_ENTRY(CLD_TRAPPED)
279 DEFINE_ENTRY(CLD_STOPPED)
282 DEFINE_ENTRY(CLD_CONTINUED)
287 #if 0 /* should this be hooked in somewhere? */
288 static struct str_table sigpoll_code_table[] = {
290 DEFINE_ENTRY(POLL_IN)
293 DEFINE_ENTRY(POLL_OUT)
296 DEFINE_ENTRY(POLL_MSG)
299 DEFINE_ENTRY(POLL_ERR)
302 DEFINE_ENTRY(POLL_PRI)
305 DEFINE_ENTRY(POLL_HUP)
311 static const char *lookup_table(int num, struct str_table *table)
315 for (p=table; p->name; p++)
321 static const char *lookup_table_fallback(int num, struct str_table *table)
324 const char *ret = lookup_table(num, table);
328 snprintf(buf, sizeof(buf), "%d", num);
329 buf[sizeof(buf)-1] = 0;
333 static void die_signal_handler(int signum, siginfo_t *siginfo,
334 void *context EXT2FS_ATTR((unused)))
336 void *stack_syms[32];
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);
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,
351 else if (signum == SIGFPE)
352 fprintf(stderr, "si_code=%s ",
353 lookup_table_fallback(siginfo->si_code,
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,
363 else if (signum == SIGCHLD)
364 fprintf(stderr, "si_code=%s ",
365 lookup_table_fallback(siginfo->si_code,
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");
375 #if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE)
376 frames = backtrace(stack_syms, 32);
377 backtrace_symbols_fd(stack_syms, frames, 2);
382 void sigcatcher_setup(void)
386 memset(&sa, 0, sizeof(struct sigaction));
387 sa.sa_sigaction = die_signal_handler;
388 sa.sa_flags = SA_SIGINFO;
390 sigaction(SIGFPE, &sa, 0);
391 sigaction(SIGILL, &sa, 0);
392 sigaction(SIGBUS, &sa, 0);
393 sigaction(SIGSEGV, &sa, 0);
402 fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
406 int main(int argc, char** argv)
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);
419 while ((c = getopt (argc, argv, "afkn")) != EOF)
425 printf("%d\n", 42/x);
427 kill(getpid(), SIGTERM);
435 printf("Sleeping for 10 seconds, send kill signal to pid %u...\n",