NativeAOT Watson changes for crashes/unhandled exceptions (#88273)
authorMike McLaughlin <mikem@microsoft.com>
Thu, 6 Jul 2023 20:38:23 +0000 (13:38 -0700)
committerGitHub <noreply@github.com>
Thu, 6 Jul 2023 20:38:23 +0000 (13:38 -0700)
commit609b86351cd7c0aa7f8d0d7627be46ce19654a46
treee1dc8121a806ef2193518fba6a3761236e8cfbc3
parent0224f86a886e0aaf72acb6a4f5573236ba929292
NativeAOT Watson changes for crashes/unhandled exceptions (#88273)

* NativeAOT Watson changes for crashes/unhandled exceptions

Adds simple JSON formatting to a static fixed triage buffer that is passed through RaiseFailFastException via
the exception record and special codes to the Watson analyzer.

The current approach is to try to fit as much of the crash and exception info into the static fixed buffer with fallbacks
when it doesn't fit:
   1) The header containing basic info about the crash should always fit
   2) Writes 500 stack frames and as many inner exceptions  as can fit
   3) If that still fails, limit the number of stack frames to 10
   4) if that still fails, limit the number of stack frames to 10 and the size of the frame method name to 100 bytes

These fallback policies are preliminary and will be adjusted for what is needed more by Watson. We also could go with
a completely different approach of resizing the triage buffer with some kind of low level memory allocation. Needs to
work across all our platforms.

I have gone out of my way to avoid GC allocations when rendering the JSON but there still are some strings, delegates/display class and StackTrace class instance allocations.

Escaped the JSON special chars.

Add the RhGetCrashInfoBuffer C++ helper

Cleaned up the RhFailFastReason enum.

Added COR_E_FAILFAST (and Furious) HRESULT.

Used Jan's suggestion of interlock and sleeping all the threads except the first one

Cleaned up RuntimeFailFast. May have took some liberties by only formatting the FailFast message that was there when there isn't an exception message. For unhandled exceptions, having a message for crash info header isn't necessary only for regular FailFasts.

Add module base address to stack frame. Watson is going to need it even though it is usually always the app exe name.
src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs
src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
src/coreclr/nativeaot/System.Private.CoreLib/src/System/CrashInfo.cs [new file with mode: 0644]
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs
src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeExceptionHelpers.cs
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.RaiseFailFastException.cs
src/libraries/Common/src/System/HResults.cs