[tor-commits] [tor/master] Basic backtrace ability

nickm at torproject.org nickm at torproject.org
Mon Nov 18 16:04:36 UTC 2013


commit 063bea58bcc1c27864a0351bba07254855903377
Author: Nick Mathewson <nickm at torproject.org>
Date:   Fri Jul 19 14:09:58 2013 -0400

    Basic backtrace ability
    
    On platforms with the backtrace/backtrace_symbols_fd interface, Tor
    can now dump stack traces on assertion failure.  By default, I log
    them to DataDir/stack_dump and to stderr.
---
 changes/stack_trace    |    6 ++
 configure.ac           |    4 ++
 src/common/backtrace.c |  157 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/common/backtrace.h |   12 ++++
 src/common/include.am  |    2 +
 src/common/util.c      |    6 ++
 src/or/config.c        |   14 +++++
 src/or/main.c          |    9 ++-
 8 files changed, 207 insertions(+), 3 deletions(-)

diff --git a/changes/stack_trace b/changes/stack_trace
new file mode 100644
index 0000000..dc63638
--- /dev/null
+++ b/changes/stack_trace
@@ -0,0 +1,6 @@
+  o Major features:
+    - On some platforms (currently, recent OSX versions, and glibc-based
+      platforms that support the ELF format), Tor can now dump
+      stack traces when an assertion fails. By default, traces are dumped
+      to stderr, and to a stack_dump file in the DataDirectory. 
+
diff --git a/configure.ac b/configure.ac
index 4aeec92..5059079 100644
--- a/configure.ac
+++ b/configure.ac
@@ -302,6 +302,8 @@ dnl exports strlcpy without defining it in a header.
 AC_CHECK_FUNCS(
         _NSGetEnviron \
         accept4 \
+        backtrace \
+        backtrace_symbols_fd \
         clock_gettime \
         flock \
         ftime \
@@ -319,6 +321,7 @@ AC_CHECK_FUNCS(
         memmem \
         prctl \
         rint \
+        sigaction \
         socketpair \
         strlcat \
         strlcpy \
@@ -802,6 +805,7 @@ dnl These headers are not essential
 AC_CHECK_HEADERS(
         arpa/inet.h \
         crt_externs.h \
+        execinfo.h \
         grp.h \
         ifaddrs.h \
         inttypes.h \
diff --git a/src/common/backtrace.c b/src/common/backtrace.c
new file mode 100644
index 0000000..d3f59b2
--- /dev/null
+++ b/src/common/backtrace.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "backtrace.h"
+#include "compat.h"
+#include "util.h"
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
+  defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
+#define USE_BACKTRACE
+#endif
+
+#if !defined(USE_BACKTRACE)
+#define NO_BACKTRACE_IMPL
+#endif
+
+static char *bt_filename = NULL;
+static char *bt_version = NULL;
+
+#ifndef NO_BACKTRACE_IMPL
+/**DOCDOC*/
+static int
+open_bt_target(void)
+{
+  int fd = -1;
+  if (bt_filename)
+    fd = open(bt_filename, O_WRONLY|O_CREAT|O_APPEND, 0700);
+  return fd;
+}
+#endif
+
+/**DOCDOC*/
+static void
+bt_write(int fd, const char *s, ssize_t n)
+{
+  int r;
+  if (n < 0) n = strlen(s);
+
+  r = write(STDERR_FILENO, s, n);
+  if (fd >= 0)
+    r = write(fd, s, n);
+  (void)r; 
+}
+
+#ifdef USE_BACKTRACE
+#define MAX_DEPTH 256
+static void *cb_buf[MAX_DEPTH];
+
+/**DOCDOC*/
+void
+dump_backtrace(const char *msg)
+{
+  char timebuf[32];
+  time_t t = time(NULL);
+  int timebuf_len;
+  int depth;
+  int fd;
+  if (!msg) msg = "unspecified crash";
+
+  depth = backtrace(cb_buf, MAX_DEPTH);
+
+  t /= 900; t *= 900; /* Round to the previous 15 minutes */
+  timebuf[0] = '\0';
+  timebuf_len = format_dec_number_sigsafe(t, timebuf, sizeof(timebuf));
+
+  fd = open_bt_target();
+  bt_write(fd, "========================================"
+               "====================================\n", -1);
+  bt_write(fd, bt_version, -1);
+  bt_write(fd, " died around T=", -1);
+  bt_write(fd, timebuf, timebuf_len);
+  bt_write(fd, ": ", 2);
+  bt_write(fd, msg, -1);
+  bt_write(fd, "\n", 1);
+  backtrace_symbols_fd(cb_buf, depth, STDERR_FILENO);
+  if (fd >= 0)
+    backtrace_symbols_fd(cb_buf, depth, fd);
+
+  close(fd);
+}
+
+/**DOCDOC*/
+static int
+install_bt_handler(void)
+{
+  /*XXXX add signal handlers */
+  /*XXXX make this idempotent */
+  return 0;
+}
+/**DOCDOC*/
+static void
+remove_bt_handler(void)
+{
+}
+#endif
+
+#ifdef NO_BACKTRACE_IMPL
+/**DOCDOC*/
+void
+dump_backtrace(const char *msg)
+{
+  bt_write(-1, bt_version, -1);
+  bt_write(-1, " died: ", -1);
+  bt_write(-1, msg, -1);
+  bt_write(-1, "\n", -1);
+}
+
+/**DOCDOC*/
+static int
+install_bt_handler(void)
+{
+  return 0;
+}
+
+/**DOCDOC*/
+static void
+remove_bt_handler(void)
+{
+}
+#endif
+
+/**DOCDOC*/
+int
+configure_backtrace_handler(const char *filename, const char *tor_version)
+{
+  tor_free(bt_filename);
+  if (filename)
+    bt_filename = tor_strdup(filename);
+  tor_free(bt_version);
+  if (!tor_version)
+    tor_version = "Tor";
+  bt_version = tor_strdup(tor_version);
+
+  return install_bt_handler();
+}
+
+/**DOCDOC*/
+void
+clean_up_backtrace_handler(void)
+{
+  remove_bt_handler();
+
+  tor_free(bt_filename);
+  tor_free(bt_version);
+}
+
diff --git a/src/common/backtrace.h b/src/common/backtrace.h
new file mode 100644
index 0000000..bb23960
--- /dev/null
+++ b/src/common/backtrace.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_BACKTRACE_H
+#define TOR_BACKTRACE_H
+
+void dump_backtrace(const char *msg);
+int configure_backtrace_handler(const char *filename, const char *tor_version);
+void clean_up_backtrace_handler(void);
+
+#endif
+
diff --git a/src/common/include.am b/src/common/include.am
index 032befd..814786b 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -50,6 +50,7 @@ endif
 
 LIBOR_A_SOURCES = \
   src/common/address.c					\
+  src/common/backtrace.c				\
   src/common/compat.c					\
   src/common/container.c				\
   src/common/di_ops.c					\
@@ -90,6 +91,7 @@ src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
 COMMONHEADERS = \
   src/common/address.h				\
+  src/common/backtrace.h			\
   src/common/aes.h				\
   src/common/ciphers.inc			\
   src/common/compat.h				\
diff --git a/src/common/util.c b/src/common/util.c
index 814eb13..0b65437 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -24,6 +24,7 @@
 #include "torint.h"
 #include "container.h"
 #include "address.h"
+#include "backtrace.h"
 
 #ifdef _WIN32
 #include <io.h>
@@ -101,8 +102,13 @@ void
 tor_assertion_failed_(const char *fname, unsigned int line,
                       const char *func, const char *expr)
 {
+  char buf[256];
   log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.",
           fname, line, func, expr);
+  tor_snprintf(buf, sizeof(buf),
+               "Assertion %s failed in %s at %s:%u",
+               expr, func, fname, line);
+  dump_backtrace(buf);
   fprintf(stderr,"%s:%u: %s: Assertion %s failed; aborting.\n",
           fname, line, func, expr);
 }
diff --git a/src/or/config.c b/src/or/config.c
index ad6689c..af5bf41 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -12,6 +12,7 @@
 #define CONFIG_PRIVATE
 #include "or.h"
 #include "addressmap.h"
+#include "backtrace.h"
 #include "channel.h"
 #include "circuitbuild.h"
 #include "circuitlist.h"
@@ -1113,6 +1114,19 @@ options_act_reversible(const or_options_t *old_options, char **msg)
     /* No need to roll back, since you can't change the value. */
   }
 
+  /* Enable crash logging to files */
+  {
+    /* XXXX we might want to set this up earlier, if possible! */
+    char *backtrace_fname = NULL;
+    char *progname = NULL;
+    tor_asprintf(&backtrace_fname, "%s"PATH_SEPARATOR"stack_dump",
+                 options->DataDirectory);
+    tor_asprintf(&progname, "Tor %s", get_version());
+    configure_backtrace_handler(backtrace_fname, progname);
+    tor_free(backtrace_fname);
+    tor_free(progname);
+  }
+
   /* Write control ports to disk as appropriate */
   control_ports_write_to_file();
 
diff --git a/src/or/main.c b/src/or/main.c
index d172825..ea86df0 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -12,6 +12,7 @@
 
 #include "or.h"
 #include "addressmap.h"
+#include "backtrace.h"
 #include "buffers.h"
 #include "channel.h"
 #include "channeltls.h"
@@ -2304,7 +2305,7 @@ handle_signals(int is_parent)
 int
 tor_init(int argc, char *argv[])
 {
-  char buf[256];
+  char progname[256];
   int i, quiet = 0;
   time_of_process_start = time(NULL);
   if (!connection_array)
@@ -2314,8 +2315,8 @@ tor_init(int argc, char *argv[])
   if (!active_linked_connection_lst)
     active_linked_connection_lst = smartlist_new();
   /* Have the log set up with our application name. */
-  tor_snprintf(buf, sizeof(buf), "Tor %s", get_version());
-  log_set_application_name(buf);
+  tor_snprintf(progname, sizeof(progname), "Tor %s", get_version());
+  log_set_application_name(progname);
   /* Initialize the history structures. */
   rep_hist_init();
   /* Initialize the service cache. */
@@ -2684,6 +2685,8 @@ tor_main(int argc, char *argv[])
   }
 #endif
 
+  configure_backtrace_handler(NULL, get_version());
+
   update_approx_time(time(NULL));
   tor_threads_init();
   init_logging();





More information about the tor-commits mailing list