Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

**Features**:

- Add `sentry_trigger_dump()` a function allowing application to trigger non-fatal minidumps when using the `crashpad` backend. ([#1144](https://github.com/getsentry/sentry-native/pull/1144))

## 0.7.20

**Features**:
Expand Down
3 changes: 3 additions & 0 deletions examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ main(int argc, char **argv)
sleep_s(10);
}

if (has_arg(argc, argv, "trigger-dump")) {
sentry_trigger_dump();
}
if (has_arg(argc, argv, "crash")) {
trigger_crash();
}
Expand Down
2 changes: 1 addition & 1 deletion external/crashpad
12 changes: 12 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,18 @@ SENTRY_API void sentry_capture_minidump_n(const char *path, size_t path_len);
SENTRY_EXPERIMENTAL_API void sentry_handle_exception(
const sentry_ucontext_t *uctx);

/**
* Captures a minidump for non-fatal errors. The program can continue after
* this call safely. It will produce a minidump context on the spot and crash-
* events will appear with log-level `error`.
*
* This trigger will also invoke the crash-handler, meaning it will call
* the `before_send` or `on_crash` hooks.
*
* Note: currently only works with the `crashpad` backend on Windows and Linux.
*/
SENTRY_EXPERIMENTAL_API void sentry_trigger_dump(void);

/**
* Adds the breadcrumb to be sent in case of an event.
*/
Expand Down
46 changes: 40 additions & 6 deletions src/backends/sentry_backend_crashpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ extern "C" {
#if defined(_WIN32)
# include "util/win/termination_codes.h"
#endif
#if defined(SENTRY_PLATFORM_MACOS)
# include "client/simulate_crash_mac.h"
#endif

#if defined(__GNUC__)
# pragma GCC diagnostic pop
Expand Down Expand Up @@ -260,11 +263,19 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
SENTRY_INFO("flushing session and queue before crashpad handler");

bool should_dump = true;
# if defined(SENTRY_PLATFORM_WINDOWS)
bool is_fatal = ExceptionInfo->ExceptionRecord->ExceptionCode != 0x517a7ed;
# elif defined(SENTRY_PLATFORM_LINUX)
bool is_fatal = signum != -1;
# else
bool is_fatal = true;
# endif

SENTRY_WITH_OPTIONS (options) {
sentry_value_t crash_event = sentry_value_new_event();
sentry_value_set_by_key(
crash_event, "level", sentry__value_new_level(SENTRY_LEVEL_FATAL));
sentry_value_t level = sentry__value_new_level(
is_fatal ? SENTRY_LEVEL_FATAL : SENTRY_LEVEL_ERROR);
sentry_value_set_by_key(crash_event, "level", level);

if (options->on_crash_func) {
sentry_ucontext_t uctx;
Expand Down Expand Up @@ -332,11 +343,18 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
// (currently returning `true`)
//
// TODO(supervacuus):
// * we need integration tests for more signal/exception types not only
// for unmapped memory access (which is the current crash in example.c).
// * we should adapt the SetFirstChanceExceptionHandler interface in
// crashpad
if (!should_dump) {
//
// We now also use this handler for non-fatal dumps in which case we don't
// want to terminate here:
// is_fatal | should_dump | expected behavior
// ------------------------------------------
// false | false | return true
// false | true | return false
// true | false | terminate
// true | true | return false
if (is_fatal && !should_dump) {
# ifdef SENTRY_PLATFORM_WINDOWS
TerminateProcess(GetCurrentProcess(),
crashpad::TerminationCodes::kTerminationCodeCrashNoDump);
Expand All @@ -346,7 +364,7 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
}

// we did not "handle" the signal, so crashpad should do that.
return false;
return !is_fatal && !should_dump;
}
#endif

Expand Down Expand Up @@ -622,6 +640,21 @@ crashpad_backend_prune_database(sentry_backend_t *backend)
crashpad::PruneCrashReportDatabase(data->db, &condition);
}

static void
crashpad_backend_trigger_dump(sentry_backend_t *backend)
{
(void)backend;
crashpad::NativeCPUContext cpu_context;
crashpad::CaptureContext(&cpu_context);
#if defined(SENTRY_PLATFORM_LINUX)
crashpad::CrashpadClient::DumpWithoutCrash(&cpu_context);
#elif defined(SENTRY_PLATFORM_WINDOWS)
crashpad::CrashpadClient::DumpWithoutCrash(cpu_context);
#elif defined(SENTRY_PLATFORM_MACOS)
crashpad::SimulateCrash(cpu_context);
#endif
}

sentry_backend_t *
sentry__backend_new(void)
{
Expand All @@ -643,6 +676,7 @@ sentry__backend_new(void)
backend->startup_func = crashpad_backend_startup;
backend->shutdown_func = crashpad_backend_shutdown;
backend->except_func = crashpad_backend_except;
backend->trigger_dump_func = crashpad_backend_trigger_dump;
backend->free_func = crashpad_backend_free;
backend->flush_scope_func = crashpad_backend_flush_scope;
backend->add_breadcrumb_func = crashpad_backend_add_breadcrumb;
Expand Down
1 change: 1 addition & 0 deletions src/sentry_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct sentry_backend_s {
void (*shutdown_func)(sentry_backend_t *);
void (*free_func)(sentry_backend_t *);
void (*except_func)(sentry_backend_t *, const struct sentry_ucontext_s *);
void (*trigger_dump_func)(sentry_backend_t *);
void (*flush_scope_func)(
sentry_backend_t *, const sentry_options_t *options);
// NOTE: The breadcrumb is not moved into the hook and does not need to be
Expand Down
11 changes: 11 additions & 0 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,17 @@ sentry_handle_exception(const sentry_ucontext_t *uctx)
}
}

void
sentry_trigger_dump(void)
{
SENTRY_WITH_OPTIONS (options) {
SENTRY_INFO("triggering dump");
if (options->backend && options->backend->except_func) {
options->backend->trigger_dump_func(options->backend);
}
}
}

sentry_uuid_t
sentry__new_event_id(void)
{
Expand Down