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
17 #ifdef HAVE_EXECINFO_H
28 #define DEFINE_ENTRY(SYM) { SYM, #SYM },
29 #define END_TABLE { 0, 0 }
31 static struct str_table sig_table[] = {
81 DEFINE_ENTRY(SIGSTKFLT)
105 DEFINE_ENTRY(SIGXCPU)
108 DEFINE_ENTRY(SIGXFSZ)
111 DEFINE_ENTRY(SIGVTALRM)
114 DEFINE_ENTRY(SIGPROF)
117 DEFINE_ENTRY(SIGWINCH)
123 DEFINE_ENTRY(SIGPOLL)
134 static struct str_table generic_code_table[] = {
136 DEFINE_ENTRY(SI_ASYNCNL)
139 DEFINE_ENTRY(SI_TKILL)
142 DEFINE_ENTRY(SI_SIGIO)
145 DEFINE_ENTRY(SI_ASYNCIO)
148 DEFINE_ENTRY(SI_MESGQ)
151 DEFINE_ENTRY(SI_TIMER)
154 DEFINE_ENTRY(SI_QUEUE)
157 DEFINE_ENTRY(SI_USER)
160 DEFINE_ENTRY(SI_KERNEL)
165 static struct str_table sigill_code_table[] = {
167 DEFINE_ENTRY(ILL_ILLOPC)
170 DEFINE_ENTRY(ILL_ILLOPN)
173 DEFINE_ENTRY(ILL_ILLADR)
176 DEFINE_ENTRY(ILL_ILLTRP)
179 DEFINE_ENTRY(ILL_PRVOPC)
182 DEFINE_ENTRY(ILL_PRVREG)
185 DEFINE_ENTRY(ILL_COPROC)
188 DEFINE_ENTRY(ILL_BADSTK)
191 DEFINE_ENTRY(BUS_ADRALN)
194 DEFINE_ENTRY(BUS_ADRERR)
197 DEFINE_ENTRY(BUS_OBJERR)
202 static struct str_table sigfpe_code_table[] = {
204 DEFINE_ENTRY(FPE_INTDIV)
207 DEFINE_ENTRY(FPE_INTOVF)
210 DEFINE_ENTRY(FPE_FLTDIV)
213 DEFINE_ENTRY(FPE_FLTOVF)
216 DEFINE_ENTRY(FPE_FLTUND)
219 DEFINE_ENTRY(FPE_FLTRES)
222 DEFINE_ENTRY(FPE_FLTINV)
225 DEFINE_ENTRY(FPE_FLTSUB)
230 static struct str_table sigsegv_code_table[] = {
232 DEFINE_ENTRY(SEGV_MAPERR)
235 DEFINE_ENTRY(SEGV_ACCERR)
241 static struct str_table sigbus_code_table[] = {
243 DEFINE_ENTRY(BUS_ADRALN)
246 DEFINE_ENTRY(BUS_ADRERR)
249 DEFINE_ENTRY(BUS_OBJERR)
254 #if 0 /* should this be hooked in somewhere? */
255 static struct str_table sigstrap_code_table[] = {
257 DEFINE_ENTRY(TRAP_BRKPT)
260 DEFINE_ENTRY(TRAP_TRACE)
266 static struct str_table sigcld_code_table[] = {
268 DEFINE_ENTRY(CLD_EXITED)
271 DEFINE_ENTRY(CLD_KILLED)
274 DEFINE_ENTRY(CLD_DUMPED)
277 DEFINE_ENTRY(CLD_TRAPPED)
280 DEFINE_ENTRY(CLD_STOPPED)
283 DEFINE_ENTRY(CLD_CONTINUED)
288 #if 0 /* should this be hooked in somewhere? */
289 static struct str_table sigpoll_code_table[] = {
291 DEFINE_ENTRY(POLL_IN)
294 DEFINE_ENTRY(POLL_OUT)
297 DEFINE_ENTRY(POLL_MSG)
300 DEFINE_ENTRY(POLL_ERR)
303 DEFINE_ENTRY(POLL_PRI)
306 DEFINE_ENTRY(POLL_HUP)
312 static const char *lookup_table(int num, struct str_table *table)
316 for (p=table; p->name; p++)
322 static const char *lookup_table_fallback(int num, struct str_table *table)
325 const char *ret = lookup_table(num, table);
329 snprintf(buf, sizeof(buf), "%d", num);
330 buf[sizeof(buf)-1] = 0;
334 static void die_signal_handler(int signum, siginfo_t *siginfo,
335 void *context EXT2FS_ATTR((unused)))
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);
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,
350 else if (signum == SIGFPE)
351 fprintf(stderr, "si_code=%s ",
352 lookup_table_fallback(siginfo->si_code,
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,
362 else if (signum == SIGCHLD)
363 fprintf(stderr, "si_code=%s ",
364 lookup_table_fallback(siginfo->si_code,
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");
374 #if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE)
376 void *stack_syms[32];
379 frames = backtrace(stack_syms, 32);
380 backtrace_symbols_fd(stack_syms, frames, 2);
386 void sigcatcher_setup(void)
390 memset(&sa, 0, sizeof(struct sigaction));
391 sa.sa_sigaction = die_signal_handler;
392 sa.sa_flags = SA_SIGINFO;
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);
407 fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
411 int main(int argc, char** argv)
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);
424 while ((c = getopt (argc, argv, "afkn")) != EOF)
430 printf("%d\n", 42/x);
432 kill(getpid(), SIGTERM);
440 printf("Sleeping for 10 seconds, send kill signal to pid %u...\n",