// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. //***************************************************************************** // DataTargetAdapter.cpp // // // implementation of compatibility adapter for ICLRDataTarget //***************************************************************************** #include "stdafx.h" #include "datatargetadapter.h" #include #include "dacimpl.h" #ifndef IMAGE_FILE_MACHINE_ARM64 #define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian #endif // // DataTargetAdaptor ctor // // Instantiate a DataTargetAdapter over the supplied legacy DataTarget interface. // Takes a ref on the supplied interface and releases it in our dtor. // DataTargetAdapter::DataTargetAdapter(ICLRDataTarget * pLegacyTarget) : m_ref(0), m_pLegacyTarget(pLegacyTarget) { m_pLegacyTarget->AddRef(); } // // DataTargetAdapter dtor // // Releases the underlying DataTarget interface // DataTargetAdapter::~DataTargetAdapter() { m_pLegacyTarget->Release(); } // Standard impl of IUnknown::QueryInterface HRESULT STDMETHODCALLTYPE DataTargetAdapter::QueryInterface( REFIID interfaceId, PVOID* pInterface) { if (interfaceId == IID_IUnknown) { *pInterface = static_cast(static_cast(this)); } else if (interfaceId == IID_ICorDebugDataTarget) { *pInterface = static_cast(this); } else if (interfaceId == IID_ICorDebugMutableDataTarget) { // Note that we always implement the mutable interface, even though our underlying target // may return E_NOTIMPL for all the functions on this interface. There is no reliable way // to tell apriori whether an ICLRDataTarget instance supports writing or not. *pInterface = static_cast(this); } else { // For ICorDebugDataTarget4 and other interfaces directly implemented by the legacy data target. return m_pLegacyTarget->QueryInterface(interfaceId, pInterface); } AddRef(); return S_OK; } // Standard impl of IUnknown::AddRef ULONG STDMETHODCALLTYPE DataTargetAdapter::AddRef() { LONG ref = InterlockedIncrement(&m_ref); return ref; } // Standard impl of IUnknown::Release ULONG STDMETHODCALLTYPE DataTargetAdapter::Release() { SUPPORTS_DAC_HOST_ONLY; LONG ref = InterlockedDecrement(&m_ref); if (ref == 0) { delete this; } return ref; } // impl of interface method ICorDebugDataTarget::GetPlatform HRESULT STDMETHODCALLTYPE DataTargetAdapter::GetPlatform( CorDebugPlatform * pPlatform) { SUPPORTS_DAC_HOST_ONLY; // Get the target machine type, and assume it's Windows HRESULT hr; ULONG32 ulMachineType; IfFailRet(m_pLegacyTarget->GetMachineType(&ulMachineType)); ULONG32 ulExpectedPointerSize; CorDebugPlatform platform; switch(ulMachineType) { #ifdef FEATURE_PAL case IMAGE_FILE_MACHINE_I386: ulExpectedPointerSize = 4; platform = CORDB_PLATFORM_POSIX_X86; break; case IMAGE_FILE_MACHINE_AMD64: ulExpectedPointerSize = 8; platform = CORDB_PLATFORM_POSIX_AMD64; break; case IMAGE_FILE_MACHINE_ARMNT: ulExpectedPointerSize = 4; platform = CORDB_PLATFORM_POSIX_ARM; break; case IMAGE_FILE_MACHINE_ARM64: ulExpectedPointerSize = 8; platform = CORDB_PLATFORM_POSIX_ARM64; break; case IMAGE_FILE_MACHINE_IA64: _ASSERTE_MSG(false, "Not supported platform."); return E_NOTIMPL; #else // FEATURE_PAL case IMAGE_FILE_MACHINE_I386: ulExpectedPointerSize = 4; platform = CORDB_PLATFORM_WINDOWS_X86; break; case IMAGE_FILE_MACHINE_AMD64: ulExpectedPointerSize = 8; platform = CORDB_PLATFORM_WINDOWS_AMD64; break; case IMAGE_FILE_MACHINE_IA64: ulExpectedPointerSize = 8; platform = CORDB_PLATFORM_WINDOWS_IA64; break; case IMAGE_FILE_MACHINE_ARMNT: ulExpectedPointerSize = 4; platform = CORDB_PLATFORM_WINDOWS_ARM; break; case IMAGE_FILE_MACHINE_ARM64: ulExpectedPointerSize = 8; platform = CORDB_PLATFORM_WINDOWS_ARM64; break; #endif // FEATURE_PAL default: // No other platforms are current supported return E_NOTIMPL; } // Validate that the target pointer size matches ULONG32 ulPointerSize; IfFailRet(m_pLegacyTarget->GetPointerSize(&ulPointerSize)); if (ulPointerSize != ulExpectedPointerSize) { return E_UNEXPECTED; } // Found a match *pPlatform = platform; return S_OK; } // impl of interface method ICorDebugDataTarget::ReadVirtual HRESULT STDMETHODCALLTYPE DataTargetAdapter::ReadVirtual( CORDB_ADDRESS address, PBYTE pBuffer, ULONG32 cbRequestSize, ULONG32 * pcbRead) { SUPPORTS_DAC_HOST_ONLY; CLRDATA_ADDRESS cdAddr = TO_CDADDR(address); return m_pLegacyTarget->ReadVirtual(cdAddr, pBuffer, cbRequestSize, pcbRead); } // impl of interface method ICorDebugMutableDataTarget::WriteVirtual HRESULT STDMETHODCALLTYPE DataTargetAdapter::WriteVirtual( CORDB_ADDRESS address, const BYTE * pBuffer, ULONG32 cbRequestSize) { SUPPORTS_DAC_HOST_ONLY; CLRDATA_ADDRESS cdAddr = TO_CDADDR(address); ULONG32 cbWritten = 0; HRESULT hr = S_OK; hr = m_pLegacyTarget->WriteVirtual(cdAddr, const_cast(pBuffer), cbRequestSize, &cbWritten); if (SUCCEEDED(hr) && cbWritten != cbRequestSize) { // This shouldn't happen - existing data target implementations make writes atomic (eg. // WriteProcessMemory), even though that isn't strictly required by the old interface. // If this does happen, we technically leave the process in an inconsistent state, and we make no // attempt to recover from that here. _ASSERTE_MSG(false, "Legacy data target WriteVirtual partial write - target left in inconsistent state"); return HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY); } return hr; } // impl of interface method ICorDebugDataTarget::GetThreadContext HRESULT STDMETHODCALLTYPE DataTargetAdapter::GetThreadContext( DWORD dwThreadID, ULONG32 contextFlags, ULONG32 contextSize, PBYTE pContext) { SUPPORTS_DAC_HOST_ONLY; return m_pLegacyTarget->GetThreadContext(dwThreadID, contextFlags, contextSize, pContext); } // impl of interface method ICorDebugMutableDataTarget::SetThreadContext HRESULT STDMETHODCALLTYPE DataTargetAdapter::SetThreadContext( DWORD dwThreadID, ULONG32 contextSize, const BYTE * pContext) { SUPPORTS_DAC_HOST_ONLY; return m_pLegacyTarget->SetThreadContext(dwThreadID, contextSize, const_cast(pContext)); } // implementation of ICorDebugMutableDataTarget::ContinueStatusChanged HRESULT STDMETHODCALLTYPE DataTargetAdapter::ContinueStatusChanged( DWORD dwThreadId, CORDB_CONTINUE_STATUS continueStatus) { SUPPORTS_DAC_HOST_ONLY; // No corresponding API in pre-arrowhead ICLRDataTarget* interfaces. // Note that we briefly had a ICLRDataTarget4 with this API, but this was never released outside the CLR so // all existing implementations should now be gone. return E_NOTIMPL; }