Use a 64-bit mask for log domains, and fix a conflict
[tor.git] / src / lib / err / backtrace.c
blobf5fa7ec299d62f9cb66071acf2371e2eff1f8a06
1 /* Copyright (c) 2013-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file backtrace.c
7 * \brief Functions to produce backtraces on bugs, crashes, or assertion
8 * failures.
10 * Currently, we've only got an implementation here using the backtrace()
11 * family of functions, which are sometimes provided by libc and sometimes
12 * provided by libexecinfo. We tie into the sigaction() backend in order to
13 * detect crashes.
15 * This is one of the lowest-level modules, since nearly everything needs to
16 * be able to log an error. As such, it doesn't call the log module or any
17 * other higher-level modules directly.
20 #include "orconfig.h"
21 #include "lib/err/torerr.h"
23 #ifdef HAVE_EXECINFO_H
24 #include <execinfo.h>
25 #endif
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #ifdef HAVE_SIGNAL_H
33 #include <signal.h>
34 #endif
35 #ifdef HAVE_SYS_PARAM_H
36 #include <sys/param.h>
37 #endif
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdio.h>
43 #ifdef HAVE_CYGWIN_SIGNAL_H
44 #include <cygwin/signal.h>
45 #elif defined(HAVE_SYS_UCONTEXT_H)
46 #include <sys/ucontext.h>
47 #elif defined(HAVE_UCONTEXT_H)
48 #include <ucontext.h>
49 #endif /* defined(HAVE_CYGWIN_SIGNAL_H) || ... */
51 #ifdef HAVE_PTHREAD_H
52 #include <pthread.h>
53 #endif
55 #define EXPOSE_CLEAN_BACKTRACE
56 #include "lib/err/backtrace.h"
57 #include "lib/err/torerr.h"
59 #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
60 defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
61 #define USE_BACKTRACE
62 #endif
64 #if !defined(USE_BACKTRACE)
65 #define NO_BACKTRACE_IMPL
66 #endif
68 // Redundant with util.h, but doing it here so we can avoid that dependency.
69 #define raw_free free
71 #ifdef USE_BACKTRACE
72 /** Version of Tor to report in backtrace messages. */
73 static char bt_version[128] = "";
75 /** Largest stack depth to try to dump. */
76 #define MAX_DEPTH 256
77 /** Static allocation of stack to dump. This is static so we avoid stack
78 * pressure. */
79 static void *cb_buf[MAX_DEPTH];
80 /** Protects cb_buf from concurrent access. Pthreads, since this code
81 * is Unix-only, and since this code needs to be lowest-level. */
82 static pthread_mutex_t cb_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
84 /** Change a stacktrace in <b>stack</b> of depth <b>depth</b> so that it will
85 * log the correct function from which a signal was received with context
86 * <b>ctx</b>. (When we get a signal, the current function will not have
87 * called any other function, and will therefore have not pushed its address
88 * onto the stack. Fortunately, we usually have the program counter in the
89 * ucontext_t structure.
91 void
92 clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx)
94 #ifdef PC_FROM_UCONTEXT
95 #if defined(__linux__)
96 const size_t n = 1;
97 #elif defined(__darwin__) || defined(__APPLE__) || defined(OpenBSD) \
98 || defined(__FreeBSD__)
99 const size_t n = 2;
100 #else
101 const size_t n = 1;
102 #endif /* defined(__linux__) || ... */
103 if (depth <= n)
104 return;
106 stack[n] = (void*) ctx->PC_FROM_UCONTEXT;
107 #else /* !(defined(PC_FROM_UCONTEXT)) */
108 (void) depth;
109 (void) ctx;
110 (void) stack;
111 #endif /* defined(PC_FROM_UCONTEXT) */
114 /** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow
115 * that with a backtrace log. Send messages via the tor_log function at
116 * logger". */
117 void
118 log_backtrace_impl(int severity, uint64_t domain, const char *msg,
119 tor_log_fn logger)
121 size_t depth;
122 char **symbols;
123 size_t i;
125 pthread_mutex_lock(&cb_buf_mutex);
127 depth = backtrace(cb_buf, MAX_DEPTH);
128 symbols = backtrace_symbols(cb_buf, (int)depth);
130 logger(severity, domain, "%s. Stack trace:", msg);
131 if (!symbols) {
132 /* LCOV_EXCL_START -- we can't provoke this. */
133 logger(severity, domain, " Unable to generate backtrace.");
134 goto done;
135 /* LCOV_EXCL_STOP */
137 for (i=0; i < depth; ++i) {
138 logger(severity, domain, " %s", symbols[i]);
140 raw_free(symbols);
142 done:
143 pthread_mutex_unlock(&cb_buf_mutex);
146 static void crash_handler(int sig, siginfo_t *si, void *ctx_)
147 __attribute__((noreturn));
149 /** Signal handler: write a crash message with a stack trace, and die. */
150 static void
151 crash_handler(int sig, siginfo_t *si, void *ctx_)
153 char buf[40];
154 size_t depth;
155 ucontext_t *ctx = (ucontext_t *) ctx_;
156 int n_fds, i;
157 const int *fds = NULL;
159 (void) si;
161 depth = backtrace(cb_buf, MAX_DEPTH);
162 /* Clean up the top stack frame so we get the real function
163 * name for the most recently failing function. */
164 clean_backtrace(cb_buf, depth, ctx);
166 format_dec_number_sigsafe((unsigned)sig, buf, sizeof(buf));
168 tor_log_err_sigsafe(bt_version, " died: Caught signal ", buf, "\n",
169 NULL);
171 n_fds = tor_log_get_sigsafe_err_fds(&fds);
172 for (i=0; i < n_fds; ++i)
173 backtrace_symbols_fd(cb_buf, (int)depth, fds[i]);
175 abort();
178 /** Write a backtrace to all of the emergency-error fds. */
179 void
180 dump_stack_symbols_to_error_fds(void)
182 int n_fds, i;
183 const int *fds = NULL;
184 size_t depth;
186 depth = backtrace(cb_buf, MAX_DEPTH);
188 n_fds = tor_log_get_sigsafe_err_fds(&fds);
189 for (i=0; i < n_fds; ++i)
190 backtrace_symbols_fd(cb_buf, (int)depth, fds[i]);
193 /** Install signal handlers as needed so that when we crash, we produce a
194 * useful stack trace. Return 0 on success, -errno on failure. */
195 static int
196 install_bt_handler(const char *software)
198 int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS,
199 SIGIO, -1 };
200 int i, rv=0;
202 strncpy(bt_version, software, sizeof(bt_version) - 1);
203 bt_version[sizeof(bt_version) - 1] = 0;
205 struct sigaction sa;
207 memset(&sa, 0, sizeof(sa));
208 sa.sa_sigaction = crash_handler;
209 sa.sa_flags = SA_SIGINFO;
210 sigfillset(&sa.sa_mask);
212 for (i = 0; trap_signals[i] >= 0; ++i) {
213 if (sigaction(trap_signals[i], &sa, NULL) == -1) {
214 /* LCOV_EXCL_START */
215 rv = -errno;
216 /* LCOV_EXCL_STOP */
221 /* Now, generate (but do not log) a backtrace. This ensures that
222 * libc has pre-loaded the symbols we need to dump things, so that later
223 * reads won't be denied by the sandbox code */
224 char **symbols;
225 size_t depth = backtrace(cb_buf, MAX_DEPTH);
226 symbols = backtrace_symbols(cb_buf, (int) depth);
227 if (symbols)
228 raw_free(symbols);
231 return rv;
234 /** Uninstall crash handlers. */
235 static void
236 remove_bt_handler(void)
239 #endif /* defined(USE_BACKTRACE) */
241 #ifdef NO_BACKTRACE_IMPL
242 void
243 log_backtrace_impl(int severity, uint64_t domain, const char *msg,
244 tor_log_fn logger)
246 logger(severity, domain, "%s. (Stack trace not available)", msg);
249 static int
250 install_bt_handler(const char *software)
252 (void) software;
253 return 0;
256 static void
257 remove_bt_handler(void)
261 void
262 dump_stack_symbols_to_error_fds(void)
265 #endif /* defined(NO_BACKTRACE_IMPL) */
267 /** Set up code to handle generating error messages on crashes. */
269 configure_backtrace_handler(const char *tor_version)
271 char version[128] = "Tor\0";
273 if (tor_version) {
274 snprintf(version, sizeof(version), "Tor %s", tor_version);
277 return install_bt_handler(version);
280 /** Perform end-of-process cleanup for code that generates error messages on
281 * crashes. */
282 void
283 clean_up_backtrace_handler(void)
285 remove_bt_handler();