22
22
#endif // FEATURE_INTERPRETER
23
23
24
24
#include " exinfo.h"
25
+ #include " excep.h"
25
26
26
27
#ifdef TARGET_X86
27
28
@@ -2075,21 +2076,68 @@ DWORD_PTR EECodeManager::CallFunclet(OBJECTREF throwable, void* pHandler, REGDIS
2075
2076
return dwResult;
2076
2077
}
2077
2078
2079
+ void EECodeManager::ResumeAfterCatch (CONTEXT *pContext, size_t targetSSP, bool fIntercepted )
2080
+ {
2081
+ Thread *pThread = GetThread ();
2082
+ DWORD_PTR dwResumePC = GetIP (pContext);
2083
+ UINT_PTR uAbortAddr = 0 ;
2084
+ if (!fIntercepted )
2085
+ {
2086
+ CopyOSContext (pThread->m_OSContext , pContext);
2087
+ uAbortAddr = (UINT_PTR)COMPlusCheckForAbort (dwResumePC);
2088
+ }
2089
+
2090
+ if (uAbortAddr)
2091
+ {
2092
+ STRESS_LOG2 (LF_EH, LL_INFO10, " Thread abort in progress, resuming under control: IP=%p, SP=%p\n " , dwResumePC, GetSP (pContext));
2093
+
2094
+ // The dwResumePC is passed to the THROW_CONTROL_FOR_THREAD_FUNCTION ASM helper so that
2095
+ // it can establish it as its return address and native stack unwinding can work properly.
2096
+ #ifdef TARGET_AMD64
2097
+ #ifdef TARGET_UNIX
2098
+ pContext->Rdi = dwResumePC;
2099
+ #else
2100
+ pContext->Rcx = dwResumePC;
2101
+ #endif
2102
+ #elif defined(TARGET_ARM) || defined(TARGET_ARM64)
2103
+ // On ARM & ARM64, we save off the original PC in Lr. This is the same as done
2104
+ // in HandleManagedFault for H/W generated exceptions.
2105
+ pContext->Lr = dwResumePC;
2106
+ #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
2107
+ pContext->Ra = dwResumePC;
2108
+ #endif
2109
+
2110
+ SetIP (pContext, uAbortAddr);
2111
+ }
2112
+ else
2113
+ {
2114
+ STRESS_LOG2 (LF_EH, LL_INFO100, " Resuming after exception at IP=%p, SP=%p\n " , GetIP (pContext), GetSP (pContext));
2115
+ }
2116
+
2117
+ ClrRestoreNonvolatileContext (pContext, targetSSP);
2118
+ }
2119
+
2078
2120
#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
2079
- void EECodeManager::UpdateSSP (PREGDISPLAY pRD)
2121
+
2122
+ size_t GetSSPForFrameOnCurrentStack (TADDR ip)
2080
2123
{
2081
2124
size_t *targetSSP = (size_t *)_rdsspq ();
2082
2125
// The SSP we search is pointing to the return address of the frame represented
2083
- // by the pRD->ControlPC . So we search for the instruction pointer from
2126
+ // by the passed in IP . So we search for the instruction pointer from
2084
2127
// the context and return one slot up from there.
2085
2128
if (targetSSP != NULL )
2086
2129
{
2087
- while (*targetSSP++ != pRD-> ControlPC )
2130
+ while (*targetSSP++ != ip )
2088
2131
{
2089
2132
}
2090
2133
}
2091
2134
2092
- pRD->SSP = (size_t )targetSSP;
2135
+ return (size_t )targetSSP;
2136
+ }
2137
+
2138
+ void EECodeManager::UpdateSSP (PREGDISPLAY pRD)
2139
+ {
2140
+ pRD->SSP = GetSSPForFrameOnCurrentStack (pRD->ControlPC );
2093
2141
}
2094
2142
#endif // HOST_AMD64 && HOST_WINDOWS
2095
2143
@@ -2101,13 +2149,64 @@ DWORD_PTR InterpreterCodeManager::CallFunclet(OBJECTREF throwable, void* pHandle
2101
2149
return 0 ;
2102
2150
}
2103
2151
2104
- void InterpreterCodeManager::PrepareForResumeAfterCatch (CONTEXT *pContext)
2152
+ void InterpreterCodeManager::ResumeAfterCatch (CONTEXT *pContext, size_t targetSSP, bool fIntercepted )
2105
2153
{
2106
2154
Thread *pThread = GetThread ();
2107
2155
InterpreterFrame * pInterpreterFrame = (InterpreterFrame*)pThread->GetFrame ();
2108
- pInterpreterFrame->SetResumeContext (GetSP (pContext), GetIP (pContext));
2109
- pInterpreterFrame->RestoreInterpExecMethodContext (pContext);
2156
+ TADDR resumeSP = GetSP (pContext);
2157
+ TADDR resumeIP = GetIP (pContext);
2158
+
2159
+ ClrCaptureContext (pContext);
2160
+
2161
+ // Unwind to the caller of the Ex.RhThrowEx / Ex.RhThrowHwEx
2162
+ Thread::VirtualUnwindToFirstManagedCallFrame (pContext);
2163
+
2164
+ #if defined(HOST_AMD64) && defined(HOST_WINDOWS)
2165
+ targetSSP = GetSSPForFrameOnCurrentStack (GetIP (pContext));
2166
+ #endif // HOST_AMD64 && HOST_WINDOWS
2167
+
2168
+ CONTEXT firstNativeContext;
2169
+ size_t firstNativeSSP;
2170
+
2171
+ // Find the native frames chain that contains the resumeSP
2172
+ do
2173
+ {
2174
+ // Skip all managed frames upto a native frame
2175
+ while (ExecutionManager::IsManagedCode (GetIP (pContext)))
2176
+ {
2177
+ Thread::VirtualUnwindCallFrame (pContext);
2178
+ #if defined(HOST_AMD64) && defined(HOST_WINDOWS)
2179
+ if (targetSSP != 0 )
2180
+ {
2181
+ targetSSP += sizeof (size_t );
2182
+ }
2183
+ #endif
2184
+ }
2185
+
2186
+ // Save the first native context after managed frames. This will be the context where we throw the resume after catch exception from.
2187
+ firstNativeContext = *pContext;
2188
+ firstNativeSSP = targetSSP;
2189
+ // Move over all native frames until we move over the resumeSP
2190
+ while ((GetSP (pContext) < resumeSP) && !ExecutionManager::IsManagedCode (GetIP (pContext)))
2191
+ {
2192
+ #ifdef TARGET_UNIX
2193
+ PAL_VirtualUnwind (pContext, NULL );
2194
+ #else
2195
+ Thread::VirtualUnwindCallFrame (pContext);
2196
+ #endif
2197
+ #if defined(HOST_AMD64) && defined(HOST_WINDOWS)
2198
+ if (targetSSP != 0 )
2199
+ {
2200
+ targetSSP += sizeof (size_t );
2201
+ }
2202
+ #endif
2203
+ }
2204
+ }
2205
+ while (GetSP (pContext) < resumeSP);
2206
+
2207
+ ExecuteFunctionBelowContext ((PCODE)ThrowResumeAfterCatchException, &firstNativeContext, firstNativeSSP, resumeSP, resumeIP);
2110
2208
}
2209
+
2111
2210
#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
2112
2211
void InterpreterCodeManager::UpdateSSP (PREGDISPLAY pRD)
2113
2212
{
@@ -2306,7 +2405,7 @@ bool InterpreterCodeManager::UnwindStackFrame(PREGDISPLAY pRD,
2306
2405
return true ;
2307
2406
}
2308
2407
2309
- void InterpreterCodeManager::EnsureCallerContextIsValid ( PREGDISPLAY pRD, EECodeInfo * pCodeInfo /* = NULL*/ , unsigned flags /* = 0*/ )
2408
+ void InterpreterCodeManager::EnsureCallerContextIsValid (PREGDISPLAY pRD, EECodeInfo * pCodeInfo /* = NULL*/ , unsigned flags /* = 0*/ )
2310
2409
{
2311
2410
CONTRACTL
2312
2411
{
@@ -2322,9 +2421,7 @@ void InterpreterCodeManager::EnsureCallerContextIsValid( PREGDISPLAY pRD, EECod
2322
2421
*(pRD->pCallerContext ) = *(pRD->pCurrentContext );
2323
2422
TADDR sp = (TADDR)GetRegdisplaySP (pRD);
2324
2423
VirtualUnwindInterpreterCallFrame (sp, pRD->pCallerContext );
2325
- // Preserve the context pointers, besides the SP, IP, FP and the first argument register, all the registers are
2326
- // kept untouched and keep the state it the InterpExecMethod. We use the context pointers to update the registers
2327
- // before resuming after a catch using the original context.
2424
+ // Preserve the context pointers, they are used by floating point registers unwind starting at the original context.
2328
2425
memcpy (pRD->pCallerContextPointers , pRD->pCurrentContextPointers , sizeof (KNONVOLATILE_CONTEXT_POINTERS));
2329
2426
2330
2427
pRD->IsCallerContextValid = TRUE ;
0 commit comments