From ab6c7c5c75ee9cd73ab1a5ed730c4d0b15f5bfc7 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Fri, 17 Jul 2026 19:59:17 -0700 Subject: [PATCH 1/4] Start DBI changes needed for non-surrogate loading --- src/coreclr/debug/di/process.cpp | 5 + src/coreclr/debug/di/shimdatatarget.cpp | 50 ++++++++++ src/coreclr/debug/di/shimdatatarget.h | 24 ++++- src/coreclr/debug/di/shimpriv.h | 3 +- src/coreclr/debug/di/shimprocess.cpp | 6 ++ src/coreclr/dlls/mscordbi/CMakeLists.txt | 1 + src/coreclr/inc/clrdata.idl | 15 ++- src/coreclr/pal/prebuilt/idl/clrdata_i.cpp | 4 +- src/coreclr/pal/prebuilt/inc/clrdata.h | 94 ++++++++++++++++++- .../Dbi/IDacDbiInterface.cs | 14 +++ .../mscordaccore_universal/Entrypoints.cs | 85 ++++++++++++++--- 11 files changed, 279 insertions(+), 22 deletions(-) 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; From 31d8aa8d28943c2aa46bf29ded297d25a887f300 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Fri, 24 Jul 2026 22:57:56 -0700 Subject: [PATCH 2/4] Pass contract descriptor address to the DacDbiInterfaceInstance export Enables live debugging through the cDAC-backed DBI. The DacDbiInterfaceInstance export takes a contractDescriptorAddress parameter alongside the runtime base. When creating the DAC/DBI interface, the DBI resolves the runtime's contract descriptor address via TryGetSymbol and passes it to the export. The cdac entrypoint uses that address to build the ContractDescriptorTarget and construct the legacy DacDbiImpl over it, so a live ICorDebug session can be served by the cDAC. The native DAC export forwards the same address into its cDAC bring-up path. --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 11 ++- src/coreclr/debug/daccess/dacdbiimpl.h | 1 + src/coreclr/debug/di/process.cpp | 25 ++++-- src/coreclr/debug/di/shimdatatarget.cpp | 51 ----------- src/coreclr/debug/di/shimdatatarget.h | 22 +---- src/coreclr/debug/di/shimpriv.h | 2 - src/coreclr/debug/di/shimprocess.cpp | 6 -- src/coreclr/inc/clrdata.idl | 14 --- src/coreclr/pal/prebuilt/idl/clrdata_i.cpp | 3 - src/coreclr/pal/prebuilt/inc/clrdata.h | 90 ------------------- .../mscordaccore_universal/Entrypoints.cs | 31 ++----- 11 files changed, 36 insertions(+), 220 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 5f96d98b6e228d..a444706edf0b10 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -32,7 +32,6 @@ #include "conditionalweaktable.h" #ifndef USE_DAC_TABLE_RVA -extern "C" bool TryGetSymbol(ICorDebugDataTarget* dataTarget, uint64_t baseAddress, const char* symbolName, uint64_t* symbolAddress); #include #define CAN_USE_CDAC #endif @@ -252,10 +251,16 @@ DLLEXPORT DacDbiInterfaceInstance( ICorDebugDataTarget * pTarget, CORDB_ADDRESS baseAddress, + CLRDATA_ADDRESS contractDescriptorAddress, IDacDbiInterface::IAllocator * pAllocator, IDacDbiInterface::IMetaDataLookup * pMetaDataLookup, IDacDbiInterface ** ppInterface) { +#ifndef CAN_USE_CDAC + // Consumed only by the cDAC path, which is compiled out here. + (void)contractDescriptorAddress; +#endif + // No marshalling is done by the instantiationf function - we just need to setup the infrastructure. // We don't want to warn if this involves creating and accessing undacized data structures, // because it's for the infrastructure, not DACized code itself. @@ -293,8 +298,8 @@ DacDbiInterfaceInstance( DWORD val; if (enable.TryAsInteger(10, val) && val == 1) { - uint64_t contractDescriptorAddr = 0; - if (TryGetSymbol(pDac->m_pTarget, pDac->m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) + uint64_t contractDescriptorAddr = contractDescriptorAddress; + if (contractDescriptorAddr != 0) { IUnknown* legacyImpl; HRESULT qiRes = pDac->QueryInterface(IID_IUnknown, (void**)&legacyImpl); diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index ec0aa77dfc66af..e733e666cc497e 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -24,6 +24,7 @@ DLLEXPORT DacDbiInterfaceInstance( ICorDebugDataTarget * pTarget, CORDB_ADDRESS baseAddress, + CLRDATA_ADDRESS contractDescriptorAddress, IDacDbiInterface::IAllocator * pAllocator, IDacDbiInterface::IMetaDataLookup * pMetaDataLookup, IDacDbiInterface ** ppInterface); diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index aa1c3efc9fbdf9..787c0f874af3b9 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -28,6 +28,13 @@ #include "readonlydatatargetfacade.h" #include "metahost.h" +// Defined in dbgutil; resolves a runtime export address from the data target. +extern "C" bool TryGetSymbol( + ICorDebugDataTarget* dataTarget, + uint64_t baseAddress, + const char* symbolName, + uint64_t* symbolAddress); + // Keep this around for retail debugging. It's very very useful because // it's global state that we can always find, regardless of how many locals the compiler // optimizes away ;) @@ -570,11 +577,6 @@ 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) // @@ -582,10 +584,21 @@ CordbProcess::CreateDacDbiInterface() IDacDbiInterface::IAllocator * pAllocator = this; IDacDbiInterface::IMetaDataLookup * pMetaDataLookup = this; + // The cDAC needs the address of the runtime's contract descriptor to initialize. The legacy + // DAC only needs it if it wants to route through cdac or to compare results. + CLRDATA_ADDRESS contractDescriptorAddress = 0; + { + uint64_t address = 0; + if (TryGetSymbol(m_pDACDataTarget, m_clrInstanceId, "DotNetRuntimeContractDescriptor", &address)) + { + contractDescriptorAddress = address; + } + } typedef HRESULT (STDAPICALLTYPE * PFN_DacDbiInterfaceInstance)( ICorDebugDataTarget *, CORDB_ADDRESS, + CLRDATA_ADDRESS, IDacDbiInterface::IAllocator *, IDacDbiInterface::IMetaDataLookup *, IDacDbiInterface **); @@ -597,7 +610,7 @@ CordbProcess::CreateDacDbiInterface() ThrowLastError(); } - hrStatus = pfnEntry(m_pDACDataTarget, m_clrInstanceId, pAllocator, pMetaDataLookup, &pInterfacePtr); + hrStatus = pfnEntry(m_pDACDataTarget, m_clrInstanceId, contractDescriptorAddress, pAllocator, pMetaDataLookup, &pInterfacePtr); IfFailThrow(hrStatus); // We now have a resource, pInterfacePtr, that needs to be freed. diff --git a/src/coreclr/debug/di/shimdatatarget.cpp b/src/coreclr/debug/di/shimdatatarget.cpp index 7546cc0b7db957..332fa4d5fca22e 100644 --- a/src/coreclr/debug/di/shimdatatarget.cpp +++ b/src/coreclr/debug/di/shimdatatarget.cpp @@ -15,12 +15,6 @@ #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( REFIID InterfaceId, @@ -43,14 +37,6 @@ 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; @@ -102,40 +88,3 @@ 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 3f43f6ebcf00cd..10a75d88a69838 100644 --- a/src/coreclr/debug/di/shimdatatarget.h +++ b/src/coreclr/debug/di/shimdatatarget.h @@ -19,17 +19,15 @@ typedef HRESULT (*FPContinueStatusChanged)(void * pUserData, DWORD dwThreadId, C //--------------------------------------------------------------------------------------- // Data target for a live process. This is used by Shim. // -class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4, ICLRContractLocator, ICLRRuntimeLocator +class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4 { public: - ShimDataTarget() : m_runtimeBase(0) {} + ShimDataTarget() {} 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; @@ -94,20 +92,6 @@ 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; @@ -119,8 +103,6 @@ class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4, FPContinueStatusChanged m_fpContinueStatusChanged; void * m_pContinueStatusChangedUserData; - CORDB_ADDRESS m_runtimeBase; - // Reference count. LONG m_ref; }; diff --git a/src/coreclr/debug/di/shimpriv.h b/src/coreclr/debug/di/shimpriv.h index 6c1efeed48ccd6..fbc1bb0a5b6f1f 100644 --- a/src/coreclr/debug/di/shimpriv.h +++ b/src/coreclr/debug/di/shimpriv.h @@ -463,8 +463,6 @@ class ShimProcess // Get the data target to access the debuggee. ICorDebugMutableDataTarget * GetDataTarget(); - void SetRuntimeBase(CORDB_ADDRESS runtimeBase); - // Get the native event pipeline INativeEventPipeline * GetNativePipeline(); diff --git a/src/coreclr/debug/di/shimprocess.cpp b/src/coreclr/debug/di/shimprocess.cpp index 67dd4c3f5d729b..363cd07f926ff1 100644 --- a/src/coreclr/debug/di/shimprocess.cpp +++ b/src/coreclr/debug/di/shimprocess.cpp @@ -921,12 +921,6 @@ 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/inc/clrdata.idl b/src/coreclr/inc/clrdata.idl index 71d1ada2c40db3..76c55520315ebe 100644 --- a/src/coreclr/inc/clrdata.idl +++ b/src/coreclr/inc/clrdata.idl @@ -211,20 +211,6 @@ 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. diff --git a/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp b/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp index 872d7e37a85708..a234e6e8eb363f 100644 --- a/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp +++ b/src/coreclr/pal/prebuilt/idl/clrdata_i.cpp @@ -78,9 +78,6 @@ 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); diff --git a/src/coreclr/pal/prebuilt/inc/clrdata.h b/src/coreclr/pal/prebuilt/inc/clrdata.h index 6a3a1d7eb4dcba..7a575eae0cf932 100644 --- a/src/coreclr/pal/prebuilt/inc/clrdata.h +++ b/src/coreclr/pal/prebuilt/inc/clrdata.h @@ -80,13 +80,6 @@ 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; @@ -929,89 +922,6 @@ 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__ diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index e5b056f0a0dbed..38ab4c6fb0652b 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -258,15 +258,16 @@ private static unsafe int CLRDataCreateInstanceWithFallback(Guid* pIID, IntPtr / private static unsafe int DacDbiInterfaceInstance( IntPtr /*ICorDebugDataTarget*/ pTarget, ulong runtimeBase, + ulong contractDescriptorAddress, IntPtr /*IDacDbiInterface::IAllocator*/ pAllocator, IntPtr /*IDacDbiInterface::IMetaDataLookup*/ pMetaDataLookup, void** iface) { - // Match the native DAC export (DacDbiInterfaceInstance in dacdbiimpl.cpp), which only - // validates the target, base address, and out parameter. The allocator and metadata - // lookup pointers are not used by the managed implementation, so don't require them. + // The allocator and metadata lookup pointers are not used by the managed implementation, + // so, unlike the native DAC export, they are not required. if (pTarget == IntPtr.Zero || runtimeBase == 0 + || contractDescriptorAddress == 0 || iface == null) { return HResults.E_INVALIDARG; @@ -277,17 +278,7 @@ private static unsafe int DacDbiInterfaceInstance( try { object dataTarget = ComInterfaceMarshaller.ConvertToManaged((void*)pTarget)!; - if (dataTarget is ICLRRuntimeLocator runtimeLocator) - { - ulong locatedRuntimeBase; - int hr = runtimeLocator.GetRuntimeBase(&locatedRuntimeBase); - if (hr < 0) - return hr; - if (locatedRuntimeBase != runtimeBase) - return HResults.E_INVALIDARG; - } - - ContractDescriptorTarget target = CreateTargetFromCorDebugDataTarget(dataTarget); + ContractDescriptorTarget target = CreateTargetFromCorDebugDataTarget(dataTarget, contractDescriptorAddress); Legacy.DacDbiImpl impl = new(target, legacyObj: null); *iface = ComInterfaceMarshaller.ConvertToUnmanaged(impl); return HResults.S_OK; @@ -433,21 +424,11 @@ private static unsafe int CLRDataCreateInstanceCore(Guid* pIID, IntPtr /*ICLRDat return 0; } - private static unsafe ContractDescriptorTarget CreateTargetFromCorDebugDataTarget(object targetObject) + private static unsafe ContractDescriptorTarget CreateTargetFromCorDebugDataTarget(object targetObject, ulong contractAddress) { 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)); - - ulong contractAddress; - int hr = contractLocator.GetContractDescriptor(&contractAddress); - if (hr != 0) - { - throw new InvalidOperationException( - $"{nameof(ICLRContractLocator)} failed to fetch the contract descriptor with HRESULT: 0x{hr:x}."); - } if (!ContractDescriptorTarget.TryCreate( contractAddress, From 6d6d4d8f078af3feb2aadafa5a89ab9ca7801384 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Sat, 25 Jul 2026 03:10:27 -0700 Subject: [PATCH 3/4] Remove stray header import --- src/coreclr/debug/di/shimdatatarget.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/debug/di/shimdatatarget.h b/src/coreclr/debug/di/shimdatatarget.h index 10a75d88a69838..1786671c8d354c 100644 --- a/src/coreclr/debug/di/shimdatatarget.h +++ b/src/coreclr/debug/di/shimdatatarget.h @@ -11,8 +11,6 @@ #ifndef SHIMDATATARGET_H_ #define SHIMDATATARGET_H_ -#include - // Function to invoke for typedef HRESULT (*FPContinueStatusChanged)(void * pUserData, DWORD dwThreadId, CORDB_CONTINUE_STATUS dwContinueStatus); From 7023dc52413c21f93d0eaf9f6797265cc763ff05 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Sat, 25 Jul 2026 05:09:18 -0700 Subject: [PATCH 4/4] Use debugger-conventional HRESULTs in the CorDebug data-target adapter Return CORDBG_E_READVIRTUAL_FAILURE for an incomplete ReadVirtual and CORDBG_E_TARGET_READONLY when the target does not implement ICorDebugMutableDataTarget, instead of the generic E_FAIL/E_NOTIMPL. --- .../CorDbHResults.cs | 1 + .../managed/cdac/mscordaccore_universal/Entrypoints.cs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs index e9677b6b92b48e..b834bdd3651b45 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs @@ -12,6 +12,7 @@ public static class CorDbgHResults public const int CORDBG_E_CLASS_NOT_LOADED = unchecked((int)0x80131303); public const int CORDBG_E_FUNCTION_NOT_IL = unchecked((int)0x8013130a); public const int CORDBG_E_TARGET_INCONSISTENT = unchecked((int)0x80131c36); + public const int CORDBG_E_TARGET_READONLY = unchecked((int)0x80131c38); public const int CORDBG_S_NOT_ALL_BITS_SET = unchecked((int)0x00131c13); public const int CORDBG_E_NON_MATCHING_CONTEXT = unchecked((int)0x80131327); public const int CORDBG_E_UNSUPPORTED_DELEGATE = unchecked((int)0x80131c68); diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index 38ab4c6fb0652b..11b392d635da3a 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -439,14 +439,14 @@ private static unsafe ContractDescriptorTarget CreateTargetFromCorDebugDataTarge uint bytesRead; int hr = dataTarget.ReadVirtual(address, bufferPtr, (uint)buffer.Length, &bytesRead); return hr >= 0 && bytesRead != (uint)buffer.Length - ? HResults.E_FAIL + ? CorDbgHResults.CORDBG_E_READVIRTUAL_FAILURE : hr; } }, (address, buffer) => { if (mutableDataTarget is null) - return HResults.E_NOTIMPL; + return CorDbgHResults.CORDBG_E_TARGET_READONLY; fixed (byte* bufferPtr = buffer) { @@ -486,7 +486,7 @@ private static unsafe ContractDescriptorTarget CreateTargetFromCorDebugDataTarge (threadId, context) => { if (mutableDataTarget is null) - return HResults.E_NOTIMPL; + return CorDbgHResults.CORDBG_E_TARGET_READONLY; fixed (byte* contextPtr = context) {