diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake index 829efbc022c5b9..0a15452b398e85 100644 --- a/src/coreclr/clrfeatures.cmake +++ b/src/coreclr/clrfeatures.cmake @@ -89,7 +89,7 @@ if(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS) endif(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS) if(NOT DEFINED FEATURE_INPROC_CRASHREPORT) - if(CLR_CMAKE_TARGET_ANDROID) + if(CLR_CMAKE_TARGET_ANDROID OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS OR CLR_CMAKE_TARGET_MACCATALYST) set(FEATURE_INPROC_CRASHREPORT 1) else() set(FEATURE_INPROC_CRASHREPORT 0) diff --git a/src/coreclr/debug/crashreport/inproccrashreporter.cpp b/src/coreclr/debug/crashreport/inproccrashreporter.cpp index d8c5257e8aff28..fe771432eee5f4 100644 --- a/src/coreclr/debug/crashreport/inproccrashreporter.cpp +++ b/src/coreclr/debug/crashreport/inproccrashreporter.cpp @@ -18,6 +18,10 @@ #include #include #include +#ifdef __APPLE__ +#include +#include +#endif // Include the .NET version string instead of linking because it is "static". #if __has_include("_version.c") @@ -26,6 +30,27 @@ static char sccsid[] = "@(#)Version N/A"; #endif +#ifdef __APPLE__ +// Query a sysctl by name into a caller-supplied buffer. Called from Initialize, NOT from the +// signal handler -- sysctl/sysctlbyname is not on POSIX's async-signal-safe list, so the +// queried values are cached for use during crash reporting (mirrors the m_hostName / +// gethostname pattern). +static void CacheSysctlString(const char* sysctlName, char* buffer, size_t bufferSize) +{ + buffer[0] = '\0'; + size_t size = bufferSize; + if (sysctlbyname(sysctlName, buffer, &size, nullptr, 0) == 0 && size > 0) + { + size_t terminatorIndex = (size < bufferSize) ? size : bufferSize - 1; + buffer[terminatorIndex] = '\0'; + } + else + { + buffer[0] = '\0'; + } +} +#endif // __APPLE__ + class ThreadEnumerationContext { public: @@ -276,6 +301,17 @@ InProcCrashReporter::CreateReport( m_jsonWriter.OpenObject("parameters"); m_jsonWriter.WriteSignedDecimalAsString("signal", static_cast(signal)); +#ifdef __APPLE__ + if (m_osVersion[0] != '\0') + { + m_jsonWriter.WriteString("OSVersion", m_osVersion); + } + if (m_systemModel[0] != '\0') + { + m_jsonWriter.WriteString("SystemModel", m_systemModel); + } + m_jsonWriter.WriteString("SystemManufacturer", "apple"); +#endif m_jsonWriter.CloseObject(); // parameters m_jsonWriter.CloseObject(); // root @@ -349,6 +385,13 @@ InProcCrashReporter::Initialize( { m_hostName[0] = '\0'; } + +#ifdef __APPLE__ + // Cache sysctl values at Initialize because sysctl/sysctlbyname is not on POSIX's + // async-signal-safe list; CreateReport reads these from the signal-handler path. + CacheSysctlString("kern.osproductversion", m_osVersion, sizeof(m_osVersion)); + CacheSysctlString("hw.model", m_systemModel, sizeof(m_systemModel)); +#endif } void @@ -667,7 +710,11 @@ CrashReportHelpers::GetInstructionPointer( } ucontext_t* ucontext = reinterpret_cast(context); -#if defined(__x86_64__) +#if defined(__APPLE__) && defined(__x86_64__) + return static_cast(ucontext->uc_mcontext->__ss.__rip); +#elif defined(__APPLE__) && defined(__aarch64__) + return reinterpret_cast(arm_thread_state64_get_pc_fptr(ucontext->uc_mcontext->__ss)); +#elif defined(__x86_64__) return static_cast(ucontext->uc_mcontext.gregs[REG_RIP]); #elif defined(__aarch64__) return static_cast(ucontext->uc_mcontext.pc); @@ -688,7 +735,11 @@ CrashReportHelpers::GetStackPointer( } ucontext_t* ucontext = reinterpret_cast(context); -#if defined(__x86_64__) +#if defined(__APPLE__) && defined(__x86_64__) + return static_cast(ucontext->uc_mcontext->__ss.__rsp); +#elif defined(__APPLE__) && defined(__aarch64__) + return static_cast(arm_thread_state64_get_sp(ucontext->uc_mcontext->__ss)); +#elif defined(__x86_64__) return static_cast(ucontext->uc_mcontext.gregs[REG_RSP]); #elif defined(__aarch64__) return static_cast(ucontext->uc_mcontext.sp); @@ -709,7 +760,11 @@ CrashReportHelpers::GetFramePointer( } ucontext_t* ucontext = reinterpret_cast(context); -#if defined(__x86_64__) +#if defined(__APPLE__) && defined(__x86_64__) + return static_cast(ucontext->uc_mcontext->__ss.__rbp); +#elif defined(__APPLE__) && defined(__aarch64__) + return static_cast(arm_thread_state64_get_fp(ucontext->uc_mcontext->__ss)); +#elif defined(__x86_64__) return static_cast(ucontext->uc_mcontext.gregs[REG_RBP]); #elif defined(__aarch64__) return static_cast(ucontext->uc_mcontext.regs[29]); diff --git a/src/coreclr/debug/crashreport/inproccrashreporter.h b/src/coreclr/debug/crashreport/inproccrashreporter.h index 01fa1e706c87da..5018f3b0d10793 100644 --- a/src/coreclr/debug/crashreport/inproccrashreporter.h +++ b/src/coreclr/debug/crashreport/inproccrashreporter.h @@ -95,6 +95,10 @@ class InProcCrashReporter char m_reportPath[CRASHREPORT_PATH_BUFFER_SIZE] = {}; char m_processName[CRASHREPORT_STRING_BUFFER_SIZE] = {}; char m_hostName[CRASHREPORT_STRING_BUFFER_SIZE] = {}; +#ifdef __APPLE__ + char m_osVersion[CRASHREPORT_STRING_BUFFER_SIZE] = {}; + char m_systemModel[CRASHREPORT_STRING_BUFFER_SIZE] = {}; +#endif }; // Free-function entry point used by the runtime to wire the in-proc crash diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp index cd47a557eb4648..c5b6886b562219 100644 --- a/src/coreclr/pal/src/exception/signal.cpp +++ b/src/coreclr/pal/src/exception/signal.cpp @@ -448,9 +448,11 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t { if (signalRestarts) { - // Shutdown and create the core dump before we restore the signal to the default handler. + // Shutdown, log the managed callstack (if a host callback is registered), + // and create the core dump before we restore the signal to the default handler. PROCNotifyProcessShutdown(IsRunningOnAlternateStack(context)); + PROCLogManagedCallstackForSignal(code); PROCCreateCrashDumpIfEnabled(code, siginfo, context, true); // Restore the original and restart h/w exception. diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index d7325f5e5796e3..613cb42fae511c 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -709,9 +709,9 @@ void EEStartupHelper() PAL_SetShutdownCallback(EESocketCleanupHelper); #endif // TARGET_UNIX -#ifdef HOST_ANDROID +#if defined(HOST_ANDROID) || defined(HOST_IOS) || defined(HOST_TVOS) || defined(HOST_MACCATALYST) PAL_SetLogManagedCallstackForSignalCallback(EEPolicy::LogManagedCallstackForSignal); -#endif // HOST_ANDROID +#endif #ifdef FEATURE_INPROC_CRASHREPORT CrashReportConfigure(); diff --git a/src/coreclr/vm/eepolicy.cpp b/src/coreclr/vm/eepolicy.cpp index 6fcbaec5aaf61a..1462aeb827f681 100644 --- a/src/coreclr/vm/eepolicy.cpp +++ b/src/coreclr/vm/eepolicy.cpp @@ -911,7 +911,7 @@ int NOINLINE EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR return -1; } -#ifdef HOST_ANDROID +#if defined(HOST_ANDROID) || defined(HOST_IOS) || defined(HOST_TVOS) || defined(HOST_MACCATALYST) // Logs the managed callstack when a signal is received. void EEPolicy::LogManagedCallstackForSignal(LPCWSTR signalName) { @@ -926,4 +926,4 @@ void EEPolicy::LogManagedCallstackForSignal(LPCWSTR signalName) LogInfoForFatalError(0, message.GetUnicode(), nullptr, nullptr, nullptr); } -#endif // HOST_ANDROID +#endif diff --git a/src/coreclr/vm/eepolicy.h b/src/coreclr/vm/eepolicy.h index d9103664195e8b..04b592aca5156c 100644 --- a/src/coreclr/vm/eepolicy.h +++ b/src/coreclr/vm/eepolicy.h @@ -38,7 +38,7 @@ class EEPolicy static void DECLSPEC_NORETURN HandleFatalStackOverflow(EXCEPTION_POINTERS *pException, BOOL fSkipDebugger = FALSE); -#ifdef HOST_ANDROID +#if defined(HOST_ANDROID) || defined(HOST_IOS) || defined(HOST_TVOS) || defined(HOST_MACCATALYST) static void LogManagedCallstackForSignal(LPCWSTR signalName); #endif