mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 13:53:31 +01:00
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.
This commit is contained in:
parent
f6d8bc9389
commit
063bea58bc
6
changes/stack_trace
Normal file
6
changes/stack_trace
Normal file
@ -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.
|
||||
|
@ -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 \
|
||||
|
157
src/common/backtrace.c
Normal file
157
src/common/backtrace.c
Normal file
@ -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);
|
||||
}
|
||||
|
12
src/common/backtrace.h
Normal file
12
src/common/backtrace.h
Normal file
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user