diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 66d33e4ff16f5c..aa1c3efc9fbdf9 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -570,6 +570,11 @@ CordbProcess::CreateDacDbiInterface() m_hDacModule = ShimProcess::GetDacModule(m_cordb->GetDacModulePath()); } + if (m_pShim != NULL) + { + m_pShim->SetRuntimeBase(m_clrInstanceId); + } + // // Get the access interface, passing our callback interfaces (data target, allocator and metadata lookup) // diff --git a/src/coreclr/debug/di/shimdatatarget.cpp b/src/coreclr/debug/di/shimdatatarget.cpp index a7eca2dacc404c..7546cc0b7db957 100644 --- a/src/coreclr/debug/di/shimdatatarget.cpp +++ b/src/coreclr/debug/di/shimdatatarget.cpp @@ -15,6 +15,11 @@ #include "shimpriv.h" +extern "C" bool TryGetSymbol( + ICorDebugDataTarget* dataTarget, + uint64_t baseAddress, + const char* symbolName, + uint64_t* symbolAddress); // Standard impl of IUnknown::QueryInterface HRESULT STDMETHODCALLTYPE ShimDataTarget::QueryInterface( @@ -38,6 +43,14 @@ HRESULT STDMETHODCALLTYPE ShimDataTarget::QueryInterface( { *pInterface = static_cast(this); } + else if (InterfaceId == IID_ICLRContractLocator) + { + *pInterface = static_cast(this); + } + else if (InterfaceId == IID_ICLRRuntimeLocator) + { + *pInterface = static_cast(this); + } else { *pInterface = NULL; @@ -89,3 +102,40 @@ void ShimDataTarget::HookContinueStatusChanged(FPContinueStatusChanged fpContinu m_fpContinueStatusChanged = fpContinueStatusChanged; m_pContinueStatusChangedUserData = pUserData; } + +void ShimDataTarget::SetRuntimeBase(CORDB_ADDRESS runtimeBase) +{ + m_runtimeBase = runtimeBase; +} + +HRESULT STDMETHODCALLTYPE ShimDataTarget::GetContractDescriptor(CLRDATA_ADDRESS * contractAddress) +{ + if (contractAddress == NULL || m_runtimeBase == 0) + { + return E_INVALIDARG; + } + + uint64_t address = 0; + if (!TryGetSymbol( + static_cast(this), + m_runtimeBase, + "DotNetRuntimeContractDescriptor", + &address)) + { + return E_FAIL; + } + + *contractAddress = address; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ShimDataTarget::GetRuntimeBase(CLRDATA_ADDRESS * baseAddress) +{ + if (baseAddress == NULL || m_runtimeBase == 0) + { + return E_INVALIDARG; + } + + *baseAddress = m_runtimeBase; + return S_OK; +} diff --git a/src/coreclr/debug/di/shimdatatarget.h b/src/coreclr/debug/di/shimdatatarget.h index c2e92c217dd6c1..3f43f6ebcf00cd 100644 --- a/src/coreclr/debug/di/shimdatatarget.h +++ b/src/coreclr/debug/di/shimdatatarget.h @@ -11,22 +11,25 @@ #ifndef SHIMDATATARGET_H_ #define SHIMDATATARGET_H_ +#include // Function to invoke for typedef HRESULT (*FPContinueStatusChanged)(void * pUserData, DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus); - //--------------------------------------------------------------------------------------- // Data target for a live process. This is used by Shim. // -class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4 +class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4, ICLRContractLocator, ICLRRuntimeLocator { public: + ShimDataTarget() : m_runtimeBase(0) {} virtual ~ShimDataTarget() {} // Allow hooking an implementation for ContinueStatusChanged. void HookContinueStatusChanged(FPContinueStatusChanged fpContinueStatusChanged, void * pUserData); + void SetRuntimeBase(CORDB_ADDRESS runtimeBase); + // Release any resources. Also called by destructor. virtual void Dispose() = 0; @@ -91,6 +94,20 @@ class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4 virtual HRESULT STDMETHODCALLTYPE VirtualUnwind( DWORD threadId, ULONG32 contextSize, PBYTE context) = 0; + // + // ICLRContractLocator. + // + + virtual HRESULT STDMETHODCALLTYPE GetContractDescriptor( + CLRDATA_ADDRESS * contractAddress); + + // + // ICLRRuntimeLocator. + // + + virtual HRESULT STDMETHODCALLTYPE GetRuntimeBase( + CLRDATA_ADDRESS * baseAddress); + protected: // Pid of the target process. DWORD m_processId; @@ -102,6 +119,8 @@ class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4 FPContinueStatusChanged m_fpContinueStatusChanged; void * m_pContinueStatusChangedUserData; + CORDB_ADDRESS m_runtimeBase; + // Reference count. LONG m_ref; }; @@ -129,4 +148,3 @@ HRESULT BuildPlatformSpecificDataTarget(MachineInfo machineInfo, ShimDataTarget ** ppDataTarget); #endif // SHIMDATATARGET_H_ - diff --git a/src/coreclr/debug/di/shimpriv.h b/src/coreclr/debug/di/shimpriv.h index acbf2b5da4b522..6c1efeed48ccd6 100644 --- a/src/coreclr/debug/di/shimpriv.h +++ b/src/coreclr/debug/di/shimpriv.h @@ -463,6 +463,8 @@ class ShimProcess // Get the data target to access the debuggee. ICorDebugMutableDataTarget * GetDataTarget(); + void SetRuntimeBase(CORDB_ADDRESS runtimeBase); + // Get the native event pipeline INativeEventPipeline * GetNativePipeline(); @@ -1046,4 +1048,3 @@ class ShimFrameEnum : public ICorDebugFrameEnum #endif // SHIMPRIV_H - diff --git a/src/coreclr/debug/di/shimprocess.cpp b/src/coreclr/debug/di/shimprocess.cpp index 363cd07f926ff1..67dd4c3f5d729b 100644 --- a/src/coreclr/debug/di/shimprocess.cpp +++ b/src/coreclr/debug/di/shimprocess.cpp @@ -921,6 +921,12 @@ ICorDebugMutableDataTarget * ShimProcess::GetDataTarget() return m_pLiveDataTarget; }; +void ShimProcess::SetRuntimeBase(CORDB_ADDRESS runtimeBase) +{ + _ASSERTE(m_pLiveDataTarget != NULL); + m_pLiveDataTarget->SetRuntimeBase(runtimeBase); +} + // Trivial accessor to get the raw native event pipeline. // In V3, ICorDebug no longer owns the event thread and it does not own the event pipeline either. diff --git a/src/coreclr/dlls/mscordbi/CMakeLists.txt b/src/coreclr/dlls/mscordbi/CMakeLists.txt index 13a0b2ac4aa228..d199a5a48ff04a 100644 --- a/src/coreclr/dlls/mscordbi/CMakeLists.txt +++ b/src/coreclr/dlls/mscordbi/CMakeLists.txt @@ -69,6 +69,7 @@ endif(CLR_CMAKE_HOST_UNIX) set(COREDBI_LIBRARIES debug-pal cordbdi + dbgutil utilcodestaticnohost mdcompiler-dbi mdruntime-dbi diff --git a/src/coreclr/inc/clrdata.idl b/src/coreclr/inc/clrdata.idl index 81b0e0bc7fc653..71d1ada2c40db3 100644 --- a/src/coreclr/inc/clrdata.idl +++ b/src/coreclr/inc/clrdata.idl @@ -211,6 +211,20 @@ interface ICLRRuntimeLocator : IUnknown HRESULT GetRuntimeBase([out] CLRDATA_ADDRESS* baseAddress); }; +[ + object, + local, + uuid(17d5b8c6-34a9-407f-af4f-a930201d4e02), + pointer_default(unique) +] +interface ICLRContractLocator : IUnknown +{ + /* + Returns the address of the runtime's contract descriptor. + */ + HRESULT GetContractDescriptor([out] CLRDATA_ADDRESS* contractAddress); +} + /* * Interface used by the data access services layer to locate metadata * of assemblies in a target. @@ -340,4 +354,3 @@ interface ICLRDataEnumMemoryRegions : IUnknown [in] ULONG32 miniDumpFlags, [in] CLRDataEnumMemoryFlags clrFlags); } - diff --git a/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp b/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp index 26d36c133bf46c..872d7e37a85708 100644 --- a/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp +++ b/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp @@ -78,6 +78,9 @@ MIDL_DEFINE_GUID(IID, IID_ICLRDataTarget3,0xa5664f95,0x0af4,0x4a1b,0x96,0x0e,0x2 MIDL_DEFINE_GUID(IID, IID_ICLRRuntimeLocator,0xb760bf44,0x9377,0x4597,0x8b,0xe7,0x58,0x08,0x3b,0xdc,0x51,0x46); +MIDL_DEFINE_GUID(IID, IID_ICLRContractLocator,0x17d5b8c6,0x34a9,0x407f,0xaf,0x4f,0xa9,0x30,0x20,0x1d,0x4e,0x02); + + MIDL_DEFINE_GUID(IID, IID_ICLRMetadataLocator,0xaa8fa804,0xbc05,0x4642,0xb2,0xc5,0xc3,0x53,0xed,0x22,0xfc,0x63); @@ -99,4 +102,3 @@ MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegions,0x471c35b4,0x7c2f,0x4ef0,0xa #endif - diff --git a/src/coreclr/pal/prebuilt/inc/clrdata.h b/src/coreclr/pal/prebuilt/inc/clrdata.h index 802c34a87bf0cb..6a3a1d7eb4dcba 100644 --- a/src/coreclr/pal/prebuilt/inc/clrdata.h +++ b/src/coreclr/pal/prebuilt/inc/clrdata.h @@ -80,6 +80,13 @@ typedef interface ICLRRuntimeLocator ICLRRuntimeLocator; #endif /* __ICLRRuntimeLocator_FWD_DEFINED__ */ +#ifndef __ICLRContractLocator_FWD_DEFINED__ +#define __ICLRContractLocator_FWD_DEFINED__ +typedef interface ICLRContractLocator ICLRContractLocator; + +#endif /* __ICLRContractLocator_FWD_DEFINED__ */ + + #ifndef __ICLRMetadataLocator_FWD_DEFINED__ #define __ICLRMetadataLocator_FWD_DEFINED__ typedef interface ICLRMetadataLocator ICLRMetadataLocator; @@ -146,7 +153,7 @@ extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0000_v0_0_s_ifspec; #define __ICLRDataTarget_INTERFACE_DEFINED__ /* interface ICLRDataTarget */ -/* [unique][uuid][local][object] */ +/* [unique][uuid][local][object] */ EXTERN_C const IID IID_ICLRDataTarget; @@ -922,6 +929,89 @@ EXTERN_C const IID IID_ICLRRuntimeLocator; #endif /* __ICLRRuntimeLocator_INTERFACE_DEFINED__ */ +#ifndef __ICLRContractLocator_INTERFACE_DEFINED__ +#define __ICLRContractLocator_INTERFACE_DEFINED__ + +/* interface ICLRContractLocator */ +/* [unique][uuid][local][object] */ + + +EXTERN_C const IID IID_ICLRContractLocator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("17d5b8c6-34a9-407f-af4f-a930201d4e02") + ICLRContractLocator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetContractDescriptor( + /* [out] */ CLRDATA_ADDRESS *contractAddress) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICLRContractLocatorVtbl + { + BEGIN_INTERFACE + + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICLRContractLocator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + DECLSPEC_XFGVIRT(IUnknown, AddRef) + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICLRContractLocator * This); + + DECLSPEC_XFGVIRT(IUnknown, Release) + ULONG ( STDMETHODCALLTYPE *Release )( + ICLRContractLocator * This); + + DECLSPEC_XFGVIRT(ICLRContractLocator, GetContractDescriptor) + HRESULT ( STDMETHODCALLTYPE *GetContractDescriptor )( + ICLRContractLocator * This, + /* [out] */ CLRDATA_ADDRESS *contractAddress); + + END_INTERFACE + } ICLRContractLocatorVtbl; + + interface ICLRContractLocator + { + CONST_VTBL struct ICLRContractLocatorVtbl *lpVtbl; + }; + + +#ifdef COBJMACROS + + +#define ICLRContractLocator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICLRContractLocator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICLRContractLocator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICLRContractLocator_GetContractDescriptor(This,contractAddress) \ + ( (This)->lpVtbl -> GetContractDescriptor(This,contractAddress) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICLRContractLocator_INTERFACE_DEFINED__ */ + + #ifndef __ICLRMetadataLocator_INTERFACE_DEFINED__ #define __ICLRMetadataLocator_INTERFACE_DEFINED__ @@ -1405,5 +1495,3 @@ EXTERN_C const IID IID_ICLRDataEnumMemoryRegions; #endif #endif - - 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..e8165a5a50006e 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 @@ -22,6 +22,20 @@ public unsafe partial interface ICorDebugDataTarget int GetThreadContext(uint threadId, uint contextFlags, uint contextSize, byte* pContext); } +[GeneratedComInterface] +[Guid("A1B8A756-3CB6-4CCB-979F-3DF999673A59")] +public unsafe partial interface ICorDebugMutableDataTarget : ICorDebugDataTarget +{ + [PreserveSig] + int WriteVirtual(ulong address, byte* pBuffer, uint bytesRequested); + + [PreserveSig] + int SetThreadContext(uint threadId, uint contextSize, byte* pContext); + + [PreserveSig] + int ContinueStatusChanged(uint threadId, uint continueStatus); +} + [StructLayout(LayoutKind.Sequential)] public struct COR_TYPEID { diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index fb7983b7154987..e5b056f0a0dbed 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -12,6 +12,9 @@ internal static class Entrypoints { private const string CDAC = "cdac_reader_"; + // Native CONTEXT and DT_CONTEXT declarations require 16-byte alignment. + private const nuint ContextAlignment = 16; + [UnmanagedCallersOnly(EntryPoint = $"{CDAC}init")] private static unsafe int Init( ulong descriptor, @@ -61,15 +64,14 @@ private static unsafe int Init( { setThreadContextDelegate = (uint threadId, ReadOnlySpan context) => { - const nuint RequiredAlignment = 16; fixed (byte* contextPtr = context) { - if (((nuint)contextPtr & (RequiredAlignment - 1)) == 0) + if (((nuint)contextPtr & (ContextAlignment - 1)) == 0) { return writeThreadContext(threadId, (uint)context.Length, contextPtr, delegateContext); } - byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)context.Length, RequiredAlignment); + byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)context.Length, ContextAlignment); try { context.CopyTo(new Span(alignedBuffer, context.Length)); @@ -102,15 +104,14 @@ private static unsafe int Init( }, (threadId, contextFlags, buffer) => { - const nuint RequiredAlignment = 16; fixed (byte* bufferPtr = buffer) { - if (((nuint)bufferPtr & (RequiredAlignment - 1)) == 0) + if (((nuint)bufferPtr & (ContextAlignment - 1)) == 0) { return readThreadContext(threadId, contextFlags, (uint)buffer.Length, bufferPtr, delegateContext); } - byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)buffer.Length, RequiredAlignment); + byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)buffer.Length, ContextAlignment); NativeMemory.Clear(alignedBuffer, (nuint)buffer.Length); try { @@ -395,15 +396,14 @@ private static unsafe int CLRDataCreateInstanceCore(Guid* pIID, IntPtr /*ICLRDat }, (threadId, context) => { - const nuint RequiredAlignment = 16; fixed (byte* contextPtr = context) { - if (((nuint)contextPtr & (RequiredAlignment - 1)) == 0) + if (((nuint)contextPtr & (ContextAlignment - 1)) == 0) { return dataTarget.SetThreadContext(threadId, (uint)context.Length, contextPtr); } - byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)context.Length, RequiredAlignment); + byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)context.Length, ContextAlignment); try { context.CopyTo(new Span(alignedBuffer, context.Length)); @@ -437,6 +437,7 @@ private static unsafe ContractDescriptorTarget CreateTargetFromCorDebugDataTarge { ICorDebugDataTarget dataTarget = targetObject as ICorDebugDataTarget ?? throw new ArgumentException( $"Data target does not implement {nameof(ICorDebugDataTarget)}", nameof(targetObject)); + ICorDebugMutableDataTarget? mutableDataTarget = targetObject as ICorDebugMutableDataTarget; ICLRContractLocator contractLocator = targetObject as ICLRContractLocator ?? throw new ArgumentException( $"Data target does not implement {nameof(ICLRContractLocator)}", nameof(targetObject)); @@ -455,18 +456,76 @@ private static unsafe ContractDescriptorTarget CreateTargetFromCorDebugDataTarge fixed (byte* bufferPtr = buffer) { uint bytesRead; - return dataTarget.ReadVirtual(address, bufferPtr, (uint)buffer.Length, &bytesRead); + int hr = dataTarget.ReadVirtual(address, bufferPtr, (uint)buffer.Length, &bytesRead); + return hr >= 0 && bytesRead != (uint)buffer.Length + ? HResults.E_FAIL + : hr; + } + }, + (address, buffer) => + { + if (mutableDataTarget is null) + return HResults.E_NOTIMPL; + + fixed (byte* bufferPtr = buffer) + { + return mutableDataTarget.WriteVirtual(address, bufferPtr, (uint)buffer.Length); } }, - (address, buffer) => HResults.E_NOTIMPL, (threadId, contextFlags, bufferToFill) => { fixed (byte* bufferPtr = bufferToFill) { - return dataTarget.GetThreadContext(threadId, contextFlags, (uint)bufferToFill.Length, bufferPtr); + if (((nuint)bufferPtr & (ContextAlignment - 1)) == 0) + { + return dataTarget.GetThreadContext(threadId, contextFlags, (uint)bufferToFill.Length, bufferPtr); + } + + byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)bufferToFill.Length, ContextAlignment); + NativeMemory.Clear(alignedBuffer, (nuint)bufferToFill.Length); + try + { + int hr = dataTarget.GetThreadContext( + threadId, + contextFlags, + (uint)bufferToFill.Length, + alignedBuffer); + if (hr >= 0) + { + new ReadOnlySpan(alignedBuffer, bufferToFill.Length).CopyTo(bufferToFill); + } + return hr; + } + finally + { + NativeMemory.AlignedFree(alignedBuffer); + } + } + }, + (threadId, context) => + { + if (mutableDataTarget is null) + return HResults.E_NOTIMPL; + + fixed (byte* contextPtr = context) + { + if (((nuint)contextPtr & (ContextAlignment - 1)) == 0) + { + return mutableDataTarget.SetThreadContext(threadId, (uint)context.Length, contextPtr); + } + + byte* alignedBuffer = (byte*)NativeMemory.AlignedAlloc((nuint)context.Length, ContextAlignment); + try + { + context.CopyTo(new Span(alignedBuffer, context.Length)); + return mutableDataTarget.SetThreadContext(threadId, (uint)context.Length, alignedBuffer); + } + finally + { + NativeMemory.AlignedFree(alignedBuffer); + } } }, - (threadId, context) => HResults.E_NOTIMPL, (ulong size, out ulong allocatedAddress) => { allocatedAddress = 0;