diff --git a/src/coreclr/debug/di/valuehome.cpp b/src/coreclr/debug/di/valuehome.cpp index 0140f0c795c7fd..5320ed22332507 100644 --- a/src/coreclr/debug/di/valuehome.cpp +++ b/src/coreclr/debug/di/valuehome.cpp @@ -451,11 +451,6 @@ void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) { - // TODO: : implement CordbValue::SetEnregisteredValue for RAK_FLOAT - #if defined(TARGET_AMD64) - PORTABILITY_ASSERT("NYI: SetEnregisteredValue (divalue.cpp): RAK_FLOAT for AMD64"); - #endif // TARGET_AMD64 - _ASSERTE((newValue.Size() == 4) || (newValue.Size() == 8)); // Convert the input to a double. @@ -463,14 +458,7 @@ void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, memcpy(&newVal, newValue.StartAddress(), newValue.Size()); - #if defined(TARGET_X86) - - // This is unfortunately non-portable. Luckily we can live with this for now since we only support - // Win/X86 debugging a Mac/X86 platform. - - #if !defined(TARGET_X86) - #error Unsupported target platform - #endif // !TARGET_X86 +#if defined(TARGET_X86) // What a pain, on X86 take the floating // point state in the context and make it our current FP @@ -576,7 +564,7 @@ void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, : "m"(currentFPUState) ); #endif - #endif // TARGET_X86 +#endif // TARGET_X86 // update the thread's floating point stack void * valueAddress = (void *) &(m_pFrame->m_pThread->m_floatValues[m_floatIndex]); @@ -596,19 +584,19 @@ void FloatRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) // RemoteValueHome implementation // ============================================================================ - // constructor - // Arguments: - // input: pProcess - the process to which the value belongs - // remoteValue - a buffer with the target address of the value and its size - // Note: It's possible a particular instance of CordbGenericValue may have neither a remote address nor a - // register address--FuncEval makes empty GenericValues for literals but for those, we will make a - // RegisterValueHome,so we can assert that we have a non-null remote address here - RemoteValueHome::RemoteValueHome(CordbProcess * pProcess, TargetBuffer remoteValue): - ValueHome(pProcess), - m_remoteValue(remoteValue) - { - _ASSERTE(remoteValue.pAddress != 0); - } // RemoteValueHome::RemoteValueHome +// constructor +// Arguments: +// input: pProcess - the process to which the value belongs +// remoteValue - a buffer with the target address of the value and its size +// Note: It's possible a particular instance of CordbGenericValue may have neither a remote address nor a +// register address--FuncEval makes empty GenericValues for literals but for those, we will make a +// RegisterValueHome,so we can assert that we have a non-null remote address here +RemoteValueHome::RemoteValueHome(CordbProcess * pProcess, TargetBuffer remoteValue): + ValueHome(pProcess), + m_remoteValue(remoteValue) +{ + _ASSERTE(remoteValue.pAddress != 0); +} // RemoteValueHome::RemoteValueHome // Gets a value and returns it in dest // virtual diff --git a/src/coreclr/inc/palclr.h b/src/coreclr/inc/palclr.h index 6985ced7f39dd5..e5bf90acea0ed1 100644 --- a/src/coreclr/inc/palclr.h +++ b/src/coreclr/inc/palclr.h @@ -88,7 +88,7 @@ // The message in these two macros should not contain any keywords like TODO // or NYI. It should be just the brief description of the problem. -#if defined(TARGET_X86) +#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) // Finished ports - compile-time errors #define PORTABILITY_WARNING(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE) #define PORTABILITY_ASSERT(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE) @@ -96,7 +96,7 @@ // Ports in progress - run-time asserts only #define PORTABILITY_WARNING(message) #define PORTABILITY_ASSERT(message) _ASSERTE(false && (message)) -#endif +#endif // TARGET_X86 || TARGET_AMD64 || TARGET_ARM || TARGET_ARM64 #define DIRECTORY_SEPARATOR_CHAR_A '\\' #define DIRECTORY_SEPARATOR_STR_A "\\" diff --git a/src/coreclr/utilcode/dacutil.cpp b/src/coreclr/utilcode/dacutil.cpp index 7df08858f2eb7b..d8bd3180bc83c5 100644 --- a/src/coreclr/utilcode/dacutil.cpp +++ b/src/coreclr/utilcode/dacutil.cpp @@ -12,6 +12,7 @@ #include #include #include +#include //---------------------------------------------------------------------------- // @@ -74,15 +75,7 @@ LiveProcDataTarget::GetMachineType( { LIMITED_METHOD_CONTRACT; -#if defined(TARGET_X86) - *machine = IMAGE_FILE_MACHINE_I386; -#elif defined(TARGET_AMD64) - *machine = IMAGE_FILE_MACHINE_AMD64; -#elif defined(TARGET_ARM) - *machine = IMAGE_FILE_MACHINE_ARMNT; -#else - PORTABILITY_ASSERT("Unknown Processor"); -#endif + *machine = IMAGE_FILE_MACHINE_NATIVE; return S_OK; } diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index 659f8c7b751119..6941ea8e633393 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -6663,14 +6663,7 @@ bool Thread::InitRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, bool validCo SetIP(pctx, 0); #ifdef TARGET_X86 SetRegdisplayPCTAddr(pRD, (TADDR)&(pctx->Eip)); -#elif defined(TARGET_AMD64) - // nothing more to do here, on Win64 setting the IP to 0 is enough. -#elif defined(TARGET_ARM) - // nothing more to do here, on Win64 setting the IP to 0 is enough. -#else - PORTABILITY_ASSERT("NYI for platform Thread::InitRegDisplay"); #endif - return false; } #endif // DACCESS_COMPILE diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index 4a2c122d453e2f..64816aada06371 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -4521,16 +4521,24 @@ void Thread::WaitSuspendEvents() // State of execution when we suspend a thread struct ExecutionState { - BOOL m_FirstPass; - BOOL m_IsJIT; // are we executing JITted code? +#ifdef TARGET_X86 + bool m_FirstPass; +#endif + bool m_IsJIT; // are we executing JITted code? + bool m_IsInterruptible; // is this code interruptible? MethodDesc *m_pFD; // current function/method we're executing VOID **m_ppvRetAddrPtr; // pointer to return address in frame DWORD m_RelOffset; // relative offset at which we're currently executing in this fcn IJitManager *m_pJitManager; METHODTOKEN m_MethodToken; - BOOL m_IsInterruptible; // is this code interruptible? - ExecutionState() : m_FirstPass(TRUE) {LIMITED_METHOD_CONTRACT; } + ExecutionState() + { + LIMITED_METHOD_CONTRACT; +#ifdef TARGET_X86 + m_FirstPass = true; +#endif + } }; // Client is responsible for suspending the thread before calling @@ -4651,183 +4659,180 @@ StackWalkAction SWCB_GetExecutionState(CrawlFrame *pCF, VOID *pData) ExecutionState *pES = (ExecutionState *) pData; StackWalkAction action = SWA_ABORT; - if (pES->m_FirstPass) +#ifdef TARGET_X86 + if (!pES->m_FirstPass) { - // This will help factor out some repeated code. - bool notJittedCase = false; + // Second pass, looking for the address of the return address so we can + // hijack: + + PREGDISPLAY pRDT = pCF->GetRegisterSet(); - // If we're jitted code at the top of the stack, grab everything - if (pCF->IsFrameless() && pCF->IsActiveFunc()) + if (pRDT != NULL) { - pES->m_IsJIT = TRUE; - pES->m_pFD = pCF->GetFunction(); - pES->m_MethodToken = pCF->GetMethodToken(); - pES->m_ppvRetAddrPtr = 0; - pES->m_IsInterruptible = pCF->IsGcSafe(); - pES->m_RelOffset = pCF->GetRelOffset(); - pES->m_pJitManager = pCF->GetJitManager(); + // pPC points to the return address sitting on the stack, as our + // current EIP for the penultimate stack frame. + pES->m_ppvRetAddrPtr = (void **) GetRegdisplayPCTAddr(pRDT); + + STRESS_LOG2(LF_SYNC, LL_INFO1000, "Partially Int case hijack address = 0x%x val = 0x%x\n", pES->m_ppvRetAddrPtr, *pES->m_ppvRetAddrPtr); + } + return action; + } +#endif // TARGET_X86 + + // This will help factor out some repeated code. + bool notJittedCase = false; - STRESS_LOG3(LF_SYNC, LL_INFO1000, "Stopped in Jitted code at pc = %p sp = %p fullyInt=%d\n", - GetControlPC(pCF->GetRegisterSet()), GetRegdisplaySP(pCF->GetRegisterSet()), pES->m_IsInterruptible); + // If we're jitted code at the top of the stack, grab everything + if (pCF->IsFrameless() && pCF->IsActiveFunc()) + { + pES->m_IsJIT = true; + pES->m_pFD = pCF->GetFunction(); + pES->m_MethodToken = pCF->GetMethodToken(); + pES->m_ppvRetAddrPtr = 0; + pES->m_IsInterruptible = pCF->IsGcSafe(); + pES->m_RelOffset = pCF->GetRelOffset(); + pES->m_pJitManager = pCF->GetJitManager(); + + STRESS_LOG3(LF_SYNC, LL_INFO1000, "Stopped in Jitted code at pc = %p sp = %p fullyInt=%d\n", + GetControlPC(pCF->GetRegisterSet()), GetRegdisplaySP(pCF->GetRegisterSet()), pES->m_IsInterruptible); #if defined(FEATURE_CONSERVATIVE_GC) && !defined(USE_GC_INFO_DECODER) - if (g_pConfig->GetGCConservative()) + if (g_pConfig->GetGCConservative()) + { + // Conservative GC enabled; behave as if HIJACK_NONINTERRUPTIBLE_THREADS had not been + // set above: + // + notJittedCase = true; + } + else +#endif // FEATURE_CONSERVATIVE_GC + { +#ifndef HIJACK_NONINTERRUPTIBLE_THREADS + if (!pES->m_IsInterruptible) { - // Conservative GC enabled; behave as if HIJACK_NONINTERRUPTIBLE_THREADS had not been - // set above: - // notJittedCase = true; } - else -#endif // FEATURE_CONSERVATIVE_GC +#else // HIJACK_NONINTERRUPTIBLE_THREADS + // if we're not interruptible right here, we need to determine the + // return address for hijacking. + if (!pES->m_IsInterruptible) { -#ifndef HIJACK_NONINTERRUPTIBLE_THREADS - if (!pES->m_IsInterruptible) +#ifdef FEATURE_EH_FUNCLETS + PREGDISPLAY pRDT = pCF->GetRegisterSet(); + _ASSERTE(pRDT != NULL); + + // For simplicity, don't hijack in funclets + bool fIsFunclet = pCF->IsFunclet(); + if (fIsFunclet) { notJittedCase = true; } -#else // HIJACK_NONINTERRUPTIBLE_THREADS - // if we're not interruptible right here, we need to determine the - // return address for hijacking. - if (!pES->m_IsInterruptible) + else { -#ifdef FEATURE_EH_FUNCLETS - PREGDISPLAY pRDT = pCF->GetRegisterSet(); - _ASSERTE(pRDT != NULL); - - // For simplicity, don't hijack in funclets - bool fIsFunclet = pCF->IsFunclet(); - if (fIsFunclet) - { - notJittedCase = true; - } - else - { - // We already have the caller context available at this point - _ASSERTE(pRDT->IsCallerContextValid); + // We already have the caller context available at this point + _ASSERTE(pRDT->IsCallerContextValid); #if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - // Why do we use CallerContextPointers below? - // - // Assume the following callstack, growing from left->right: - // - // C -> B -> A - // - // Assuming A is non-interruptible function and pushes LR on stack, - // when we get the stackwalk callback for A, the CallerContext would - // contain non-volatile register state for B and CallerContextPtrs would - // contain the location where the caller's (B's) non-volatiles where restored - // from. This would be the stack location in A where they were pushed. Thus, - // CallerContextPtrs->Lr would contain the stack location in A where LR (representing an address in B) - // was pushed and thus, contains the return address in B. - - // Note that the JIT always pushes LR even for leaf methods to make hijacking - // work for them. See comment in code:Compiler::genPushCalleeSavedRegisters. + // Why do we use CallerContextPointers below? + // + // Assume the following callstack, growing from left->right: + // + // C -> B -> A + // + // Assuming A is non-interruptible function and pushes LR on stack, + // when we get the stackwalk callback for A, the CallerContext would + // contain non-volatile register state for B and CallerContextPtrs would + // contain the location where the caller's (B's) non-volatiles where restored + // from. This would be the stack location in A where they were pushed. Thus, + // CallerContextPtrs->Lr would contain the stack location in A where LR (representing an address in B) + // was pushed and thus, contains the return address in B. + + // Note that the JIT always pushes LR even for leaf methods to make hijacking + // work for them. See comment in code:Compiler::genPushCalleeSavedRegisters. #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - if (pRDT->pCallerContextPointers->Ra == &pRDT->pContext->Ra) + if (pRDT->pCallerContextPointers->Ra == &pRDT->pContext->Ra) #else - if(pRDT->pCallerContextPointers->Lr == &pRDT->pContext->Lr) + if(pRDT->pCallerContextPointers->Lr == &pRDT->pContext->Lr) #endif - { - // This is the case when we are either: - // - // 1) In a leaf method that does not push LR on stack, OR - // 2) In the prolog/epilog of a non-leaf method that has not yet pushed LR on stack - // or has LR already popped off. - // - // The remaining case of non-leaf method is that of IP being in the body of the - // function. In such a case, LR would be have been pushed on the stack and thus, - // we wouldnt be here but in the "else" clause below. - // - // For (1) we can use CallerContext->ControlPC to be used as the return address - // since we know that leaf frames will return back to their caller. - // For this, we may need JIT support to do so. - notJittedCase = true; - } - else if (pCF->HasTailCalls()) - { - // Do not hijack functions that have tail calls, since there are two problems: - // 1. When a function that tail calls another one is hijacked, the LR may be - // stored at a different location in the stack frame of the tail call target. - // So just by performing tail call, the hijacked location becomes invalid and - // unhijacking would corrupt stack by writing to that location. - // 2. There is a small window after the caller pops LR from the stack in its - // epilog and before the tail called function pushes LR in its prolog when - // the hijacked return address would not be not on the stack and so we would - // not be able to unhijack. - notJittedCase = true; - } - else - { - // This is the case of IP being inside the method body and LR is - // pushed on the stack. We get it to determine the return address - // in the caller of the current non-interruptible frame. + { + // This is the case when we are either: + // + // 1) In a leaf method that does not push LR on stack, OR + // 2) In the prolog/epilog of a non-leaf method that has not yet pushed LR on stack + // or has LR already popped off. + // + // The remaining case of non-leaf method is that of IP being in the body of the + // function. In such a case, LR would be have been pushed on the stack and thus, + // we wouldnt be here but in the "else" clause below. + // + // For (1) we can use CallerContext->ControlPC to be used as the return address + // since we know that leaf frames will return back to their caller. + // For this, we may need JIT support to do so. + notJittedCase = true; + } + else if (pCF->HasTailCalls()) + { + // Do not hijack functions that have tail calls, since there are two problems: + // 1. When a function that tail calls another one is hijacked, the LR may be + // stored at a different location in the stack frame of the tail call target. + // So just by performing tail call, the hijacked location becomes invalid and + // unhijacking would corrupt stack by writing to that location. + // 2. There is a small window after the caller pops LR from the stack in its + // epilog and before the tail called function pushes LR in its prolog when + // the hijacked return address would not be not on the stack and so we would + // not be able to unhijack. + notJittedCase = true; + } + else + { + // This is the case of IP being inside the method body and LR is + // pushed on the stack. We get it to determine the return address + // in the caller of the current non-interruptible frame. #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - pES->m_ppvRetAddrPtr = (void **) pRDT->pCallerContextPointers->Ra; + pES->m_ppvRetAddrPtr = (void **) pRDT->pCallerContextPointers->Ra; #else - pES->m_ppvRetAddrPtr = (void **) pRDT->pCallerContextPointers->Lr; + pES->m_ppvRetAddrPtr = (void **) pRDT->pCallerContextPointers->Lr; #endif - } + } #elif defined(TARGET_X86) - // peel off the next frame to expose the return address on the stack - pES->m_FirstPass = FALSE; - action = SWA_CONTINUE; + // peel off the next frame to expose the return address on the stack + pES->m_FirstPass = FALSE; + action = SWA_CONTINUE; #elif defined(TARGET_AMD64) - pES->m_ppvRetAddrPtr = (void **) (EECodeManager::GetCallerSp(pRDT) - sizeof(void*)); + pES->m_ppvRetAddrPtr = (void **) (EECodeManager::GetCallerSp(pRDT) - sizeof(void*)); #else // TARGET_X86 || TARGET_AMD64 - PORTABILITY_ASSERT("Platform NYI"); + PORTABILITY_ASSERT("Platform NYI"); #endif // _TARGET_???_ - } + } #else // FEATURE_EH_FUNCLETS - // peel off the next frame to expose the return address on the stack - pES->m_FirstPass = FALSE; - action = SWA_CONTINUE; + // peel off the next frame to expose the return address on the stack + pES->m_FirstPass = FALSE; + action = SWA_CONTINUE; #endif // !FEATURE_EH_FUNCLETS - } -#endif // HIJACK_NONINTERRUPTIBLE_THREADS } - // else we are successfully out of here with SWA_ABORT - } - else - { -#ifdef TARGET_X86 - STRESS_LOG2(LF_SYNC, LL_INFO1000, "Not in Jitted code at EIP = %p, &EIP = %p\n", GetControlPC(pCF->GetRegisterSet()), GetRegdisplayPCTAddr(pCF->GetRegisterSet())); -#else - STRESS_LOG1(LF_SYNC, LL_INFO1000, "Not in Jitted code at pc = %p\n", GetControlPC(pCF->GetRegisterSet())); -#endif - notJittedCase = true; - } - - // Cases above may have set "notJITtedCase", which we handle as follows: - if (notJittedCase) - { - pES->m_IsJIT = FALSE; -#ifdef _DEBUG - pES->m_pFD = (MethodDesc *)POISONC; - pES->m_ppvRetAddrPtr = (void **)POISONC; - pES->m_IsInterruptible = FALSE; -#endif +#endif // HIJACK_NONINTERRUPTIBLE_THREADS } + // else we are successfully out of here with SWA_ABORT } else { #ifdef TARGET_X86 - // Second pass, looking for the address of the return address so we can - // hijack: - - PREGDISPLAY pRDT = pCF->GetRegisterSet(); - - if (pRDT != NULL) - { - // pPC points to the return address sitting on the stack, as our - // current EIP for the penultimate stack frame. - pES->m_ppvRetAddrPtr = (void **) GetRegdisplayPCTAddr(pRDT); - - STRESS_LOG2(LF_SYNC, LL_INFO1000, "Partially Int case hijack address = 0x%x val = 0x%x\n", pES->m_ppvRetAddrPtr, *pES->m_ppvRetAddrPtr); - } + STRESS_LOG2(LF_SYNC, LL_INFO1000, "Not in Jitted code at EIP = %p, &EIP = %p\n", GetControlPC(pCF->GetRegisterSet()), GetRegdisplayPCTAddr(pCF->GetRegisterSet())); #else - PORTABILITY_ASSERT("Platform NYI"); + STRESS_LOG1(LF_SYNC, LL_INFO1000, "Not in Jitted code at pc = %p\n", GetControlPC(pCF->GetRegisterSet())); +#endif + notJittedCase = true; + } + + // Cases above may have set "notJITtedCase", which we handle as follows: + if (notJittedCase) + { + pES->m_IsJIT = false; +#ifdef _DEBUG + pES->m_pFD = (MethodDesc *)POISONC; + pES->m_ppvRetAddrPtr = (void **)POISONC; + pES->m_IsInterruptible = false; #endif }