Fix past tense of 'catch'
[siginfo.git] / siginfo.c
blobad6d3fa34285519ac06124ea591f3f311e77e01a
1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
2 /*
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)
26 # include "config.h"
27 #endif
29 /* These are "defined" for documentation purposes. They should come from the build system with or without config.h */
30 #if 0
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 */
33 #endif
35 #if !defined(SIGINFO_TEST)
36 # if !defined siginfo_log
37 # error "siginfo_log not defined"
38 # endif
39 #else
40 # define siginfo_log(fmt, args...) fprintf(stderr, fmt "\n", ##args);
41 #endif
43 /* dladdr() is a glibc extension */
44 #ifndef _GNU_SOURCE
45 # define _GNU_SOURCE
46 #endif
48 #include <memory.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <signal.h>
52 #include <dlfcn.h>
53 #include <execinfo.h>
54 #include <errno.h>
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__) && !defined(__aarch64__)
59 # define USE_UCONTEXT
60 # include <ucontext.h>
61 #endif
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])
69 #else
70 # define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.gregs[index])
71 #endif
73 #if defined(REG_RIP)
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
83 #else
84 # define SIGINFO_REGFORMAT "%x"
85 # define SIGINFO_STACK_GENERIC
86 # define UINT_PTR_TYPE unsigned int
87 #endif
89 struct si_code_descriptor
91 int code;
92 const char * description;
95 #ifdef USE_UCONTEXT
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" },
106 { 0, NULL }
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" },
119 { 0, NULL }
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" },
125 { 0, NULL }
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" },
133 { 0, NULL }
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" },
141 #endif
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" },
148 #endif
149 #if defined(SI_SIGIO)
150 { SI_SIGIO, "SI_SIGIO; sent by queued SIGIO" },
151 #endif
152 #if defined(SI_TKILL)
153 { SI_TKILL, "SI_TKILL; sent by tkill system call" },
154 #endif
155 #if defined(SI_DETHREAD)
156 { SI_DETHREAD, "SI_DETHREAD; sent by execve() killing subsidiary threads" },
157 #endif
158 { 0, NULL }
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
169 int signo;
170 const char * descr;
171 struct si_code_descriptor * codes;
172 const char * msg;
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
187 #endif
189 #if defined(SIGINFO_STACK_GENERIC)
191 static void dump_stack(ucontext_t * ucontext)
193 size_t i;
194 void * bt[SIGINFO_MAX_BT_FRAMES];
195 char ** strings;
196 size_t sz;
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);
217 #endif
219 static void dump_stack(ucontext_t * ucontext)
221 int frame;
222 Dl_info dlinfo;
223 void ** bp;
224 void * ip;
225 const char * symname;
226 #if defined(SIGINFO_CPP_DEMANGLE)
227 int demangle_status;
228 char * demangled_name;
229 #endif
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);
242 continue;
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;
252 #endif
254 siginfo_log(
255 "%2d: 0x" SIGINFO_REGFORMAT " <%s+%d> (%s)",
256 frame,
257 (UINT_PTR_TYPE)ip,
258 symname,
259 (int)(ip - dlinfo.dli_saddr),
260 dlinfo.dli_fname);
262 #if defined(SIGINFO_NO_CPP_DEMANGLE)
263 free(demangled_name);
264 #endif
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)
276 size_t i;
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;
286 return NULL;
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;
299 descr_ptr++;
302 return NULL;
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)
312 return si_code_str;
315 if (descr_ptr != NULL && descr_ptr->codes != NULL)
317 return si_code_description_lookup(descr_ptr->codes, si_code);
320 return "unknown";
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);
333 else
335 siginfo_log("Unknown bad signal %d caught!", 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);
343 #else
344 (void)info; /* unused parameter */
345 #endif
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)
352 switch (i)
354 #if defined(REG_EIP)
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);
374 #endif
377 return NULL;
380 static void dump_registers(ucontext_t * ucontext)
382 size_t index;
383 const char * name;
384 char buffer[64];
386 for (index = 0; index < NGREG; index++)
388 name = register_name(index);
389 if (name == NULL)
391 snprintf(buffer, sizeof(buffer), "reg[%02d]", (int)index);
392 name = buffer;
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)
404 dump_registers(ptr);
405 #endif
406 dump_stack(ptr);
407 exit(-1);
410 #if defined(SIGINFO_AUTO_INIT)
411 static
412 #endif
413 int setup_siginfo(void)
415 struct sigaction action;
416 size_t i;
418 memset(&action, 0, sizeof(action));
419 action.sa_sigaction = signal_handler;
420 #ifdef SA_SIGINFO
421 action.sa_flags = SA_SIGINFO;
422 #endif
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));
429 return 0;
433 return 1;
436 #if defined(SIGINFO_AUTO_INIT)
437 static void __attribute((constructor)) init(void)
439 setup_siginfo();
441 #endif
443 #if defined(SIGINFO_TEST)
445 void crash_abort(void)
447 abort();
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) =
463 crash_abort,
464 crash_access,
465 crash_call,
468 int main(int argc, char ** argv)
470 unsigned int index;
472 setup_siginfo();
474 if (argc > 1)
476 index = atoi(argv[1]);
477 if (index >= sizeof(tests) / sizeof(tests[0]))
479 siginfo_log("invalid index %d, using 0 instead", index);
480 index = 0;
483 else
485 index = 0;
488 tests[index]();
490 return 0;
492 #endif