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
8 changes: 3 additions & 5 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@ endif(CLR_CMAKE_HOST_WIN32)
if (NOT (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX))
add_compile_definitions(EnC_SUPPORTED)
endif()
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64)
if(CLR_CMAKE_TARGET_WIN32)
add_compile_definitions(FEATURE_ENC_SUPPORTED)
endif(CLR_CMAKE_TARGET_WIN32)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64)
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_WIN32))
add_compile_definitions(FEATURE_ENC_SUPPORTED)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_WIN32))

if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64)
add_compile_definitions(OUT_OF_PROCESS_SETTHREADCONTEXT)
Expand Down
6 changes: 0 additions & 6 deletions src/coreclr/debug/di/rsthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2135,11 +2135,6 @@ HRESULT CordbThread::InterceptCurrentException(ICorDebugFrame * pFrame)
FAIL_IF_NEUTERED(this);
ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());

#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
// Continuable exceptions are not implemented on Unix-like platforms.
return E_NOTIMPL;

#else // !FEATURE_DBGIPC_TRANSPORT_DI
HRESULT hr = S_OK;
EX_TRY
{
Expand Down Expand Up @@ -2216,7 +2211,6 @@ HRESULT CordbThread::InterceptCurrentException(ICorDebugFrame * pFrame)
}
EX_CATCH_HRESULT(hr);
return hr;
#endif // FEATURE_DBGIPC_TRANSPORT_DI
}

//---------------------------------------------------------------------------------------
Expand Down
8 changes: 4 additions & 4 deletions src/coreclr/inc/eetwain.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ virtual void LeaveCatch(GCInfoToken gcInfoToken,
PCONTEXT pCtx)=0;
#endif // FEATURE_EH_FUNCLETS

#ifdef EnC_SUPPORTED
#ifdef FEATURE_ENC_SUPPORTED

/*
Last chance for the runtime support to do fixups in the context
Expand All @@ -347,7 +347,7 @@ virtual HRESULT FixContextForEnC(PCONTEXT pCtx,
const ICorDebugInfo::NativeVarInfo * newMethodVars,
SIZE_T newMethodVarsCount) = 0;

#endif // EnC_SUPPORTED
#endif // FEATURE_ENC_SUPPORTED

#endif // #ifndef DACCESS_COMPILE

Expand Down Expand Up @@ -597,7 +597,7 @@ virtual void LeaveCatch(GCInfoToken gcInfoToken,
PCONTEXT pCtx);
#endif // FEATURE_EH_FUNCLETS

#ifdef EnC_SUPPORTED
#ifdef FEATURE_ENC_SUPPORTED
/*
Last chance for the runtime support to do fixups in the context
before execution continues inside an EnC updated function.
Expand All @@ -610,7 +610,7 @@ HRESULT FixContextForEnC(PCONTEXT pCtx,
EECodeInfo * pNewCodeInfo,
const ICorDebugInfo::NativeVarInfo * newMethodVars,
SIZE_T newMethodVarsCount);
#endif // EnC_SUPPORTED
#endif // FEATURE_ENC_SUPPORTED

#endif // #ifndef DACCESS_COMPILE

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8910,7 +8910,7 @@ void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize
// -saved bool for synchronized methods

// slots for ret address + FP + EnC callee-saves
int preservedAreaSize = (2 + genCountBits(RBM_ENC_CALLEE_SAVED)) * REGSIZE_BYTES;
int preservedAreaSize = (2 + genCountBits((uint64_t)RBM_ENC_CALLEE_SAVED)) * REGSIZE_BYTES;

if (compiler->info.compFlags & CORINFO_FLG_SYNCH)
{
Expand Down
9 changes: 6 additions & 3 deletions src/coreclr/jit/targetamd64.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@
/* NOTE: Sync with variable name defined in compiler.h */
#define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
#define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15

// For SysV we have more volatile registers so we do not save any callee saves for EnC.
#define RBM_ENC_CALLEE_SAVED 0
#else // !UNIX_AMD64_ABI
#define CNT_CALLEE_SAVED (7 + REG_ETW_FRAMED_EBP_COUNT)
#define CNT_CALLEE_TRASH (7)
Expand All @@ -314,6 +317,9 @@
/* NOTE: Sync with variable name defined in compiler.h */
#define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ESI,REG_EDI,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
#define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ESI,RBM_EDI,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15

// Callee-preserved registers we always save and allow use of for EnC code, since there are quite few volatile registers.
#define RBM_ENC_CALLEE_SAVED (RBM_RSI | RBM_RDI)
#endif // !UNIX_AMD64_ABI

#define CNT_CALLEE_TRASH_FLOAT get_CNT_CALLEE_TRASH_FLOAT()
Expand All @@ -327,9 +333,6 @@
#define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES)
#define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT*16)

// callee-preserved registers we always save and allow use of for EnC code
#define RBM_ENC_CALLEE_SAVED (RBM_RSI | RBM_RDI)

// register to hold shift amount
#define REG_SHIFT REG_ECX
#define RBM_SHIFT RBM_ECX
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/pal/inc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -4490,6 +4490,7 @@ struct PAL_SEHException
ExceptionPointers.ExceptionRecord = ex.ExceptionPointers.ExceptionRecord;
ExceptionPointers.ContextRecord = ex.ExceptionPointers.ContextRecord;
TargetFrameSp = ex.TargetFrameSp;
TargetIp = ex.TargetIp;
RecordsOnStack = ex.RecordsOnStack;
IsExternal = ex.IsExternal;
ManagedToNativeExceptionCallback = ex.ManagedToNativeExceptionCallback;
Expand All @@ -4512,6 +4513,8 @@ struct PAL_SEHException
EXCEPTION_POINTERS ExceptionPointers;
// Target frame stack pointer set before the 2nd pass.
SIZE_T TargetFrameSp;
SIZE_T TargetIp;
SIZE_T ReturnValue;
bool RecordsOnStack;
// The exception is a hardware exception coming from a native code out of
// the well known runtime helpers
Expand All @@ -4525,6 +4528,7 @@ struct PAL_SEHException
ExceptionPointers.ExceptionRecord = pExceptionRecord;
ExceptionPointers.ContextRecord = pContextRecord;
TargetFrameSp = NoTargetFrameSp;
TargetIp = 0;
RecordsOnStack = onStack;
IsExternal = false;
ManagedToNativeExceptionCallback = NULL;
Expand Down Expand Up @@ -4564,6 +4568,7 @@ struct PAL_SEHException
ExceptionPointers.ExceptionRecord = NULL;
ExceptionPointers.ContextRecord = NULL;
TargetFrameSp = NoTargetFrameSp;
TargetIp = 0;
RecordsOnStack = false;
IsExternal = false;
ManagedToNativeExceptionCallback = NULL;
Expand Down
59 changes: 36 additions & 23 deletions src/coreclr/vm/eetwain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ bool VarIsInReg(ICorDebugInfo::VarLoc varLoc)
}
}

#ifdef EnC_SUPPORTED
#ifdef FEATURE_ENC_SUPPORTED
/*****************************************************************************
* Last chance for the runtime support to do fixups in the context
* before execution continues inside an EnC updated function.
Expand Down Expand Up @@ -831,7 +831,6 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
T_CONTEXT oldCtx = *pCtx;

#if defined(TARGET_X86)
LOG((LF_CORDB, LL_INFO100, "EECM::FixContextForEnC\n"));

/* Extract the necessary information from the info block header */

Expand Down Expand Up @@ -997,22 +996,29 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
_ASSERTE(pOldCodeInfo->HasFrameRegister());
_ASSERTE(pNewCodeInfo->HasFrameRegister());

LOG((LF_CORDB, LL_INFO100, "EECM::FixContextForEnC: Old and new fixed stack sizes are %u and %u\n", oldFixedStackSize, newFixedStackSize));

// x64: SP == FP before localloc
if (oldStackBase != GetFP(&oldCtx))
return E_FAIL;
#elif defined(TARGET_ARM64)
DWORD oldFixedStackSize = oldGcDecoder.GetSizeOfEditAndContinueFixedStackFrame();
DWORD newFixedStackSize = newGcDecoder.GetSizeOfEditAndContinueFixedStackFrame();
#else
PORTABILITY_ASSERT("Edit-and-continue not enabled on this platform.");
#endif

LOG((LF_CORDB, LL_INFO100, "EECM::FixContextForEnC: Old and new fixed stack sizes are %u and %u\n", oldFixedStackSize, newFixedStackSize));

// ARM64: FP + 16 == SP + oldFixedStackSize before localloc
if (GetFP(&oldCtx) + 16 != oldStackBase + oldFixedStackSize)
#if defined(TARGET_AMD64) && defined(TARGET_WINDOWS)
// win-x64: SP == FP before localloc
if (oldStackBase != GetFP(&oldCtx))
{
return E_FAIL;
}
#else
PORTABILITY_ASSERT("Edit-and-continue not enabled on this platform.");
// All other 64-bit targets use frame chaining with the FP stored right below the
// return address (LR is always pushed on arm64). FP + 16 == SP + oldFixedStackSize
// gives the caller's SP before stack alloc.
if (GetFP(&oldCtx) + 16 != oldStackBase + oldFixedStackSize)
{
return E_FAIL;
}
#endif

// EnC remap inside handlers is not supported
Expand All @@ -1028,14 +1034,15 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
TADDR callerSP = oldStackBase + oldFixedStackSize;

#ifdef _DEBUG
// If the old method has a PSPSym, then its value should == FP for x64 and callerSP for arm64
// If the old method has a PSPSym, then its value should == initial-SP (i.e.
// oldStackBase) for x64 and callerSP for arm64
INT32 nOldPspSymStackSlot = oldGcDecoder.GetPSPSymStackSlot();
if (nOldPspSymStackSlot != NO_PSP_SYM)
{
#if defined(TARGET_AMD64)
TADDR oldPSP = *PTR_TADDR(oldStackBase + nOldPspSymStackSlot);
_ASSERTE(oldPSP == GetFP(&oldCtx));
#elif defined(TARGET_ARM64)
_ASSERTE(oldPSP == oldStackBase);
#else
TADDR oldPSP = *PTR_TADDR(callerSP + nOldPspSymStackSlot);
_ASSERTE(oldPSP == callerSP);
#endif
Expand Down Expand Up @@ -1222,8 +1229,7 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,

#if defined(TARGET_X86)
// Zero out all the registers as some may hold new variables.
pCtx->Eax = pCtx->Ecx = pCtx->Edx = pCtx->Ebx =
pCtx->Esi = pCtx->Edi = 0;
pCtx->Eax = pCtx->Ecx = pCtx->Edx = pCtx->Ebx = pCtx->Esi = pCtx->Edi = 0;

// 3) zero out the stack frame - this'll initialize _all_ variables

Expand All @@ -1240,7 +1246,7 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
_ASSERTE( frameHeaderSize <= oldInfo.stackSize );
_ASSERTE( GetSizeOfFrameHeaderForEnC( &oldInfo ) == frameHeaderSize );

#elif defined(TARGET_AMD64)
#elif defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)

// Next few statements zero out all registers that may end up holding new variables.

Expand Down Expand Up @@ -1276,14 +1282,24 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
// For EnC-compliant x64 code, FP == SP. Since SP changed above, update FP now
pCtx->Rbp = newStackBase;

#elif defined(TARGET_ARM64)
#else
#if defined(TARGET_ARM64)
// Zero out volatile part of stack frame
// x0-x17
memset(&pCtx->X[0], 0, sizeof(pCtx->X[0]) * 18);
// v0-v7
memset(&pCtx->V[0], 0, sizeof(pCtx->V[0]) * 8);
// v16-v31
memset(&pCtx->V[16], 0, sizeof(pCtx->V[0]) * 16);
#elif defined(TARGET_AMD64)
// SysV ABI
pCtx->Rax = pCtx->Rdi = pCtx->Rsi = pCtx->Rdx = pCtx->Rcx = pCtx->R8 = pCtx->R9 = 0;

// volatile float registers
memset(&pCtx->Xmm0, 0, sizeof(pCtx->Xmm0) * 16);
#else
PORTABILITY_ASSERT("Edit-and-continue not enabled on this platform.");
#endif

TADDR newStackBase = callerSP - newFixedStackSize;

Expand All @@ -1293,12 +1309,9 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
_ASSERTE(frameHeaderSize <= oldFixedStackSize);
_ASSERTE(frameHeaderSize <= newFixedStackSize);

// EnC prolog saves only fp,lr and does it at sp-16. It should already
// be set up from previous version.
// EnC prolog saves only FP (and LR on arm64), and FP points to saved FP for frame chaining.
// These should already be set up from previous version.
_ASSERTE(GetFP(pCtx) == callerSP - 16);

#else // !X86
PORTABILITY_ASSERT("Edit-and-continue not enabled on this platform.");
#endif

// Perform some debug-only sanity checks on stack variables. Some checks are
Expand Down Expand Up @@ -1416,7 +1429,7 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
if (nNewPspSymStackSlot != NO_PSP_SYM)
{
#if defined(TARGET_AMD64)
*PTR_TADDR(newStackBase + nNewPspSymStackSlot) = GetFP(pCtx);
*PTR_TADDR(newStackBase + nNewPspSymStackSlot) = newStackBase;
#elif defined(TARGET_ARM64)
*PTR_TADDR(callerSP + nNewPspSymStackSlot) = callerSP;
#else
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/vm/encee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,9 +733,11 @@ HRESULT EditAndContinueModule::ResumeInUpdatedFunction(
// Win32 handlers on the stack so cannot ever return from this function.
EEPOLICY_HANDLE_FATAL_ERROR(CORDBG_E_ENC_INTERNAL_ERROR);
return E_FAIL;
#endif // #if defined(TARGET_ARM) || defined(TARGET_LOONGARCH64)
#endif // #if defined(TARGET_ARM) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)

}

#ifdef FEATURE_ENC_SUPPORTED
//---------------------------------------------------------------------------------------
//
// FixContextAndResume - Modify the thread context for EnC remap and resume execution
Expand Down Expand Up @@ -871,6 +873,8 @@ NOINLINE void EditAndContinueModule::FixContextAndResume(
LOG((LF_ENC, LL_ERROR, "**Error** EnCModule::ResumeInUpdatedFunction returned from ResumeAtJit"));
_ASSERTE(!"Should not return from ResumeAtJit()");
}
#endif // #ifdef FEATURE_ENC_SUPPORTED

#endif // #ifndef DACCESS_COMPILE

//---------------------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/encee.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,14 @@ class EditAndContinueModule : public Module
SIZE_T newILOffset,
T_CONTEXT *pContext);

#ifdef FEATURE_ENC_SUPPORTED
// Modify the thread context for EnC remap and resume execution
void FixContextAndResume(MethodDesc *pMD,
void *oldDebuggerFuncHandle,
T_CONTEXT *pContext,
EECodeInfo *pOldCodeInfo,
EECodeInfo *pNewCodeInfo);
#endif // FEATURE_ENC_SUPPORTED

// Get a pointer to the value of a field added by EnC or return NULL if it doesn't exist
PTR_CBYTE ResolveField(OBJECTREF thisPointer,
Expand Down
5 changes: 2 additions & 3 deletions src/coreclr/vm/excep.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,10 +710,9 @@ bool IsInterceptableException(Thread *pThread);
// perform simple checking to see if the current exception is intercepted
bool CheckThreadExceptionStateForInterception();

#ifndef TARGET_UNIX
// Currently, only Windows supports ClrUnwindEx (used inside ClrDebuggerDoUnwindAndIntercept)
#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_X86)
#define DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED
#endif // !TARGET_UNIX
#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_X86)

#ifdef DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED
// Intercept the current exception and start an unwind. This function may never return.
Expand Down
36 changes: 36 additions & 0 deletions src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ ClrUnwindEx(EXCEPTION_RECORD* pExceptionRecord,
UINT_PTR TargetFrameSp);
#endif // !TARGET_UNIX

#if defined(TARGET_UNIX) && !defined(DACCESS_COMPILE)
VOID UnwindManagedExceptionPass2(PAL_SEHException& ex, CONTEXT* unwindStartContext);
#endif // TARGET_UNIX && !DACCESS_COMPILE

#ifdef USE_CURRENT_CONTEXT_IN_FILTER
inline void CaptureNonvolatileRegisters(PKNONVOLATILE_CONTEXT pNonvolatileContext, PCONTEXT pContext)
{
Expand Down Expand Up @@ -4210,7 +4214,16 @@ EXCEPTION_DISPOSITION ClrDebuggerDoUnwindAndIntercept(X86_FIRST_ARG(EXCEPTION_RE
(PBYTE*)&uInterceptStackFrame,
NULL, NULL);

#ifdef TARGET_UNIX
CONTEXT *pContext = pThread->GetExceptionState()->GetContextRecord();
PAL_SEHException ex(pThread->GetExceptionState()->GetExceptionRecord(), pContext, /* onStack */ false);
ex.TargetIp = INVALID_RESUME_ADDRESS;
ex.TargetFrameSp = uInterceptStackFrame;
ex.ReturnValue = (UINT_PTR)pThread;
UnwindManagedExceptionPass2(ex, pContext);
#else // TARGET_UNIX
ClrUnwindEx(pExceptionRecord, (UINT_PTR)pThread, INVALID_RESUME_ADDRESS, uInterceptStackFrame);
#endif // TARGET_UNIX

UNREACHABLE();
}
Expand Down Expand Up @@ -4554,6 +4567,29 @@ VOID UnwindManagedExceptionPass2(PAL_SEHException& ex, CONTEXT* unwindStartConte

} while (Thread::IsAddressInCurrentStack(sp) && (establisherFrame != ex.TargetFrameSp));

#ifdef DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED
if ((establisherFrame == ex.TargetFrameSp) && (ex.TargetIp != 0))
{
#ifdef TARGET_AMD64
#define RETURN_REG Rax
#elif defined(TARGET_ARM64)
#define RETURN_REG X0
#elif defined(TARGET_ARM)
#define RETURN_REG R0
#elif defined(TARGET_X86)
#define RETURN_REG Eax
#else
#error Missing definition of RETURN_REG for the current architecture
#endif
currentFrameContext->RETURN_REG = ex.ReturnValue;
if (ex.GetExceptionRecord()->ExceptionCode != STATUS_UNWIND_CONSOLIDATE)
{
SetIP(currentFrameContext, ex.TargetIp);
}
ExceptionTracker::ResumeExecution(currentFrameContext);
}
#endif // DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED

_ASSERTE(!"UnwindManagedExceptionPass2: Unwinding failed. Reached the end of the stack");
EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
}
Expand Down