diff --git a/src/coreclr/nativeaot/Runtime/unix/HardwareExceptions.cpp b/src/coreclr/nativeaot/Runtime/unix/HardwareExceptions.cpp index 44a0b068a82811..d62c1fc6414a11 100644 --- a/src/coreclr/nativeaot/Runtime/unix/HardwareExceptions.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/HardwareExceptions.cpp @@ -559,7 +559,7 @@ void SIGSEGVHandler(int code, siginfo_t *siginfo, void *context) RestoreSignalHandler(code, &g_previousSIGSEGV); } - PalCreateCrashDumpIfEnabled(code, siginfo); + PalCreateCrashDumpIfEnabled(code, siginfo, context); } // Handler for the SIGFPE signal @@ -581,7 +581,7 @@ void SIGFPEHandler(int code, siginfo_t *siginfo, void *context) RestoreSignalHandler(code, &g_previousSIGFPE); } - PalCreateCrashDumpIfEnabled(code, siginfo); + PalCreateCrashDumpIfEnabled(code, siginfo, context); } // Initialize hardware exception handling diff --git a/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp b/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp index a8acc1b9f676c0..d99c719814ee98 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp @@ -346,6 +346,19 @@ CreateCrashDump( #endif // !defined(HOST_MACCATALYST) && !defined(HOST_IOS) && !defined(HOST_TVOS) +// Helper function to prevent compiler from optimizing away a variable +#if defined(__llvm__) +__attribute__((noinline, optnone)) +#else +__attribute__((noinline, optimize("O0"))) +#endif +static void DoNotOptimize(const void* p) +{ + // This function takes the address of a variable to ensure + // it's preserved and available in crash dumps + (void)p; +} + /*++ Function: PalCreateCrashDumpIfEnabled @@ -355,13 +368,17 @@ CreateCrashDump( Parameters: signal - POSIX signal number or 0 siginfo - signal info or nullptr + context - signal context or nullptr exceptionRecord - address of exception record or nullptr (no return value) --*/ void -PalCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, void* exceptionRecord) +PalCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, void* context, void* exceptionRecord) { + // Preserve context pointer to prevent optimization + DoNotOptimize(&context); + #if !defined(HOST_MACCATALYST) && !defined(HOST_IOS) && !defined(HOST_TVOS) // If enabled, launch the create minidump utility and wait until it completes if (g_argvCreateDump[0] != nullptr) @@ -454,13 +471,13 @@ PalCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, void* exceptionRecor void PalCreateCrashDumpIfEnabled() { - PalCreateCrashDumpIfEnabled(SIGABRT, nullptr, nullptr); + PalCreateCrashDumpIfEnabled(SIGABRT, nullptr, nullptr, nullptr); } void PalCreateCrashDumpIfEnabled(void* pExceptionRecord) { - PalCreateCrashDumpIfEnabled(SIGABRT, nullptr, pExceptionRecord); + PalCreateCrashDumpIfEnabled(SIGABRT, nullptr, nullptr, pExceptionRecord); } /*++ diff --git a/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.h b/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.h index c5768a031e98a0..0487a13c218605 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.h +++ b/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.h @@ -7,5 +7,5 @@ extern bool PalCreateDumpInitialize(); extern void PalCreateCrashDumpIfEnabled(); -extern void PalCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo = nullptr, void* exceptionRecord = nullptr); +extern void PalCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo = nullptr, void* context = nullptr, void* exceptionRecord = nullptr); extern void PalCreateCrashDumpIfEnabled(void* pExceptionRecord); diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp index 732d1d5db05933..2fdd83b88d24f1 100644 --- a/src/coreclr/pal/src/exception/signal.cpp +++ b/src/coreclr/pal/src/exception/signal.cpp @@ -422,7 +422,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t if (signalRestarts) { // This signal mustn't be ignored because it will be restarted. - PROCAbort(code, siginfo); + PROCAbort(code, siginfo, context); } return; } @@ -433,7 +433,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t // Shutdown and create the core dump before we restore the signal to the default handler. PROCNotifyProcessShutdown(IsRunningOnAlternateStack(context)); - PROCCreateCrashDumpIfEnabled(code, siginfo, true); + PROCCreateCrashDumpIfEnabled(code, siginfo, context, true); // Restore the original and restart h/w exception. restore_signal(code, action); @@ -444,7 +444,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t { // We can't invoke the original handler because returning from the // handler doesn't restart the exception. - PROCAbort(code, siginfo); + PROCAbort(code, siginfo, context); } } else if (IsSaSigInfo(action)) @@ -462,7 +462,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t PROCNotifyProcessShutdown(IsRunningOnAlternateStack(context)); - PROCCreateCrashDumpIfEnabled(code, siginfo, true); + PROCCreateCrashDumpIfEnabled(code, siginfo, context, true); } /*++ @@ -655,7 +655,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context) { #if defined(TARGET_TVOS) (void)!write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1); - PROCAbort(SIGSEGV, siginfo); + PROCAbort(SIGSEGV, siginfo, context); #else // TARGET_TVOS size_t handlerStackTop = __sync_val_compare_and_swap((size_t*)&g_stackOverflowHandlerStack, (size_t)g_stackOverflowHandlerStack, 0); if (handlerStackTop == 0) @@ -682,7 +682,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context) if (SwitchStackAndExecuteHandler(code | StackOverflowFlag, siginfo, context, (size_t)handlerStackTop)) { - PROCAbort(SIGSEGV, siginfo); + PROCAbort(SIGSEGV, siginfo, context); } (void)!write(STDERR_FILENO, StackOverflowHandlerReturnedMessage, sizeof(StackOverflowHandlerReturnedMessage) - 1); #endif // TARGET_TVOS @@ -851,7 +851,7 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context) DWORD val = 0; if (enableDumpOnSigTerm.IsSet() && enableDumpOnSigTerm.TryAsInteger(10, val) && val == 1) { - PROCCreateCrashDumpIfEnabled(code, siginfo, false); + PROCCreateCrashDumpIfEnabled(code, siginfo, context, false); } } diff --git a/src/coreclr/pal/src/include/pal/process.h b/src/coreclr/pal/src/include/pal/process.h index 45ef76577ad197..fde6cce8d88956 100644 --- a/src/coreclr/pal/src/include/pal/process.h +++ b/src/coreclr/pal/src/include/pal/process.h @@ -152,6 +152,7 @@ BOOL PROCAbortInitialize(); Parameters: signal - POSIX signal number siginfo - POSIX signal info + context - signal context or nullptr Does not return --*/ @@ -159,7 +160,7 @@ BOOL PROCAbortInitialize(); // making crash dumps impossible to analyze PAL_NORETURN #endif -VOID PROCAbort(int signal = SIGABRT, siginfo_t* siginfo = nullptr); +VOID PROCAbort(int signal = SIGABRT, siginfo_t* siginfo = nullptr, void* context = nullptr); /*++ Function: @@ -182,11 +183,12 @@ VOID PROCNotifyProcessShutdown(bool isExecutingOnAltStack = false); Parameters: signal - POSIX signal number siginfo - POSIX signal info or nullptr + context - signal context or nullptr serialize - allow only one thread to generate core dump (no return value) --*/ -VOID PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, bool serialize); +VOID PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, void* context, bool serialize); #ifdef __cplusplus } diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 12ba9ac544f849..da14cbcc204a3f 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -2706,6 +2706,15 @@ PAL_GenerateCoreDump( return result; } +// Helper function to prevent compiler from optimizing away a variable +__attribute__((noinline,NOOPT_ATTRIBUTE)) +static void DoNotOptimize(const void* p) +{ + // This function takes the address of a variable to ensure + // it's preserved and available in crash dumps + (void)p; +} + /*++ Function: PROCCreateCrashDumpIfEnabled @@ -2716,6 +2725,7 @@ PAL_GenerateCoreDump( Parameters: signal - POSIX signal number siginfo - POSIX signal info or nullptr + context - signal context or nullptr serialize - allow only one thread to generate core dump (no return value) @@ -2723,16 +2733,22 @@ PAL_GenerateCoreDump( #ifdef HOST_ANDROID #include VOID -PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, bool serialize) +PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, void* context, bool serialize) { + // Preserve context pointer to prevent optimization + DoNotOptimize(&context); + // TODO: Dump all managed threads callstacks into logcat and/or file? // TODO: Dump stress log into logcat and/or file when enabled? minipal_log_write_fatal("Aborting process.\n"); } #else VOID -PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, bool serialize) +PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, void* context, bool serialize) { + // Preserve context pointer to prevent optimization + DoNotOptimize(&context); + // If enabled, launch the create minidump utility and wait until it completes if (!g_argvCreateDump.empty()) { @@ -2809,6 +2825,7 @@ PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, bool serialize) Parameters: signal - POSIX signal number + context - signal context or nullptr Does not return --*/ @@ -2816,12 +2833,12 @@ PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, bool serialize) PAL_NORETURN #endif VOID -PROCAbort(int signal, siginfo_t* siginfo) +PROCAbort(int signal, siginfo_t* siginfo, void* context) { // Do any shutdown cleanup before aborting or creating a core dump PROCNotifyProcessShutdown(); - PROCCreateCrashDumpIfEnabled(signal, siginfo, true); + PROCCreateCrashDumpIfEnabled(signal, siginfo, context, true); // Restore all signals; the SIGABORT handler to prevent recursion and // the others to prevent multiple core dumps from being generated.