tor  0.4.2.1-alpha-dev
backtrace.c
Go to the documentation of this file.
1 /* Copyright (c) 2013-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
20 #include "orconfig.h"
21 #include "lib/err/torerr.h"
22 
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>
42 
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) || ... */
50 
51 #ifdef HAVE_PTHREAD_H
52 #include <pthread.h>
53 #endif
54 
55 #define EXPOSE_CLEAN_BACKTRACE
56 #include "lib/err/backtrace.h"
57 #include "lib/err/torerr.h"
58 
59 #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
60  defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
61 #define USE_BACKTRACE
62 #endif
63 
64 #if !defined(USE_BACKTRACE)
65 #define NO_BACKTRACE_IMPL
66 #endif
67 
68 // Redundant with util.h, but doing it here so we can avoid that dependency.
69 #define raw_free free
70 
72 static char bt_version[128] = "";
73 
74 #ifdef USE_BACKTRACE
75 
76 #define MAX_DEPTH 256
77 
79 static void *cb_buf[MAX_DEPTH];
82 static pthread_mutex_t cb_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
83 
91 void
92 clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx)
93 {
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;
105 
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) */
112 }
113 
117 void
118 log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg,
119  tor_log_fn logger)
120 {
121  size_t depth;
122  char **symbols;
123  size_t i;
124 
125  pthread_mutex_lock(&cb_buf_mutex);
126 
127  depth = backtrace(cb_buf, MAX_DEPTH);
128  symbols = backtrace_symbols(cb_buf, (int)depth);
129 
130  logger(severity, domain, "%s: %s. Stack trace:", bt_version, 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 */
136  }
137  for (i=0; i < depth; ++i) {
138  logger(severity, domain, " %s", symbols[i]);
139  }
140  raw_free(symbols);
141 
142  done:
143  pthread_mutex_unlock(&cb_buf_mutex);
144 }
145 
146 static void crash_handler(int sig, siginfo_t *si, void *ctx_)
147  __attribute__((noreturn));
148 
150 static void
151 crash_handler(int sig, siginfo_t *si, void *ctx_)
152 {
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;
158 
159  (void) si;
160 
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);
165 
166  format_dec_number_sigsafe((unsigned)sig, buf, sizeof(buf));
167 
168  tor_log_err_sigsafe(bt_version, " died: Caught signal ", buf, "\n",
169  NULL);
170 
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]);
174 
175  tor_raw_abort_();
176 }
177 
179 void
180 dump_stack_symbols_to_error_fds(void)
181 {
182  int n_fds, i;
183  const int *fds = NULL;
184  size_t depth;
185 
186  depth = backtrace(cb_buf, MAX_DEPTH);
187 
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]);
191 }
192 
195 static int
196 install_bt_handler(void)
197 {
198  int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS,
199  SIGIO, -1 };
200  int i, rv=0;
201 
202  struct sigaction sa;
203 
204  memset(&sa, 0, sizeof(sa));
205  sa.sa_sigaction = crash_handler;
206  sa.sa_flags = SA_SIGINFO;
207  sigfillset(&sa.sa_mask);
208 
209  for (i = 0; trap_signals[i] >= 0; ++i) {
210  if (sigaction(trap_signals[i], &sa, NULL) == -1) {
211  /* LCOV_EXCL_START */
212  rv = -errno;
213  /* LCOV_EXCL_STOP */
214  }
215  }
216 
217  {
218  /* Now, generate (but do not log) a backtrace. This ensures that
219  * libc has pre-loaded the symbols we need to dump things, so that later
220  * reads won't be denied by the sandbox code */
221  char **symbols;
222  size_t depth = backtrace(cb_buf, MAX_DEPTH);
223  symbols = backtrace_symbols(cb_buf, (int) depth);
224  if (symbols)
225  raw_free(symbols);
226  }
227 
228  return rv;
229 }
230 
232 static void
233 remove_bt_handler(void)
234 {
235 }
236 #endif /* defined(USE_BACKTRACE) */
237 
238 #ifdef NO_BACKTRACE_IMPL
239 void
240 log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg,
241  tor_log_fn logger)
242 {
243  logger(severity, domain, "%s: %s. (Stack trace not available)",
244  bt_version, msg);
245 }
246 
247 static int
248 install_bt_handler(void)
249 {
250  return 0;
251 }
252 
253 static void
254 remove_bt_handler(void)
255 {
256 }
257 
258 void
259 dump_stack_symbols_to_error_fds(void)
260 {
261 }
262 #endif /* defined(NO_BACKTRACE_IMPL) */
263 
266 const char *
268 {
269  return bt_version;
270 }
271 
273 int
274 configure_backtrace_handler(const char *tor_version)
275 {
276  char version[128] = "Tor\0";
277 
278  if (tor_version) {
279  int snp_rv = 0;
280  /* We can't use strlcat() here, because it is defined in
281  * string/compat_string.h on some platforms, and string uses torerr. */
282  snp_rv = snprintf(version, sizeof(version), "Tor %s", tor_version);
283  /* It's safe to call raw_assert() here, because raw_assert() does not
284  * call configure_backtrace_handler(). */
285  raw_assert(snp_rv < (int)sizeof(version));
286  raw_assert(snp_rv >= 0);
287  }
288 
289  char *str_rv = NULL;
290  /* We can't use strlcpy() here, see the note about strlcat() above. */
291  str_rv = strncpy(bt_version, version, sizeof(bt_version) - 1);
292  /* We must terminate bt_version, then raw_assert(), because raw_assert()
293  * uses bt_version. */
294  bt_version[sizeof(bt_version) - 1] = 0;
295  raw_assert(str_rv == bt_version);
296 
297  return install_bt_handler();
298 }
299 
302 void
304 {
305  remove_bt_handler();
306 }
Header for backtrace.c.
void tor_log_err_sigsafe(const char *m,...)
Definition: torerr.c:70
int configure_backtrace_handler(const char *tor_version)
Definition: backtrace.c:274
static char bt_version[128]
Definition: backtrace.c:72
int format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len)
Definition: torerr.c:307
void clean_up_backtrace_handler(void)
Definition: backtrace.c:303
uint64_t log_domain_mask_t
Definition: logging_types.h:21
Headers for torerr.c.
int tor_log_get_sigsafe_err_fds(const int **out)
Definition: torerr.c:103
void tor_raw_abort_(void)
Definition: torerr.c:224
const char * get_tor_backtrace_version(void)
Definition: backtrace.c:267