1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
3 * Copyright (C) 2012 Nedko Arnaudov
5 * print out a stack-trace when program segfaults
7 * Inspiration: sigsegv.c by Jaco Kroon
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
21 * or write to the Free Software Foundation, Inc.,
22 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25 #if defined(HAVE_CONFIG_H)
29 /* These are "defined" for documentation purposes. They should come from the build system with or without config.h */
31 # define SIGINFO_CPP_DEMANGLE /* whether to attempt c++ demangle. if used, you must link with libstdc++ */
32 # define SIGINFO_AUTO_INIT /* whether to use gcc constructor function for automatic initialization */
35 #if !defined(SIGINFO_TEST)
36 # if !defined siginfo_log
37 # error "siginfo_log not defined"
40 # define siginfo_log(fmt, args...) fprintf(stderr, fmt "\n", ##args);
43 /* dladdr() is a glibc extension */
56 #define SIGINFO_MAX_BT_FRAMES 20
58 #if defined(SA_SIGINFO) && !defined(__arm__) && !defined(__ia64__) && !defined(__alpha__) && !defined (__FreeBSD_kernel__) && !defined (__sh__) && !defined(__APPLE__)
60 # include <ucontext.h>
63 #if defined(__powerpc64__)
64 # define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.gp_regs[index])
65 #elif defined(__powerpc__)
66 # define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.uc_regs->gregs[index])
67 #elif defined(__sparc__) && defined(__arch64__)
68 # define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.mc_gregs[index])
70 # define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.gregs[index])
74 # define SIGINFO_IP_REG REG_RIP
75 # define SIGINFO_BP_REG REG_RBP
76 # define SIGINFO_REGFORMAT "%016llx"
77 # define UINT_PTR_TYPE unsigned long long
78 #elif defined(REG_EIP)
79 # define SIGINFO_IP_REG REG_EIP
80 # define SIGINFO_BP_REG REG_EBP
81 # define SIGINFO_REGFORMAT "%08lx"
82 # define UINT_PTR_TYPE unsigned long
84 # define SIGINFO_REGFORMAT "%x"
85 # define SIGINFO_STACK_GENERIC
86 # define UINT_PTR_TYPE unsigned int
89 struct si_code_descriptor
92 const char * description
;
96 static struct si_code_descriptor sig_ill_codes
[] =
98 { ILL_ILLOPC
, "ILL_ILLOPC; Illegal opcode" },
99 { ILL_ILLOPN
, "ILL_ILLOPN; Illegal operand" },
100 { ILL_ILLADR
, "ILL_ILLADR; Illegal addressing mode" },
101 { ILL_ILLTRP
, "ILL_ILLTRP; Illegal trap" },
102 { ILL_PRVOPC
, "ILL_PRVOPC; Privileged opcode" },
103 { ILL_PRVREG
, "ILL_PRVREG; Privileged register" },
104 { ILL_COPROC
, "ILL_COPROC; Coprocessor error" },
105 { ILL_BADSTK
, "ILL_BADSTK; Internal stack error" },
109 static struct si_code_descriptor sig_fpe_codes
[] =
111 { FPE_INTDIV
, "FPE_INTDIV; Integer divide by zero" },
112 { FPE_INTOVF
, "FPE_INTOVF; Integer overflow" },
113 { FPE_FLTDIV
, "FPE_FLTDIV; Floating-point divide by zero" },
114 { FPE_FLTOVF
, "FPE_FLTOVF; Floating-point overflow" },
115 { FPE_FLTUND
, "FPE_FLTUND; Floating-point underflow" },
116 { FPE_FLTRES
, "FPE_FLTRES; Floating-point inexact result" },
117 { FPE_FLTINV
, "FPE_FLTINV; Invalid floating-point operation" },
118 { FPE_FLTSUB
, "FPE_FLTSUB; Subscript out of range" },
122 static struct si_code_descriptor sig_segv_codes
[] = {
123 { SEGV_MAPERR
, "SEGV_MAPERR; Address not mapped to object" },
124 { SEGV_ACCERR
, "SEGV_ACCERR; Invalid permissions for mapped object" },
128 static struct si_code_descriptor sig_bus_codes
[] =
130 { BUS_ADRALN
, "BUS_ADRALN; Invalid address alignment" },
131 { BUS_ADRERR
, "BUS_ADRERR; Nonexistent physical address" },
132 { BUS_OBJERR
, "BUS_OBJERR; Object-specific hardware error" },
136 static struct si_code_descriptor sig_any_codes
[] =
138 { SI_USER
, "SI_USER; sent by kill, sigsend, raise" },
139 #if defined(SI_KERNEL)
140 { SI_KERNEL
, "SI_KERNEL; sent by the kernel from somewhere" },
142 { SI_QUEUE
, "SI_QUEUE; Signal sent by the sigqueue()" },
143 { SI_TIMER
, "SI_TIMER; Signal generated by expiration of a timer set by timer_settime()" },
144 { SI_ASYNCIO
, "SI_ASYNCIO; Signal generated by completion of an asynchronous I/O request" },
145 { SI_MESGQ
, "SI_MESGQ; Signal generated by arrival of a message on an empty message queue" },
146 #if defined(SI_ASYNCIO)
147 { SI_ASYNCIO
, "SI_ASYNCIO; sent by AIO completion" },
149 #if defined(SI_SIGIO)
150 { SI_SIGIO
, "SI_SIGIO; sent by queued SIGIO" },
152 #if defined(SI_TKILL)
153 { SI_TKILL
, "SI_TKILL; sent by tkill system call" },
155 #if defined(SI_DETHREAD)
156 { SI_DETHREAD
, "SI_DETHREAD; sent by execve() killing subsidiary threads" },
160 #else /* #ifdef USE_UCONTEXT */
161 # define sig_ill_codes NULL
162 # define sig_fpe_codes NULL
163 # define sig_segv_codes NULL
164 # define sig_bus_codes NULL
165 #endif /* #ifdef USE_UCONTEXT */
167 struct signal_descriptor
171 struct si_code_descriptor
* codes
;
175 static struct signal_descriptor signal_descriptors
[] =
177 { SIGILL
, "SIGILL", sig_ill_codes
, "Illegal instruction" },
178 { SIGFPE
, "SIGFPE", sig_fpe_codes
, "Floating point exception" },
179 { SIGSEGV
, "SIGSEGV", sig_segv_codes
, "Segmentation Fault" },
180 { SIGBUS
, "SIGBUS", sig_bus_codes
, "Bus error (bad memory access)" },
181 { SIGABRT
, "SIGABRT", NULL
, "Abort" },
184 /* ucontext is required for non-generic stack backtrace */
185 #if !defined(USE_UCONTEXT) && !defined(SIGINFO_STACK_GENERIC)
186 # define SIGINFO_STACK_GENERIC
189 #if defined(SIGINFO_STACK_GENERIC)
191 static void dump_stack(ucontext_t
* ucontext
)
194 void * bt
[SIGINFO_MAX_BT_FRAMES
];
198 ((void)(ucontext
)); /* unreferenced parameter */
200 siginfo_log("Stack trace (generic):");
202 sz
= backtrace(bt
, SIGINFO_MAX_BT_FRAMES
);
203 strings
= backtrace_symbols(bt
, sz
);
205 for (i
= 0; i
< sz
; i
++)
207 siginfo_log("%2zu: %s", i
, strings
[i
]);
210 siginfo_log("End of stack trace");
213 #else /* #if defined(SIGINFO_STACK_GENERIC) */
215 #if defined(SIGINFO_CPP_DEMANGLE)
216 char * __cxa_demangle(const char * __mangled_name
, char * __output_buffer
, size_t * __length
, int * __status
);
219 static void dump_stack(ucontext_t
* ucontext
)
225 const char * symname
;
226 #if defined(SIGINFO_CPP_DEMANGLE)
228 char * demangled_name
;
231 ip
= (void *) SIGINFO_REGISTER(ucontext
, SIGINFO_IP_REG
);
232 bp
= (void **)SIGINFO_REGISTER(ucontext
, SIGINFO_BP_REG
);
234 siginfo_log("Stack trace:");
236 for (frame
= 0; bp
!= NULL
&& ip
!= NULL
; frame
++, ip
= bp
[1], bp
= (void **)bp
[0])
238 //siginfo_log("IP=%p BP=%p", ip, bp);
239 if (dladdr(ip
, &dlinfo
) == 0)
241 siginfo_log("%2d: [dladdr failed for %p]", frame
, ip
);
245 symname
= dlinfo
.dli_sname
;
246 #if defined(SIGINFO_CPP_DEMANGLE)
247 demangled_name
= __cxa_demangle(symname
, NULL
, 0, &demangle_status
);
248 if (demangle_status
== 0 && demangled_name
!= NULL
)
250 symname
= demangled_name
;
255 "%2d: 0x" SIGINFO_REGFORMAT
" <%s+%d> (%s)",
259 (int)(ip
- dlinfo
.dli_saddr
),
262 #if defined(SIGINFO_NO_CPP_DEMANGLE)
263 free(demangled_name
);
266 if (dlinfo
.dli_sname
&& strcmp(dlinfo
.dli_sname
, "main") == 0) break;
269 siginfo_log("End of stack trace");
272 #endif /* #if defined(SIGINFO_STACK_GENERIC) */
274 static struct signal_descriptor
* lookup_signal_descriptor(int signo
)
278 for (i
= 0; i
< sizeof(signal_descriptors
) / sizeof(signal_descriptors
[0]); i
++)
280 if (signal_descriptors
[i
].signo
== signo
)
282 return signal_descriptors
+ i
;
289 #if defined(USE_UCONTEXT)
290 static const char * si_code_description_lookup(struct si_code_descriptor
* descr_ptr
, int si_code
)
292 while (descr_ptr
->description
!= NULL
)
294 if (descr_ptr
->code
== si_code
)
296 return descr_ptr
->description
;
305 static const char * si_code_description(struct signal_descriptor
* descr_ptr
, int si_code
)
307 const char * si_code_str
= NULL
;
309 si_code_str
= si_code_description_lookup(sig_any_codes
, si_code
);
310 if (si_code_str
!= NULL
)
315 if (descr_ptr
!= NULL
&& descr_ptr
->codes
!= NULL
)
317 return si_code_description_lookup(descr_ptr
->codes
, si_code
);
322 #endif /* #if defined(USE_UCONTEXT) */
324 static void dump_siginfo(int signo
, siginfo_t
* info
)
326 struct signal_descriptor
* descr_ptr
;
328 descr_ptr
= lookup_signal_descriptor(signo
);
329 if (descr_ptr
!= NULL
)
331 siginfo_log("%s! (%s)", descr_ptr
->msg
, descr_ptr
->descr
);
335 siginfo_log("Unknown bad signal %d catched!", signo
);
338 #if defined(USE_UCONTEXT)
339 siginfo_log("info.si_signo = %d", info
->si_signo
);
340 siginfo_log("info.si_errno = %d", info
->si_errno
);
341 siginfo_log("info.si_code = %d (%s)", info
->si_code
, si_code_description(descr_ptr
, info
->si_code
));
342 siginfo_log("info.si_addr = %p", info
->si_addr
);
344 (void)info
; /* unused parameter */
348 #if defined(USE_UCONTEXT)
349 #define REGISTER_NAME_CASE(x) case REG_ ## x: return #x
350 static const char * register_name(size_t i
)
355 REGISTER_NAME_CASE(GS
);
356 REGISTER_NAME_CASE(FS
);
357 REGISTER_NAME_CASE(ES
);
358 REGISTER_NAME_CASE(DS
);
359 REGISTER_NAME_CASE(EDI
);
360 REGISTER_NAME_CASE(ESI
);
361 REGISTER_NAME_CASE(EBP
);
362 REGISTER_NAME_CASE(ESP
);
363 REGISTER_NAME_CASE(EBX
);
364 REGISTER_NAME_CASE(EDX
);
365 REGISTER_NAME_CASE(ECX
);
366 REGISTER_NAME_CASE(EAX
);
367 REGISTER_NAME_CASE(TRAPNO
);
368 REGISTER_NAME_CASE(ERR
);
369 REGISTER_NAME_CASE(EIP
);
370 REGISTER_NAME_CASE(CS
);
371 REGISTER_NAME_CASE(EFL
);
372 REGISTER_NAME_CASE(UESP
);
373 REGISTER_NAME_CASE(SS
);
380 static void dump_registers(ucontext_t
* ucontext
)
386 for (index
= 0; index
< NGREG
; index
++)
388 name
= register_name(index
);
391 snprintf(buffer
, sizeof(buffer
), "reg[%02d]", (int)index
);
395 siginfo_log("%6s = 0x" SIGINFO_REGFORMAT
, name
, (UINT_PTR_TYPE
)SIGINFO_REGISTER(ucontext
, index
));
398 #endif /* #if defined(USE_UCONTEXT) */
400 static void signal_handler(int signum
, siginfo_t
* info
, void * ptr
)
402 dump_siginfo(signum
, info
);
403 #if defined(USE_UCONTEXT)
410 #if defined(SIGINFO_AUTO_INIT)
413 int setup_siginfo(void)
415 struct sigaction action
;
418 memset(&action
, 0, sizeof(action
));
419 action
.sa_sigaction
= signal_handler
;
421 action
.sa_flags
= SA_SIGINFO
;
424 for (i
= 0; i
< sizeof(signal_descriptors
) / sizeof(signal_descriptors
[0]); i
++)
426 if (sigaction(signal_descriptors
[i
].signo
, &action
, NULL
) < 0)
428 siginfo_log("sigaction failed for signal %d. errno is %d (%s)", signal_descriptors
[i
].signo
, errno
, strerror(errno
));
436 #if defined(SIGINFO_AUTO_INIT)
437 static void __attribute((constructor
)) init(void)
443 #if defined(SIGINFO_TEST)
445 void crash_abort(void)
450 void crash_access(void)
452 /* why this doesnt cause FPE? */
453 *((float *)123) = 1000.0 / 0.0;
456 void crash_call(void)
458 ((void (*)(void))(0xDEADBEEF))();
461 static void (* tests
[])(void) =
468 int main(int argc
, char ** argv
)
476 index
= atoi(argv
[1]);
477 if (index
>= sizeof(tests
) / sizeof(tests
[0]))
479 siginfo_log("invalid index %d, using 0 instead", index
);