2626//
2727
2828#include "SentryCrashMonitor_Signal.h"
29+ #include "SentryCrashCPU.h"
2930#include "SentryCrashID.h"
3031#include "SentryCrashMachineContext.h"
3132#include "SentryCrashMonitorContext.h"
@@ -67,6 +68,29 @@ static char g_eventID[37];
6768# pragma mark - Callbacks -
6869// ============================================================================
6970
71+ /** Invoke previously installed signal handlers, adapted from Sentry Native:
72+ * https://github.com/getsentry/sentry-native/blob/9895a5c3ffab4e59e0c8020484cdd5dbc648666d/src/backends/sentry_backend_inproc.c#L59-L76
73+ */
74+ static void
75+ invokePreviousSignalHandlers (int sigNum , siginfo_t * signalInfo , void * userContext )
76+ {
77+ const int * fatalSignals = sentrycrashsignal_fatalSignals ();
78+ int fatalSignalsCount = sentrycrashsignal_numFatalSignals ();
79+
80+ for (int i = 0 ; i < fatalSignalsCount ; ++ i ) {
81+ if (fatalSignals [i ] == sigNum ) {
82+ struct sigaction * handler = & g_previousSignalHandlers [i ];
83+ if (handler -> sa_flags & SA_SIGINFO ) {
84+ handler -> sa_sigaction (sigNum , signalInfo , userContext );
85+ } else if (handler -> sa_handler != SIG_DFL && handler -> sa_handler != SIG_IGN ) {
86+ // This handler can only handle to signal number (ANSI C)
87+ void (* func )(int ) = handler -> sa_handler ;
88+ func (sigNum );
89+ }
90+ }
91+ }
92+ }
93+
7094/** Our custom signal handler.
7195 * Restore the default signal handlers, record the signal information, and
7296 * write a crash report.
@@ -83,6 +107,29 @@ static void
83107handleSignal (int sigNum , siginfo_t * signalInfo , void * userContext )
84108{
85109 SENTRY_ASYNC_SAFE_LOG_DEBUG ("Trapped signal %d" , sigNum );
110+
111+ if (sentrycrashcm_isManagedRuntime ()) {
112+ // Let managed Mono/CoreCLR runtime handle the signal first,
113+ // as they may convert it into a managed exception.
114+ SENTRY_ASYNC_SAFE_LOG_DEBUG (
115+ "Detected managed Mono/CoreCLR runtime. Passing signal to previous handlers." );
116+
117+ uintptr_t sp = sentrycrashcpu_stackPointerFromUserContext (userContext );
118+ uintptr_t ip = sentrycrashcpu_instructionAddressFromUserContext (userContext );
119+
120+ invokePreviousSignalHandlers (sigNum , signalInfo , userContext );
121+
122+ // If the stack or instruction pointer changed, the managed runtime
123+ // converted the signal into a managed exception and changed the context.
124+ // https://github.com/dotnet/runtime/blob/6d96e28597e7da0d790d495ba834cc4908e442cd/src/mono/mono/mini/exceptions-arm64.c#L538
125+ if (sp != sentrycrashcpu_stackPointerFromUserContext (userContext )
126+ || ip != sentrycrashcpu_instructionAddressFromUserContext (userContext )) {
127+ SENTRY_ASYNC_SAFE_LOG_DEBUG (
128+ "Signal converted to a managed exception. Aborting signal handling." );
129+ return ;
130+ }
131+ }
132+
86133 if (g_isEnabled ) {
87134 thread_act_array_t threads = NULL ;
88135 mach_msg_type_number_t numThreads = 0 ;
@@ -110,9 +157,13 @@ handleSignal(int sigNum, siginfo_t *signalInfo, void *userContext)
110157 sentrycrashmc_resumeEnvironment (threads , numThreads );
111158 }
112159
113- SENTRY_ASYNC_SAFE_LOG_DEBUG ("Re-raising signal for regular handlers to catch." );
114- // This is technically not allowed, but it works in OSX and iOS.
115- raise (sigNum );
160+ // Re-raise the signal to invoke the previous handlers unless already called
161+ // above for managed runtimes.
162+ if (!sentrycrashcm_isManagedRuntime ()) {
163+ SENTRY_ASYNC_SAFE_LOG_DEBUG ("Re-raising signal for regular handlers to catch." );
164+ // This is technically not allowed, but it works in OSX and iOS.
165+ raise (sigNum );
166+ }
116167}
117168
118169// ============================================================================
0 commit comments