mirror of
https://github.com/cofyc/dnscrypt-wrapper.git
synced 2024-10-03 22:58:01 +03:00
Add debug facilities to log stack trace in case of segment fault.
This commit is contained in:
parent
fc8126da47
commit
1af1f602ea
3
Makefile
3
Makefile
@ -7,7 +7,7 @@ all::
|
|||||||
|
|
||||||
### Defaults
|
### Defaults
|
||||||
|
|
||||||
BASIC_CFLAGS = -O2 -std=c99 -pedantic -Wall -I./argparse
|
BASIC_CFLAGS = -O2 -std=c99 -Wall -I./argparse
|
||||||
BASIC_LDFLAGS = -lm -lsodium
|
BASIC_LDFLAGS = -lm -lsodium
|
||||||
|
|
||||||
# Guard against environment variables
|
# Guard against environment variables
|
||||||
@ -86,6 +86,7 @@ LIB_OBJS += rfc1035.o
|
|||||||
LIB_OBJS += safe_rw.o
|
LIB_OBJS += safe_rw.o
|
||||||
LIB_OBJS += cert.o
|
LIB_OBJS += cert.o
|
||||||
LIB_OBJS += pidfile.o
|
LIB_OBJS += pidfile.o
|
||||||
|
LIB_OBJS += debug.o
|
||||||
|
|
||||||
DEP_LIBS += argparse/libargparse.a
|
DEP_LIBS += argparse/libargparse.a
|
||||||
|
|
||||||
|
15
compat.h
15
compat.h
@ -43,4 +43,19 @@
|
|||||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[1]))
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[1]))
|
||||||
#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1])
|
#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1])
|
||||||
|
|
||||||
|
/* Test for backtrace() */
|
||||||
|
#if defined(__APPLE__) || defined(__linux__)
|
||||||
|
#define HAVE_BACKTRACE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__OpenBSD__)
|
||||||
|
#define _XOPEN_SOURCE 700
|
||||||
|
/*
|
||||||
|
* * On NetBSD, _XOPEN_SOURCE undefines _NETBSD_SOURCE and
|
||||||
|
* * thus hides inet_aton etc.
|
||||||
|
* */
|
||||||
|
#elif !defined(__NetBSD__)
|
||||||
|
#define _XOPEN_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
110
debug.c
Normal file
110
debug.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include "debug.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
static char *assert_err = "<no assertion failed>";
|
||||||
|
static char *assert_file = "<no file>";
|
||||||
|
static int assert_line = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
_debug_assert(char *err, char *file, int line)
|
||||||
|
{
|
||||||
|
logger(LOG_WARNING, "=== ASSERTION FAILED ===");
|
||||||
|
logger(LOG_WARNING, "%s:%d '%s' is not true", file, line, err);
|
||||||
|
assert_err = err;
|
||||||
|
assert_file = file;
|
||||||
|
assert_line = line;
|
||||||
|
// force SIGSEGV to print the bug report
|
||||||
|
*((char *)-1) = 'x';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_init(void)
|
||||||
|
{
|
||||||
|
struct sigaction act;
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
act.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
|
||||||
|
act.sa_sigaction = debug_segv_handler;
|
||||||
|
sigaction(SIGSEGV, &act, NULL);
|
||||||
|
sigaction(SIGBUS, &act, NULL);
|
||||||
|
sigaction(SIGFPE, &act, NULL);
|
||||||
|
sigaction(SIGILL, &act, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BACKTRACE
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
static void *
|
||||||
|
getMcontextEip(ucontext_t *uc)
|
||||||
|
{
|
||||||
|
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
|
||||||
|
/* OSX < 10.6 */
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
return (void *) uc->uc_mcontext->__ss.__rip;
|
||||||
|
#elif defined(__i386__)
|
||||||
|
return (void *) uc->uc_mcontext->__ss.__eip;
|
||||||
|
#else
|
||||||
|
return (void *) uc->uc_mcontext->__ss.__srr0;
|
||||||
|
#endif
|
||||||
|
#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
||||||
|
/* OSX >= 10.6 */
|
||||||
|
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
||||||
|
return (void *) uc->uc_mcontext->__ss.__rip;
|
||||||
|
#else
|
||||||
|
return (void *) uc->uc_mcontext->__ss.__eip;
|
||||||
|
#endif
|
||||||
|
#elif defined(__linux__)
|
||||||
|
/* Linux */
|
||||||
|
#if defined(__i386__)
|
||||||
|
return (void *) uc->uc_mcontext.gregs[14]; /* Linux 32 */
|
||||||
|
#elif defined(__X86_64__) || defined(__x86_64__)
|
||||||
|
return (void *) uc->uc_mcontext.gregs[16]; /* Linux 64 */
|
||||||
|
#elif defined(__ia64__) /* Linux IA64 */
|
||||||
|
return (void *) uc->uc_mcontext.sc_ip;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the stack trace using the backtrace() call. This function is designed to
|
||||||
|
* be called from signal handlers safely.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
log_stack_trace(ucontext_t *uc)
|
||||||
|
{
|
||||||
|
void *trace[100];
|
||||||
|
int trace_size = 0;
|
||||||
|
int fd = logger_fd >= 0 ? logger_fd : STDOUT_FILENO;
|
||||||
|
/* Generate the stack trace */
|
||||||
|
trace_size = backtrace(trace, 100);
|
||||||
|
/* overwrite sigaction with caller's address */
|
||||||
|
if (getMcontextEip(uc) != NULL)
|
||||||
|
trace[1] = getMcontextEip(uc);
|
||||||
|
|
||||||
|
backtrace_symbols_fd(trace, trace_size, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_segv_handler(int sig, siginfo_t *info, void *secret)
|
||||||
|
{
|
||||||
|
logger(LOG_WARNING, "Crashed by signal: %d", sig);
|
||||||
|
logger(LOG_WARNING, "--- STACK TRACE");
|
||||||
|
logger(LOG_WARNING, "Failed assertion: %s (%s:%d)", assert_err, assert_file,
|
||||||
|
assert_line);
|
||||||
|
#ifdef HAVE_BACKTRACE
|
||||||
|
logger(LOG_WARNING, "--- STACK TRACE");
|
||||||
|
ucontext_t *uc = (ucontext_t *) secret;
|
||||||
|
log_stack_trace(uc);
|
||||||
|
#endif
|
||||||
|
/* Make sure we exit with the right signal at the end. So for instance
|
||||||
|
* the core will be dumped if enabled. */
|
||||||
|
struct sigaction act;
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
|
||||||
|
act.sa_handler = SIG_DFL;
|
||||||
|
sigaction(sig, &act, NULL);
|
||||||
|
kill(getpid(), sig);
|
||||||
|
}
|
15
debug.h
Normal file
15
debug.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef DEBUG_H
|
||||||
|
#define DEBUG_H
|
||||||
|
/**
|
||||||
|
* Debug facilities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
#define debug_assert(e) ((e) ? (void)0 : (_debug_assert(#e, __FILE__, __LINE__), _exit(1)))
|
||||||
|
void _debug_assert(char *err, char *file, int line);
|
||||||
|
|
||||||
|
void debug_init(void);
|
||||||
|
void debug_segv_handler(int sig, siginfo_t *info, void *secret);
|
||||||
|
|
||||||
|
#endif
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "debug.h"
|
||||||
#include <event2/event.h>
|
#include <event2/event.h>
|
||||||
#include <event2/listener.h>
|
#include <event2/listener.h>
|
||||||
#include <event2/bufferevent.h>
|
#include <event2/bufferevent.h>
|
||||||
|
94
logger.c
94
logger.c
@ -1,34 +1,33 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "compat.h"
|
|
||||||
|
|
||||||
int logger_verbosity = LOG_DEBUG;
|
int logger_verbosity = LOG_INFO;
|
||||||
char *logger_logfile = NULL;
|
char *logger_logfile = NULL;
|
||||||
|
int logger_fd = -1;
|
||||||
|
|
||||||
// prioritynames (from <syslog.h>)
|
#define LOGGER_LINESIZE 1024
|
||||||
#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */
|
|
||||||
|
// priority names (from <syslog.h>)
|
||||||
|
#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */
|
||||||
typedef struct _code {
|
typedef struct _code {
|
||||||
const char *c_name;
|
const char *c_name;
|
||||||
int c_val;
|
int c_val;
|
||||||
} CODE;
|
} CODE;
|
||||||
|
|
||||||
CODE prioritynames[] = {
|
CODE prioritynames[] = {
|
||||||
{"alert", LOG_ALERT,},
|
{"emerg", LOG_EMERG},
|
||||||
{"crit", LOG_CRIT,},
|
{"alert", LOG_ALERT},
|
||||||
{"debug", LOG_DEBUG,},
|
{"crit", LOG_CRIT},
|
||||||
{"emerg", LOG_EMERG,},
|
{"err", LOG_ERR},
|
||||||
{"err", LOG_ERR,},
|
{"warning", LOG_WARNING},
|
||||||
{"error", LOG_ERR,}, /* DEPRECATED */
|
{"notice", LOG_NOTICE},
|
||||||
{"info", LOG_INFO,},
|
{"info", LOG_INFO},
|
||||||
{"none", INTERNAL_NOPRI,}, /* INTERNAL */
|
{"debug", LOG_DEBUG},
|
||||||
{"notice", LOG_NOTICE,},
|
{"none", INTERNAL_NOPRI}, /* INTERNAL */
|
||||||
{"panic", LOG_EMERG,}, /* DEPRECATED */
|
{NULL, -1}
|
||||||
{"warn", LOG_WARNING,}, /* DEPRECATED */
|
|
||||||
{"warning", LOG_WARNING,},
|
|
||||||
{NULL, -1,}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
logger(int priority, const char *fmt, ...)
|
_logger(int priority, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char msg[LOGGER_MAXLEN];
|
char msg[LOGGER_MAXLEN];
|
||||||
@ -43,7 +42,26 @@ logger(int priority, const char *fmt, ...)
|
|||||||
logger_lograw(priority, msg);
|
logger_lograw(priority, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void
|
||||||
|
_logger_with_fileline(int priority, const char *fmt, const char *file, int line,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char msg[LOGGER_MAXLEN];
|
||||||
|
|
||||||
|
if (priority > logger_verbosity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t n = snprintf(msg, sizeof(msg), "[%s:%d] ", file, line);
|
||||||
|
|
||||||
|
va_start(ap, line);
|
||||||
|
vsnprintf(msg + n, sizeof(msg), fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
logger_lograw(priority, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
* Low-level logging. It's only used when you want to log arbitrary length message.
|
* Low-level logging. It's only used when you want to log arbitrary length message.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -59,6 +77,12 @@ logger_lograw(int priority, const char *msg)
|
|||||||
if (priority < 0 || priority > LOG_PRIMASK)
|
if (priority < 0 || priority > LOG_PRIMASK)
|
||||||
priority = INTERNAL_NOPRI;
|
priority = INTERNAL_NOPRI;
|
||||||
|
|
||||||
|
if (logger_fd < 0) {
|
||||||
|
logger_reopen();
|
||||||
|
}
|
||||||
|
if (logger_fd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
fp = (logger_logfile == NULL) ? stdout : fopen(logger_logfile, "a");
|
fp = (logger_logfile == NULL) ? stdout : fopen(logger_logfile, "a");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return;
|
return;
|
||||||
@ -69,16 +93,38 @@ logger_lograw(int priority, const char *msg)
|
|||||||
priority_flag = c.c_name;
|
priority_flag = c.c_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert(priority_flag);
|
||||||
|
|
||||||
|
// prefix
|
||||||
int off;
|
int off;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
char buf[64];
|
char buf[64];
|
||||||
off = strftime(buf, sizeof(buf), "%d %b %H:%M:%S.", localtime(&tv.tv_sec));
|
off = strftime(buf, sizeof(buf), "%d %b %H:%M:%S.", localtime(&tv.tv_sec));
|
||||||
snprintf(buf + off, sizeof(buf) - off, "%03d", (int)tv.tv_usec / 1000);
|
snprintf(buf + off, sizeof(buf) - off, "%03d", (int)tv.tv_usec / 1000);
|
||||||
fprintf(fp, "[%d] %s [%s] %s\n", (int)getpid(), buf, priority_flag, msg);
|
// format log
|
||||||
fflush(fp);
|
char logbuf[LOGGER_LINESIZE];
|
||||||
|
size_t len = snprintf(logbuf, LOGGER_LINESIZE, "[%d] %s [%s] %s\n",
|
||||||
if (logger_logfile)
|
(int)getpid(), buf, priority_flag, msg);
|
||||||
fclose(fp);
|
// write
|
||||||
|
write(logger_fd, logbuf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logger_reopen(void)
|
||||||
|
{
|
||||||
|
if (logger_logfile) {
|
||||||
|
logger_fd = open(logger_logfile, O_APPEND | O_CREAT | O_WRONLY, 0644);
|
||||||
|
} else {
|
||||||
|
logger_fd = STDOUT_FILENO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logger_close(void)
|
||||||
|
{
|
||||||
|
if (logger_fd >= 0) {
|
||||||
|
close(logger_fd);
|
||||||
|
}
|
||||||
|
logger_fd = -1;
|
||||||
}
|
}
|
||||||
|
17
logger.h
17
logger.h
@ -1,5 +1,12 @@
|
|||||||
#ifndef LOGGER_H
|
#ifndef LOGGER_H
|
||||||
#define LOGGER_H
|
#define LOGGER_H
|
||||||
|
/**
|
||||||
|
* Logger
|
||||||
|
*
|
||||||
|
* @link http://en.wikipedia.org/wiki/Syslog
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
@ -21,7 +28,15 @@
|
|||||||
extern int logger_verbosity;
|
extern int logger_verbosity;
|
||||||
extern char *logger_logfile;
|
extern char *logger_logfile;
|
||||||
|
|
||||||
void logger(int priority, const char *fmt, ...);
|
/* Global Variables. */
|
||||||
|
extern int logger_fd;
|
||||||
|
|
||||||
|
// see http://stackoverflow.com/q/5588855/288089
|
||||||
|
#define logger(p, fmt, ...) _logger_with_fileline((p), (fmt), __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
void _logger(int priority, const char *fmt, ...);
|
||||||
|
void _logger_with_fileline(int priority, const char *fmt, const char *file, int line, ...);
|
||||||
void logger_lograw(int priority, const char *msg);
|
void logger_lograw(int priority, const char *msg);
|
||||||
|
void logger_reopen(void);
|
||||||
|
void logger_close(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
2
main.c
2
main.c
@ -235,6 +235,8 @@ main(int argc, const char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_init();
|
||||||
|
|
||||||
if (gen_provider_keypair) {
|
if (gen_provider_keypair) {
|
||||||
uint8_t provider_publickey[crypto_sign_ed25519_PUBLICKEYBYTES];
|
uint8_t provider_publickey[crypto_sign_ed25519_PUBLICKEYBYTES];
|
||||||
uint8_t provider_secretkey[crypto_sign_ed25519_SECRETKEYBYTES];
|
uint8_t provider_secretkey[crypto_sign_ed25519_SECRETKEYBYTES];
|
||||||
|
Loading…
Reference in New Issue
Block a user