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",