Skip to content

Commit

Permalink
Add support for windows inproc backend
Browse files Browse the repository at this point in the history
  • Loading branch information
eakoli committed Jun 16, 2020
1 parent f2c9589 commit 8d7a4fc
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 9 deletions.
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ endif()
if(SENTRY_BACKEND_BREAKPAD AND NOT LINUX)
message(FATAL_ERROR "The Breakpad backend is currently only supported on Linux")
endif()
if(SENTRY_BACKEND_INPROC AND WIN32)
message(FATAL_ERROR "The in-process backend is not supported on Windows")
endif()

message(STATUS "SENTRY_TRANSPORT=${SENTRY_TRANSPORT}")
message(STATUS "SENTRY_BACKEND=${SENTRY_BACKEND}")
Expand Down
96 changes: 91 additions & 5 deletions src/backends/sentry_backend_inproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
Sig, #Sig, Desc \
}

#define MAX_FRAMES 128

#ifdef SENTRY_PLATFORM_UNIX
struct signal_slot {
int signum;
const char *signame;
const char *sigdesc;
};

#define MAX_FRAMES 128

// we need quite a bit of space for backtrace generation
#define SIGNAL_COUNT 6
#define SIGNAL_STACK_SIZE 65536
# define SIGNAL_COUNT 6
# define SIGNAL_STACK_SIZE 65536
static struct sigaction g_sigaction;
static struct sigaction g_previous_handlers[SIGNAL_COUNT];
static stack_t g_signal_stack;
Expand All @@ -41,6 +42,8 @@ static const struct signal_slot SIGNAL_DEFINITIONS[SIGNAL_COUNT] = {
SIGNAL_DEF(SIGSEGV, "Segfault"),
};

static void handle_signal(int signum, siginfo_t *info, void *user_context);

static void
reset_signal_handlers(void)
{
Expand Down Expand Up @@ -102,6 +105,60 @@ shutdown_inproc_backend(sentry_backend_t *UNUSED(backend))
sentry_free(g_signal_stack.ss_sp);
}

#elif defined SENTRY_PLATFORM_WINDOWS
struct signal_slot {
DWORD signum;
const char *signame;
const char *sigdesc;
};

# define SIGNAL_COUNT 20

static LPTOP_LEVEL_EXCEPTION_FILTER g_previous_handler = NULL;

static const struct signal_slot SIGNAL_DEFINITIONS[SIGNAL_COUNT] = {
SIGNAL_DEF(EXCEPTION_ACCESS_VIOLATION, "AccessViolation"),
SIGNAL_DEF(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "ArrayBoundsExceeded"),
SIGNAL_DEF(EXCEPTION_BREAKPOINT, "BreakPoint"),
SIGNAL_DEF(EXCEPTION_DATATYPE_MISALIGNMENT, "DatatypeMisalignment"),
SIGNAL_DEF(EXCEPTION_FLT_DENORMAL_OPERAND, "FloatDenormalOperand"),
SIGNAL_DEF(EXCEPTION_FLT_DIVIDE_BY_ZERO, "FloatDivideByZero"),
SIGNAL_DEF(EXCEPTION_FLT_INEXACT_RESULT, "FloatInexactResult"),
SIGNAL_DEF(EXCEPTION_FLT_INVALID_OPERATION, "FloatInvalidOperation"),
SIGNAL_DEF(EXCEPTION_FLT_OVERFLOW, "FloatOverflow"),
SIGNAL_DEF(EXCEPTION_FLT_STACK_CHECK, "FloatStackCheck"),
SIGNAL_DEF(EXCEPTION_FLT_UNDERFLOW, "FloatUnderflow"),
SIGNAL_DEF(EXCEPTION_ILLEGAL_INSTRUCTION, "IllegalInstruction"),
SIGNAL_DEF(EXCEPTION_IN_PAGE_ERROR, "InPageError"),
SIGNAL_DEF(EXCEPTION_INT_DIVIDE_BY_ZERO, "IntegerDivideByZero"),
SIGNAL_DEF(EXCEPTION_INT_OVERFLOW, "IntegerOverflow"),
SIGNAL_DEF(EXCEPTION_INVALID_DISPOSITION, "InvalidDisposition"),
SIGNAL_DEF(EXCEPTION_NONCONTINUABLE_EXCEPTION, "NonContinuableException"),
SIGNAL_DEF(EXCEPTION_PRIV_INSTRUCTION, "PrivilgedInstruction"),
SIGNAL_DEF(EXCEPTION_SINGLE_STEP, "SingleStep"),
SIGNAL_DEF(EXCEPTION_STACK_OVERFLOW, "StackOverflow")
};

static LONG WINAPI handle_exception(EXCEPTION_POINTERS *);

static void
startup_inproc_backend(sentry_backend_t *UNUSED(backend))
{
g_previous_handler = SetUnhandledExceptionFilter(&handle_exception);
SetErrorMode(SEM_FAILCRITICALERRORS);
}

static void
shutdown_inproc_backend(sentry_backend_t *UNUSED(backend))
{
LPTOP_LEVEL_EXCEPTION_FILTER current_handler
= SetUnhandledExceptionFilter(g_previous_handler);
if (current_handler != &handle_exception) {
SetUnhandledExceptionFilter(current_handler);
}
}
#endif

static sentry_value_t
make_signal_event(
const struct signal_slot *sig_slot, const sentry_ucontext_t *uctx)
Expand Down Expand Up @@ -140,7 +197,7 @@ make_signal_event(
void *backtrace[MAX_FRAMES];
size_t frame_count
= sentry_unwind_stack_from_ucontext(uctx, &backtrace[0], MAX_FRAMES);
SENTRY_TRACEF("captured backtrace with %zu frames", frame_count);
SENTRY_TRACEF("captured backtrace with %lu frames", frame_count);

sentry_value_t frames = sentry__value_new_list_with_size(frame_count);
for (size_t i = 0; i < frame_count; i++) {
Expand Down Expand Up @@ -169,18 +226,27 @@ handle_ucontext(const sentry_ucontext_t *uctx)
{
const struct signal_slot *sig_slot = NULL;
for (int i = 0; i < SIGNAL_COUNT; ++i) {
#ifdef SENTRY_PLATFORM_UNIX
if (SIGNAL_DEFINITIONS[i].signum == uctx->signum) {
#elif defined SENTRY_PLATFORM_WINDOWS
if (SIGNAL_DEFINITIONS[i].signum
== uctx->exception_ptrs.ExceptionRecord->ExceptionCode) {
#else
# error Unsupported platform
#endif
sig_slot = &SIGNAL_DEFINITIONS[i];
}
}

#ifdef SENTRY_PLATFORM_UNIX
// give us an allocator we can use safely in signals before we tear down.
sentry__page_allocator_enable();

// inform the sentry_sync system that we're in a signal handler. This will
// make mutexes spin on a spinlock instead as it's no longer safe to use a
// pthread mutex.
sentry__enter_signal_handler();
#endif

const sentry_options_t *opts = sentry_get_options();
sentry__write_crash_marker(opts);
Expand All @@ -203,6 +269,7 @@ handle_ucontext(const sentry_ucontext_t *uctx)
}
SENTRY_DEBUG("crash has been captured");

#ifdef SENTRY_PLATFORM_UNIX
// reset signal handlers and invoke the original ones. This will then tear
// down the process. In theory someone might have some other handler here
// which recovers the process but this will cause a memory leak going
Expand All @@ -211,8 +278,10 @@ handle_ucontext(const sentry_ucontext_t *uctx)
sentry__leave_signal_handler();
invoke_signal_handler(
uctx->signum, uctx->siginfo, (void *)uctx->user_context);
#endif
}

#ifdef SENTRY_PLATFORM_UNIX
static void
handle_signal(int signum, siginfo_t *info, void *user_context)
{
Expand All @@ -222,6 +291,23 @@ handle_signal(int signum, siginfo_t *info, void *user_context)
uctx.user_context = (ucontext_t *)user_context;
handle_ucontext(&uctx);
}
#elif defined SENTRY_PLATFORM_WINDOWS
static LONG WINAPI
handle_exception(EXCEPTION_POINTERS *ExceptionInfo)
{
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT
|| ExceptionInfo->ExceptionRecord->ExceptionCode
== EXCEPTION_SINGLE_STEP) {
return EXCEPTION_CONTINUE_SEARCH;
}

sentry_ucontext_t uctx;
memset(&uctx, 0, sizeof(uctx));
uctx.exception_ptrs = *ExceptionInfo;
handle_ucontext(&uctx);
return EXCEPTION_CONTINUE_SEARCH;
}
#endif

static void
handle_except(sentry_backend_t *UNUSED(backend), const sentry_ucontext_t *uctx)
Expand Down
2 changes: 1 addition & 1 deletion tests/conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
has_crashpad = sys.platform != "linux" and not is_android
# 32-bit linux has no proper curl support
has_http = not is_android and not is_x86
has_inproc = sys.platform != "win32"
has_inproc = True
has_breakpad = sys.platform == "linux"
# android has no local filesystem
has_files = not is_android

0 comments on commit 8d7a4fc

Please sign in to comment.