Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <clrconfignocache.h>
#define CAN_USE_CDAC
#endif
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/debug/daccess/dacdbiimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ DLLEXPORT
DacDbiInterfaceInstance(
ICorDebugDataTarget * pTarget,
CORDB_ADDRESS baseAddress,
CLRDATA_ADDRESS contractDescriptorAddress,
IDacDbiInterface::IAllocator * pAllocator,
IDacDbiInterface::IMetaDataLookup * pMetaDataLookup,
IDacDbiInterface ** ppInterface);
Expand Down
20 changes: 19 additions & 1 deletion src/coreclr/debug/di/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;)
Expand Down Expand Up @@ -577,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;
Comment thread
hoyosjs marked this conversation as resolved.
if (TryGetSymbol(m_pDACDataTarget, m_clrInstanceId, "DotNetRuntimeContractDescriptor", &address))
{
Comment thread
hoyosjs marked this conversation as resolved.
contractDescriptorAddress = address;
}
}

typedef HRESULT (STDAPICALLTYPE * PFN_DacDbiInterfaceInstance)(
ICorDebugDataTarget *,
CORDB_ADDRESS,
CLRDATA_ADDRESS,
IDacDbiInterface::IAllocator *,
IDacDbiInterface::IMetaDataLookup *,
IDacDbiInterface **);
Expand All @@ -592,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.
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/debug/di/shimdatatarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

#include "shimpriv.h"


// Standard impl of IUnknown::QueryInterface
HRESULT STDMETHODCALLTYPE ShimDataTarget::QueryInterface(
REFIID InterfaceId,
Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/debug/di/shimdatatarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@
#ifndef SHIMDATATARGET_H_
#define SHIMDATATARGET_H_


// 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
{
public:
ShimDataTarget() {}
virtual ~ShimDataTarget() {}

// Allow hooking an implementation for ContinueStatusChanged.
Expand Down Expand Up @@ -129,4 +128,3 @@ HRESULT BuildPlatformSpecificDataTarget(MachineInfo machineInfo,
ShimDataTarget ** ppDataTarget);

#endif // SHIMDATATARGET_H_

1 change: 0 additions & 1 deletion src/coreclr/debug/di/shimpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1046,4 +1046,3 @@ class ShimFrameEnum : public ICorDebugFrameEnum


#endif // SHIMPRIV_H

1 change: 1 addition & 0 deletions src/coreclr/dlls/mscordbi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ endif(CLR_CMAKE_HOST_UNIX)
set(COREDBI_LIBRARIES
debug-pal
cordbdi
dbgutil
utilcodestaticnohost
mdcompiler-dbi
mdruntime-dbi
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/inc/clrdata.idl
Original file line number Diff line number Diff line change
Expand Up @@ -340,4 +340,3 @@ interface ICLRDataEnumMemoryRegions : IUnknown
[in] ULONG32 miniDumpFlags,
[in] CLRDataEnumMemoryFlags clrFlags);
}

1 change: 0 additions & 1 deletion src/coreclr/pal/prebuilt/idl/clrdata_i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,3 @@ MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegions,0x471c35b4,0x7c2f,0x4ef0,0xa
#endif



4 changes: 1 addition & 3 deletions src/coreclr/pal/prebuilt/inc/clrdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,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;
Expand Down Expand Up @@ -1405,5 +1405,3 @@ EXTERN_C const IID IID_ICLRDataEnumMemoryRegions;
#endif

#endif


Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
116 changes: 78 additions & 38 deletions src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -61,15 +64,14 @@ private static unsafe int Init(
{
setThreadContextDelegate = (uint threadId, ReadOnlySpan<byte> 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<byte>(alignedBuffer, context.Length));
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -257,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.
Comment thread
hoyosjs marked this conversation as resolved.
if (pTarget == IntPtr.Zero
|| runtimeBase == 0
|| contractDescriptorAddress == 0
|| iface == null)
{
return HResults.E_INVALIDARG;
Expand All @@ -276,17 +278,7 @@ private static unsafe int DacDbiInterfaceInstance(
try
{
object dataTarget = ComInterfaceMarshaller<ICorDebugDataTarget>.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<IDacDbiInterface>.ConvertToUnmanaged(impl);
return HResults.S_OK;
Expand Down Expand Up @@ -395,15 +387,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)
Comment thread
hoyosjs marked this conversation as resolved.
{
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<byte>(alignedBuffer, context.Length));
Expand Down Expand Up @@ -433,20 +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));
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}.");
}
ICorDebugMutableDataTarget? mutableDataTarget = targetObject as ICorDebugMutableDataTarget;

if (!ContractDescriptorTarget.TryCreate(
contractAddress,
Expand All @@ -455,18 +437,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
? CorDbgHResults.CORDBG_E_READVIRTUAL_FAILURE
: hr;
Comment thread
hoyosjs marked this conversation as resolved.
}
},
(address, buffer) =>
{
if (mutableDataTarget is null)
return CorDbgHResults.CORDBG_E_TARGET_READONLY;

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<byte>(alignedBuffer, bufferToFill.Length).CopyTo(bufferToFill);
}
return hr;
}
finally
{
NativeMemory.AlignedFree(alignedBuffer);
}
}
},
(threadId, context) =>
{
if (mutableDataTarget is null)
return CorDbgHResults.CORDBG_E_TARGET_READONLY;

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<byte>(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;
Expand Down