From 6b9b05a89badb31c839c5b233f268bbb4c7ac01f Mon Sep 17 00:00:00 2001 From: cammm <81903+cammm@users.noreply.github.com> Date: Thu, 26 Mar 2020 19:03:58 -0700 Subject: [PATCH 1/5] New handle exception API Allows manually triggering of the backend given a completed ucontext --- include/sentry.h | 6 ++++++ src/backends/sentry_backend_breakpad.cpp | 9 +++++++++ src/backends/sentry_backend_crashpad.cpp | 9 +++++++++ src/backends/sentry_backend_inproc.c | 11 +++++++++-- src/sentry_backend.h | 2 ++ src/sentry_core.c | 8 ++++++++ 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index c52d28d2d..f7799ce9d 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -320,6 +320,7 @@ typedef struct sentry_ucontext_s { #ifdef _WIN32 EXCEPTION_POINTERS exception_ptrs; #else + int signum; siginfo_t *siginfo; ucontext_t *user_context; #endif @@ -650,6 +651,11 @@ SENTRY_API sentry_user_consent_t sentry_user_consent_get(void); */ SENTRY_API sentry_uuid_t sentry_capture_event(sentry_value_t event); +/* + * Captures an exception to be handled by the backend. + */ +SENTRY_API void sentry_handle_exception(sentry_ucontext_t *context); + /* * Adds the breadcrumb to be sent in case of an event. */ diff --git a/src/backends/sentry_backend_breakpad.cpp b/src/backends/sentry_backend_breakpad.cpp index 9091c05ec..e536a8150 100644 --- a/src/backends/sentry_backend_breakpad.cpp +++ b/src/backends/sentry_backend_breakpad.cpp @@ -146,6 +146,14 @@ sentry__breakpad_backend_shutdown(sentry_backend_t *backend) delete eh; } +static void sentry__breakpad_backend_except( + sentry_backend_t *UNUSED(backend), sentry_ucontext_t *context) +{ + google_breakpad::ExceptionHandler *eh + = (google_breakpad::ExceptionHandler *)backend->data; + eh->HandleSignal(context->signum, context->siginfo, context->user_context); +} + extern "C" { sentry_backend_t * @@ -158,6 +166,7 @@ sentry__backend_new(void) backend->startup_func = sentry__breakpad_backend_startup; backend->shutdown_func = sentry__breakpad_backend_shutdown; + backend->except_func = sentry__breakpad_backend_except; backend->free_func = NULL; backend->flush_scope_func = NULL; backend->add_breadcrumb_func = NULL; diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index 0a32cdd83..b672b085e 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -243,6 +243,14 @@ sentry__crashpad_backend_free(sentry_backend_t *backend) sentry_free(data); } +static void sentry__crashpad_backend_except( + sentry_backend_t *UNUSED(backend), sentry_ucontext_t *context) +{ +#ifdef SENTRY_PLATFORM_WINDOWS + crashpad::CrashpadClient::DumpAndCrash(&context->exception_ptrs); +#endif +} + sentry_backend_t * sentry__backend_new(void) { @@ -259,6 +267,7 @@ sentry__backend_new(void) backend->startup_func = sentry__crashpad_backend_startup; backend->shutdown_func = sentry__crashpad_backend_shutdown; + backend->except_func = sentry__crashpad_backend_except; backend->free_func = sentry__crashpad_backend_free; backend->flush_scope_func = sentry__crashpad_backend_flush_scope; backend->add_breadcrumb_func = sentry__crashpad_backend_add_breadcrumb; diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index 3d74b7bc5..05976aab1 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -150,12 +150,18 @@ static void handle_signal(int signum, siginfo_t *info, void *user_context) { sentry_ucontext_t uctx; + uctx.signum = signum; uctx.siginfo = info; uctx.user_context = (ucontext_t *)user_context; + handle_ucontext(&uctx); +} +static void +handle_ucontext(sentry_ucontext_t* uctx) +{ const struct signal_slot *sig_slot = NULL; for (int i = 0; i < SIGNAL_COUNT; ++i) { - if (SIGNAL_DEFINITIONS[i].signum == signum) { + if (SIGNAL_DEFINITIONS[i].signum == uctx->signum) { sig_slot = &SIGNAL_DEFINITIONS[i]; } } @@ -178,7 +184,7 @@ handle_signal(int signum, siginfo_t *info, void *user_context) // only dumps to disk at the moment. SENTRY_DEBUG("capturing event from signal"); sentry__end_current_session_with_status(SENTRY_SESSION_STATUS_CRASHED); - sentry_capture_event(make_signal_event(sig_slot, &uctx)); + sentry_capture_event(make_signal_event(sig_slot, uctx)); // after capturing the crash event, try to dump all the in-flight data of // the previous transport @@ -221,6 +227,7 @@ sentry__backend_new(void) backend->startup_func = startup_inproc_backend; backend->shutdown_func = NULL; + backend->except_func = handle_ucontext; backend->free_func = free_backend; backend->flush_scope_func = NULL; backend->add_breadcrumb_func = NULL; diff --git a/src/sentry_backend.h b/src/sentry_backend.h index bd25872cb..95ba05895 100644 --- a/src/sentry_backend.h +++ b/src/sentry_backend.h @@ -6,10 +6,12 @@ #include "sentry_scope.h" struct sentry_backend_s; +struct sentry_ucontext_s; typedef struct sentry_backend_s { void (*startup_func)(struct sentry_backend_s *); void (*shutdown_func)(struct sentry_backend_s *); void (*free_func)(struct sentry_backend_s *); + void (*except_func)(struct sentry_backend_s *, struct sentry_ucontext_s *); void (*flush_scope_func)( struct sentry_backend_s *, const sentry_scope_t *scope); void (*add_breadcrumb_func)( diff --git a/src/sentry_core.c b/src/sentry_core.c index 9c9ef0e1c..71cda9607 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -253,6 +253,14 @@ sentry_capture_event(sentry_value_t event) return event_id; } +void sentry_handle_exception(sentry_ucontext_t *context) +{ + SENTRY_DEBUG("handling exception"); + if (g_options->backend && g_options->backend->except_func) { + g_options->backend->except_func(g_options->backend, context); + } +} + sentry_options_t * sentry_options_new(void) { From 931cc6087a27321f0d70117b634732180561e691 Mon Sep 17 00:00:00 2001 From: cammm <81903+cammm@users.noreply.github.com> Date: Fri, 27 Mar 2020 08:38:32 -0700 Subject: [PATCH 2/5] Mark handle except as experimental --- include/sentry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sentry.h b/include/sentry.h index f7799ce9d..ef1eef4dd 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -654,7 +654,7 @@ SENTRY_API sentry_uuid_t sentry_capture_event(sentry_value_t event); /* * Captures an exception to be handled by the backend. */ -SENTRY_API void sentry_handle_exception(sentry_ucontext_t *context); +SENTRY_EXPERIMENTAL_API void sentry_handle_exception(sentry_ucontext_t *context); /* * Adds the breadcrumb to be sent in case of an event. From 8c2899a02d136702acb9301260f63ca7a77f22d6 Mon Sep 17 00:00:00 2001 From: cammm <81903+cammm@users.noreply.github.com> Date: Fri, 27 Mar 2020 09:03:17 -0700 Subject: [PATCH 3/5] Fixing compile errors on linux / mac --- src/backends/sentry_backend_breakpad.cpp | 2 +- src/backends/sentry_backend_inproc.c | 30 ++++++++++++++---------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/backends/sentry_backend_breakpad.cpp b/src/backends/sentry_backend_breakpad.cpp index e536a8150..0684246a1 100644 --- a/src/backends/sentry_backend_breakpad.cpp +++ b/src/backends/sentry_backend_breakpad.cpp @@ -147,7 +147,7 @@ sentry__breakpad_backend_shutdown(sentry_backend_t *backend) } static void sentry__breakpad_backend_except( - sentry_backend_t *UNUSED(backend), sentry_ucontext_t *context) + sentry_backend_t *backend, sentry_ucontext_t *context) { google_breakpad::ExceptionHandler *eh = (google_breakpad::ExceptionHandler *)backend->data; diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index 05976aab1..5e8cb794c 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -146,16 +146,6 @@ make_signal_event( return event; } -static void -handle_signal(int signum, siginfo_t *info, void *user_context) -{ - sentry_ucontext_t uctx; - uctx.signum = signum; - uctx.siginfo = info; - uctx.user_context = (ucontext_t *)user_context; - handle_ucontext(&uctx); -} - static void handle_ucontext(sentry_ucontext_t* uctx) { @@ -198,7 +188,23 @@ handle_ucontext(sentry_ucontext_t* uctx) // forward as we're not restoring the page allocator. reset_signal_handlers(); sentry__leave_signal_handler(); - invoke_signal_handler(signum, info, user_context); + invoke_signal_handler(uctx->signum, uctx->info, (void *)uctx->user_context); +} + +static void +handle_signal(int signum, siginfo_t *info, void *user_context) +{ + sentry_ucontext_t uctx; + uctx.signum = signum; + uctx.siginfo = info; + uctx.user_context = (ucontext_t *)user_context; + handle_ucontext(&uctx); +} + +static void handle_except( + sentry_backend_t *UNUSED(backend), sentry_ucontext_t *uctx) +{ + handle_ucontext(uctx); } static void @@ -227,7 +233,7 @@ sentry__backend_new(void) backend->startup_func = startup_inproc_backend; backend->shutdown_func = NULL; - backend->except_func = handle_ucontext; + backend->except_func = handle_except; backend->free_func = free_backend; backend->flush_scope_func = NULL; backend->add_breadcrumb_func = NULL; From 17362852b5f84c4f57f23d4c0e59b46b050ae2cf Mon Sep 17 00:00:00 2001 From: cammm <81903+cammm@users.noreply.github.com> Date: Fri, 27 Mar 2020 09:20:25 -0700 Subject: [PATCH 4/5] More mac/linux compile errors --- src/backends/sentry_backend_crashpad.cpp | 4 ++++ src/backends/sentry_backend_inproc.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index b672b085e..1a247bae8 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -248,6 +248,10 @@ static void sentry__crashpad_backend_except( { #ifdef SENTRY_PLATFORM_WINDOWS crashpad::CrashpadClient::DumpAndCrash(&context->exception_ptrs); +#else + // TODO: Crashpad has the ability to do this on linux / mac but the + // method interface is not exposed for it, a patch would be required + (void)context; #endif } diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index 5e8cb794c..028bdf4e8 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -188,7 +188,7 @@ handle_ucontext(sentry_ucontext_t* uctx) // forward as we're not restoring the page allocator. reset_signal_handlers(); sentry__leave_signal_handler(); - invoke_signal_handler(uctx->signum, uctx->info, (void *)uctx->user_context); + invoke_signal_handler(uctx->signum, uctx->siginfo, (void *)uctx->user_context); } static void From 7cf948bff6677a1e56ad3822baab5e217dc076a0 Mon Sep 17 00:00:00 2001 From: cammm <81903+cammm@users.noreply.github.com> Date: Fri, 27 Mar 2020 09:40:56 -0700 Subject: [PATCH 5/5] Review feedback --- include/sentry.h | 4 +++- src/sentry_backend.h | 1 - src/sentry_core.c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index ef1eef4dd..7cbec99f0 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -653,8 +653,10 @@ SENTRY_API sentry_uuid_t sentry_capture_event(sentry_value_t event); /* * Captures an exception to be handled by the backend. + * + * This is safe to be called from a crashing thread and may not return. */ -SENTRY_EXPERIMENTAL_API void sentry_handle_exception(sentry_ucontext_t *context); +SENTRY_EXPERIMENTAL_API void sentry_handle_exception(sentry_ucontext_t *uctx); /* * Adds the breadcrumb to be sent in case of an event. diff --git a/src/sentry_backend.h b/src/sentry_backend.h index 95ba05895..cd7ea1f14 100644 --- a/src/sentry_backend.h +++ b/src/sentry_backend.h @@ -6,7 +6,6 @@ #include "sentry_scope.h" struct sentry_backend_s; -struct sentry_ucontext_s; typedef struct sentry_backend_s { void (*startup_func)(struct sentry_backend_s *); void (*shutdown_func)(struct sentry_backend_s *); diff --git a/src/sentry_core.c b/src/sentry_core.c index 71cda9607..70c2d9972 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -253,11 +253,11 @@ sentry_capture_event(sentry_value_t event) return event_id; } -void sentry_handle_exception(sentry_ucontext_t *context) +void sentry_handle_exception(sentry_ucontext_t *uctx) { SENTRY_DEBUG("handling exception"); if (g_options->backend && g_options->backend->except_func) { - g_options->backend->except_func(g_options->backend, context); + g_options->backend->except_func(g_options->backend, uctx); } }