Skip to content

Conversation

tommcdon
Copy link
Member

SOS supports a feature that is able to read a serialized exception embedded in a NativeAOT mini-dump, known as !crashinfo. This feature was added in the .NET 8 timeframe, but only worked when executing NativeAOT's internal crash dump code path. #114392 added the ability for hosts to notify the runtime of an impending unhandled exception through the ExceptionHandling.RaiseAppDomainUnhandledExceptionEvent API.

0:000> !crashinfo
Loading extension C:\Program Files\WindowsApps\Microsoft.WinDbg.Fast_1.2507.17002.0_x64__8wekyb3d8bbwe\amd64\winext\sos\extensions\Microsoft.Diagnostics.DataContractReader.dll
Loading extension C:\Program Files\WindowsApps\Microsoft.WinDbg.Fast_1.2507.17002.0_x64__8wekyb3d8bbwe\amd64\winext\sos\extensions\Microsoft.Diagnostics.DataContractReader.Extension.dll
Loading extension C:\Program Files\WindowsApps\Microsoft.WinDbg.Fast_1.2507.17002.0_x64__8wekyb3d8bbwe\amd64\winext\sos\extensions\Microsoft.Diagnostics.DebuggerCommands.dll
CrashReason:        UnhandledException
ThreadId:           F2C4C
HResult:            80131509
RuntimeType:        NativeAOT
RuntimeBaseAddress: 00007FF677250000
RuntimeVersion:     10.0.0-dev
Message:            Recursion complete. Terminating process.

** Current Exception **

-----------------------------------------------
Exception object:   0000025B9C80BDD8
Exception type:     System.InvalidOperationException
HResult:            80131509
Message:            Recursion complete. Terminating process.
StackTrace:
    IP               Function
    00007FF677371CA9 test!Program.<<<Main>$>g__Method1|0_0>d.MoveNext() + 0x229
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677372756 test!Program.<<<Main>$>g__Method5|0_4>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF6773724A6 test!Program.<<<Main>$>g__Method4|0_3>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF6773721F6 test!Program.<<<Main>$>g__Method3|0_2>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677371F46 test!Program.<<<Main>$>g__Method2|0_1>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677371C7B test!Program.<<<Main>$>g__Method1|0_0>d.MoveNext() + 0x1FB
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677372A13 test!Program.<<Main>$>d__0.MoveNext() + 0x203

** Thread 994380 Exception **

-----------------------------------------------
Exception object:   0000025B9C80BDD8
Exception type:     System.InvalidOperationException
HResult:            80131509
Message:            Recursion complete. Terminating process.
StackTrace:
    IP               Function
    00007FF677371CA9 test!Program.<<<Main>$>g__Method1|0_0>d.MoveNext() + 0x229
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677372756 test!Program.<<<Main>$>g__Method5|0_4>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF6773724A6 test!Program.<<<Main>$>g__Method4|0_3>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF6773721F6 test!Program.<<<Main>$>g__Method3|0_2>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677371F46 test!Program.<<<Main>$>g__Method2|0_1>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677371C7B test!Program.<<<Main>$>g__Method1|0_0>d.MoveNext() + 0x1FB
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677372A13 test!Program.<<Main>$>d__0.MoveNext() + 0x203

** Nested Exceptions **

-----------------------------------------------
Exception object:   0000025B9C80BDD8
Exception type:     System.InvalidOperationException
HResult:            80131509
Message:            Recursion complete. Terminating process.
StackTrace:
    IP               Function
    00007FF677371CA9 test!Program.<<<Main>$>g__Method1|0_0>d.MoveNext() + 0x229
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677372756 test!Program.<<<Main>$>g__Method5|0_4>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF6773724A6 test!Program.<<<Main>$>g__Method4|0_3>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF6773721F6 test!Program.<<<Main>$>g__Method3|0_2>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677371F46 test!Program.<<<Main>$>g__Method2|0_1>d.MoveNext() + 0x1F6
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677371C7B test!Program.<<<Main>$>g__Method1|0_0>d.MoveNext() + 0x1FB
    00007FF677307D93 test!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x33
    00007FF67730D557 test!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xE7
    00007FF67730D450 test!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x80
    00007FF67730D3C2 test!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task, ConfigureAwaitOptions) + 0x32
    00007FF67730D37D test!System.Runtime.CompilerServices.TaskAwaiter.GetResult() + 0x1D
    00007FF677372A13 test!Program.<<Main>$>d__0.MoveNext() + 0x203

…andler.RaiseUnhandledExceptionEvent is called
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 18, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR extends the NativeAOT crash dump analysis feature to work with host-notified unhandled exceptions by adding exception serialization when ExceptionHandling.RaiseAppDomainUnhandledExceptionEvent is called. Previously, the SOS !crashinfo command only worked for NativeAOT's internal crash dump code path.

  • Adds crash info serialization to the OnUnhandledException method in AppContext.cs
  • Refactors crash info handling in RuntimeExceptionHelpers.cs to enable reuse across different crash scenarios

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/libraries/System.Private.CoreLib/src/System/AppContext.cs Adds call to serialize crash info for unhandled exceptions in NativeAOT builds
src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs Refactors crash info creation into reusable method and adds thread-safe caching

@tommcdon tommcdon added area-Diagnostics-coreclr area-NativeAOT-coreclr and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 18, 2025
Copy link
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 10.0.0 milestone Jul 18, 2025
Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@tommcdon
Copy link
Member Author

/ba-g failures are unrelated

@tommcdon tommcdon merged commit ea721e7 into dotnet:main Jul 19, 2025
136 of 143 checks passed
tommcdon added a commit to tommcdon/runtime that referenced this pull request Jul 22, 2025
…andler.RaiseUnhandledExceptionEvent is called (dotnet#117832)

* Serialize unhandled exception for crash dump analysis when ExceptionHandler.RaiseUnhandledExceptionEvent is called

* Use cheaper locking mechanism for SerializeCrashInfo

* Remove superfluous assignment

* Apply suggestions from code review

Co-authored-by: Jan Kotas <[email protected]>

* Block secondary calls to SerializeCrashInfo until the data has been serialized (prevents early process exit)

* Update src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs

* Update src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs

---------

Co-authored-by: Jan Kotas <[email protected]>
jeffschwMSFT added a commit that referenced this pull request Jul 23, 2025
…andler.RaiseUnhandledExceptionEvent is called (#117832) (#117913)

* Serialize unhandled exception for crash dump analysis when ExceptionHandler.RaiseUnhandledExceptionEvent is called

* Use cheaper locking mechanism for SerializeCrashInfo

* Remove superfluous assignment

* Apply suggestions from code review



* Block secondary calls to SerializeCrashInfo until the data has been serialized (prevents early process exit)

* Update src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs

* Update src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs

---------

Co-authored-by: Jan Kotas <[email protected]>
Co-authored-by: Jeff Schwartz <[email protected]>
tommcdon added a commit to dotnet/diagnostics that referenced this pull request Jul 30, 2025
SOS supports reading NAOT crash information using a JSON encoding
mechanism. The mechanism relies on passing the serialized exception
address via a [FailFast exception
parameter](https://github.com/dotnet/runtime/blob/67837792faa88beb3f44105dfa7a3a430961ff12/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs#L322-L332)
along with a special code. SOS can read this data via `!crashinfo` as
well as `!clrma`. As of dotnet/runtime#117832,
NAOT can serialize exception data when
`ExceptionHandling.RaiseAppDomainUnhandledExceptionEvent` is called.
This PR adds the corresponding SOS functionality to locate the
[g_CrashInfoBuffer](https://github.com/dotnet/runtime/blob/67837792faa88beb3f44105dfa7a3a430961ff12/src/coreclr/nativeaot/Runtime/DebugHeader.cpp#L261)
global as an alternate mechanism in the event the exception does not
contain the address of the buffer. Since this requires reading module
exports, this change introduces a configurable module enumeration
mechanism via the `!crashinfo` command.

---------

Co-authored-by: Michal Strehovský <[email protected]>
@github-actions github-actions bot locked and limited conversation to collaborators Aug 19, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants