backtrace: Add DbgHelp based Windows support for creating/printing backtraces
This commit is contained in:
@@ -272,6 +272,7 @@ ARG_DISBL_SET([tools], [disable additional utilities (scepclient and pk
|
|||||||
ARG_ENABL_SET([aikgen], [enable AIK generator.])
|
ARG_ENABL_SET([aikgen], [enable AIK generator.])
|
||||||
# optional features
|
# optional features
|
||||||
ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
|
ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
|
||||||
|
ARG_ENABL_SET([dbghelp-backtraces],[use dbghlp.dll on Windows to create and print backtraces for memory leaks and segfaults.])
|
||||||
ARG_DISBL_SET([ikev1], [disable IKEv1 protocol support in charon.])
|
ARG_DISBL_SET([ikev1], [disable IKEv1 protocol support in charon.])
|
||||||
ARG_DISBL_SET([ikev2], [disable IKEv2 protocol support in charon.])
|
ARG_DISBL_SET([ikev2], [disable IKEv2 protocol support in charon.])
|
||||||
ARG_ENABL_SET([integrity-test], [enable integrity testing of libstrongswan and plugins.])
|
ARG_ENABL_SET([integrity-test], [enable integrity testing of libstrongswan and plugins.])
|
||||||
@@ -1410,6 +1411,7 @@ AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers -o x$aikgen = xtrue)
|
|||||||
AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
|
AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
|
||||||
AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes)
|
AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes)
|
||||||
AM_CONDITIONAL(COVERAGE, test x$coverage = xtrue)
|
AM_CONDITIONAL(COVERAGE, test x$coverage = xtrue)
|
||||||
|
AM_CONDITIONAL(USE_DBGHELP, test x$dbghelp_backtraces = xtrue)
|
||||||
AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
|
AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
|
||||||
AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue)
|
AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue)
|
||||||
AM_CONDITIONAL(USE_AIKGEN, test x$aikgen = xtrue)
|
AM_CONDITIONAL(USE_AIKGEN, test x$aikgen = xtrue)
|
||||||
|
|||||||
@@ -114,6 +114,11 @@ if USE_WINDOWS
|
|||||||
libstrongswan_la_LIBADD += -lws2_32
|
libstrongswan_la_LIBADD += -lws2_32
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_DBGHELP
|
||||||
|
libstrongswan_la_LIBADD += -ldbghelp
|
||||||
|
AM_CPPFLAGS += -DHAVE_DBGHELP
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_LEAK_DETECTIVE
|
if USE_LEAK_DETECTIVE
|
||||||
AM_CPPFLAGS += -DLEAK_DETECTIVE
|
AM_CPPFLAGS += -DLEAK_DETECTIVE
|
||||||
libstrongswan_la_SOURCES += utils/leak_detective.c
|
libstrongswan_la_SOURCES += utils/leak_detective.c
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2006-2008 Martin Willi
|
* Copyright (C) 2006-2013 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
|
* Copyright (C) 2013 revosec AG
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the
|
* under the terms of the GNU General Public License as published by the
|
||||||
@@ -15,14 +16,14 @@
|
|||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#ifdef HAVE_DLADDR
|
|
||||||
# include <dlfcn.h>
|
|
||||||
#endif /* HAVE_DLADDR */
|
|
||||||
|
|
||||||
#ifdef HAVE_BACKTRACE
|
#ifdef HAVE_BACKTRACE
|
||||||
# include <execinfo.h>
|
# include <execinfo.h>
|
||||||
#endif /* HAVE_BACKTRACE */
|
#endif /* HAVE_BACKTRACE */
|
||||||
|
#ifdef HAVE_DBGHELP
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <windows.h>
|
||||||
|
# include <dbghelp.h>
|
||||||
|
#endif /* HAVE_DBGHELP */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
@@ -81,6 +82,8 @@ static void println(FILE *file, char *format, ...)
|
|||||||
|
|
||||||
#ifdef HAVE_DLADDR
|
#ifdef HAVE_DLADDR
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as tty_escape_get(), but for a potentially NULL FILE*
|
* Same as tty_escape_get(), but for a potentially NULL FILE*
|
||||||
*/
|
*/
|
||||||
@@ -375,7 +378,30 @@ static void print_sourceline(FILE *file, char *filename, void *ptr, void* base)
|
|||||||
|
|
||||||
#endif /* HAVE_BFD_H */
|
#endif /* HAVE_BFD_H */
|
||||||
|
|
||||||
#else /* !HAVE_DLADDR */
|
#elif defined(HAVE_DBGHELP) /* && !HAVE_DLADDR */
|
||||||
|
|
||||||
|
#include <dbghelp.h>
|
||||||
|
#include <threading/mutex.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex to access non-thread-safe dbghelp functions
|
||||||
|
*/
|
||||||
|
static mutex_t *dbghelp_mutex;
|
||||||
|
|
||||||
|
void backtrace_init()
|
||||||
|
{
|
||||||
|
SymSetOptions(SYMOPT_LOAD_LINES);
|
||||||
|
SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
||||||
|
dbghelp_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void backtrace_deinit()
|
||||||
|
{
|
||||||
|
dbghelp_mutex->destroy(dbghelp_mutex);
|
||||||
|
SymCleanup(GetCurrentProcess());
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !HAVE_DLADDR && !HAVE_DBGHELP */
|
||||||
|
|
||||||
void backtrace_init() {}
|
void backtrace_init() {}
|
||||||
void backtrace_deinit() {}
|
void backtrace_deinit() {}
|
||||||
@@ -385,7 +411,7 @@ void backtrace_deinit() {}
|
|||||||
METHOD(backtrace_t, log_, void,
|
METHOD(backtrace_t, log_, void,
|
||||||
private_backtrace_t *this, FILE *file, bool detailed)
|
private_backtrace_t *this, FILE *file, bool detailed)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H)
|
#if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H) || defined(HAVE_DBGHELP)
|
||||||
size_t i;
|
size_t i;
|
||||||
char **strings = NULL;
|
char **strings = NULL;
|
||||||
|
|
||||||
@@ -425,7 +451,64 @@ METHOD(backtrace_t, log_, void,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif /* HAVE_DLADDR */
|
#elif defined(HAVE_DBGHELP)
|
||||||
|
struct {
|
||||||
|
SYMBOL_INFO hdr;
|
||||||
|
char buf[128];
|
||||||
|
} symbol;
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
HINSTANCE module;
|
||||||
|
HANDLE process;
|
||||||
|
DWORD64 displace, frame;
|
||||||
|
|
||||||
|
process = GetCurrentProcess();
|
||||||
|
frame = (uintptr_t)this->frames[i];
|
||||||
|
|
||||||
|
memset(&symbol, 0, sizeof(symbol));
|
||||||
|
symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
|
||||||
|
symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
|
||||||
|
|
||||||
|
dbghelp_mutex->lock(dbghelp_mutex);
|
||||||
|
|
||||||
|
module = (HINSTANCE)SymGetModuleBase64(process, frame);
|
||||||
|
|
||||||
|
if (module && GetModuleFileName(module, filename, sizeof(filename)))
|
||||||
|
{
|
||||||
|
if (SymFromAddr(process, frame, &displace, &symbol.hdr) &&
|
||||||
|
symbol.hdr.Name)
|
||||||
|
{
|
||||||
|
println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
|
||||||
|
esc(file, TTY_FG_YELLOW), filename,
|
||||||
|
esc(file, TTY_FG_DEF), (void*)module,
|
||||||
|
esc(file, TTY_FG_RED), symbol.hdr.Name,
|
||||||
|
esc(file, TTY_FG_DEF), displace,
|
||||||
|
this->frames[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println(file, " %s%s%s @ %p [%p]",
|
||||||
|
esc(file, TTY_FG_YELLOW), filename,
|
||||||
|
esc(file, TTY_FG_DEF), (void*)module, this->frames[i]);
|
||||||
|
}
|
||||||
|
if (detailed)
|
||||||
|
{
|
||||||
|
IMAGEHLP_LINE64 line;
|
||||||
|
DWORD off;
|
||||||
|
|
||||||
|
memset(&line, 0, sizeof(line));
|
||||||
|
line.SizeOfStruct = sizeof(line);
|
||||||
|
|
||||||
|
if (SymGetLineFromAddr64(process, frame, &off, &line))
|
||||||
|
{
|
||||||
|
|
||||||
|
println(file, " -> %s%s:%u%s", esc(file, TTY_FG_GREEN),
|
||||||
|
line.FileName, line.LineNumber,
|
||||||
|
esc(file, TTY_FG_DEF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* HAVE_DLADDR/HAVE_DBGHELP */
|
||||||
{
|
{
|
||||||
#ifdef HAVE_BACKTRACE
|
#ifdef HAVE_BACKTRACE
|
||||||
if (!strings)
|
if (!strings)
|
||||||
@@ -442,10 +525,13 @@ METHOD(backtrace_t, log_, void,
|
|||||||
println(file, " %p", this->frames[i]);
|
println(file, " %p", this->frames[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_DBGHELP
|
||||||
|
dbghelp_mutex->unlock(dbghelp_mutex);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
free(strings);
|
free(strings);
|
||||||
#else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
|
#else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
|
||||||
println(file, "no support for backtrace()/libunwind");
|
println(file, "no support for capturing backtraces");
|
||||||
#endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
|
#endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +556,43 @@ METHOD(backtrace_t, contains_function, bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* HAVE_DLADDR */
|
#elif defined(HAVE_DBGHELP)
|
||||||
|
int i, j;
|
||||||
|
HANDLE process;
|
||||||
|
|
||||||
|
process = GetCurrentProcess();
|
||||||
|
|
||||||
|
dbghelp_mutex->lock(dbghelp_mutex);
|
||||||
|
|
||||||
|
for (i = 0; i < this->frame_count; i++)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
SYMBOL_INFO hdr;
|
||||||
|
char buf[128];
|
||||||
|
} symbol;
|
||||||
|
|
||||||
|
memset(&symbol, 0, sizeof(symbol));
|
||||||
|
symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
|
||||||
|
symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
|
||||||
|
|
||||||
|
if (SymFromAddr(process, (DWORD64)this->frames[i], NULL, &symbol.hdr))
|
||||||
|
{
|
||||||
|
if (symbol.hdr.Name)
|
||||||
|
{
|
||||||
|
for (j = 0; j < count; j++)
|
||||||
|
{
|
||||||
|
if (streq(symbol.hdr.Name, function[j]))
|
||||||
|
{
|
||||||
|
dbghelp_mutex->unlock(dbghelp_mutex);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbghelp_mutex->unlock(dbghelp_mutex);
|
||||||
|
#endif /* HAVE_DLADDR/HAVE_DBGHELP */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,6 +706,65 @@ static inline int backtrace_unwind(void **frames, int count)
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_UNWIND */
|
#endif /* HAVE_UNWIND */
|
||||||
|
|
||||||
|
#ifdef HAVE_DBGHELP
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Windows variant for glibc backtrace()
|
||||||
|
*/
|
||||||
|
static inline int backtrace_win(void **frames, int count)
|
||||||
|
{
|
||||||
|
STACKFRAME frame;
|
||||||
|
HANDLE process, thread;
|
||||||
|
DWORD machine;
|
||||||
|
CONTEXT context;
|
||||||
|
int got = 0;
|
||||||
|
|
||||||
|
memset(&frame, 0, sizeof(frame));
|
||||||
|
memset(&context, 0, sizeof(context));
|
||||||
|
|
||||||
|
process = GetCurrentProcess();
|
||||||
|
thread = GetCurrentThread();
|
||||||
|
|
||||||
|
#ifdef __x86_64
|
||||||
|
machine = IMAGE_FILE_MACHINE_AMD64;
|
||||||
|
|
||||||
|
frame.AddrPC.Offset = context.Rip;
|
||||||
|
frame.AddrPC.Mode = AddrModeFlat;
|
||||||
|
frame.AddrStack.Offset = context.Rsp;
|
||||||
|
frame.AddrStack.Mode = AddrModeFlat;
|
||||||
|
frame.AddrFrame.Offset = context.Rbp;
|
||||||
|
frame.AddrFrame.Mode = AddrModeFlat;
|
||||||
|
#else /* x86 */
|
||||||
|
machine = IMAGE_FILE_MACHINE_I386;
|
||||||
|
|
||||||
|
frame.AddrPC.Offset = context.Eip;
|
||||||
|
frame.AddrPC.Mode = AddrModeFlat;
|
||||||
|
frame.AddrStack.Offset = context.Esp;
|
||||||
|
frame.AddrStack.Mode = AddrModeFlat;
|
||||||
|
frame.AddrFrame.Offset = context.Ebp;
|
||||||
|
frame.AddrFrame.Mode = AddrModeFlat;
|
||||||
|
#endif /* x86_64/x86 */
|
||||||
|
|
||||||
|
dbghelp_mutex->lock(dbghelp_mutex);
|
||||||
|
|
||||||
|
RtlCaptureContext(&context);
|
||||||
|
|
||||||
|
while (got < count)
|
||||||
|
{
|
||||||
|
if (!StackWalk64(machine, process, thread, &frame, &context,
|
||||||
|
NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
frames[got++] = (void*)frame.AddrPC.Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbghelp_mutex->unlock(dbghelp_mutex);
|
||||||
|
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_DBGHELP */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get implementation methods of backtrace_t
|
* Get implementation methods of backtrace_t
|
||||||
*/
|
*/
|
||||||
@@ -612,7 +793,9 @@ backtrace_t *backtrace_create(int skip)
|
|||||||
frame_count = backtrace_unwind(frames, countof(frames));
|
frame_count = backtrace_unwind(frames, countof(frames));
|
||||||
#elif defined(HAVE_BACKTRACE)
|
#elif defined(HAVE_BACKTRACE)
|
||||||
frame_count = backtrace(frames, countof(frames));
|
frame_count = backtrace(frames, countof(frames));
|
||||||
#endif /* HAVE_BACKTRACE */
|
#elif defined(HAVE_DBGHELP)
|
||||||
|
frame_count = backtrace_win(frames, countof(frames));
|
||||||
|
#endif
|
||||||
frame_count = max(frame_count - skip, 0);
|
frame_count = max(frame_count - skip, 0);
|
||||||
this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
|
this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
|
||||||
memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
|
memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
|
||||||
|
|||||||
Reference in New Issue
Block a user