diff options
Diffstat (limited to 'src/common/backtrace.c')
-rw-r--r-- | src/common/backtrace.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/common/backtrace.c b/src/common/backtrace.c new file mode 100644 index 000000000..d3f59b2c7 --- /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); +} + |