1 #include "debug.h"
2 #include "logger.h"
3
4 #ifdef __CYGWIN__
5 #ifndef SA_ONSTACK
6 #define SA_ONSTACK 0x08000000
7 #endif
8 #endif
9
10 static char *assert_err = "<no assertion failed>";
11 static char *assert_file = "<no file>";
12 static int assert_line = 0;
13
14 void
_debug_assert(char * err,char * file,int line)15 _debug_assert(char *err, char *file, int line)
16 {
17 logger(LOG_WARNING, "=== ASSERTION FAILED ===");
18 logger(LOG_WARNING, "%s:%d '%s' is not true", file, line, err);
19 assert_err = err;
20 assert_file = file;
21 assert_line = line;
22 // force SIGSEGV to print the bug report
23 *((char *)-1) = 'x';
24 }
25
26 void
debug_init(void)27 debug_init(void)
28 {
29 struct sigaction act;
30 sigemptyset(&act.sa_mask);
31 act.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
32 act.sa_sigaction = debug_segv_handler;
33 sigaction(SIGSEGV, &act, NULL);
34 sigaction(SIGBUS, &act, NULL);
35 sigaction(SIGFPE, &act, NULL);
36 sigaction(SIGILL, &act, NULL);
37 }
38
39 #ifdef HAVE_BACKTRACE
40 #include <execinfo.h>
41 #include <ucontext.h>
42 static void *
getMcontextEip(ucontext_t * uc)43 getMcontextEip(ucontext_t *uc)
44 {
45 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
46 /* OSX < 10.6 */
47 #if defined(__x86_64__)
48 return (void *) uc->uc_mcontext->__ss.__rip;
49 #elif defined(__i386__)
50 return (void *) uc->uc_mcontext->__ss.__eip;
51 #else
52 return (void *) uc->uc_mcontext->__ss.__srr0;
53 #endif
54 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
55 /* OSX >= 10.6 */
56 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
57 return (void *) uc->uc_mcontext->__ss.__rip;
58 #else
59 return (void *) uc->uc_mcontext->__ss.__eip;
60 #endif
61 #elif defined(__linux__)
62 /* Linux */
63 #if defined(__i386__)
64 return (void *) uc->uc_mcontext.gregs[14]; /* Linux 32 */
65 #elif defined(__X86_64__) || defined(__x86_64__)
66 return (void *) uc->uc_mcontext.gregs[16]; /* Linux 64 */
67 #elif defined(__ia64__) /* Linux IA64 */
68 return (void *) uc->uc_mcontext.sc_ip;
69 #else
70 return NULL;
71 #endif
72 #else
73 return NULL;
74 #endif
75 }
76
77 /**
78 * Logs the stack trace using the backtrace() call. This function is designed to
79 * be called from signal handlers safely.
80 */
81 static void
log_stack_trace(ucontext_t * uc)82 log_stack_trace(ucontext_t *uc)
83 {
84 void *trace[100];
85 int trace_size = 0;
86 int fd = logger_fd >= 0 ? logger_fd : STDOUT_FILENO;
87 /* Generate the stack trace */
88 trace_size = backtrace(trace, 100);
89 /* overwrite sigaction with caller's address */
90 if (getMcontextEip(uc) != NULL)
91 trace[1] = getMcontextEip(uc);
92
93 backtrace_symbols_fd(trace, trace_size, fd);
94 }
95
96 #endif
97
98 void
debug_segv_handler(int sig,siginfo_t * info,void * secret)99 debug_segv_handler(int sig, siginfo_t *info, void *secret)
100 {
101 logger(LOG_WARNING, "Crashed by signal: %d", sig);
102 logger(LOG_WARNING, "--- STACK TRACE");
103 logger(LOG_WARNING, "Failed assertion: %s (%s:%d)", assert_err, assert_file,
104 assert_line);
105 #ifdef HAVE_BACKTRACE
106 logger(LOG_WARNING, "--- STACK TRACE");
107 ucontext_t *uc = (ucontext_t *) secret;
108 log_stack_trace(uc);
109 #endif
110 /* Make sure we exit with the right signal at the end. So for instance
111 * the core will be dumped if enabled. */
112 struct sigaction act;
113 sigemptyset(&act.sa_mask);
114 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
115 act.sa_handler = SIG_DFL;
116 sigaction(sig, &act, NULL);
117 kill(getpid(), sig);
118 }
119