1 /* Copyright (c) 2013-2015, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
12 #ifdef HAVE_EXECINFO_H
25 #ifdef HAVE_CYGWIN_SIGNAL_H
26 #include <cygwin/signal.h>
27 #elif defined(HAVE_SYS_UCONTEXT_H)
28 #include <sys/ucontext.h>
29 #elif defined(HAVE_UCONTEXT_H)
33 #define EXPOSE_CLEAN_BACKTRACE
34 #include "backtrace.h"
36 #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
37 defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
41 #if !defined(USE_BACKTRACE)
42 #define NO_BACKTRACE_IMPL
45 /** Version of Tor to report in backtrace messages. */
46 static char *bt_version
= NULL
;
49 /** Largest stack depth to try to dump. */
51 /** Static allocation of stack to dump. This is static so we avoid stack
53 static void *cb_buf
[MAX_DEPTH
];
54 /** Protects cb_buf from concurrent access */
55 static tor_mutex_t cb_buf_mutex
;
57 /** Change a stacktrace in <b>stack</b> of depth <b>depth</b> so that it will
58 * log the correct function from which a signal was received with context
59 * <b>ctx</b>. (When we get a signal, the current function will not have
60 * called any other function, and will therefore have not pushed its address
61 * onto the stack. Fortunately, we usually have the program counter in the
62 * ucontext_t structure.
65 clean_backtrace(void **stack
, int depth
, const ucontext_t
*ctx
)
67 #ifdef PC_FROM_UCONTEXT
68 #if defined(__linux__)
70 #elif defined(__darwin__) || defined(__APPLE__) || defined(__OpenBSD__) \
71 || defined(__FreeBSD__)
79 stack
[n
] = (void*) ctx
->PC_FROM_UCONTEXT
;
87 /** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow
88 * that with a backtrace log. */
90 log_backtrace(int severity
, int domain
, const char *msg
)
96 tor_mutex_acquire(&cb_buf_mutex
);
98 depth
= backtrace(cb_buf
, MAX_DEPTH
);
99 symbols
= backtrace_symbols(cb_buf
, depth
);
101 tor_log(severity
, domain
, "%s. Stack trace:", msg
);
103 tor_log(severity
, domain
, " Unable to generate backtrace.");
106 for (i
=0; i
< depth
; ++i
) {
107 tor_log(severity
, domain
, " %s", symbols
[i
]);
112 tor_mutex_release(&cb_buf_mutex
);
115 static void crash_handler(int sig
, siginfo_t
*si
, void *ctx_
)
116 __attribute__((noreturn
));
118 /** Signal handler: write a crash message with a stack trace, and die. */
120 crash_handler(int sig
, siginfo_t
*si
, void *ctx_
)
124 ucontext_t
*ctx
= (ucontext_t
*) ctx_
;
126 const int *fds
= NULL
;
130 depth
= backtrace(cb_buf
, MAX_DEPTH
);
131 /* Clean up the top stack frame so we get the real function
132 * name for the most recently failing function. */
133 clean_backtrace(cb_buf
, depth
, ctx
);
135 format_dec_number_sigsafe((unsigned)sig
, buf
, sizeof(buf
));
137 tor_log_err_sigsafe(bt_version
, " died: Caught signal ", buf
, "\n",
140 n_fds
= tor_log_get_sigsafe_err_fds(&fds
);
141 for (i
=0; i
< n_fds
; ++i
)
142 backtrace_symbols_fd(cb_buf
, depth
, fds
[i
]);
147 /** Install signal handlers as needed so that when we crash, we produce a
148 * useful stack trace. Return 0 on success, -1 on failure. */
150 install_bt_handler(void)
152 int trap_signals
[] = { SIGSEGV
, SIGILL
, SIGFPE
, SIGBUS
, SIGSYS
,
158 tor_mutex_init(&cb_buf_mutex
);
160 memset(&sa
, 0, sizeof(sa
));
161 sa
.sa_sigaction
= crash_handler
;
162 sa
.sa_flags
= SA_SIGINFO
;
163 sigfillset(&sa
.sa_mask
);
165 for (i
= 0; trap_signals
[i
] >= 0; ++i
) {
166 if (sigaction(trap_signals
[i
], &sa
, NULL
) == -1) {
167 log_warn(LD_BUG
, "Sigaction failed: %s", strerror(errno
));
173 /* Now, generate (but do not log) a backtrace. This ensures that
174 * libc has pre-loaded the symbols we need to dump things, so that later
175 * reads won't be denied by the sandbox code */
177 int depth
= backtrace(cb_buf
, MAX_DEPTH
);
178 symbols
= backtrace_symbols(cb_buf
, depth
);
186 /** Uninstall crash handlers. */
188 remove_bt_handler(void)
190 tor_mutex_uninit(&cb_buf_mutex
);
194 #ifdef NO_BACKTRACE_IMPL
196 log_backtrace(int severity
, int domain
, const char *msg
)
198 tor_log(severity
, domain
, "%s. (Stack trace not available)", msg
);
202 install_bt_handler(void)
208 remove_bt_handler(void)
213 /** Set up code to handle generating error messages on crashes. */
215 configure_backtrace_handler(const char *tor_version
)
217 tor_free(bt_version
);
220 tor_asprintf(&bt_version
, "Tor %s", tor_version
);
222 return install_bt_handler();
225 /** Perform end-of-process cleanup for code that generates error messages on
228 clean_up_backtrace_handler(void)
232 tor_free(bt_version
);