Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -649,11 +649,18 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo)
public static void RhThrowEx(object exceptionObj, ref ExInfo exInfo)
{
#if NATIVEAOT

#if TARGET_WINDOWS
// Alert the debugger that we threw an exception.
InternalCalls.RhpFirstChanceExceptionNotification();
#endif // TARGET_WINDOWS

// trigger a GC (only if gcstress) to ensure we can stackwalk at this point
GCStress.TriggerGC();

InternalCalls.RhpValidateExInfoStack();
#endif
#endif // NATIVEAOT

// Transform attempted throws of null to a throw of NullReferenceException.
if (exceptionObj == null)
{
Expand All @@ -665,6 +672,7 @@ public static void RhThrowEx(object exceptionObj, ref ExInfo exInfo)
DispatchEx(ref exInfo._frameIter, ref exInfo);
FallbackFailFast(RhFailFastReason.InternalError, null);
}

#if !NATIVEAOT
public static void RhUnwindAndIntercept(ref ExInfo exInfo, UIntPtr interceptStackFrameSP)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ internal static extern unsafe IntPtr RhpCallPropagateExceptionCallback(
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void RhpValidateExInfoStack();

#if TARGET_WINDOWS
[RuntimeImport(Redhawk.BaseName, "RhpFirstChanceExceptionNotification")]
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void RhpFirstChanceExceptionNotification();
#endif

#if TARGET_WINDOWS
[RuntimeImport(Redhawk.BaseName, "RhpCopyContextFromExInfo")]
[MethodImpl(MethodImplOptions.InternalCall)]
Expand Down
22 changes: 22 additions & 0 deletions src/coreclr/nativeaot/Runtime/EHHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "MethodTable.inl"
#include "CommonMacros.inl"
#include "NativeContext.h"
#include <minipal/debugger.h>
#include "corexcep.h"

struct MethodRegionInfo
{
Expand Down Expand Up @@ -85,6 +87,26 @@ FCIMPL0(void, RhpValidateExInfoStack)
}
FCIMPLEND

#ifdef TARGET_WINDOWS
FCIMPL0(void, RhpFirstChanceExceptionNotification)
{
// Throw an SEH exception and immediately catch it. This is used to notify debuggers and other tools
// that an exception has been thrown.
if (minipal_is_native_debugger_present())
{
__try
{
RaiseException(EXCEPTION_COMPLUS, 0, 0, NULL);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
// Do nothing, we just want to notify the debugger.
}
}
}
FCIMPLEND
#endif // TARGET_WINDOWS

FCIMPL0(void, RhpClearThreadDoNotTriggerGC)
{
Thread * pThisThread = ThreadStore::GetCurrentThread();
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/nativeaot/Runtime/corexcep.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "../../inc/corexcep.h"
22 changes: 12 additions & 10 deletions src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord,
// The 3rd argument passes to PopExplicitFrame is normally the parent SP to correctly handle InlinedCallFrame embbeded
// in parent managed frame. But at this point there are no further managed frames are on the stack, so we can pass NULL.
// Also don't pop the GC frames, their destructor will pop them as the exception propagates.
// NOTE: this needs to be popped in the 2nd pass to ensure that crash dumps and Watson get the dump with these still
// NOTE: this needs to be popped in the 2nd pass to ensure that crash dumps and Watson get the dump with these still
Copy link
Member Author

@agocke agocke May 17, 2025

Choose a reason for hiding this comment

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

My editor stripped trailing whitespace from the file. Feel free to look at this diff with ws-only changes disabled.

// present.
ExInfo *pExInfo = (ExInfo*)pThread->GetExceptionState()->GetCurrentExceptionTracker();
void *sp = (void*)GetRegdisplaySP(pExInfo->m_frameIter.m_crawl.GetRegisterSet());
Expand Down Expand Up @@ -624,7 +624,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord,

#ifdef TARGET_X86
CallRtlUnwind((PEXCEPTION_REGISTRATION_RECORD)pEstablisherFrame, NULL, pExceptionRecord, 0);
#else
#else
ClrUnwindEx(pExceptionRecord,
(UINT_PTR)pThread,
INVALID_RESUME_ADDRESS,
Expand Down Expand Up @@ -1557,19 +1557,21 @@ BOOL HandleHardwareException(PAL_SEHException* ex)

void FirstChanceExceptionNotification()
{
#ifndef TARGET_UNIX
#ifdef TARGET_WINDOWS
// Throw an SEH exception and immediately catch it. This is used to notify debuggers and other tools
// that an exception has been thrown.
if (minipal_is_native_debugger_present())
{
PAL_TRY(VOID *, unused, NULL)
__try
{
RaiseException(EXCEPTION_COMPLUS, 0, 0, NULL);
}
PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
__except (EXCEPTION_EXECUTE_HANDLER)
{
// Do nothing, we just want to notify the debugger.
}
PAL_ENDTRY;
}
#endif // TARGET_UNIX
#endif // TARGET_WINDOWS
}

VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, CONTEXT* pExceptionContext, EXCEPTION_RECORD* pExceptionRecord)
Expand Down Expand Up @@ -3313,7 +3315,7 @@ extern "C" void QCALLTYPE ResumeAtInterceptionLocation(REGDISPLAY* pvRegDisplay)
uResumePC = codeInfo.GetJitManager()->GetCodeAddressForRelOffset(codeInfo.GetMethodToken(), static_cast<DWORD>(ulRelOffset));

SetIP(pvRegDisplay->pCurrentContext, uResumePC);

STRESS_LOG2(LF_EH, LL_INFO100, "Resuming at interception location at IP=%p, SP=%p\n", uResumePC, GetSP(pvRegDisplay->pCurrentContext));
ClrRestoreNonvolatileContext(pvRegDisplay->pCurrentContext, targetSSP);
}
Expand Down Expand Up @@ -3408,7 +3410,7 @@ extern "C" CLR_BOOL QCALLTYPE EHEnumInitFromStackFrameIterator(StackFrameIterato
IJitManager* pJitMan = pFrameIter->m_crawl.GetJitManager();
const METHODTOKEN& MethToken = pFrameIter->m_crawl.GetMethodToken();
pExtendedEHEnum->EHCount = pJitMan->InitializeEHEnumeration(MethToken, pEHEnum);
EH_LOG((LL_INFO100, "Initialized EH enumeration, %d clauses found\n", pExtendedEHEnum->EHCount));
EH_LOG((LL_INFO100, "Initialized EH enumeration, %d clauses found\n", pExtendedEHEnum->EHCount));

if (pExtendedEHEnum->EHCount == 0)
{
Expand Down Expand Up @@ -4037,7 +4039,7 @@ extern "C" CLR_BOOL QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollid

// Unwind to the frame of the prevExInfo
ExInfo* pPrevExInfo = pThis->GetNextExInfo();
EH_LOG((LL_INFO100, "SfiNext: collided with previous exception handling, skipping from IP=%p, SP=%p to IP=%p, SP=%p\n",
EH_LOG((LL_INFO100, "SfiNext: collided with previous exception handling, skipping from IP=%p, SP=%p to IP=%p, SP=%p\n",
GetControlPC(&pTopExInfo->m_regDisplay), GetRegdisplaySP(&pTopExInfo->m_regDisplay),
GetControlPC(&pPrevExInfo->m_regDisplay), GetRegdisplaySP(&pPrevExInfo->m_regDisplay)));

Expand Down
Loading