diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index be660d432..a2e03f7d3 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -2119,14 +2119,18 @@ build_stacktrace_from_ctx(const sentry_crash_context_t *ctx) } /** - * Build native crash event with exception, mechanism, and debug_meta + * Build a native event and set the level, mechanism, and handled state * * @param ctx Crash context - * @param event_file_path Path to event file from parent process + * @param event_file_path Path to base event file from parent process + * @param level Event level (e.g. "fatal") + * @param mechanism_type Exception mechanism type (e.g. "signalhandler") + * @param handled Whether the mechanism was handled */ static sentry_value_t -build_native_crash_event( - const sentry_crash_context_t *ctx, const char *event_file_path) +build_native_event(const sentry_crash_context_t *ctx, + const char *event_file_path, const char *level, const char *mechanism_type, + bool handled) { // Read base event from parent's file sentry_value_t event = sentry_value_new_null(); @@ -2152,8 +2156,7 @@ build_native_crash_event( sentry_value_set_by_key( event, "platform", sentry_value_new_string("native")); - // Set level to fatal - sentry_value_set_by_key(event, "level", sentry_value_new_string("fatal")); + sentry_value_set_by_key(event, "level", sentry_value_new_string(level)); // Build exception const char *signal_name = "UNKNOWN"; @@ -2175,10 +2178,11 @@ build_native_crash_event( // Add mechanism sentry_value_t mechanism = sentry_value_new_object(); sentry_value_set_by_key( - mechanism, "type", sentry_value_new_string("signalhandler")); + mechanism, "type", sentry_value_new_string(mechanism_type)); sentry_value_set_by_key( mechanism, "synthetic", sentry_value_new_bool(true)); - sentry_value_set_by_key(mechanism, "handled", sentry_value_new_bool(false)); + sentry_value_set_by_key( + mechanism, "handled", sentry_value_new_bool(handled)); // Add signal metadata sentry_value_t meta = sentry_value_new_object(); @@ -2477,7 +2481,8 @@ write_envelope_with_native_stacktrace(const sentry_options_t *options, // Build native crash event (always include threads with names) SENTRY_DEBUGF("write_envelope_with_native_stacktrace: minidump_path=%s", minidump_path ? minidump_path : "(null)"); - sentry_value_t event = build_native_crash_event(ctx, event_file_path); + sentry_value_t event = build_native_event( + ctx, event_file_path, "fatal", "signalhandler", false); // Serialize event to JSON size_t event_size = 0; diff --git a/src/backends/sentry_backend_native.c b/src/backends/sentry_backend_native.c index 3c3e50843..7768fe030 100644 --- a/src/backends/sentry_backend_native.c +++ b/src/backends/sentry_backend_native.c @@ -767,9 +767,42 @@ native_backend_write_attachments(const sentry_path_t *event_path) } } +#if defined(SENTRY_PLATFORM_WINDOWS) +// Sentry's symbolicator needs `contexts.device.arch` to process PE modules. If +// the scope already carries a device context with arch (host SDKs like Unity +// provide one), leave it; otherwise synthesize a minimal one so native-only +// consumers still symbolicate. +static void +ensure_device_arch(sentry_value_t event) +{ + sentry_value_t contexts = sentry_value_get_by_key(event, "contexts"); + if (sentry_value_is_null(contexts)) { + contexts = sentry_value_new_object(); + sentry_value_set_by_key(event, "contexts", contexts); + } + sentry_value_t device = sentry_value_get_by_key(contexts, "device"); + if (sentry_value_is_null(device)) { + device = sentry_value_new_object(); + sentry_value_set_by_key( + device, "type", sentry_value_new_string("device")); + sentry_value_set_by_key(contexts, "device", device); + } + if (!sentry_value_is_null(sentry_value_get_by_key(device, "arch"))) { + return; + } +# if defined(_M_AMD64) + sentry_value_set_by_key(device, "arch", sentry_value_new_string("x86_64")); +# elif defined(_M_IX86) + sentry_value_set_by_key(device, "arch", sentry_value_new_string("x86")); +# elif defined(_M_ARM64) + sentry_value_set_by_key(device, "arch", sentry_value_new_string("arm64")); +# endif +} +#endif + static void native_backend_flush_scope( - sentry_backend_t *backend, const sentry_options_t *UNUSED(options)) + sentry_backend_t *backend, const sentry_options_t *options) { native_backend_state_t *state = (native_backend_state_t *)backend->data; if (!state || !state->event_path) { @@ -789,60 +822,14 @@ native_backend_flush_scope( sentry_value_set_by_key( event, "level", sentry__value_new_level(SENTRY_LEVEL_FATAL)); - // Apply scope with contexts (includes OS, device info from Sentry) + // Apply scope with contexts SENTRY_WITH_SCOPE (scope) { - // Get contexts from scope (includes OS info) - sentry_value_t os_context - = sentry_value_get_by_key(scope->contexts, "os"); - if (!sentry_value_is_null(os_context)) { - sentry_value_t event_contexts = sentry_value_new_object(); - sentry_value_set_by_key(event_contexts, "os", os_context); - sentry_value_incref(os_context); - + sentry__scope_apply_to_event(scope, options, event, SENTRY_SCOPE_NONE); + } #if defined(SENTRY_PLATFORM_WINDOWS) - // Add device context with arch for Windows native events - // This is required for Sentry's symbolicator to process PE modules - sentry_value_t device_context = sentry_value_new_object(); - sentry_value_set_by_key( - device_context, "type", sentry_value_new_string("device")); -# if defined(_M_AMD64) - sentry_value_set_by_key( - device_context, "arch", sentry_value_new_string("x86_64")); -# elif defined(_M_IX86) - sentry_value_set_by_key( - device_context, "arch", sentry_value_new_string("x86")); -# elif defined(_M_ARM64) - sentry_value_set_by_key( - device_context, "arch", sentry_value_new_string("arm64")); -# endif - sentry_value_set_by_key(event_contexts, "device", device_context); + ensure_device_arch(event); #endif - sentry_value_set_by_key(event, "contexts", event_contexts); - } - - // Also copy other scope data (user, tags, extra, etc.) - sentry_value_t user = scope->user; - if (sentry_value_get_type(user) == SENTRY_VALUE_TYPE_OBJECT - && sentry_value_get_length(user) > 0) { - sentry_value_set_by_key(event, "user", user); - sentry_value_incref(user); - } - - sentry_value_t tags = scope->tags; - if (!sentry_value_is_null(tags)) { - sentry_value_set_by_key(event, "tags", tags); - sentry_value_incref(tags); - } - - sentry_value_t extra = scope->extra; - if (!sentry_value_is_null(extra)) { - sentry_value_set_by_key(event, "extra", extra); - sentry_value_incref(extra); - } - } - - // Serialize to JSON (so it can be deserialized on next start) size_t json_len = 0; char *json_str = sentry__value_to_json(event, &json_len); sentry_value_decref(event); @@ -1029,32 +1016,8 @@ native_backend_except(sentry_backend_t *backend, const sentry_ucontext_t *uctx) sentry__scope_apply_to_event( scope, options, event, SENTRY_SCOPE_BREADCRUMBS); } - #if defined(SENTRY_PLATFORM_WINDOWS) - // Add device context with arch for Windows native events - // This is required for Sentry's symbolicator to process PE - // modules - sentry_value_t contexts - = sentry_value_get_by_key(event, "contexts"); - if (sentry_value_is_null(contexts)) { - contexts = sentry_value_new_object(); - sentry_value_set_by_key(event, "contexts", contexts); - } - sentry_value_t device_context = sentry_value_new_object(); - sentry_value_set_by_key( - device_context, "type", sentry_value_new_string("device")); -# if defined(_M_AMD64) - sentry_value_set_by_key( - device_context, "arch", sentry_value_new_string("x86_64")); -# elif defined(_M_IX86) - sentry_value_set_by_key( - device_context, "arch", sentry_value_new_string("x86")); -# elif defined(_M_ARM64) - sentry_value_set_by_key( - device_context, "arch", sentry_value_new_string("arm64")); -# endif - sentry_value_set_by_key(contexts, "device", device_context); - + ensure_device_arch(event); #endif #ifndef SENTRY_SCREENSHOT_NONE