diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 5f96d98b6e228d..dd869b413149c8 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -7327,6 +7327,48 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetGenericArgTokenIndex(VMPTR_Met return S_OK; } +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetInfo(OUT TargetInfo * pTargetInfo) +{ + DD_ENTER_MAY_THROW; + + if (pTargetInfo == NULL) + return E_INVALIDARG; + +#if defined(TARGET_X86) + pTargetInfo->arch = kArchX86; +#elif defined(TARGET_AMD64) + pTargetInfo->arch = kArchAMD64; +#elif defined(TARGET_ARM) + pTargetInfo->arch = kArchArm; +#elif defined(TARGET_ARM64) + pTargetInfo->arch = kArchArm64; +#elif defined(TARGET_LOONGARCH64) + pTargetInfo->arch = kArchLoongArch64; +#elif defined(TARGET_RISCV64) + pTargetInfo->arch = kArchRiscV64; +#elif defined(TARGET_WASM) + pTargetInfo->arch = kArchWasm; +#else + pTargetInfo->arch = kArchUnknown; +#endif + +#if defined(TARGET_UNIX) + pTargetInfo->os = kOSUnix; +#elif defined(TARGET_WINDOWS) + pTargetInfo->os = kOSWindows; +#else + pTargetInfo->os = kOSUnknown; +#endif + +#if defined(TARGET_64BIT) + pTargetInfo->pointerSize = 8; +#else + pTargetInfo->pointerSize = 4; +#endif + + return S_OK; +} + DacRefWalker::DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, UINT32 handleMask, BOOL resolvePointers) : mDac(dac), mWalkStacks(walkStacks), mHandleMask(handleMask), mStackWalker(NULL), mResolvePointers(resolvePointers), mHandleWalker(NULL) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index ec0aa77dfc66af..93494db1d0412c 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -151,6 +151,8 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE EnumerateAsyncLocals(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeAddr, UINT32 state, FP_ASYNC_LOCAL_CALLBACK fpCallback, CALLBACK_DATA pUserData); HRESULT STDMETHODCALLTYPE GetGenericArgTokenIndex(VMPTR_MethodDesc vmMethod, OUT UINT32* pIndex); + HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo); + private: void TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed, TypeHandle typeHandle, diff --git a/src/coreclr/debug/di/cordb.cpp b/src/coreclr/debug/di/cordb.cpp index 036ae1fb217491..6010e1404ee4e2 100644 --- a/src/coreclr/debug/di/cordb.cpp +++ b/src/coreclr/debug/di/cordb.cpp @@ -18,13 +18,6 @@ #include "dbgtransportmanager.h" #endif // FEATURE_DBGIPC_TRANSPORT_DI -#if defined(TARGET_UNIX) || defined(__ANDROID__) -// Local (in-process) debugging is not supported for UNIX and Android. -#define SUPPORT_LOCAL_DEBUGGING 0 -#else -#define SUPPORT_LOCAL_DEBUGGING 1 -#endif - //----------------------------------------------------------------------------- // SxS Versioning story for Mscordbi (ICorDebug + friends) //----------------------------------------------------------------------------- @@ -437,7 +430,7 @@ DbiGetThreadContext(HANDLE hThread, DT_CONTEXT *lpContext) { // if we aren't local debugging this isn't going to work -#if !defined(HOST_ARM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING +#if !defined(HOST_ARM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(__ANDROID__) _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget"); return FALSE; #else @@ -476,7 +469,7 @@ BOOL DbiSetThreadContext(HANDLE hThread, const DT_CONTEXT *lpContext) { -#if !defined(HOST_ARM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING +#if !defined(HOST_ARM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(__ANDROID__) _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget"); return FALSE; #else diff --git a/src/coreclr/debug/di/module.cpp b/src/coreclr/debug/di/module.cpp index c261d88df78c6b..07e76f9c2d0290 100644 --- a/src/coreclr/debug/di/module.cpp +++ b/src/coreclr/debug/di/module.cpp @@ -883,7 +883,7 @@ HRESULT CordbModule::InitPublicMetaDataFromFile(const WCHAR * pszFullPathName, } return hr; -#endif // TARGET_UNIX +#endif // HOST_UNIX } //--------------------------------------------------------------------------------------- @@ -2412,7 +2412,7 @@ HRESULT CordbModule::CreateReaderForInMemorySymbols(REFIID riid, void** ppObj) ReleaseHolder pBinder; if (symFormat == IDacDbiInterface::kSymbolFormatPDB) { -#ifndef TARGET_UNIX +#ifndef HOST_UNIX // PDB format - use diasymreader.dll with COM activation InlineSString ssBuf; IfFailThrow(GetClrModuleDirectory(ssBuf)); diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 66d33e4ff16f5c..4e55414cf752f6 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -178,11 +178,11 @@ STDAPI DLLEXPORT OpenVirtualProcessImpl2( IUnknown ** ppInstance, CLR_DEBUGGING_PROCESS_FLAGS* pFlagsOut) { -#ifdef TARGET_WINDOWS +#ifdef HOST_WINDOWS HMODULE hDac = WszLoadLibrary(pDacModulePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); #else HMODULE hDac = WszLoadLibrary(pDacModulePath); -#endif // !TARGET_WINDOWS +#endif // !HOST_WINDOWS if (hDac == NULL) { return HRESULT_FROM_WIN32(GetLastError()); @@ -648,6 +648,35 @@ IDacDbiInterface * CordbProcess::GetDAC() return m_pDacPrimitives; } +HRESULT CordbProcess::GetTargetInfo(IDacDbiInterface::TargetInfo * pTargetInfo) +{ + CONTRACTL + { + THROWS; + } + CONTRACTL_END; + + if (pTargetInfo == NULL) + return E_INVALIDARG; + + HRESULT hr = S_OK; + EX_TRY + { + RSLockHolder lockHolder(GetProcessLock()); + + if (!m_fHasCachedTargetInfo) + { + IfFailThrow(GetDAC()->GetTargetInfo(&m_cachedTargetInfo)); + m_fHasCachedTargetInfo = true; + } + + *pTargetInfo = m_cachedTargetInfo; + } + EX_CATCH_HRESULT(hr); + + return hr; +} + //--------------------------------------------------------------------------------------- // Get the Data-Target // @@ -852,6 +881,7 @@ CordbProcess::CordbProcess(ULONG64 clrInstanceId, m_dispatchedEvent(DB_IPCE_DEBUGGER_INVALID), m_hDacModule(hDacModule), m_pDacPrimitives(NULL), + m_fHasCachedTargetInfo(false), m_pEventChannel(NULL), m_fAssertOnTargetInconsistency(false), m_runtimeOffsetsInitialized(false), @@ -6582,15 +6612,9 @@ HRESULT CordbProcess::FindPatchByAddress(CORDB_ADDRESS address, bool *pfPatchFou if (*pfPatchFound == false) { // Read one instruction from the faulting address... -#if defined(TARGET_ARM) || defined(TARGET_ARM64) - PRD_TYPE TrapCheck = 0; -#else - BYTE TrapCheck = 0; -#endif - - HRESULT hr2 = SafeReadStruct(address, &TrapCheck); - - if (SUCCEEDED(hr2) && (TrapCheck != CORDbg_BREAK_INSTRUCTION)) + ULONG32 TrapCheck = 0; + HRESULT hr2 = SafeReadBreakpointPatch(address, &TrapCheck); + if (SUCCEEDED(hr2) && (TrapCheck != (ULONG32) CORDbg_BREAK_INSTRUCTION)) { LOG((LF_CORDB, LL_INFO1000, "CP::FPBA: patchFound=true based on odd missing int 3 case.\n")); @@ -6627,16 +6651,19 @@ HRESULT CordbProcess::WriteMemory(CORDB_ADDRESS address, DWORD size, DWORD fCheckInt3 = configCheckInt3.val(CLRConfig::INTERNAL_DbgCheckInt3); if (fCheckInt3) { -#if defined(TARGET_X86) || defined(TARGET_AMD64) - if (size == 1 && buffer[0] == 0xCC) + IDacDbiInterface::TargetInfo targetInfo; + if (SUCCEEDED(GetTargetInfo(&targetInfo)) && + (targetInfo.arch == IDacDbiInterface::kArchX86 || targetInfo.arch == IDacDbiInterface::kArchAMD64)) { - CONSISTENCY_CHECK_MSGF(false, - ("You're using ICorDebugProcess::WriteMemory() to write an 'int3' (1 byte 0xCC) at address 0x%p.\n" - "If you're trying to set a breakpoint, you should be using ICorDebugProcess::SetUnmanagedBreakpoint() instead.\n" - "(This assert is only enabled under the CLR knob DbgCheckInt3.)\n", - CORDB_ADDRESS_TO_PTR(address))); + if (size == 1 && buffer[0] == 0xCC) + { + CONSISTENCY_CHECK_MSGF(false, + ("You're using ICorDebugProcess::WriteMemory() to write an 'int3' (1 byte 0xCC) at address 0x%p.\n" + "If you're trying to set a breakpoint, you should be using ICorDebugProcess::SetUnmanagedBreakpoint() instead.\n" + "(This assert is only enabled under the CLR knob DbgCheckInt3.)\n", + CORDB_ADDRESS_TO_PTR(address))); + } } -#endif // TARGET_X86 || TARGET_AMD64 // check if we're replaced an opcode. if (size == 1) @@ -7074,7 +7101,7 @@ HRESULT CordbProcess::GetRuntimeOffsets() { -#if TARGET_UNIX +#if HOST_UNIX m_hHelperThread = NULL; //RS is supposed to be able to live without a helper thread handle. #else m_hHelperThread = OpenThread(SYNCHRONIZE, FALSE, dwHelperTid); @@ -8128,6 +8155,89 @@ HRESULT CordbProcess::SafeReadBuffer(TargetBuffer tb, BYTE * pLocalBuffer, BOOL return S_OK; } +//----------------------------------------------------------------------------- +// Returns the width, in bytes, of the breakpoint opcode in the target's +// instruction stream, determined from the target's architecture at runtime. +//----------------------------------------------------------------------------- +HRESULT CordbProcess::GetTargetBreakpointSize(ULONG32 * pcbSize) +{ + _ASSERTE(pcbSize != NULL); + + IDacDbiInterface::TargetInfo targetInfo; + HRESULT hr = GetTargetInfo(&targetInfo); + if (FAILED(hr)) + return hr; + + switch (targetInfo.arch) + { + case IDacDbiInterface::kArchX86: + case IDacDbiInterface::kArchAMD64: + case IDacDbiInterface::kArchWasm: + *pcbSize = 1; + break; + + case IDacDbiInterface::kArchArm: + *pcbSize = 2; + break; + + case IDacDbiInterface::kArchArm64: + case IDacDbiInterface::kArchLoongArch64: + case IDacDbiInterface::kArchRiscV64: + *pcbSize = 4; + break; + + default: + _ASSERTE(!"NYI: breakpoint opcode size for this target architecture"); + return E_NOTIMPL; + } + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Reads the breakpoint opcode from the target using the target's instruction +// width. The value is zero-extended into pOpcode. +//----------------------------------------------------------------------------- +HRESULT CordbProcess::SafeReadBreakpointPatch(CORDB_ADDRESS pRemotePtr, ULONG32 * pOpcode) +{ + ULONG32 cbSize = 0; + HRESULT hr = GetTargetBreakpointSize(&cbSize); + if (FAILED(hr)) + return hr; + + _ASSERTE(cbSize <= sizeof(ULONG32)); + + *pOpcode = 0; + EX_TRY + { + TargetBuffer tb(pRemotePtr, cbSize); + SafeReadBuffer(tb, (PBYTE) pOpcode); + } + EX_CATCH_HRESULT(hr); + return hr; +} + +//----------------------------------------------------------------------------- +// Writes an opcode to the target using the target's instruction width. +//----------------------------------------------------------------------------- +HRESULT CordbProcess::SafeWriteBreakpointPatch(CORDB_ADDRESS pRemotePtr, ULONG32 opcode) +{ + ULONG32 cbSize = 0; + HRESULT hr = GetTargetBreakpointSize(&cbSize); + if (FAILED(hr)) + return hr; + + _ASSERTE(cbSize <= sizeof(ULONG32)); + + EX_TRY + { + TargetBuffer tb(pRemotePtr, cbSize); + SafeWriteBuffer(tb, (const BYTE *) &opcode); + } + EX_CATCH_HRESULT(hr); + return hr; +} + CordbAppDomain * CordbProcess::GetAppDomain() { // Return the one and only app domain @@ -8332,18 +8442,12 @@ bool CordbProcess::IsBreakOpcodeAtAddress(const void * address) { // There should have been an int3 there already. Since we already put it in there, // we should be able to safely read it out. -#if defined(TARGET_ARM) || defined(TARGET_ARM64) - PRD_TYPE opcodeTest = 0; -#elif defined(TARGET_AMD64) || defined(TARGET_X86) - BYTE opcodeTest = 0; -#else - PORTABILITY_ASSERT("NYI: Architecture specific opcode type to read"); -#endif + ULONG32 opcodeTest = 0; - HRESULT hr = SafeReadStruct(PTR_TO_CORDB_ADDRESS(address), &opcodeTest); + HRESULT hr = SafeReadBreakpointPatch(PTR_TO_CORDB_ADDRESS(address), &opcodeTest); SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr); - return (opcodeTest == CORDbg_BREAK_INSTRUCTION); + return (opcodeTest == (ULONG32) CORDbg_BREAK_INSTRUCTION); } #endif // FEATURE_INTEROP_DEBUGGING @@ -8397,20 +8501,14 @@ CordbProcess::SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufs HRESULT hr = S_OK; NativePatch * p = NULL; -#if defined(TARGET_X86) || defined(TARGET_AMD64) - const BYTE patch = CORDbg_BREAK_INSTRUCTION; - BYTE opcode; -#elif defined(TARGET_ARM64) - const PRD_TYPE patch = CORDbg_BREAK_INSTRUCTION; - PRD_TYPE opcode; -#else - PORTABILITY_ASSERT("NYI: CordbProcess::SetUnmanagedBreakpoint, interop debugging NYI on this platform"); - hr = E_NOTIMPL; - goto ErrExit; -#endif + ULONG32 opcode = 0; + ULONG32 cbOpcode = 0; + hr = GetTargetBreakpointSize(&cbOpcode); + if (FAILED(hr)) + goto ErrExit; // Make sure args are good - if ((buffer == NULL) || (bufsize < sizeof(patch)) || (bufLen == NULL)) + if ((buffer == NULL) || (bufsize < cbOpcode) || (bufLen == NULL)) { hr = E_INVALIDARG; goto ErrExit; @@ -8431,24 +8529,14 @@ CordbProcess::SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufs goto ErrExit; } - - // Read out opcode. 1 byte on x86 - hr = ApplyRemotePatch(this, CORDB_ADDRESS_TO_PTR(address), &p->opcode); if (FAILED(hr)) goto ErrExit; // It's all successful, so now update our out-params & internal bookkeaping. -#if defined(TARGET_X86) || defined(TARGET_AMD64) - opcode = (BYTE)p->opcode; - buffer[0] = opcode; -#elif defined(TARGET_ARM64) opcode = p->opcode; - memcpy_s(buffer, bufsize, &opcode, sizeof(opcode)); -#else - PORTABILITY_ASSERT("NYI: CordbProcess::SetUnmanagedBreakpoint, interop debugging NYI on this platform"); -#endif - *bufLen = sizeof(opcode); + memcpy_s(buffer, bufsize, &opcode, cbOpcode); + *bufLen = cbOpcode; p->pAddress = CORDB_ADDRESS_TO_PTR(address); p->opcode = opcode; @@ -8487,7 +8575,7 @@ CordbProcess::ClearUnmanagedBreakpoint(CORDB_ADDRESS address) _ASSERTE(!ThreadHoldsProcessLock()); HRESULT hr = S_OK; - PRD_TYPE opcode; + ULONG32 opcode; Lock(); @@ -10341,7 +10429,7 @@ bool CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) { LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded\n")); -#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64) +#if defined(HOST_WINDOWS) && defined(HOST_AMD64) // Before we can read the left side context information, we must: // 1. obtain the thread handle // 2. suspened the thread @@ -10362,7 +10450,7 @@ bool CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) bool m_fIsInPlaceSingleStep = false; bool m_fHasDebuggerPatchSkip = false; bool m_fClearSetIP = false; - PRD_TYPE m_opcode = 0; + ULONG32 m_opcode = 0; public: void Update(DT_CONTEXT * pContext) @@ -10372,7 +10460,7 @@ bool CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) this->m_fIsInPlaceSingleStep = (pContext->R8 & 0x1) != 0; this->m_fHasDebuggerPatchSkip = (pContext->R8 & 0x2) != 0; this->m_fClearSetIP = (pContext->R8 & 0x4) != 0; - this->m_opcode = (PRD_TYPE)pContext->R9; + this->m_opcode = (ULONG32)pContext->R9; } TADDR ContextAddr() { return m_lsContextAddr; } @@ -10380,7 +10468,7 @@ bool CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) bool IsInPlaceSingleStep() { return m_fIsInPlaceSingleStep; } bool HasDebuggerPatchSkip() { return m_fHasDebuggerPatchSkip; } bool IsClearSetIP() { return m_fClearSetIP; } - PRD_TYPE Opcode() { return m_opcode; } + ULONG32 Opcode() { return m_opcode; } HRESULT IsValid() { @@ -10594,7 +10682,7 @@ bool CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) #endif } -HRESULT CordbProcess::EnableInPlaceSingleStepping(UnmanagedThreadTracker * pCurThread, CORDB_ADDRESS_TYPE *patchSkipAddr, PRD_TYPE opcode) +HRESULT CordbProcess::EnableInPlaceSingleStepping(UnmanagedThreadTracker * pCurThread, CORDB_ADDRESS_TYPE *patchSkipAddr, ULONG32 opcode) { if (pCurThread == NULL || patchSkipAddr == NULL) { @@ -12451,14 +12539,9 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven tempDebugContext.ContextFlags = DT_CONTEXT_FULL; DbiGetThreadContext(pUnmanagedThread->m_handle, &tempDebugContext); CordbUnmanagedThread::LogContext(&tempDebugContext); -#if defined(TARGET_X86) || defined(TARGET_AMD64) - const ULONG_PTR breakpointOpcodeSize = 1; -#elif defined(TARGET_ARM64) - const ULONG_PTR breakpointOpcodeSize = 4; -#else - const ULONG_PTR breakpointOpcodeSize = 1; - PORTABILITY_ASSERT("NYI: Breakpoint size offset for this platform"); -#endif + + ULONG32 breakpointOpcodeSize = 0; + IfFailThrow(GetTargetBreakpointSize(&breakpointOpcodeSize)); _ASSERTE(CORDbgGetIP(&tempDebugContext) == pEvent->u.Exception.ExceptionRecord.ExceptionAddress || (DWORD)(size_t)CORDbgGetIP(&tempDebugContext) == ((DWORD)(size_t)pEvent->u.Exception.ExceptionRecord.ExceptionAddress)+breakpointOpcodeSize); } @@ -12674,10 +12757,13 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven // Because hijacks don't return normally they might have pushed handlers without poping them // back off. To take care of that we explicitly restore the old SEH chain. - #ifdef TARGET_X86 - hr = pUnmanagedThread->RestoreLeafSeh(); - _ASSERTE(SUCCEEDED(hr)); - #endif + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + hr = pUnmanagedThread->RestoreLeafSeh(); + _ASSERTE(SUCCEEDED(hr)); + } } else { @@ -13046,6 +13132,7 @@ bool CordbProcess::IsUnmanagedThreadHijacked(ICorDebugThread * pICorDebugThread) // this here. We have a check such that if we do get headers, the value won't change underneath us. #define MY_DBG_FORCE_CONTINUE ((DWORD )0x00010003L) #ifndef DBG_FORCE_CONTINUE + #define DBG_FORCE_CONTINUE MY_DBG_FORCE_CONTINUE #else static_assert(DBG_FORCE_CONTINUE == MY_DBG_FORCE_CONTINUE); @@ -13081,7 +13168,7 @@ void EnableDebugTrace(CordbUnmanagedThread *ut) return; // Give us a nop so that we can setip in the optimized case. -#ifdef TARGET_X86 +#if defined(HOST_X86) __asm { nop } diff --git a/src/coreclr/debug/di/rsmain.cpp b/src/coreclr/debug/di/rsmain.cpp index c7d5c5a9e24e49..7501d3f45e799b 100644 --- a/src/coreclr/debug/di/rsmain.cpp +++ b/src/coreclr/debug/di/rsmain.cpp @@ -508,7 +508,7 @@ void CordbCommonBase::InitializeCommon() // setting this since V1.0 and removing it may be a breaking change. void CordbCommonBase::AddDebugPrivilege() { -#ifndef TARGET_UNIX +#ifndef HOST_UNIX HANDLE hToken; TOKEN_PRIVILEGES Privileges; BOOL fSucc; diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index d4d9537c78f660..e025afdc92ef41 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -1153,11 +1153,11 @@ typedef enum { struct NativePatch { void * pAddress; // pointer into the LS address space. - PRD_TYPE opcode; // opcode to restore with. + ULONG32 opcode; // opcode to restore with. inline bool operator==(NativePatch p2) { - return memcmp(this, &p2, sizeof(p2)) == 0; + return (pAddress == p2.pAddress) && (opcode == p2.opcode); } }; @@ -1166,13 +1166,13 @@ struct NativePatch //----------------------------------------------------------------------------- // Remove the int3 from the remote address -HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE opcode); +HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, ULONG32 opcode); // This flavor is assuming our caller already knows the opcode. HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress); // Apply the patch and get the opcode that we're replacing. -HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE * pOpcode); +HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, ULONG32 * pOpcode); class CordbHashTable; @@ -2860,6 +2860,8 @@ class IProcessShimHooks virtual bool IsThreadSuspendedOrHijacked(ICorDebugThread * pThread) = 0; + virtual HRESULT GetTargetInfo(IDacDbiInterface::TargetInfo * pTargetInfo) = 0; + #ifdef FEATURE_INTEROP_DEBUGGING virtual bool IsUnmanagedThreadHijacked(ICorDebugThread * pICorDebugThread) = 0; #endif @@ -3277,6 +3279,12 @@ class CordbProcess : // Writes a buffer to the target void SafeWriteBuffer(TargetBuffer tb, const BYTE * pLocalBuffer); + // Reads the breakpoint opcode from the target, using the target's instruction width. + HRESULT SafeReadBreakpointPatch(CORDB_ADDRESS pRemotePtr, ULONG32 * pOpcode); + + // Writes an opcode to the target, using the target's instruction width. + HRESULT SafeWriteBreakpointPatch(CORDB_ADDRESS pRemotePtr, ULONG32 opcode); + #if defined(FEATURE_INTEROP_DEBUGGING) void DuplicateHandleToLocalProcess(HANDLE * pLocalHandle, RemoteHANDLE * pRemoteHandle); #endif // FEATURE_INTEROP_DEBUGGING @@ -3598,6 +3606,11 @@ class CordbProcess : // Get the DAC interface. IDacDbiInterface * GetDAC(); + HRESULT GetTargetInfo(IDacDbiInterface::TargetInfo * pTargetInfo); + + // Get the width, in bytes, of the breakpoint opcode in the target's instruction stream. + HRESULT GetTargetBreakpointSize(ULONG32 * pcbSize); + // Get the data-target, which provides access to the debuggee. ICorDebugDataTarget * GetDataTarget(); @@ -3961,7 +3974,7 @@ class CordbProcess : PRD_TYPE *m_rgUncommittedOpcode; // CORDB_ADDRESS's are UINT_PTR's (64 bit under HOST_64BIT, 32 bit otherwise) -#if defined(TARGET_64BIT) +#if defined(HOST_64BIT) #define MAX_ADDRESS (UINT64_MAX) #else #define MAX_ADDRESS (UINT32_MAX) @@ -4086,6 +4099,9 @@ class CordbProcess : IDacDbiInterface * m_pDacPrimitives; + IDacDbiInterface::TargetInfo m_cachedTargetInfo; + bool m_fHasCachedTargetInfo; + IEventChannel * m_pEventChannel; // If true, then we'll ASSERT if we detect the target is corrupt or inconsistent @@ -4104,7 +4120,7 @@ class CordbProcess : CUnmanagedThreadHashTableImpl m_unmanagedThreadHashTable; DWORD m_dwOutOfProcessStepping; bool m_fOutOfProcessSetThreadContextEventReceived; - HRESULT EnableInPlaceSingleStepping(UnmanagedThreadTracker * pCurThread, CORDB_ADDRESS_TYPE *patchSkipAddr, PRD_TYPE opcode); + HRESULT EnableInPlaceSingleStepping(UnmanagedThreadTracker * pCurThread, CORDB_ADDRESS_TYPE *patchSkipAddr, ULONG32 opcode); public: void HandleDebugEventForInPlaceStepping(const DEBUG_EVENT * pEvent); bool CanDetach(); // Must only be called on the Win32ET, determines if it is safe to detach. Only used by W32ETA_CAN_DETACH @@ -4770,11 +4786,9 @@ class CordbType : public CordbBase, public ICorDebugType, public ICorDebugType2 // Is this type a GC-root. bool IsGCRoot(); -#ifdef FEATURE_64BIT_ALIGNMENT // checks if the type requires 8-byte alignment. // this is not exposed via ICorDebug at present. HRESULT RequiresAlign8(BOOL* isRequired); -#endif //----------------------------------------------------------- // Data members @@ -10481,7 +10495,6 @@ class CordbUnmanagedThread : public CordbBase void HijackToRaiseException(); void RestoreFromRaiseExceptionHijack(); - void SaveRaiseExceptionEntryContext(); void ClearRaiseExceptionEntryContext(); BOOL IsExceptionFromLastRaiseException(const EXCEPTION_RECORD* pExceptionRecord); @@ -10494,12 +10507,10 @@ class CordbUnmanagedThread : public CordbBase return (DWORD) this->m_id; } -#ifdef TARGET_X86 // Stores the thread's current leaf SEH handler HRESULT SaveCurrentLeafSeh(); // Restores the thread's leaf SEH handler from the previously saved value HRESULT RestoreLeafSeh(); -#endif // Logs basic data about a context to the debugging log static VOID LogContext(DT_CONTEXT* pContext); @@ -10542,10 +10553,8 @@ class CordbUnmanagedThread : public CordbBase ULONG_PTR m_raiseExceptionExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; -#ifdef TARGET_X86 // the SEH handler which was the leaf when SaveCurrentSeh was called (prior to hijack) REMOTE_PTR m_pSavedLeafSeh; -#endif HRESULT EnableSSAfterBP(); @@ -11384,17 +11393,11 @@ inline void ValidateOrThrow(const void * p) // aligns argBase on platforms that require it else it's a no-op inline void AlignAddressForType(CordbType* pArgType, CORDB_ADDRESS& argBase) { -#ifdef TARGET_ARM -// TODO: review the following -#ifdef FEATURE_64BIT_ALIGNMENT BOOL align = FALSE; - HRESULT hr = pArgType->RequiresAlign8(&align); - _ASSERTE(SUCCEEDED(hr)); + IfFailThrow(pArgType->RequiresAlign8(&align)); if (align) argBase = ALIGN_ADDRESS(argBase, 8); -#endif // FEATURE_64BIT_ALIGNMENT -#endif // TARGET_ARM } //----------------------------------------------------------------------------- diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index 08c760735f91a1..60975a94813389 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -1388,18 +1388,18 @@ HRESULT CordbThread::FindFrame(ICorDebugFrame ** ppFrame, FramePointer fp) PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess()); ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this); + IDacDbiInterface::TargetInfo targetInfo; + HRESULT hr = GetProcess()->GetTargetInfo(&targetInfo); + if (FAILED(hr)) + return hr; + for (UINT32 i = 0; i < pSSW->GetFrameCount(); i++) { ICorDebugFrame * pIFrame = pSSW->GetFrame(i); CordbFrame * pCFrame = CordbFrame::GetCordbFrameFromInterface(pIFrame); -#if !defined(TARGET_X86) - // Compare the FramePointer to determine if the frame matches - if (pCFrame->GetFramePointer() == fp) -#else - // On x86 we need to do a more elaborate check. The reason is that on x86, the FramePointer is always the same as the value of EBP, so we can just check if the input FramePointer is contained in the frame. However, on other platforms, the FramePointer may not be the same as the value of RSP, so we need to check if the input FramePointer is the same as the one of the frame. - if (pCFrame->IsContainedInFrame(fp)) -#endif + bool frameMatches = targetInfo.arch == IDacDbiInterface::kArchX86 ? pCFrame->IsContainedInFrame(fp) : pCFrame->GetFramePointer() == fp; + if (frameMatches) { *ppFrame = pIFrame; (*ppFrame)->AddRef(); @@ -2734,9 +2734,7 @@ CordbUnmanagedThread::CordbUnmanagedThread(CordbProcess *pProcess, DWORD dwThrea m_pTLSExtendedArray(NULL), m_state(CUTS_None), m_originalHandler(NULL), -#ifdef TARGET_X86 m_pSavedLeafSeh(NULL), -#endif m_continueCountCached(0) { m_pLeftSideContext.Set(NULL); @@ -2873,7 +2871,6 @@ VOID CordbUnmanagedThread::VerifyFSChain() return; }*/ -#ifdef TARGET_X86 HRESULT CordbUnmanagedThread::SaveCurrentLeafSeh() { _ASSERTE(m_pSavedLeafSeh == NULL); @@ -2900,7 +2897,6 @@ HRESULT CordbUnmanagedThread::RestoreLeafSeh() m_pSavedLeafSeh = NULL; return S_OK; } -#endif // Read the contents from the LS's Predefined TLS block. // This is an auxiliary TLS storage array-of-void*, indexed off the TLS. @@ -3616,9 +3612,9 @@ VOID CordbUnmanagedThread::LogContext(DT_CONTEXT* pContext) DBG_ADDR(pContext->Sp), DBG_ADDR(pContext->Lr), DBG_ADDR(pContext->Cpsr))); -#else // TARGET_X86 +#else PORTABILITY_ASSERT("LogContext needs a PC and stack pointer."); -#endif // TARGET_X86 +#endif } // Hijacks this thread using the FirstChanceSuspend hijack @@ -3758,11 +3754,14 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijack(EHijackReason::EHijackReaso { // We save off the SEH handler on X86 to make sure we restore it properly after the hijack is complete // The hijacks don't return normally and the SEH chain might have handlers added that don't get removed by default -#ifdef TARGET_X86 - hr = SaveCurrentLeafSeh(); - if(FAILED(hr)) - ThrowHR(hr); -#endif + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + hr = SaveCurrentLeafSeh(); + if(FAILED(hr)) + ThrowHR(hr); + } CORDB_ADDRESS LSContextAddr; IfFailThrow(GetProcess()->GetDAC()->Hijack(VMPTR_Thread::NullPtr(), GetOSTid(), @@ -3814,55 +3813,59 @@ HRESULT CordbUnmanagedThread::SetupGenericHijack(DWORD eventCode, const EXCEPTIO return HRESULT_FROM_WIN32(GetLastError()); } -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) - - // On X86 Debugger::GenericHijackFunc() ensures the stack is walkable - // by simply using the EBP chain, therefore we can execute the hijack - // by setting the thread's context EIP to point to this function. - // On X64, however, we first attempt to set up a "proper" hijack, with - // a function that allows the OS to unwind the stack (ExceptionHijack). - // If this fails we'll use the same method as on X86, even though the - // stack will become un-walkable + IDacDbiInterface::TargetInfo targetInfo; + HRESULT hr = GetProcess()->GetTargetInfo(&targetInfo); + if (FAILED(hr)) + return hr; + if (targetInfo.arch != IDacDbiInterface::kArchX86) + { + // On X86 Debugger::GenericHijackFunc() ensures the stack is walkable + // by simply using the EBP chain, therefore we can execute the hijack + // by setting the thread's context EIP to point to this function. + // On X64, however, we first attempt to set up a "proper" hijack, with + // a function that allows the OS to unwind the stack (ExceptionHijack). + // If this fails we'll use the same method as on X86, even though the + // stack will become un-walkable - ULONG32 dwThreadId = GetOSTid(); - CordbThread * pThread = GetProcess()->TryLookupOrCreateThreadByVolatileOSId(dwThreadId); + ULONG32 dwThreadId = GetOSTid(); + CordbThread * pThread = GetProcess()->TryLookupOrCreateThreadByVolatileOSId(dwThreadId); - // For threads in the thread store we set up the full size - // hijack, otherwise we fallback to hijacking by SetIP. - if (pThread != NULL) - { - HRESULT hr = S_OK; - EX_TRY + // For threads in the thread store we set up the full size + // hijack, otherwise we fallback to hijacking by SetIP. + if (pThread != NULL) { - // Note that the data-target is not atomic, and we have no rollback mechanism. - // We have to do several writes. If the data-target fails the writes half-way through the - // target will be inconsistent. - IfFailThrow(GetProcess()->GetDAC()->Hijack( - pThread->m_vmThreadToken, - dwThreadId, - pRecord, - (T_CONTEXT*) GetHijackCtx(), - sizeof(T_CONTEXT), - EHijackReason::kGenericHijack, - NULL, - NULL)); - } - EX_CATCH_HRESULT(hr); - if (SUCCEEDED(hr)) - { - // Remember that we've hijacked the thread. - SetState(CUTS_GenericHijacked); + HRESULT hr = S_OK; + EX_TRY + { + // Note that the data-target is not atomic, and we have no rollback mechanism. + // We have to do several writes. If the data-target fails the writes half-way through the + // target will be inconsistent. + IfFailThrow(GetProcess()->GetDAC()->Hijack( + pThread->m_vmThreadToken, + dwThreadId, + pRecord, + (T_CONTEXT*) GetHijackCtx(), + sizeof(T_CONTEXT), + EHijackReason::kGenericHijack, + NULL, + NULL)); + } + EX_CATCH_HRESULT(hr); + if (SUCCEEDED(hr)) + { + // Remember that we've hijacked the thread. + SetState(CUTS_GenericHijacked); - return S_OK; - } + return S_OK; + } - STRESS_LOG1(LF_CORDB, LL_INFO1000, "CUT::SGH: Error setting up hijack context hr=0x%x\n", hr); - // fallthrough (above hijack might have failed due to stack overflow, for example) + STRESS_LOG1(LF_CORDB, LL_INFO1000, "CUT::SGH: Error setting up hijack context hr=0x%x\n", hr); + // fallthrough (above hijack might have failed due to stack overflow, for example) - } - // else (non-threadstore threads) fallthrough + } + // else (non-threadstore threads) fallthrough -#endif // TARGET_AMD64 || defined(TARGET_ARM64) + } // Remember that we've hijacked the thread. SetState(CUTS_GenericHijacked); @@ -4027,9 +4030,12 @@ void CordbUnmanagedThread::SetupForSkipBreakpoint(NativePatch * pNativePatch) fTrapOnSkip = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgTrapOnSkip); } #endif -#if defined(TARGET_X86) - STRESS_LOG2(LF_CORDB, LL_INFO100, "CUT::SetupSkip. addr=%p. Opcode=%x\n", pNativePatch->pAddress, (DWORD) pNativePatch->opcode); -#endif + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + STRESS_LOG2(LF_CORDB, LL_INFO100, "CUT::SetupSkip. addr=%p. Opcode=%x\n", pNativePatch->pAddress, (DWORD) pNativePatch->opcode); + } // Replace the BP w/ the opcode. RemoveRemotePatch(GetProcess(), pNativePatch->pAddress, pNativePatch->opcode); @@ -4202,90 +4208,6 @@ void CordbUnmanagedThread::RestoreFromRaiseExceptionHijack() _ASSERTE(SUCCEEDED(hr)); } -//----------------------------------------------------------------------------- -// Attempts to store the state of a thread currently entering RaiseException -// This grabs both a full context and enough state to determine what exception -// RaiseException should be raising. If any of the state can not be retrieved -// then this entrance to RaiseException is silently ignored -//----------------------------------------------------------------------------- -void CordbUnmanagedThread::SaveRaiseExceptionEntryContext() -{ - _ASSERTE(FALSE); // should be unused now - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: saving raise exception context.\n")); - _ASSERTE(!HasRaiseExceptionEntryCtx()); - _ASSERTE(!IsRaiseExceptionHijacked()); - HRESULT hr = S_OK; - DT_CONTEXT context; - context.ContextFlags = DT_CONTEXT_FULL; - DbiGetThreadContext(m_handle, &context); - // if the flag is set, unset it - // we don't want to be single stepping through RaiseException the second time - // sending out OOB SS events. Ultimately we will rethrow the exception which would - // cleared the SS flag anyways. - UnsetSSFlag(&context); - memcpy(&m_raiseExceptionEntryContext, &context, sizeof(DT_CONTEXT)); - - // calculate the exception that we would expect to come from this invocation of RaiseException - REMOTE_PTR pExceptionInformation = NULL; -#if defined(TARGET_AMD64) - m_raiseExceptionExceptionCode = (DWORD)m_raiseExceptionEntryContext.Rcx; - m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.Rdx; - m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.R8; - pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.R9; -#elif defined(TARGET_ARM64) - m_raiseExceptionExceptionCode = (DWORD)m_raiseExceptionEntryContext.X0; - m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.X1; - m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.X2; - pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.X3; -#elif defined(TARGET_X86) - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+4), &m_raiseExceptionExceptionCode); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception code.\n")); - return; - } - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+8), &m_raiseExceptionExceptionFlags); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception flags.\n")); - return; - } - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+12), &m_raiseExceptionNumberParameters); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read number of parameters.\n")); - return; - } - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+16), &pExceptionInformation); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception information pointer.\n")); - return; - } -#else - _ASSERTE(!"Implement this for your platform"); - return; -#endif - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: RaiseException parameters are 0x%x 0x%x 0x%x 0x%p.\n", - m_raiseExceptionExceptionCode, m_raiseExceptionExceptionFlags, - m_raiseExceptionNumberParameters, pExceptionInformation)); - TargetBuffer exceptionInfoTargetBuffer(pExceptionInformation, sizeof(REMOTE_PTR)*m_raiseExceptionNumberParameters); - EX_TRY - { - m_pProcess->SafeReadBuffer(exceptionInfoTargetBuffer, (BYTE*)m_raiseExceptionExceptionInformation); - } - EX_CATCH_HRESULT(hr); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception information.\n")); - return; - } - - // If everything was successful then set this flag, otherwise none of the above data is considered valid - SetState(CUTS_HasRaiseExceptionEntryCtx); - return; -} - //----------------------------------------------------------------------------- // Clears all the state saved in SaveRaiseExceptionContext and returns the thread // to the state as if RaiseException has yet to be called. This is typically called @@ -4357,41 +4279,22 @@ BOOL CordbUnmanagedThread::IsExceptionFromLastRaiseException(const EXCEPTION_REC // This flavor is assuming our caller already knows the opcode. HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress) { -#if defined(TARGET_X86) || defined(TARGET_AMD64) - const BYTE patch = CORDbg_BREAK_INSTRUCTION; -#elif defined(TARGET_ARM64) - const PRD_TYPE patch = CORDbg_BREAK_INSTRUCTION; -#else - const BYTE patch = 0; - PORTABILITY_ASSERT("NYI: ApplyRemotePatch for this platform"); -#endif - HRESULT hr = pProcess->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &patch); + ULONG32 patch = CORDbg_BREAK_INSTRUCTION; + HRESULT hr = pProcess->SafeWriteBreakpointPatch(PTR_TO_CORDB_ADDRESS(pRemoteAddress), patch); SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr); return S_OK; } // Get the opcode that we're replacing. -HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE * pOpcode) +HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, ULONG32 * pOpcode) { -#if defined(TARGET_X86) || defined(TARGET_AMD64) - // Read out opcode. 1 byte on x86 - BYTE opcode; -#elif defined(TARGET_ARM64) - // Read out opcode. 4 bytes on arm64 - PRD_TYPE opcode; -#else - BYTE opcode; - PORTABILITY_ASSERT("NYI: ApplyRemotePatch for this platform"); -#endif - - HRESULT hr = pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &opcode); + HRESULT hr = pProcess->SafeReadBreakpointPatch(PTR_TO_CORDB_ADDRESS(pRemoteAddress), pOpcode); if (FAILED(hr)) { return hr; } - *pOpcode = (PRD_TYPE) opcode; ApplyRemotePatch(pProcess, pRemoteAddress); return S_OK; } @@ -4399,20 +4302,9 @@ HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, P //----------------------------------------------------------------------------- // Remove the int3 from the remote address //----------------------------------------------------------------------------- -HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE opcode) +HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, ULONG32 opcode) { -#if defined(TARGET_X86) || defined(TARGET_AMD64) - // Replace the BP w/ the opcode. - BYTE opcode2 = (BYTE) opcode; -#elif defined(TARGET_ARM64) - // 4 bytes on arm64 - PRD_TYPE opcode2 = opcode; -#else - PRD_TYPE opcode2 = opcode; - PORTABILITY_ASSERT("NYI: RemoveRemotePatch for this platform"); -#endif - - pProcess->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &opcode2); + pProcess->SafeWriteBreakpointPatch(PTR_TO_CORDB_ADDRESS(pRemoteAddress), opcode); // This may fail because the module has been unloaded. In which case, the patch is also // gone so it makes sense to return success. @@ -4712,7 +4604,7 @@ HRESULT CordbFrame::CreateStepper(ICorDebugStepper **ppStepper) //--------------------------------------------------------------------------------------- // -// Given a frame pointer, determine if it is in the stack range owned by the frame. +// X86-specific helper: Given a frame pointer, determine if it is in the stack range owned by the frame. // // Arguments: // fp - frame pointer to check @@ -4733,7 +4625,6 @@ bool CordbFrame::IsContainedInFrame(FramePointer fp) CORDB_ADDRESS sp = PTR_TO_CORDB_ADDRESS(fp.GetSPValue()); -#if defined(TARGET_X86) // On x86, the runtime sends CallerSP - sizeof(TADDR) as the frame pointer // for exception notifications (see GetSpForDiagnosticReporting). Since this // does not account for the stack parameter size, we adjust for it here. @@ -4752,7 +4643,6 @@ bool CordbFrame::IsContainedInFrame(FramePointer fp) } } } -#endif // TARGET_X86 if ((stackStart <= sp) && (sp <= stackEnd)) { @@ -5937,13 +5827,18 @@ HRESULT CordbNativeFrame::GetStackParameterSize(ULONG32 * pSize) ThrowHR(E_INVALIDARG); } -#if defined(TARGET_X86) IDacDbiInterface * pDAC = GetProcess()->GetDAC(); - IfFailThrow(pDAC->GetStackParameterSize(PTR_TO_CORDB_ADDRESS(CORDbgGetIP(&m_context)), pSize)); -#else // !TARGET_X86 - hr = S_FALSE; - *pSize = 0; -#endif // TARGET_X86 + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + IfFailThrow(pDAC->GetStackParameterSize(PTR_TO_CORDB_ADDRESS(CORDbgGetIP(&m_context)), pSize)); + } + else + { + hr = S_FALSE; + *pSize = 0; + } } EX_CATCH_HRESULT(hr); @@ -6708,23 +6603,50 @@ HRESULT CordbNativeFrame::GetLocalRegisterValue(CorDebugRegister reg, VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **); ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); -#if defined(TARGET_X86) || defined(TARGET_64BIT) -#if defined(TARGET_X86) - if ((reg >= REGISTER_X86_FPSTACK_0) && (reg <= REGISTER_X86_FPSTACK_7)) -#elif defined(TARGET_AMD64) - if ((reg >= REGISTER_AMD64_XMM0) && (reg <= REGISTER_AMD64_XMM15)) -#elif defined(TARGET_ARM64) - if ((reg >= REGISTER_ARM64_V0) && (reg <= REGISTER_ARM64_V31)) -#endif + DWORD floatingPointIndex = 0; + bool isFloatingPoint = false; + IDacDbiInterface::TargetInfo targetInfo; + HRESULT hr = GetProcess()->GetTargetInfo(&targetInfo); + if (FAILED(hr)) { - return GetLocalFloatingPointValue(reg, pType, ppValue); + return hr; + } + switch (targetInfo.arch) + { + case IDacDbiInterface::kArchX86: + isFloatingPoint = (reg >= REGISTER_X86_FPSTACK_0) && (reg <= REGISTER_X86_FPSTACK_7); + floatingPointIndex = reg - REGISTER_X86_FPSTACK_0; + break; + case IDacDbiInterface::kArchAMD64: + isFloatingPoint = (reg >= REGISTER_AMD64_XMM0) && (reg <= REGISTER_AMD64_XMM15); + floatingPointIndex = reg - REGISTER_AMD64_XMM0; + break; + case IDacDbiInterface::kArchArm: + isFloatingPoint = (reg >= REGISTER_ARM_D0) && (reg <= REGISTER_ARM_D31); + floatingPointIndex = reg - REGISTER_ARM_D0; + break; + case IDacDbiInterface::kArchArm64: + isFloatingPoint = (reg >= REGISTER_ARM64_V0) && (reg <= REGISTER_ARM64_V31); + floatingPointIndex = reg - REGISTER_ARM64_V0; + break; + case IDacDbiInterface::kArchRiscV64: + isFloatingPoint = (reg >= REGISTER_RISCV64_F0) && (reg <= REGISTER_RISCV64_F31); + floatingPointIndex = reg - REGISTER_RISCV64_F0; + break; + case IDacDbiInterface::kArchLoongArch64: + isFloatingPoint = (reg >= REGISTER_LOONGARCH64_F0) && (reg <= REGISTER_LOONGARCH64_F31); + floatingPointIndex = reg - REGISTER_LOONGARCH64_F0; + break; + default: + break; } -#endif + + if (isFloatingPoint) + return GetLocalFloatingPointValue(floatingPointIndex, pType, ppValue); // The address of the given register is the address of the value // in this process. We have no remote address here. void *pLocalValue = (void*)GetAddressOfRegister(reg); - HRESULT hr = S_OK; EX_TRY { @@ -6958,33 +6880,6 @@ HRESULT CordbNativeFrame::GetLocalFloatingPointValue(DWORD index, (et != ELEMENT_TYPE_R8)) return E_INVALIDARG; -#if defined(TARGET_AMD64) - if (!((index >= REGISTER_AMD64_XMM0) && - (index <= REGISTER_AMD64_XMM15))) - return E_INVALIDARG; - index -= REGISTER_AMD64_XMM0; -#elif defined(TARGET_ARM64) - if (!((index >= REGISTER_ARM64_V0) && - (index <= REGISTER_ARM64_V31))) - return E_INVALIDARG; - index -= REGISTER_ARM64_V0; -#elif defined(TARGET_ARM) - if (!((index >= REGISTER_ARM_D0) && - (index <= REGISTER_ARM_D31))) - return E_INVALIDARG; - index -= REGISTER_ARM_D0; -#elif defined(TARGET_RISCV64) - if (!((index >= REGISTER_RISCV64_F0) && - (index <= REGISTER_RISCV64_F31))) - return E_INVALIDARG; - index -= REGISTER_RISCV64_F0; -#else - if (!((index >= REGISTER_X86_FPSTACK_0) && - (index <= REGISTER_X86_FPSTACK_7))) - return E_INVALIDARG; - index -= REGISTER_X86_FPSTACK_0; -#endif - ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); @@ -7003,22 +6898,26 @@ HRESULT CordbNativeFrame::GetLocalFloatingPointValue(DWORD index, EX_CATCH_HRESULT(hr); if (SUCCEEDED(hr)) { -#if !defined(TARGET_64BIT) - // This is needed on x86 because we are dealing with a stack. - index = pThread->m_floatStackTop - index; -#endif + IDacDbiInterface::TargetInfo targetInfo; + IfFailRet(GetProcess()->GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + // This is needed on x86 because we are dealing with a stack. + index = pThread->m_floatStackTop - index; + } if (index >= (sizeof(pThread->m_floatValues) / sizeof(pThread->m_floatValues[0]))) return E_INVALIDARG; -#ifdef TARGET_X86 - // A workaround (sort of) to get around the difference in format between - // a float value and a double value. We can't simply cast a double pointer to - // a float pointer. Instead, we have to cast the double itself to a float. - if (pType->m_elementType == ELEMENT_TYPE_R4) - *(float *)&(pThread->m_floatValues[index]) = (float)pThread->m_floatValues[index]; -#endif + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + // A workaround (sort of) to get around the difference in format between + // a float value and a double value. We can't simply cast a double pointer to + // a float pointer. Instead, we have to cast the double itself to a float. + if (pType->m_elementType == ELEMENT_TYPE_R4) + *(float *)&(pThread->m_floatValues[index]) = (float)pThread->m_floatValues[index]; + } ICorDebugValue* pValue; @@ -7469,12 +7368,17 @@ HRESULT CordbJITILFrame::Init() IfFailThrow(GetArgumentType(0, &pArgType)); ULONG32 argSize = 0; IfFailThrow(pArgType->GetUnboxedObjectSize(&argSize)); -#if defined(TARGET_X86) // (STACK_GROWS_DOWN_ON_ARGS_WALK) - m_FirstArgAddr = argBase - argSize; -#else // !TARGET_X86 (STACK_GROWS_UP_ON_ARGS_WALK) - AlignAddressForType(pArgType, argBase); - m_FirstArgAddr = argBase; -#endif // !TARGET_X86 (STACK_GROWS_UP_ON_ARGS_WALK) + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + m_FirstArgAddr = argBase - argSize; + } + else + { + AlignAddressForType(pArgType, argBase); + m_FirstArgAddr = argBase; + } } // The stackwalking code can't always successfully retrieve the generics type token. @@ -8102,21 +8006,8 @@ HRESULT CordbJITILFrame::FabricateNativeInfo(DWORD dwIndex, } else { - // We'll initialize everything at once - ULONG cbArchitectureMin; - - // m_FirstArgAddr will already be aligned on platforms that require alignment CORDB_ADDRESS rpCur = m_FirstArgAddr; -#if defined(TARGET_X86) || defined(TARGET_ARM) - cbArchitectureMin = 4; -#elif defined(TARGET_64BIT) - cbArchitectureMin = 8; -#else - cbArchitectureMin = 8; //REVISIT_TODO not sure if this is correct - PORTABILITY_ASSERT("What is the architecture-dependent minimum word size?"); -#endif // TARGET_X86 - // make a copy of the cached SigParser SigParser sigParser = m_sigParserCached; @@ -8134,13 +8025,16 @@ HRESULT CordbJITILFrame::FabricateNativeInfo(DWORD dwIndex, IfFailThrow(pArgType->GetUnboxedObjectSize(&cbType)); -#if defined(TARGET_X86) // STACK_GROWS_DOWN_ON_ARGS_WALK - // The rpCur pointer starts off in the right spot for the - // first argument, but thereafter we have to decrement it - // before getting the variable's location from it. So increment - // it here to be consistent later. - rpCur += max((ULONG)cbType, cbArchitectureMin); -#endif + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + // The rpCur pointer starts off in the right spot for the + // first argument, but thereafter we have to decrement it + // before getting the variable's location from it. So increment + // it here to be consistent later. + rpCur += max((ULONG)cbType, (ULONG)targetInfo.pointerSize); + } // Grab the IL code's function's method signature so we can see if it's static. BOOL fMethodIsStatic; @@ -8171,20 +8065,23 @@ HRESULT CordbJITILFrame::FabricateNativeInfo(DWORD dwIndex, IfFailThrow(pArgType->GetUnboxedObjectSize(&cbType)); -#if defined(TARGET_X86) // STACK_GROWS_DOWN_ON_ARGS_WALK - rpCur -= max((ULONG)cbType, cbArchitectureMin); - m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset = - (unsigned)(m_FirstArgAddr - rpCur); - - // Since the JIT adds in the size of this field, we do too to - // be consistent. - m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset += sizeof(((CORINFO_VarArgInfo*)0)->argBytes); -#else // STACK_GROWS_UP_ON_ARGS_WALK - m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset = - (unsigned)(rpCur - m_FirstArgAddr); - rpCur += max((ULONG)cbType, cbArchitectureMin); - AlignAddressForType(pArgType, rpCur); -#endif + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + rpCur -= max((ULONG)cbType, (ULONG)targetInfo.pointerSize); + m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset = + (unsigned)(m_FirstArgAddr - rpCur); + + // Since the JIT adds in the size of this field, we do too to + // be consistent. + m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset += sizeof(((CORINFO_VarArgInfo*)0)->argBytes); + } + else + { + m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset = + (unsigned)(rpCur - m_FirstArgAddr); + rpCur += max((ULONG)cbType, (ULONG)targetInfo.pointerSize); + AlignAddressForType(pArgType, rpCur); + } IfFailThrow(sigParser.SkipExactlyOne()); } // for ( ; i M m_allArgsCount; i++) @@ -8355,27 +8252,37 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, } break; -#if defined(TARGET_64BIT) || defined(TARGET_ARM) case ICorDebugInfo::VLT_REG_FP: -#if defined(TARGET_ARM) // @ARMTODO - hr = E_NOTIMPL; -#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) - // AMD64/ARM64 enumerate the FP registers in the debug RegNum enum - // (XMM0-15 / V0-31), so g_JITToCorDbgReg maps vlrReg directly to the - // corresponding CorDebugRegister. - hr = m_nativeFrame->GetLocalFloatingPointValue(ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg), - type, ppValue); -#elif defined(TARGET_LOONGARCH64) - hr = m_nativeFrame->GetLocalFloatingPointValue(pNativeVarInfo->loc.vlReg.vlrReg + REGISTER_LOONGARCH64_F0, - type, ppValue); -#elif defined(TARGET_RISCV64) - hr = m_nativeFrame->GetLocalFloatingPointValue(pNativeVarInfo->loc.vlReg.vlrReg + REGISTER_RISCV64_F0, - type, ppValue); -#else -#error Platform not implemented -#endif // TARGET_ARM @ARMTODO + { + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + switch (targetInfo.arch) + { + case IDacDbiInterface::kArchArm: + hr = E_NOTIMPL; + break; + case IDacDbiInterface::kArchLoongArch64: + case IDacDbiInterface::kArchRiscV64: + hr = m_nativeFrame->GetLocalFloatingPointValue(pNativeVarInfo->loc.vlReg.vlrReg, type, ppValue); + break; + case IDacDbiInterface::kArchAMD64: + hr = m_nativeFrame->GetLocalFloatingPointValue( + ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg) - REGISTER_AMD64_XMM0, + type, + ppValue); + break; + case IDacDbiInterface::kArchArm64: + hr = m_nativeFrame->GetLocalFloatingPointValue( + ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg) - REGISTER_ARM64_V0, + type, + ppValue); + break; + default: + hr = CORDBG_E_IL_VAR_NOT_AVAILABLE; + break; + } + } break; -#endif // TARGET_64BIT || TARGET_ARM case ICorDebugInfo::VLT_STK_BYREF: { @@ -8466,18 +8373,25 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, break; case ICorDebugInfo::VLT_FPSTK: -#if defined(TARGET_X86) - // On x86 floating-point values (including return values) live on the x87 - // FP stack. vlfReg is the depth from the top of the stack, so add the base - // register to form the CorDebugRegister index expected by the helper. - hr = m_nativeFrame->GetLocalFloatingPointValue( - pNativeVarInfo->loc.vlFPstk.vlfReg + REGISTER_X86_FPSTACK_0, - type, ppValue); -#elif defined(TARGET_ARM) // @ARMTODO - hr = E_NOTIMPL; -#else - hr = CORDBG_E_IL_VAR_NOT_AVAILABLE; -#endif + { + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + switch (targetInfo.arch) + { + case IDacDbiInterface::kArchX86: + hr = m_nativeFrame->GetLocalFloatingPointValue( + pNativeVarInfo->loc.vlFPstk.vlfReg, + type, + ppValue); + break; + case IDacDbiInterface::kArchArm: + hr = E_NOTIMPL; + break; + default: + hr = CORDBG_E_IL_VAR_NOT_AVAILABLE; + break; + } + } break; case ICorDebugInfo::VLT_FIXED_VA: @@ -8487,13 +8401,18 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, CORDB_ADDRESS pRemoteValue; -#if defined(TARGET_X86) // STACK_GROWS_DOWN_ON_ARGS_WALK - pRemoteValue = m_FirstArgAddr - pNativeVarInfo->loc.vlFixedVarArg.vlfvOffset; - // Remember to subtract out this amount - pRemoteValue += sizeof(((CORINFO_VarArgInfo*)0)->argBytes); -#else // STACK_GROWS_UP_ON_ARGS_WALK - pRemoteValue = m_FirstArgAddr + pNativeVarInfo->loc.vlFixedVarArg.vlfvOffset; -#endif + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(GetProcess()->GetTargetInfo(&targetInfo)); + if (targetInfo.arch == IDacDbiInterface::kArchX86) + { + pRemoteValue = m_FirstArgAddr - pNativeVarInfo->loc.vlFixedVarArg.vlfvOffset; + // Remember to subtract out this amount + pRemoteValue += sizeof(((CORINFO_VarArgInfo*)0)->argBytes); + } + else + { + pRemoteValue = m_FirstArgAddr + pNativeVarInfo->loc.vlFixedVarArg.vlfvOffset; + } hr = m_nativeFrame->GetLocalMemoryValue(pRemoteValue, type, diff --git a/src/coreclr/debug/di/rstype.cpp b/src/coreclr/debug/di/rstype.cpp index 86bc53ec3985f7..bae56b32603335 100644 --- a/src/coreclr/debug/di/rstype.cpp +++ b/src/coreclr/debug/di/rstype.cpp @@ -2726,7 +2726,6 @@ void CordbType::GatherTypeDataForInstantiation(unsigned int genericArgsCount, IC } } -#ifdef FEATURE_64BIT_ALIGNMENT // checks if the type requires 8-byte alignment. the algorithm used here // was adapted from AdjustArgPtrForAlignment() in bcltype/VarArgsNative.cpp HRESULT CordbType::RequiresAlign8(BOOL* isRequired) @@ -2770,7 +2769,6 @@ HRESULT CordbType::RequiresAlign8(BOOL* isRequired) return hr; } -#endif /* ------------------------------------------------------------------------- * * TypeParameter Enumerator class diff --git a/src/coreclr/debug/di/shimlocaldatatarget.cpp b/src/coreclr/debug/di/shimlocaldatatarget.cpp index 8bad40ee735e29..88a7b0f65f2f67 100644 --- a/src/coreclr/debug/di/shimlocaldatatarget.cpp +++ b/src/coreclr/debug/di/shimlocaldatatarget.cpp @@ -81,7 +81,7 @@ class ShimLocalDataTarget : public ShimDataTarget // Note: throws BOOL CompatibleHostAndTargetPlatforms(HANDLE hTargetProcess) { -#if defined(TARGET_UNIX) +#if defined(HOST_UNIX) return TRUE; #else // get the platform for the host process @@ -278,17 +278,17 @@ HRESULT STDMETHODCALLTYPE ShimLocalDataTarget::GetPlatform( CorDebugPlatform *pPlatform) { -#ifdef TARGET_UNIX +#ifdef HOST_UNIX #error ShimLocalDataTarget is not implemented on PAL systems yet #endif // Assume that we're running on Windows for now. -#if defined(TARGET_X86) +#if defined(HOST_X86) *pPlatform = CORDB_PLATFORM_WINDOWS_X86; -#elif defined(TARGET_AMD64) +#elif defined(HOST_AMD64) *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64; -#elif defined(TARGET_ARM) +#elif defined(HOST_ARM) *pPlatform = CORDB_PLATFORM_WINDOWS_ARM; -#elif defined(TARGET_ARM64) +#elif defined(HOST_ARM64) *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64; #else #error Unknown Processor. @@ -462,9 +462,6 @@ ShimLocalDataTarget::ContinueStatusChanged( HRESULT STDMETHODCALLTYPE ShimLocalDataTarget::VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context) { -#ifndef TARGET_UNIX - _ASSERTE(!"ShimLocalDataTarget::VirtualUnwind NOT IMPLEMENTED"); -#endif return E_NOTIMPL; } diff --git a/src/coreclr/debug/di/shimpriv.h b/src/coreclr/debug/di/shimpriv.h index acbf2b5da4b522..24c3b72a895318 100644 --- a/src/coreclr/debug/di/shimpriv.h +++ b/src/coreclr/debug/di/shimpriv.h @@ -20,6 +20,7 @@ // Forward declarations class CordbWin32EventThread; class Cordb; +struct IDacDbiInterface; class ShimStackWalk; class ShimChain; diff --git a/src/coreclr/debug/di/shimremotedatatarget.cpp b/src/coreclr/debug/di/shimremotedatatarget.cpp index de3413e1c7fc1b..b1074bc418c5e5 100644 --- a/src/coreclr/debug/di/shimremotedatatarget.cpp +++ b/src/coreclr/debug/di/shimremotedatatarget.cpp @@ -340,7 +340,7 @@ ShimRemoteDataTarget::ReadVirtual( // pread on /proc//mem treats the offset as a file position, not a virtual address, // so the kernel does not apply TBI -- tagged pointers cause EINVAL. // See https://www.kernel.org/doc/html/latest/arch/arm64/tagged-address-abi.html -#ifdef TARGET_ARM64 +#ifdef HOST_ARM64 address &= 0x00FFFFFFFFFFFFFFULL; #endif ssize_t r = pread((int)m_memoryHandle, pBuffer, cbRequestSize, (off_t)address); diff --git a/src/coreclr/debug/di/shimstackwalk.cpp b/src/coreclr/debug/di/shimstackwalk.cpp index f289788507a54e..bd8a6310c09900 100644 --- a/src/coreclr/debug/di/shimstackwalk.cpp +++ b/src/coreclr/debug/di/shimstackwalk.cpp @@ -14,14 +14,6 @@ #include "stdafx.h" #include "primitives.h" -#if defined(TARGET_X86) -static const ULONG32 REGISTER_X86_MAX = REGISTER_X86_FPSTACK_7 + 1; -static const ULONG32 MAX_MASK_COUNT = (REGISTER_X86_MAX + 7) >> 3; -#elif defined(TARGET_AMD64) -static const ULONG32 REGISTER_AMD64_MAX = REGISTER_AMD64_XMM15 + 1; -static const ULONG32 MAX_MASK_COUNT = (REGISTER_AMD64_MAX + 7) >> 3; -#endif - ShimStackWalk::ShimStackWalk(ShimProcess * pProcess, ICorDebugThread * pThread) : m_pChainEnumList(NULL), m_pFrameEnumList(NULL) @@ -1119,12 +1111,18 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa // We need to send an extra enter-managed chain. _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); BYTE * sp = reinterpret_cast(CORDB_ADDRESS_TO_PTR(CORDbgGetSP(&(pChainInfo->m_leafNativeContext)))); -#if !defined(TARGET_ARM) && !defined(TARGET_ARM64) + IDacDbiInterface::TargetInfo targetInfo; // Dev11 324806: on ARM we use the caller's SP for a frame's ending delimiter so we cannot - // subtract 4 bytes from the chain's ending delimiter else the frame might never be in range. + // subtract from the chain's ending delimiter else the frame might never be in range. // TODO: revisit overlapping ranges on ARM, it would be nice to make it consistent with the other architectures. - sp -= sizeof(LPVOID); -#endif + CordbProcess * pProcess = static_cast(m_pProcess->GetProcess()); + if (pProcess != NULL && + SUCCEEDED(pProcess->GetTargetInfo(&targetInfo)) && + targetInfo.arch != IDacDbiInterface::kArchArm && + targetInfo.arch != IDacDbiInterface::kArchArm64) + { + sp -= targetInfo.pointerSize; + } FramePointer fp = FramePointer::MakeFramePointer(sp); AppendChainWorker(pStackWalkInfo, diff --git a/src/coreclr/debug/di/valuehome.cpp b/src/coreclr/debug/di/valuehome.cpp index 24230bb6c85cd1..0552f2efda1469 100644 --- a/src/coreclr/debug/di/valuehome.cpp +++ b/src/coreclr/debug/di/valuehome.cpp @@ -190,6 +190,7 @@ void RegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pCont // If the value is in a reg, then it's going to be a register's width (regardless of // the actual width of the data). // For signed types, like i2, i1, make sure we sign extend. + IDacDbiInterface::TargetInfo targetInfo; if (fIsSigned) { @@ -203,11 +204,16 @@ void RegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pCont extendedVal = (SSIZE_T) *(short*)newValue.StartAddress(); break; case 4: _ASSERTE(sizeof(DWORD) == 4); extendedVal = (SSIZE_T) *(int*)newValue.StartAddress(); break; -#if defined(TARGET_64BIT) - case 8: _ASSERTE(sizeof(ULONGLONG) == 8); - extendedVal = (SSIZE_T) *(ULONGLONG*)newValue.StartAddress(); break; -#endif // TARGET_64BIT - default: _ASSERTE(!"bad size"); + case 8: + { + IfFailThrow(m_pFrame->GetProcess()->GetTargetInfo(&targetInfo)); + _ASSERTE(targetInfo.pointerSize == 8); + extendedVal = (SSIZE_T) *(INT64*)newValue.StartAddress(); + break; + } + default: + _ASSERTE(!"bad size"); + ThrowHR(E_FAIL); } } else @@ -221,11 +227,16 @@ void RegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pCont extendedVal = *( WORD*)newValue.StartAddress(); break; case 4: _ASSERTE(sizeof(DWORD) == 4); extendedVal = *(DWORD*)newValue.StartAddress(); break; -#if defined(TARGET_64BIT) - case 8: _ASSERTE(sizeof(ULONGLONG) == 8); - extendedVal = *(ULONGLONG*)newValue.StartAddress(); break; -#endif // TARGET_64BIT - default: _ASSERTE(!"bad size"); + case 8: + { + IfFailThrow(m_pFrame->GetProcess()->GetTargetInfo(&targetInfo)); + _ASSERTE(targetInfo.pointerSize == 8); + extendedVal = (SIZE_T) *(UINT64*)newValue.StartAddress(); + break; + } + default: + _ASSERTE(!"bad size"); + ThrowHR(E_FAIL); } } @@ -889,21 +900,18 @@ void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) } // RegisterValueHome::SetEnregisteredValue -// Get an enregistered value from the register display of the native frame -// Arguments: -// output: dest - buffer will hold the register value -// Note: Throws E_NOTIMPL for attempts to get an enregistered value for a float register -// or for 64-bit platforms void RegisterValueHome::GetEnregisteredValue(MemoryRange dest) { -#if !defined(TARGET_X86) - _ASSERTE(!"@TODO IA64/AMD64 -- Not Yet Implemented"); - ThrowHR(E_NOTIMPL); -#else // TARGET_X86 + IDacDbiInterface::TargetInfo targetInfo; + IfFailThrow(m_pProcess->GetTargetInfo(&targetInfo)); + if (targetInfo.arch != IDacDbiInterface::kArchX86) + { + _ASSERTE(!"@TODO IA64/AMD64 -- Not Yet Implemented"); + ThrowHR(E_NOTIMPL); + } _ASSERTE(m_pRemoteRegAddr != NULL); m_pRemoteRegAddr->GetEnregisteredValue(dest); // throws -#endif // !TARGET_X86 } // RegisterValueHome::GetEnregisteredValue // Is this a signed type or unsigned type? diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index e739a2e98395b7..9da9b9806c5588 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -2208,6 +2208,35 @@ IDacDbiInterface : public IUnknown VMPTR_MethodDesc vmMethod, OUT UINT32* pTokenIndex) = 0; + typedef enum + { + kArchUnknown = 0, + kArchX86, + kArchAMD64, + kArchArm, + kArchArm64, + kArchLoongArch64, + kArchRiscV64, + kArchWasm, + } TargetArchitecture; + + typedef enum + { + kOSUnknown = 0, + kOSWindows, + kOSUnix, + } TargetOperatingSystem; + + struct TargetInfo + { + TargetArchitecture arch; + TargetOperatingSystem os; + ULONG32 pointerSize; + }; + + // Returns the target's processor architecture, OS family, and pointer size. + virtual HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo) = 0; + // The following tag tells the DD-marshalling tool to stop scanning. // END_MARSHAL diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index 73610b87d4a3d4..32926530d4ffa7 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -129,6 +129,7 @@ typedef struct { void *pList; int nEntries; } DacDbiArrayList_CORDB_ADDRESS; typedef struct { void *pList; int nEntries; } DacDbiArrayList_GUID; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_SEGMENT; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_MEMORY_RANGE; +typedef struct { int arch; int os; ULONG32 pointerSize; } TargetInfo; cpp_quote("#endif") @@ -440,4 +441,7 @@ interface IDacDbiInterface : IUnknown // Generic Arg Token HRESULT GetGenericArgTokenIndex([in] VMPTR_MethodDesc vmMethod, [out] UINT32 * pTokenIndex); + + // Returns the target's processor architecture, OS family, and pointer size. + HRESULT GetTargetInfo([out] TargetInfo * pTargetInfo); }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index dfdd0766072cb6..56bf4cb8814462 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -5788,6 +5788,58 @@ public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) return hr; } + public int GetTargetInfo(TargetInfo* pTargetInfo) + { + int hr = HResults.S_OK; + try + { + if (pTargetInfo is null) + throw new ArgumentException("Output pointer cannot be null.", nameof(pTargetInfo)); + Contracts.IRuntimeInfo runtimeInfo = _target.Contracts.RuntimeInfo; + + pTargetInfo->Arch = runtimeInfo.GetTargetArchitecture() switch + { + Contracts.RuntimeInfoArchitecture.X86 => TargetArchitecture.X86, + Contracts.RuntimeInfoArchitecture.X64 => TargetArchitecture.AMD64, + Contracts.RuntimeInfoArchitecture.Arm => TargetArchitecture.Arm, + Contracts.RuntimeInfoArchitecture.Arm64 => TargetArchitecture.Arm64, + Contracts.RuntimeInfoArchitecture.LoongArch64 => TargetArchitecture.LoongArch64, + Contracts.RuntimeInfoArchitecture.RiscV64 => TargetArchitecture.RiscV64, + Contracts.RuntimeInfoArchitecture.Wasm => TargetArchitecture.Wasm, + _ => TargetArchitecture.Unknown, + }; + + pTargetInfo->OS = runtimeInfo.GetTargetOperatingSystem() switch + { + Contracts.RuntimeInfoOperatingSystem.Windows => TargetOperatingSystem.Windows, + Contracts.RuntimeInfoOperatingSystem.Unix => TargetOperatingSystem.Unix, + Contracts.RuntimeInfoOperatingSystem.Apple => TargetOperatingSystem.Unix, + _ => TargetOperatingSystem.Unknown, + }; + + pTargetInfo->PointerSize = (uint)_target.PointerSize; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + TargetInfo targetInfoLocal; + int hrLocal = _legacy.GetTargetInfo(&targetInfoLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(pTargetInfo->Arch == targetInfoLocal.Arch, $"cDAC: {pTargetInfo->Arch}, DAC: {targetInfoLocal.Arch}"); + Debug.Assert(pTargetInfo->OS == targetInfoLocal.OS, $"cDAC: {pTargetInfo->OS}, DAC: {targetInfoLocal.OS}"); + Debug.Assert(pTargetInfo->PointerSize == targetInfoLocal.PointerSize, $"cDAC: {pTargetInfo->PointerSize}, DAC: {targetInfoLocal.PointerSize}"); + } + } +#endif + return hr; + } + // Fills a DebuggerIPCE_ExpandedTypeData entry for a single type parameter, falling back to System.__Canon on failure. private void FillExpandedTypeDataWithCanonFallback(IRuntimeTypeSystem rts, ITypeHandle typeHandle, ITypeHandle thCanon, DebuggerIPCE_ExpandedTypeData* pTypeInfo) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index cc96dd9fc20abd..df516e92389d7e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -896,4 +896,34 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, [PreserveSig] int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex); + + [PreserveSig] + int GetTargetInfo(TargetInfo* pTargetInfo); +} + +public enum TargetArchitecture +{ + Unknown = 0, + X86, + AMD64, + Arm, + Arm64, + LoongArch64, + RiscV64, + Wasm, +} + +public enum TargetOperatingSystem +{ + Unknown = 0, + Windows, + Unix, +} + +[StructLayout(LayoutKind.Sequential)] +public struct TargetInfo +{ + public TargetArchitecture Arch; + public TargetOperatingSystem OS; + public uint PointerSize; }