From f149dcab5d10bddca0773ec33d6b52118a8f3376 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 10 Apr 2024 18:28:13 -0700 Subject: [PATCH 01/17] Load cdacreader if found next to DAC --- src/coreclr/debug/daccess/CMakeLists.txt | 4 + src/coreclr/debug/daccess/cdac.cpp | 128 +++++++++++++++++++++++ src/coreclr/debug/daccess/cdac.h | 30 ++++++ src/coreclr/debug/daccess/daccess.cpp | 8 ++ src/coreclr/debug/daccess/dacimpl.h | 9 +- src/coreclr/debug/daccess/request.cpp | 30 +++++- src/libraries/externals.csproj | 4 + src/native/managed/compile-native.proj | 2 +- 8 files changed, 206 insertions(+), 9 deletions(-) create mode 100644 src/coreclr/debug/daccess/cdac.cpp create mode 100644 src/coreclr/debug/daccess/cdac.h diff --git a/src/coreclr/debug/daccess/CMakeLists.txt b/src/coreclr/debug/daccess/CMakeLists.txt index 5332e957c9eca..9ed71521d4283 100644 --- a/src/coreclr/debug/daccess/CMakeLists.txt +++ b/src/coreclr/debug/daccess/CMakeLists.txt @@ -1,5 +1,7 @@ add_definitions(-DFEATURE_NO_HOST) +add_subdirectory(${CLR_SRC_NATIVE_DIR}/managed/cdacreader/cmake ${CLR_ARTIFACTS_OBJ_DIR}/cdacreader) + include_directories(BEFORE ${VM_DIR}) include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR}) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) @@ -12,6 +14,7 @@ if(CLR_CMAKE_HOST_UNIX) endif(CLR_CMAKE_HOST_UNIX) set(DACCESS_SOURCES + cdac.cpp dacdbiimpl.cpp dacdbiimpllocks.cpp dacdbiimplstackwalk.cpp @@ -40,6 +43,7 @@ convert_to_absolute_path(DACCESS_SOURCES ${DACCESS_SOURCES}) add_library_clr(daccess ${DACCESS_SOURCES}) set_target_properties(daccess PROPERTIES DAC_COMPONENT TRUE) target_precompile_headers(daccess PRIVATE [["stdafx.h"]]) +target_link_libraries(daccess PRIVATE cdacreader_api) add_dependencies(daccess eventing_headers) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp new file mode 100644 index 0000000000000..b84e99ac295b9 --- /dev/null +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -0,0 +1,128 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include +#include +#include +#include "dbgutil.h" +#include "cdac_reader.h" +#include "cdac.h" + +namespace +{ + #define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader")) + bool TryLoadCDACLibrary(HMODULE *phCDAC) + { + // Load cdacreader from next to DAC binary + PathString path; + if (FAILED(GetClrModuleDirectory(path))) + return false; + + path.Append(CDAC_LIB_NAME); + *phCDAC = CLRLoadLibrary(path.GetUnicode()); + if (*phCDAC == NULL) + return false; + + return true; + } +} + +class CDACImpl final { +public: + explicit CDACImpl(HMODULE module, ICorDebugDataTarget* target); + CDACImpl(const CDACImpl&) = delete; + CDACImpl& operator=(CDACImpl&) = delete; + + CDACImpl(CDACImpl&& other) + : m_module(other.m_module) + , m_cdac_handle{other.m_cdac_handle} + , m_target{other.m_target} + , m_init{other.m_init} + , m_free{other.m_free} + , m_getSosInterface{other.m_getSosInterface} + { + other.m_module = nullptr; + other.m_cdac_handle = 0; + other.m_target = nullptr; + } + + IUnknown* SosInterface() const + { + return m_sos; + } + +public: + ~CDACImpl() + { + if (m_cdac_handle != NULL) + m_free(m_cdac_handle); + + if (m_sos != NULL) + m_sos->Release(); + + if (m_module != NULL) + ::FreeLibrary(m_module); + } + +private: + HMODULE m_module; + intptr_t m_cdac_handle; + ICorDebugDataTarget* m_target; + IUnknown* m_sos; + +private: + decltype(&cdac_reader_init) m_init; + decltype(&cdac_reader_free) m_free; + decltype(&cdac_reader_get_sos_interface) m_getSosInterface; +}; + +CDACImpl::CDACImpl(HMODULE module, ICorDebugDataTarget* target) + : m_module(module) + , m_target{target} +{ + m_init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init")); + m_free = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_free")); + m_getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); + + m_init(0, &m_cdac_handle); + m_getSosInterface(m_cdac_handle, &m_sos); +} + + +const CDAC* CDAC::Create(TADDR descriptor, ICorDebugDataTarget* target) +{ + HRESULT hr = S_OK; + + HMODULE cdacLib; + if (!TryLoadCDACLibrary(&cdacLib)) + return nullptr; + + CDACImpl *impl = new (nothrow) CDACImpl{cdacLib, target}; + if (!impl) + return nullptr; + + CDAC *cdac = new (nothrow) CDAC(impl); + if (!cdac) + { + delete impl; + return nullptr; + } + + return cdac; +} + +CDAC::CDAC(CDACImpl *impl) : m_impl(impl) +{ +} + +IUnknown* CDAC::SosInterface() const +{ + return m_impl->SosInterface(); +} + +CDAC::~CDAC() +{ + delete m_impl; +} diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h new file mode 100644 index 0000000000000..13d42d84a4dee --- /dev/null +++ b/src/coreclr/debug/daccess/cdac.h @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef CDAC_H +#define CDAC_H + +#include "cdac_reader.h" + +class CDACImpl; + +class CDAC final +{ +public: + static const CDAC* Create(TADDR descriptor, ICorDebugDataTarget *pDataTarget); + virtual ~CDAC(); + CDAC(const CDAC&) = delete; + CDAC& operator=(const CDAC&) = delete; + + IUnknown* SosInterface() const; + +private: + explicit CDAC(CDACImpl *impl); + +private: + CDACImpl* m_impl; + + friend class CDACImpl; +}; + +#endif // CDAC_H diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index d6b8d99d7c37e..a4a19ab7c6fde 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -23,6 +23,7 @@ #include "dwreport.h" #include "primitives.h" #include "dbgutil.h" +#include "cdac.h" #ifdef USE_DAC_TABLE_RVA #include @@ -3124,6 +3125,7 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe m_fEnableDllVerificationAsserts = false; #endif + m_cdac = CDAC::Create(0, m_pTarget); } ClrDataAccess::~ClrDataAccess(void) @@ -3160,6 +3162,12 @@ ClrDataAccess::~ClrDataAccess(void) } m_pTarget->Release(); m_pMutableTarget->Release(); + + if (m_cdac) + { + delete m_cdac; + m_cdac = NULL; + } } STDMETHODIMP diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index e698eed4c1803..f4ae12f7d577b 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -794,6 +794,7 @@ class DacStreamManager; #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS +class CDAC; //---------------------------------------------------------------------------- // @@ -1208,7 +1209,7 @@ class ClrDataAccess CLRDATA_ADDRESS *allocLimit); // ISOSDacInterface13 - virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback); + virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback); virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator); virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded); virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded); @@ -1221,7 +1222,7 @@ class ClrDataAccess virtual HRESULT STDMETHODCALLTYPE GetStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress); virtual HRESULT STDMETHODCALLTYPE GetThreadStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS thread, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress); virtual HRESULT STDMETHODCALLTYPE GetMethodTableInitializationFlags(CLRDATA_ADDRESS methodTable, MethodTableInitializationFlags *initializationStatus); - + // // ClrDataAccess. // @@ -1414,6 +1415,8 @@ class ClrDataAccess ULONG32 m_instanceAge; bool m_debugMode; + const CDAC* m_cdac; + #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS protected: @@ -1964,7 +1967,7 @@ class DacMemoryEnumerator : public DefaultCOMImpl sos9; + if (SUCCEEDED(m_cdac->SosInterface()->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&sos9))) + { + if (SUCCEEDED(sos9->GetBreakingChangeVersion(pVersion))) + { + useDacFallback = false; + _ASSERTE(*pVersion == SOS_BREAKING_CHANGE_VERSION); + } + } + } + else + { + *pVersion = SOS_BREAKING_CHANGE_VERSION; + } + return S_OK; } @@ -5406,10 +5426,10 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetStaticBaseAddress(CLRDATA_ADDRESS me { if (!nonGCStaticsAddress && !GCStaticsAddress) return E_POINTER; - + if (!methodTable) return E_INVALIDARG; - + SOSDacEnter(); PTR_MethodTable mTable = PTR_MethodTable(TO_TADDR(methodTable)); @@ -5440,13 +5460,13 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetThreadStaticBaseAddress(CLRDATA_ADDR { if (!nonGCStaticsAddress && !GCStaticsAddress) return E_POINTER; - + if (!methodTable) return E_INVALIDARG; if (!threadPtr) return E_INVALIDARG; - + SOSDacEnter(); PTR_MethodTable mTable = PTR_MethodTable(TO_TADDR(methodTable)); diff --git a/src/libraries/externals.csproj b/src/libraries/externals.csproj index 7f85d5d67e31f..6aa753ec79b23 100644 --- a/src/libraries/externals.csproj +++ b/src/libraries/externals.csproj @@ -85,6 +85,10 @@ + + + diff --git a/src/native/managed/compile-native.proj b/src/native/managed/compile-native.proj index 769954456f346..17cf7ae3236fb 100644 --- a/src/native/managed/compile-native.proj +++ b/src/native/managed/compile-native.proj @@ -1,7 +1,7 @@ - Release + $(Configuration) shared From 19a2de94fada4d2a128b9764de598cc7f0c7041c Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 15:03:42 -0700 Subject: [PATCH 02/17] Get cdac ISOSDacInterfaces on Init --- src/coreclr/debug/daccess/cdac.cpp | 12 +++++------- src/coreclr/debug/daccess/cdac.h | 2 +- src/coreclr/debug/daccess/daccess.cpp | 7 +++++++ src/coreclr/debug/daccess/dacimpl.h | 2 ++ src/coreclr/debug/daccess/request.cpp | 13 ++----------- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index b84e99ac295b9..0a65592446fe1 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -31,7 +31,7 @@ namespace class CDACImpl final { public: - explicit CDACImpl(HMODULE module, ICorDebugDataTarget* target); + explicit CDACImpl(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); CDACImpl(const CDACImpl&) = delete; CDACImpl& operator=(CDACImpl&) = delete; @@ -48,6 +48,7 @@ class CDACImpl final { other.m_target = nullptr; } + // Returns the SOS interface. This does not AddRef the interface. IUnknown* SosInterface() const { return m_sos; @@ -59,9 +60,6 @@ class CDACImpl final { if (m_cdac_handle != NULL) m_free(m_cdac_handle); - if (m_sos != NULL) - m_sos->Release(); - if (m_module != NULL) ::FreeLibrary(m_module); } @@ -70,7 +68,7 @@ class CDACImpl final { HMODULE m_module; intptr_t m_cdac_handle; ICorDebugDataTarget* m_target; - IUnknown* m_sos; + NonVMComHolder m_sos; private: decltype(&cdac_reader_init) m_init; @@ -91,7 +89,7 @@ CDACImpl::CDACImpl(HMODULE module, ICorDebugDataTarget* target) } -const CDAC* CDAC::Create(TADDR descriptor, ICorDebugDataTarget* target) +const CDAC* CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target) { HRESULT hr = S_OK; @@ -99,7 +97,7 @@ const CDAC* CDAC::Create(TADDR descriptor, ICorDebugDataTarget* target) if (!TryLoadCDACLibrary(&cdacLib)) return nullptr; - CDACImpl *impl = new (nothrow) CDACImpl{cdacLib, target}; + CDACImpl *impl = new (nothrow) CDACImpl{cdacLib, descriptorAddr, target}; if (!impl) return nullptr; diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index 13d42d84a4dee..0c37764598c27 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -11,7 +11,7 @@ class CDACImpl; class CDAC final { public: - static const CDAC* Create(TADDR descriptor, ICorDebugDataTarget *pDataTarget); + static const CDAC* Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); virtual ~CDAC(); CDAC(const CDAC&) = delete; CDAC& operator=(const CDAC&) = delete; diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index a4a19ab7c6fde..6ec10a9a74be9 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -3126,6 +3126,13 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe #endif m_cdac = CDAC::Create(0, m_pTarget); + if (m_cdac != NULL) + { + // Get SOS interfaces from the cDAC if available. + IUnknown* unk = m_cdac->SosInterface(); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + } } ClrDataAccess::~ClrDataAccess(void) diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index f4ae12f7d577b..1492767d582fd 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1416,6 +1416,8 @@ class ClrDataAccess bool m_debugMode; const CDAC* m_cdac; + NonVMComHolder m_cdacSos; + NonVMComHolder m_cdacSos9; #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 0cd3095a2a338..8d712907d4ab7 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -4954,18 +4954,9 @@ HRESULT ClrDataAccess::GetBreakingChangeVersion(int* pVersion) if (pVersion == nullptr) return E_INVALIDARG; - bool useDacFallback = true; - if (m_cdac != nullptr) + if (m_cdacSos9 != nullptr && SUCCEEDED(m_cdacSos9->GetBreakingChangeVersion(pVersion))) { - NonVMComHolder sos9; - if (SUCCEEDED(m_cdac->SosInterface()->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&sos9))) - { - if (SUCCEEDED(sos9->GetBreakingChangeVersion(pVersion))) - { - useDacFallback = false; - _ASSERTE(*pVersion == SOS_BREAKING_CHANGE_VERSION); - } - } + _ASSERTE(*pVersion == SOS_BREAKING_CHANGE_VERSION); } else { From 12c10c8bde20d836c7295aa46f511f6199aaab5b Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 15:04:44 -0700 Subject: [PATCH 03/17] Implement ISOSDacInterface - return E_NOTIMPL --- .../managed/cdacreader/src/Entrypoints.cs | 2 +- .../cdacreader/src/Legacy/ISOSDacInterface.cs | 287 ++++++++++++++++++ .../cdacreader/src/Legacy/SOSDacImpl.cs | 119 ++++++++ .../managed/cdacreader/src/SOSDacImpl.cs | 36 --- .../managed/cdacreader/src/cdacreader.csproj | 4 + 5 files changed, 411 insertions(+), 37 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs create mode 100644 src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs delete mode 100644 src/native/managed/cdacreader/src/SOSDacImpl.cs diff --git a/src/native/managed/cdacreader/src/Entrypoints.cs b/src/native/managed/cdacreader/src/Entrypoints.cs index a65ba9c5fa5ea..90a851413fc71 100644 --- a/src/native/managed/cdacreader/src/Entrypoints.cs +++ b/src/native/managed/cdacreader/src/Entrypoints.cs @@ -42,7 +42,7 @@ private static unsafe int GetSOSInterface(IntPtr handle, nint* obj) if (target == null) return -1; - SOSDacImpl impl = new(target); + Legacy.SOSDacImpl impl = new(target); nint ptr = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); *obj = ptr; return 0; diff --git a/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs b/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs new file mode 100644 index 0000000000000..0c88b2b0dacc1 --- /dev/null +++ b/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs @@ -0,0 +1,287 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Microsoft.Diagnostics.DataContractReader.Legacy; + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value +internal struct DacpThreadStoreData +{ + public int threadCount; + public int unstartedThreadCount; + public int backgroundThreadCount; + public int pendingThreadCount; + public int deadThreadCount; + public ulong firstThread; + public ulong finalizerThread; + public ulong gcThread; + public int fHostConfig; // Uses hosting flags defined above +}; + +internal struct DacpThreadData +{ + public int corThreadId; + public int osThreadId; + public int state; + public uint preemptiveGCDisabled; + public ulong allocContextPtr; + public ulong allocContextLimit; + public ulong context; + public ulong domain; + public ulong pFrame; + public int lockCount; + public ulong firstNestedException; // Pass this pointer to DacpNestedExceptionInfo + public ulong teb; + public ulong fiberData; + public ulong lastThrownObjectHandle; + public ulong nextThread; +} +#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value + +[GeneratedComInterface] +[Guid("436f00f2-b42a-4b9f-870c-e73db66ae930")] +internal unsafe partial interface ISOSDacInterface +{ + // ThreadStore + [PreserveSig] + int GetThreadStoreData(DacpThreadStoreData* data); + + // AppDomains + [PreserveSig] + int GetAppDomainStoreData(/*struct DacpAppDomainStoreData*/ void* data); + [PreserveSig] + int GetAppDomainList(uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] values, uint* pNeeded); + [PreserveSig] + int GetAppDomainData(ulong addr, /*struct DacpAppDomainData*/ void* data); + [PreserveSig] + int GetAppDomainName(ulong addr, uint count, char* name, uint* pNeeded); + [PreserveSig] + int GetDomainFromContext(ulong context, ulong* domain); + + // Assemblies + [PreserveSig] + int GetAssemblyList(ulong appDomain, int count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] values, int* pNeeded); + [PreserveSig] + int GetAssemblyData(ulong baseDomainPtr, ulong assembly, /*struct DacpAssemblyData*/ void* data); + [PreserveSig] + int GetAssemblyName(ulong assembly, uint count, char* name, uint* pNeeded); + + // Modules + [PreserveSig] + int GetModule(ulong addr, /*IXCLRDataModule*/ void** mod); + [PreserveSig] + int GetModuleData(ulong moduleAddr, /*struct DacpModuleData*/ void* data); + [PreserveSig] + int TraverseModuleMap(/*ModuleMapType*/ int mmt, ulong moduleAddr, /*MODULEMAPTRAVERSE*/ void* pCallback, void* token); + [PreserveSig] + int GetAssemblyModuleList(ulong assembly, uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] modules, uint* pNeeded); + [PreserveSig] + int GetILForModule(ulong moduleAddr, int rva, ulong* il); + + // Threads + [PreserveSig] + int GetThreadData(ulong thread, DacpThreadData *data); + [PreserveSig] + int GetThreadFromThinlockID(uint thinLockId, ulong* pThread); + [PreserveSig] + int GetStackLimits(ulong threadPtr, ulong* lower, ulong* upper, ulong* fp); + + // MethodDescs + [PreserveSig] + int GetMethodDescData(ulong methodDesc, ulong ip, /*struct DacpMethodDescData*/ void* data, uint cRevertedRejitVersions, /*struct DacpReJitData*/ void* rgRevertedRejitData, uint* pcNeededRevertedRejitData); + [PreserveSig] + int GetMethodDescPtrFromIP(ulong ip, ulong* ppMD); + [PreserveSig] + int GetMethodDescName(ulong methodDesc, uint count, char* name, uint* pNeeded); + [PreserveSig] + int GetMethodDescPtrFromFrame(ulong frameAddr, ulong* ppMD); + [PreserveSig] + int GetMethodDescFromToken(ulong moduleAddr, /*mdToken*/ uint token, ulong* methodDesc); + [PreserveSig] + int GetMethodDescTransparencyData(ulong methodDesc, /*struct DacpMethodDescTransparencyData*/ void* data); + + // JIT Data + [PreserveSig] + int GetCodeHeaderData(ulong ip, /*struct DacpCodeHeaderData*/ void* data); + [PreserveSig] + int GetJitManagerList(uint count, /*struct DacpJitManagerInfo*/ void* managers, uint* pNeeded); + [PreserveSig] + int GetJitHelperFunctionName(ulong ip, uint count, byte* name, uint* pNeeded); + [PreserveSig] + int GetJumpThunkTarget(/*T_CONTEXT*/void* ctx, ulong* targetIP, ulong* targetMD); + + // ThreadPool + [PreserveSig] + int GetThreadpoolData(/*struct DacpThreadpoolData*/ void* data); + [PreserveSig] + int GetWorkRequestData(ulong addrWorkRequest, /*struct DacpWorkRequestData*/ void* data); + [PreserveSig] + int GetHillClimbingLogEntry(ulong addr, /*struct DacpHillClimbingLogEntry*/ void* data); + + // Objects + [PreserveSig] + int GetObjectData(ulong objAddr, /*struct DacpObjectData*/ void* data); + [PreserveSig] + int GetObjectStringData(ulong obj, uint count, char* stringData, uint* pNeeded); + [PreserveSig] + int GetObjectClassName(ulong obj, uint count, char* className, uint* pNeeded); + + // MethodTable + [PreserveSig] + int GetMethodTableName(ulong mt, uint count, char* mtName, uint* pNeeded); + [PreserveSig] + int GetMethodTableData(ulong mt, /*struct DacpMethodTableData*/ void* data); + [PreserveSig] + int GetMethodTableSlot(ulong mt, uint slot, ulong* value); + [PreserveSig] + int GetMethodTableFieldData(ulong mt, /*struct DacpMethodTableFieldData*/ void* data); + [PreserveSig] + int GetMethodTableTransparencyData(ulong mt, /*struct DacpMethodTableTransparencyData*/ void* data); + + // EEClass + [PreserveSig] + int GetMethodTableForEEClass(ulong eeClass, ulong* value); + + // FieldDesc + [PreserveSig] + int GetFieldDescData(ulong fieldDesc, /*struct DacpFieldDescData*/ void* data); + + // Frames + [PreserveSig] + int GetFrameName(ulong vtable, uint count, char* frameName, uint* pNeeded); + + // PEFiles + [PreserveSig] + int GetPEFileBase(ulong addr, ulong* peBase); + [PreserveSig] + int GetPEFileName(ulong addr, uint count, char* fileName, uint* pNeeded); + + // GC + [PreserveSig] + int GetGCHeapData(/*struct DacpGcHeapData*/ void* data); + [PreserveSig] + int GetGCHeapList(uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] heaps, uint* pNeeded); // svr only + [PreserveSig] + int GetGCHeapDetails(ulong heap, /*struct DacpGcHeapDetails */ void* details); // wks only + [PreserveSig] + int GetGCHeapStaticData(/*struct DacpGcHeapDetails */ void* data); + [PreserveSig] + int GetHeapSegmentData(ulong seg, /*struct DacpHeapSegmentData */ void* data); + [PreserveSig] + int GetOOMData(ulong oomAddr, /*struct DacpOomData */ void* data); + [PreserveSig] + int GetOOMStaticData(/*struct DacpOomData */ void* data); + [PreserveSig] + int GetHeapAnalyzeData(ulong addr, /*struct DacpGcHeapAnalyzeData */ void* data); + [PreserveSig] + int GetHeapAnalyzeStaticData(/*struct DacpGcHeapAnalyzeData */ void* data); + + // DomainLocal + [PreserveSig] + int GetDomainLocalModuleData(ulong addr, /*struct DacpDomainLocalModuleData */ void* data); + [PreserveSig] + int GetDomainLocalModuleDataFromAppDomain(ulong appDomainAddr, int moduleID, /*struct DacpDomainLocalModuleData */ void* data); + [PreserveSig] + int GetDomainLocalModuleDataFromModule(ulong moduleAddr, /*struct DacpDomainLocalModuleData */ void* data); + + // ThreadLocal + [PreserveSig] + int GetThreadLocalModuleData(ulong thread, uint index, /*struct DacpThreadLocalModuleData */ void* data); + + // SyncBlock + [PreserveSig] + int GetSyncBlockData(uint number, /*struct DacpSyncBlockData */ void* data); + [PreserveSig] + int GetSyncBlockCleanupData(ulong addr, /*struct DacpSyncBlockCleanupData */ void* data); + + // Handles + [PreserveSig] + int GetHandleEnum(/*ISOSHandleEnum*/ void** ppHandleEnum); + [PreserveSig] + int GetHandleEnumForTypes([In, MarshalUsing(CountElementName = nameof(count))] uint[] types, uint count, /*ISOSHandleEnum*/ void** ppHandleEnum); + [PreserveSig] + int GetHandleEnumForGC(uint gen, /*ISOSHandleEnum*/ void** ppHandleEnum); + + // EH + [PreserveSig] + int TraverseEHInfo(ulong ip, /*DUMPEHINFO*/ void* pCallback, void* token); + [PreserveSig] + int GetNestedExceptionData(ulong exception, ulong* exceptionObject, ulong* nextNestedException); + + // StressLog + [PreserveSig] + int GetStressLogAddress(ulong* stressLog); + + // Heaps + [PreserveSig] + int TraverseLoaderHeap(ulong loaderHeapAddr, /*VISITHEAP*/ void* pCallback); + [PreserveSig] + int GetCodeHeapList(ulong jitManager, uint count, /*struct DacpJitCodeHeapInfo*/ void* codeHeaps, uint* pNeeded); + [PreserveSig] + int TraverseVirtCallStubHeap(ulong pAppDomain, /*VCSHeapType*/ int heaptype, /*VISITHEAP*/ void* pCallback); + + // Other + [PreserveSig] + int GetUsefulGlobals(/*struct DacpUsefulGlobalsData */ void* data); + [PreserveSig] + int GetClrWatsonBuckets(ulong thread, void* pGenericModeBlock); + [PreserveSig] + int GetTLSIndex(uint* pIndex); + [PreserveSig] + int GetDacModuleHandle(/*HMODULE*/ void* phModule); + + // COM + [PreserveSig] + int GetRCWData(ulong addr, /*struct DacpRCWData */ void* data); + [PreserveSig] + int GetRCWInterfaces(ulong rcw, uint count, /*struct DacpCOMInterfacePointerData*/ void* interfaces, uint* pNeeded); + [PreserveSig] + int GetCCWData(ulong ccw, /*struct DacpCCWData */ void* data); + [PreserveSig] + int GetCCWInterfaces(ulong ccw, uint count, /*struct DacpCOMInterfacePointerData*/ void* interfaces, uint* pNeeded); + [PreserveSig] + int TraverseRCWCleanupList(ulong cleanupListPtr, /*VISITRCWFORCLEANUP*/ void* pCallback, void* token); + + // GC Reference Functions + + /* GetStackReferences + * Enumerates all references on a given callstack. + */ + [PreserveSig] + int GetStackReferences(int osThreadID, /*ISOSStackRefEnum*/ void** ppEnum); + [PreserveSig] + int GetRegisterName(int regName, uint count, char* buffer, uint* pNeeded); + + [PreserveSig] + int GetThreadAllocData(ulong thread, /*struct DacpAllocData */ void* data); + [PreserveSig] + int GetHeapAllocData(uint count, /*struct DacpGenerationAllocData */ void* data, uint* pNeeded); + + // For BindingDisplay plugin + [PreserveSig] + int GetFailedAssemblyList(ulong appDomain, int count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] values, uint* pNeeded); + [PreserveSig] + int GetPrivateBinPaths(ulong appDomain, int count, char* paths, uint* pNeeded); + [PreserveSig] + int GetAssemblyLocation(ulong assembly, int count, char* location, uint* pNeeded); + [PreserveSig] + int GetAppDomainConfigFile(ulong appDomain, int count, char* configFile, uint* pNeeded); + [PreserveSig] + int GetApplicationBase(ulong appDomain, int count, char* appBase, uint* pNeeded); + [PreserveSig] + int GetFailedAssemblyData(ulong assembly, uint* pContext, int* pResult); + [PreserveSig] + int GetFailedAssemblyLocation(ulong assesmbly, uint count, char* location, uint* pNeeded); + [PreserveSig] + int GetFailedAssemblyDisplayName(ulong assembly, uint count, char* name, uint* pNeeded); +}; + +[GeneratedComInterface] +[Guid("4eca42d8-7e7b-4c8a-a116-7bfbf6929267")] +internal partial interface ISOSDacInterface9 +{ + int GetBreakingChangeVersion(); +} diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs new file mode 100644 index 0000000000000..b0640c44efc98 --- /dev/null +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Microsoft.Diagnostics.DataContractReader.Legacy; + +/// +/// Implementation of ISOSDacInterface* interfaces intended to be passed out to consumers +/// interacting with the DAC via those COM interfaces. +/// +[GeneratedComClass] +internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface9 +{ + private readonly Target _target; + + public SOSDacImpl(Target target) + { + _target = target; + } + + public unsafe int GetAppDomainConfigFile(ulong appDomain, int count, char* configFile, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetAppDomainData(ulong addr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetAppDomainList(uint count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] values, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetAppDomainName(ulong addr, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetAppDomainStoreData(void* data) => HResults.E_NOTIMPL; + public unsafe int GetApplicationBase(ulong appDomain, int count, char* appBase, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetAssemblyData(ulong baseDomainPtr, ulong assembly, void* data) => HResults.E_NOTIMPL; + public unsafe int GetAssemblyList(ulong appDomain, int count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] values, int* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetAssemblyLocation(ulong assembly, int count, char* location, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetAssemblyModuleList(ulong assembly, uint count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] modules, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetAssemblyName(ulong assembly, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL; + + public int GetBreakingChangeVersion() + { + // TODO: Return non-hard-coded version + return 4; + } + + public unsafe int GetCCWData(ulong ccw, void* data) => HResults.E_NOTIMPL; + public unsafe int GetCCWInterfaces(ulong ccw, uint count, void* interfaces, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetClrWatsonBuckets(ulong thread, void* pGenericModeBlock) => HResults.E_NOTIMPL; + public unsafe int GetCodeHeaderData(ulong ip, void* data) => HResults.E_NOTIMPL; + public unsafe int GetCodeHeapList(ulong jitManager, uint count, void* codeHeaps, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetDacModuleHandle(void* phModule) => HResults.E_NOTIMPL; + public unsafe int GetDomainFromContext(ulong context, ulong* domain) => HResults.E_NOTIMPL; + public unsafe int GetDomainLocalModuleData(ulong addr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetDomainLocalModuleDataFromAppDomain(ulong appDomainAddr, int moduleID, void* data) => HResults.E_NOTIMPL; + public unsafe int GetDomainLocalModuleDataFromModule(ulong moduleAddr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetFailedAssemblyData(ulong assembly, uint* pContext, int* pResult) => HResults.E_NOTIMPL; + public unsafe int GetFailedAssemblyDisplayName(ulong assembly, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetFailedAssemblyList(ulong appDomain, int count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] values, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetFailedAssemblyLocation(ulong assesmbly, uint count, char* location, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetFieldDescData(ulong fieldDesc, void* data) => HResults.E_NOTIMPL; + public unsafe int GetFrameName(ulong vtable, uint count, char* frameName, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetGCHeapData(void* data) => HResults.E_NOTIMPL; + public unsafe int GetGCHeapDetails(ulong heap, void* details) => HResults.E_NOTIMPL; + public unsafe int GetGCHeapList(uint count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] heaps, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetGCHeapStaticData(void* data) => HResults.E_NOTIMPL; + public unsafe int GetHandleEnum(void** ppHandleEnum) => HResults.E_NOTIMPL; + public unsafe int GetHandleEnumForGC(uint gen, void** ppHandleEnum) => HResults.E_NOTIMPL; + public unsafe int GetHandleEnumForTypes([In, MarshalUsing(CountElementName = "count")] uint[] types, uint count, void** ppHandleEnum) => HResults.E_NOTIMPL; + public unsafe int GetHeapAllocData(uint count, void* data, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetHeapAnalyzeData(ulong addr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetHeapAnalyzeStaticData(void* data) => HResults.E_NOTIMPL; + public unsafe int GetHeapSegmentData(ulong seg, void* data) => HResults.E_NOTIMPL; + public unsafe int GetHillClimbingLogEntry(ulong addr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetILForModule(ulong moduleAddr, int rva, ulong* il) => HResults.E_NOTIMPL; + public unsafe int GetJitHelperFunctionName(ulong ip, uint count, byte* name, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetJitManagerList(uint count, void* managers, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetJumpThunkTarget(void* ctx, ulong* targetIP, ulong* targetMD) => HResults.E_NOTIMPL; + public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, void* data, uint cRevertedRejitVersions, void* rgRevertedRejitData, uint* pcNeededRevertedRejitData) => HResults.E_NOTIMPL; + public unsafe int GetMethodDescFromToken(ulong moduleAddr, uint token, ulong* methodDesc) => HResults.E_NOTIMPL; + public unsafe int GetMethodDescName(ulong methodDesc, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetMethodDescPtrFromFrame(ulong frameAddr, ulong* ppMD) => HResults.E_NOTIMPL; + public unsafe int GetMethodDescPtrFromIP(ulong ip, ulong* ppMD) => HResults.E_NOTIMPL; + public unsafe int GetMethodDescTransparencyData(ulong methodDesc, void* data) => HResults.E_NOTIMPL; + public unsafe int GetMethodTableData(ulong mt, void* data) => HResults.E_NOTIMPL; + public unsafe int GetMethodTableFieldData(ulong mt, void* data) => HResults.E_NOTIMPL; + public unsafe int GetMethodTableForEEClass(ulong eeClass, ulong* value) => HResults.E_NOTIMPL; + public unsafe int GetMethodTableName(ulong mt, uint count, char* mtName, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetMethodTableSlot(ulong mt, uint slot, ulong* value) => HResults.E_NOTIMPL; + public unsafe int GetMethodTableTransparencyData(ulong mt, void* data) => HResults.E_NOTIMPL; + public unsafe int GetModule(ulong addr, void** mod) => HResults.E_NOTIMPL; + public unsafe int GetModuleData(ulong moduleAddr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetNestedExceptionData(ulong exception, ulong* exceptionObject, ulong* nextNestedException) => HResults.E_NOTIMPL; + public unsafe int GetObjectClassName(ulong obj, uint count, char* className, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetObjectData(ulong objAddr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetObjectStringData(ulong obj, uint count, char* stringData, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetOOMData(ulong oomAddr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetOOMStaticData(void* data) => HResults.E_NOTIMPL; + public unsafe int GetPEFileBase(ulong addr, ulong* peBase) => HResults.E_NOTIMPL; + public unsafe int GetPEFileName(ulong addr, uint count, char* fileName, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetPrivateBinPaths(ulong appDomain, int count, char* paths, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetRCWData(ulong addr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetRCWInterfaces(ulong rcw, uint count, void* interfaces, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetRegisterName(int regName, uint count, char* buffer, uint* pNeeded) => HResults.E_NOTIMPL; + public unsafe int GetStackLimits(ulong threadPtr, ulong* lower, ulong* upper, ulong* fp) => HResults.E_NOTIMPL; + public unsafe int GetStackReferences(int osThreadID, void** ppEnum) => HResults.E_NOTIMPL; + public unsafe int GetStressLogAddress(ulong* stressLog) => HResults.E_NOTIMPL; + public unsafe int GetSyncBlockCleanupData(ulong addr, void* data) => HResults.E_NOTIMPL; + public unsafe int GetSyncBlockData(uint number, void* data) => HResults.E_NOTIMPL; + public unsafe int GetThreadAllocData(ulong thread, void* data) => HResults.E_NOTIMPL; + public unsafe int GetThreadData(ulong thread, DacpThreadData* data) => HResults.E_NOTIMPL; + public unsafe int GetThreadFromThinlockID(uint thinLockId, ulong* pThread) => HResults.E_NOTIMPL; + public unsafe int GetThreadLocalModuleData(ulong thread, uint index, void* data) => HResults.E_NOTIMPL; + public unsafe int GetThreadpoolData(void* data) => HResults.E_NOTIMPL; + public unsafe int GetThreadStoreData(DacpThreadStoreData* data) => HResults.E_NOTIMPL; + public unsafe int GetTLSIndex(uint* pIndex) => HResults.E_NOTIMPL; + public unsafe int GetUsefulGlobals(void* data) => HResults.E_NOTIMPL; + public unsafe int GetWorkRequestData(ulong addrWorkRequest, void* data) => HResults.E_NOTIMPL; + public unsafe int TraverseEHInfo(ulong ip, void* pCallback, void* token) => HResults.E_NOTIMPL; + public unsafe int TraverseLoaderHeap(ulong loaderHeapAddr, void* pCallback) => HResults.E_NOTIMPL; + public unsafe int TraverseModuleMap(int mmt, ulong moduleAddr, void* pCallback, void* token) => HResults.E_NOTIMPL; + public unsafe int TraverseRCWCleanupList(ulong cleanupListPtr, void* pCallback, void* token) => HResults.E_NOTIMPL; + public unsafe int TraverseVirtCallStubHeap(ulong pAppDomain, int heaptype, void* pCallback) => HResults.E_NOTIMPL; +} diff --git a/src/native/managed/cdacreader/src/SOSDacImpl.cs b/src/native/managed/cdacreader/src/SOSDacImpl.cs deleted file mode 100644 index 893c39bff8830..0000000000000 --- a/src/native/managed/cdacreader/src/SOSDacImpl.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace Microsoft.Diagnostics.DataContractReader; - -[GeneratedComInterface] -[Guid("4eca42d8-7e7b-4c8a-a116-7bfbf6929267")] -internal partial interface ISOSDacInterface9 -{ - int GetBreakingChangeVersion(); -} - -/// -/// Implementation of ISOSDacInterface* interfaces intended to be passed out to consumers -/// interacting with the DAC via those COM interfaces. -/// -[GeneratedComClass] -internal sealed partial class SOSDacImpl : ISOSDacInterface9 -{ - private readonly Target _target; - - public SOSDacImpl(Target target) - { - _target = target; - } - - public int GetBreakingChangeVersion() - { - // TODO: Return non-hard-coded version - return 4; - } -} diff --git a/src/native/managed/cdacreader/src/cdacreader.csproj b/src/native/managed/cdacreader/src/cdacreader.csproj index 51f87fa8908d9..8ef4d16ae20f6 100644 --- a/src/native/managed/cdacreader/src/cdacreader.csproj +++ b/src/native/managed/cdacreader/src/cdacreader.csproj @@ -8,6 +8,10 @@ false + + + From 2249161c641ff2a08f7642fbb35040a29ac98a8c Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 16:23:44 -0700 Subject: [PATCH 04/17] Add read_from_target callback --- src/coreclr/debug/daccess/cdac.cpp | 22 +++++++++++++++++-- src/coreclr/debug/daccess/daccess.cpp | 17 +++++++++----- .../managed/cdacreader/inc/cdac_reader.h | 2 +- .../managed/cdacreader/src/Entrypoints.cs | 4 ++-- src/native/managed/cdacreader/src/Target.cs | 16 ++++++++++++-- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index 0a65592446fe1..e067b9a0a963d 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -54,6 +54,15 @@ class CDACImpl final { return m_sos; } + int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count) + { + HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count); + if (FAILED(hr)) + return hr; + + return 0; + } + public: ~CDACImpl() { @@ -76,7 +85,16 @@ class CDACImpl final { decltype(&cdac_reader_get_sos_interface) m_getSosInterface; }; -CDACImpl::CDACImpl(HMODULE module, ICorDebugDataTarget* target) +namespace +{ + int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context) + { + CDACImpl* cdac = reinterpret_cast(context); + return cdac->ReadFromTarget(addr, dest, count); + } +} + +CDACImpl::CDACImpl(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) : m_module(module) , m_target{target} { @@ -84,7 +102,7 @@ CDACImpl::CDACImpl(HMODULE module, ICorDebugDataTarget* target) m_free = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_free")); m_getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); - m_init(0, &m_cdac_handle); + m_init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle); m_getSosInterface(m_cdac_handle, &m_sos); } diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 6ec10a9a74be9..4d74c9f472fa1 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -3125,13 +3125,18 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe m_fEnableDllVerificationAsserts = false; #endif - m_cdac = CDAC::Create(0, m_pTarget); - if (m_cdac != NULL) + // TODO: [cdac] Get contract descriptor from exported symbol + uint64_t contractDescriptorAddr = 0; + //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) { - // Get SOS interfaces from the cDAC if available. - IUnknown* unk = m_cdac->SosInterface(); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); + if (m_cdac != NULL) + { + // Get SOS interfaces from the cDAC if available. + IUnknown* unk = m_cdac->SosInterface(); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + } } } diff --git a/src/native/managed/cdacreader/inc/cdac_reader.h b/src/native/managed/cdacreader/inc/cdac_reader.h index b6c71b671a6ed..158bdd42ef75e 100644 --- a/src/native/managed/cdacreader/inc/cdac_reader.h +++ b/src/native/managed/cdacreader/inc/cdac_reader.h @@ -9,7 +9,7 @@ extern "C" { #endif -int cdac_reader_init(intptr_t descriptor, intptr_t* handle); +int cdac_reader_init(uint64_t descriptor, int(*read_from_target)(uint64_t, uint8_t*, uint32_t, void*), void* read_context, intptr_t* handle); int cdac_reader_free(intptr_t handle); int cdac_reader_get_sos_interface(intptr_t handle, IUnknown** obj); diff --git a/src/native/managed/cdacreader/src/Entrypoints.cs b/src/native/managed/cdacreader/src/Entrypoints.cs index 90a851413fc71..30cab9ec85188 100644 --- a/src/native/managed/cdacreader/src/Entrypoints.cs +++ b/src/native/managed/cdacreader/src/Entrypoints.cs @@ -12,9 +12,9 @@ internal static class Entrypoints private const string CDAC = "cdac_reader_"; [UnmanagedCallersOnly(EntryPoint = $"{CDAC}init")] - private static unsafe int Init(nint descriptor, IntPtr* handle) + private static unsafe int Init(ulong descriptor, delegate* unmanaged readFromTarget, void* readContext, IntPtr* handle) { - Target target = new(descriptor); + Target target = new(descriptor, readFromTarget, readContext); GCHandle gcHandle = GCHandle.Alloc(target); *handle = GCHandle.ToIntPtr(gcHandle); return 0; diff --git a/src/native/managed/cdacreader/src/Target.cs b/src/native/managed/cdacreader/src/Target.cs index 1590984f017c3..cc1d7a7a98d8a 100644 --- a/src/native/managed/cdacreader/src/Target.cs +++ b/src/native/managed/cdacreader/src/Target.cs @@ -3,9 +3,21 @@ namespace Microsoft.Diagnostics.DataContractReader; -internal sealed class Target +internal sealed unsafe class Target { - public Target(nint _) + private readonly delegate* unmanaged _readFromTarget; + private readonly void* _readContext; + + private bool _isLittleEndian; + private int _pointerSize; + + public Target(ulong _, delegate* unmanaged readFromTarget, void* readContext) { + _readFromTarget = readFromTarget; + _readContext = readContext; + + // TODO: [cdac] Populate from descriptor + _isLittleEndian = BitConverter.IsLittleEndian; + _pointerSize = IntPtr.Size; } } From a458b37677a606a88b57fb52b01c98e31a23d92a Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 16:30:12 -0700 Subject: [PATCH 05/17] Call cdac for GetThreadStoreData (returns E_NOTIMPL) --- src/coreclr/debug/daccess/dacimpl.h | 2 + src/coreclr/debug/daccess/request.cpp | 62 ++++++++++++++++++++------- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index 1492767d582fd..1461797e0917b 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1229,6 +1229,8 @@ class ClrDataAccess HRESULT Initialize(void); + HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data); + BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord); #ifndef TARGET_UNIX HRESULT GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM); diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 8d712907d4ab7..61fa52a481576 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -302,31 +302,63 @@ HRESULT ClrDataAccess::GetThreadStoreData(struct DacpThreadStoreData *threadStor { SOSDacEnter(); - ThreadStore* threadStore = ThreadStore::s_pThreadStore; - if (!threadStore) + if (m_cdacSos != NULL) { - hr = E_UNEXPECTED; + hr = m_cdacSos->GetThreadStoreData(threadStoreData); + if (FAILED(hr)) + { + hr = GetThreadStoreDataImpl(threadStoreData); + } +#ifdef _DEBUG + else + { + // Assert that the data is the same as what we get from the DAC. + DacpThreadStoreData threadStoreDataLocal; + HRESULT hrLocal = GetThreadStoreDataImpl(&threadStoreDataLocal); + _ASSERTE(hr == hrLocal); + _ASSERTE(threadStoreData->threadCount == threadStoreDataLocal.threadCount); + _ASSERTE(threadStoreData->unstartedThreadCount == threadStoreDataLocal.unstartedThreadCount); + _ASSERTE(threadStoreData->backgroundThreadCount == threadStoreDataLocal.backgroundThreadCount); + _ASSERTE(threadStoreData->pendingThreadCount == threadStoreDataLocal.pendingThreadCount); + _ASSERTE(threadStoreData->deadThreadCount == threadStoreDataLocal.deadThreadCount); + _ASSERTE(threadStoreData->fHostConfig == threadStoreDataLocal.fHostConfig); + _ASSERTE(threadStoreData->firstThread == threadStoreDataLocal.firstThread); + _ASSERTE(threadStoreData->finalizerThread == threadStoreDataLocal.finalizerThread); + _ASSERTE(threadStoreData->gcThread == threadStoreDataLocal.gcThread); + } +#endif } else { - // initialize the fields of our local structure - threadStoreData->threadCount = threadStore->m_ThreadCount; - threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount; - threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount; - threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount; - threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount; - threadStoreData->fHostConfig = FALSE; - - // identify the "important" threads - threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead()); - threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread); - threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread); + hr = GetThreadStoreDataImpl(threadStoreData); } SOSDacLeave(); return hr; } +HRESULT ClrDataAccess::GetThreadStoreDataImpl(struct DacpThreadStoreData *threadStoreData) +{ + ThreadStore* threadStore = ThreadStore::s_pThreadStore; + if (!threadStore) + return E_UNEXPECTED; + + // initialize the fields of our local structure + threadStoreData->threadCount = threadStore->m_ThreadCount; + threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount; + threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount; + threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount; + threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount; + threadStoreData->fHostConfig = FALSE; + + // identify the "important" threads + threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead()); + threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread); + threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread); + + return S_OK; +} + HRESULT ClrDataAccess::GetStressLogAddress(CLRDATA_ADDRESS *stressLog) { From 1ba48a2cf193a00bdc29778f58e4bd54a99700d0 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 21:00:34 -0700 Subject: [PATCH 06/17] Add reading pointer from target --- src/native/managed/cdacreader/src/Target.cs | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/native/managed/cdacreader/src/Target.cs b/src/native/managed/cdacreader/src/Target.cs index cc1d7a7a98d8a..898cab774bfb5 100644 --- a/src/native/managed/cdacreader/src/Target.cs +++ b/src/native/managed/cdacreader/src/Target.cs @@ -1,8 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Buffers.Binary; + namespace Microsoft.Diagnostics.DataContractReader; +public struct TargetPointer +{ + public static TargetPointer Null = new(0); + + public ulong Value; + public TargetPointer(ulong value) => Value = value; +} + internal sealed unsafe class Target { private readonly delegate* unmanaged _readFromTarget; @@ -20,4 +31,34 @@ public Target(ulong _, delegate* unmanaged readF _isLittleEndian = BitConverter.IsLittleEndian; _pointerSize = IntPtr.Size; } + + public bool TryReadPointer(ulong address, out TargetPointer pointer) + { + pointer = TargetPointer.Null; + + byte* buffer = stackalloc byte[_pointerSize]; + ReadOnlySpan span = new ReadOnlySpan(buffer, _pointerSize); + if (ReadFromTarget(address, buffer, (uint)_pointerSize) < 0) + return false; + + if (_pointerSize == sizeof(uint)) + { + pointer = new TargetPointer( + _isLittleEndian + ? BinaryPrimitives.ReadUInt32LittleEndian(span) + : BinaryPrimitives.ReadUInt32BigEndian(span)); + } + else if (_pointerSize == sizeof(ulong)) + { + pointer = new TargetPointer( + _isLittleEndian + ? BinaryPrimitives.ReadUInt64LittleEndian(span) + : BinaryPrimitives.ReadUInt64BigEndian(span)); + } + + return true; + } + + private int ReadFromTarget(ulong address, byte* buffer, uint bytesToRead) + => _readFromTarget(address, buffer, bytesToRead, _readContext); } From 32dbc446e3abfc0428c0abab38020693cd1a4cb6 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 22:11:15 -0700 Subject: [PATCH 07/17] Collapse cdac impl --- src/coreclr/debug/daccess/cdac.cpp | 115 +++++++--------------------- src/coreclr/debug/daccess/cdac.h | 27 ++++--- src/coreclr/debug/daccess/dacimpl.h | 2 +- 3 files changed, 43 insertions(+), 101 deletions(-) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index e067b9a0a963d..250456c472563 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -7,12 +7,12 @@ #include #include #include "dbgutil.h" -#include "cdac_reader.h" #include "cdac.h" +#define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader")) + namespace { - #define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader")) bool TryLoadCDACLibrary(HMODULE *phCDAC) { // Load cdacreader from next to DAC binary @@ -27,74 +27,25 @@ namespace return true; } -} - -class CDACImpl final { -public: - explicit CDACImpl(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); - CDACImpl(const CDACImpl&) = delete; - CDACImpl& operator=(CDACImpl&) = delete; - - CDACImpl(CDACImpl&& other) - : m_module(other.m_module) - , m_cdac_handle{other.m_cdac_handle} - , m_target{other.m_target} - , m_init{other.m_init} - , m_free{other.m_free} - , m_getSosInterface{other.m_getSosInterface} - { - other.m_module = nullptr; - other.m_cdac_handle = 0; - other.m_target = nullptr; - } - // Returns the SOS interface. This does not AddRef the interface. - IUnknown* SosInterface() const + int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context) { - return m_sos; - } - - int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count) - { - HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count); - if (FAILED(hr)) - return hr; - - return 0; + CDAC* cdac = reinterpret_cast(context); + return cdac->ReadFromTarget(addr, dest, count); } +} -public: - ~CDACImpl() - { - if (m_cdac_handle != NULL) - m_free(m_cdac_handle); - - if (m_module != NULL) - ::FreeLibrary(m_module); - } - -private: - HMODULE m_module; - intptr_t m_cdac_handle; - ICorDebugDataTarget* m_target; - NonVMComHolder m_sos; - -private: - decltype(&cdac_reader_init) m_init; - decltype(&cdac_reader_free) m_free; - decltype(&cdac_reader_get_sos_interface) m_getSosInterface; -}; - -namespace +CDAC* CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target) { - int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context) - { - CDACImpl* cdac = reinterpret_cast(context); - return cdac->ReadFromTarget(addr, dest, count); - } + HMODULE cdacLib; + if (!TryLoadCDACLibrary(&cdacLib)) + return nullptr; + + CDAC *impl = new (nothrow) CDAC{cdacLib, descriptorAddr, target}; + return impl; } -CDACImpl::CDACImpl(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) +CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) : m_module(module) , m_target{target} { @@ -106,39 +57,25 @@ CDACImpl::CDACImpl(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* m_getSosInterface(m_cdac_handle, &m_sos); } - -const CDAC* CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target) +CDAC::~CDAC() { - HRESULT hr = S_OK; - - HMODULE cdacLib; - if (!TryLoadCDACLibrary(&cdacLib)) - return nullptr; + if (m_cdac_handle != NULL) + m_free(m_cdac_handle); - CDACImpl *impl = new (nothrow) CDACImpl{cdacLib, descriptorAddr, target}; - if (!impl) - return nullptr; - - CDAC *cdac = new (nothrow) CDAC(impl); - if (!cdac) - { - delete impl; - return nullptr; - } - - return cdac; + if (m_module != NULL) + ::FreeLibrary(m_module); } -CDAC::CDAC(CDACImpl *impl) : m_impl(impl) +IUnknown* CDAC::SosInterface() { + return m_sos; } -IUnknown* CDAC::SosInterface() const +int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count) { - return m_impl->SosInterface(); -} + HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count); + if (FAILED(hr)) + return hr; -CDAC::~CDAC() -{ - delete m_impl; + return 0; } diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index 0c37764598c27..ea756de63a62a 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -4,27 +4,32 @@ #ifndef CDAC_H #define CDAC_H -#include "cdac_reader.h" - -class CDACImpl; +#include +#include class CDAC final { public: - static const CDAC* Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); - virtual ~CDAC(); - CDAC(const CDAC&) = delete; - CDAC& operator=(const CDAC&) = delete; + static CDAC* Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); - IUnknown* SosInterface() const; +public: + ~CDAC(); + IUnknown* SosInterface(); + int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count); private: - explicit CDAC(CDACImpl *impl); + explicit CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); private: - CDACImpl* m_impl; + HMODULE m_module; + intptr_t m_cdac_handle; + ICorDebugDataTarget* m_target; + NonVMComHolder m_sos; - friend class CDACImpl; +private: + decltype(&cdac_reader_init) m_init; + decltype(&cdac_reader_free) m_free; + decltype(&cdac_reader_get_sos_interface) m_getSosInterface; }; #endif // CDAC_H diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index 1461797e0917b..c4d484ec8a7ca 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1417,7 +1417,7 @@ class ClrDataAccess ULONG32 m_instanceAge; bool m_debugMode; - const CDAC* m_cdac; + CDAC* m_cdac; NonVMComHolder m_cdacSos; NonVMComHolder m_cdacSos9; From ae07b257eb9756f0acaf7075c3837df6c90d07f4 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 22:32:24 -0700 Subject: [PATCH 08/17] Remove unnecessary member --- src/coreclr/debug/daccess/cdac.cpp | 14 ++++++-------- src/coreclr/debug/daccess/cdac.h | 3 --- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index 250456c472563..0d95aab01679f 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -1,13 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#include -#include +#include "cdac.h" #include #include -#include #include "dbgutil.h" -#include "cdac.h" #define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader")) @@ -49,12 +46,13 @@ CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) : m_module(module) , m_target{target} { - m_init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init")); + decltype(&cdac_reader_init) init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init")); + decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); m_free = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_free")); - m_getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); + _ASSERTE(init != nullptr && getSosInterface != nullptr && m_free != nullptr); - m_init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle); - m_getSosInterface(m_cdac_handle, &m_sos); + init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle); + getSosInterface(m_cdac_handle, &m_sos); } CDAC::~CDAC() diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index ea756de63a62a..5137225fc6121 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -5,7 +5,6 @@ #define CDAC_H #include -#include class CDAC final { @@ -27,9 +26,7 @@ class CDAC final NonVMComHolder m_sos; private: - decltype(&cdac_reader_init) m_init; decltype(&cdac_reader_free) m_free; - decltype(&cdac_reader_get_sos_interface) m_getSosInterface; }; #endif // CDAC_H From 7b6d1b284be0b229ee68e6b5f93fd3f7ce7049bd Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 11 Apr 2024 23:22:39 -0700 Subject: [PATCH 09/17] Use lib prefix on non-Windows --- src/native/managed/cdacreader/src/cdacreader.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/native/managed/cdacreader/src/cdacreader.csproj b/src/native/managed/cdacreader/src/cdacreader.csproj index 8ef4d16ae20f6..feab7da8a20d8 100644 --- a/src/native/managed/cdacreader/src/cdacreader.csproj +++ b/src/native/managed/cdacreader/src/cdacreader.csproj @@ -1,7 +1,9 @@ + lib$(MSBuildProjectName) $(NetCoreAppToolCurrent) + Microsoft.Diagnostics.DataContractReader enable true @@ -9,8 +11,7 @@ - + From e8179997e92e7c04975d4bc1a7c4dfa045768c82 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 12 Apr 2024 10:22:07 -0700 Subject: [PATCH 10/17] More comments --- src/coreclr/debug/daccess/cdac.h | 4 +++- src/coreclr/debug/daccess/request.cpp | 2 +- src/native/managed/cdacreader/inc/cdac_reader.h | 14 +++++++++++++- .../cdacreader/src/Legacy/ISOSDacInterface.cs | 6 ++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index 5137225fc6121..44b4911c95223 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -8,11 +8,13 @@ class CDAC final { -public: +public: // static static CDAC* Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); public: ~CDAC(); + + // This does not AddRef the returned interface IUnknown* SosInterface(); int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count); diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 61fa52a481576..a261a9d29893a 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -39,7 +39,6 @@ typedef DPTR(InteropLib::ABI::ManagedObjectWrapperLayout) PTR_ManagedObjectWrapp #include "request_common.h" #include "cdac.h" -#include "wrappers.h" // GC headers define these to EE-specific stuff that we don't want. #undef EnterCriticalSection @@ -304,6 +303,7 @@ HRESULT ClrDataAccess::GetThreadStoreData(struct DacpThreadStoreData *threadStor if (m_cdacSos != NULL) { + // Try the cDAC first - it will return E_NOTIMPL if it doesn't support this method yet. Fall back to the DAC. hr = m_cdacSos->GetThreadStoreData(threadStoreData); if (FAILED(hr)) { diff --git a/src/native/managed/cdacreader/inc/cdac_reader.h b/src/native/managed/cdacreader/inc/cdac_reader.h index 158bdd42ef75e..505dab92815db 100644 --- a/src/native/managed/cdacreader/inc/cdac_reader.h +++ b/src/native/managed/cdacreader/inc/cdac_reader.h @@ -9,8 +9,20 @@ extern "C" { #endif -int cdac_reader_init(uint64_t descriptor, int(*read_from_target)(uint64_t, uint8_t*, uint32_t, void*), void* read_context, intptr_t* handle); +// Initialize the cDAC reader +// descriptor: the address of the descriptor in the target process +// read_from_target: a callback that reads memory from the target process +// read_context: a context pointer that will be passed to read_from_target +// handle: returned opaque the handle to the reader. This should be passed to other functions in this API. +int cdac_reader_init(uint64_t descriptor, int(*read_from_target)(uint64_t, uint8_t*, uint32_t, void*), void* read_context, /*out*/ intptr_t* handle); + +// Free the cDAC reader +// handle: handle to the reader int cdac_reader_free(intptr_t handle); + +// Get the SOS interface from the cDAC reader +// handle: handle to the reader +// obj: returned SOS interface that can be QI'd to ISOSDacInterface* int cdac_reader_get_sos_interface(intptr_t handle, IUnknown** obj); #ifdef __cplusplus diff --git a/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs b/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs index 0c88b2b0dacc1..bd0d20e65b77c 100644 --- a/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs @@ -7,6 +7,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; +// This file contains managed declarations for the SOS-DAC interfaces. +// See src/coreclr/inc/sospriv.idl + #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value internal struct DacpThreadStoreData { @@ -45,6 +48,9 @@ internal struct DacpThreadData [Guid("436f00f2-b42a-4b9f-870c-e73db66ae930")] internal unsafe partial interface ISOSDacInterface { + // All functions are explicitly PreserveSig so that we can just return E_NOTIMPL instead of throwing + // as the cDAC slowly replaces parts of the DAC. + // ThreadStore [PreserveSig] int GetThreadStoreData(DacpThreadStoreData* data); From f24cc2899a5fcaf65e8ec9ff625322299ee6725f Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 15 Apr 2024 18:41:33 -0700 Subject: [PATCH 11/17] Switch CDAC from allocation mechanism to move semantics --- src/coreclr/debug/daccess/cdac.cpp | 20 ++++++++---- src/coreclr/debug/daccess/cdac.h | 46 +++++++++++++++++++++++---- src/coreclr/debug/daccess/daccess.cpp | 11 ++----- src/coreclr/debug/daccess/dacimpl.h | 4 +-- 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index 0d95aab01679f..ea54b66da3e64 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -5,6 +5,7 @@ #include #include #include "dbgutil.h" +#include #define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader")) @@ -32,24 +33,25 @@ namespace } } -CDAC* CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target) +CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target) { HMODULE cdacLib; if (!TryLoadCDACLibrary(&cdacLib)) - return nullptr; + return CDAC::Invalid(); - CDAC *impl = new (nothrow) CDAC{cdacLib, descriptorAddr, target}; - return impl; + return CDAC{cdacLib, descriptorAddr, target}; } CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) : m_module(module) , m_target{target} { + if (m_module == NULL) + return; + decltype(&cdac_reader_init) init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init")); decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); - m_free = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_free")); - _ASSERTE(init != nullptr && getSosInterface != nullptr && m_free != nullptr); + _ASSERTE(init != nullptr && getSosInterface != nullptr); init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle); getSosInterface(m_cdac_handle, &m_sos); @@ -58,7 +60,11 @@ CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) CDAC::~CDAC() { if (m_cdac_handle != NULL) - m_free(m_cdac_handle); + { + decltype(&cdac_reader_free) free = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_free")); + _ASSERTE(free != nullptr); + free(m_cdac_handle); + } if (m_module != NULL) ::FreeLibrary(m_module); diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index 44b4911c95223..3350a8aa07d43 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -4,31 +4,63 @@ #ifndef CDAC_H #define CDAC_H -#include - class CDAC final { public: // static - static CDAC* Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); + static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); + + static CDAC Invalid() + { + return CDAC{nullptr, 0, nullptr}; + } public: + CDAC(CDAC&& other) + : m_module{ other.m_module } + , m_cdac_handle{ other.m_cdac_handle } + , m_target{ other.m_target } + , m_sos{ other.m_sos.Extract() } + { + other.m_module = NULL; + other.m_cdac_handle = 0; + other.m_target = NULL; + other.m_sos = NULL; + } + + CDAC& operator=(CDAC&& other) + { + m_module = other.m_module; + m_cdac_handle = other.m_cdac_handle; + m_target = other.m_target; + m_sos = other.m_sos.Extract(); + + other.m_module = NULL; + other.m_cdac_handle = 0; + other.m_target = NULL; + other.m_sos = NULL; + + return *this; + } + ~CDAC(); + bool IsValid() const + { + return m_module != NULL && m_cdac_handle != 0; + } + // This does not AddRef the returned interface IUnknown* SosInterface(); int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count); private: - explicit CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); + CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); private: HMODULE m_module; intptr_t m_cdac_handle; ICorDebugDataTarget* m_target; NonVMComHolder m_sos; - -private: - decltype(&cdac_reader_free) m_free; }; #endif // CDAC_H diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 4d74c9f472fa1..8b0a8aee3cc74 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -3035,6 +3035,7 @@ class DacStreamManager //---------------------------------------------------------------------------- ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget/*=0*/) + : m_cdac{CDAC::Invalid()} { SUPPORTS_DAC_HOST_ONLY; // ctor does no marshalling - don't check with DacCop @@ -3130,10 +3131,10 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) { m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); - if (m_cdac != NULL) + if (m_cdac.IsValid()) { // Get SOS interfaces from the cDAC if available. - IUnknown* unk = m_cdac->SosInterface(); + IUnknown* unk = m_cdac.SosInterface(); (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); } @@ -3174,12 +3175,6 @@ ClrDataAccess::~ClrDataAccess(void) } m_pTarget->Release(); m_pMutableTarget->Release(); - - if (m_cdac) - { - delete m_cdac; - m_cdac = NULL; - } } STDMETHODIMP diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index c4d484ec8a7ca..081ff88da8157 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -794,7 +794,7 @@ class DacStreamManager; #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS -class CDAC; +#include "cdac.h" //---------------------------------------------------------------------------- // @@ -1417,7 +1417,7 @@ class ClrDataAccess ULONG32 m_instanceAge; bool m_debugMode; - CDAC* m_cdac; + CDAC m_cdac; NonVMComHolder m_cdacSos; NonVMComHolder m_cdacSos9; From f319081232bd205266084715f4318c889bbcafc0 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 15 Apr 2024 18:51:33 -0700 Subject: [PATCH 12/17] Remove NativeLibsPublishConfiguration --- src/native/managed/compile-native.proj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/native/managed/compile-native.proj b/src/native/managed/compile-native.proj index 17cf7ae3236fb..d227466bfcebd 100644 --- a/src/native/managed/compile-native.proj +++ b/src/native/managed/compile-native.proj @@ -1,8 +1,6 @@ - - $(Configuration) - + shared @@ -39,7 +37,7 @@ - + From 0b46f317decf9fd6b46375d7bc7547d8102bca9a Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 15 Apr 2024 20:30:51 -0700 Subject: [PATCH 13/17] Move cdac creation to ClrDataAccess::Initialize --- src/coreclr/debug/daccess/daccess.cpp | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 8b0a8aee3cc74..0fa167d0aa7b9 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -3125,20 +3125,6 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe // see ClrDataAccess::VerifyDlls for details. m_fEnableDllVerificationAsserts = false; #endif - - // TODO: [cdac] Get contract descriptor from exported symbol - uint64_t contractDescriptorAddr = 0; - //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) - { - m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); - if (m_cdac.IsValid()) - { - // Get SOS interfaces from the cDAC if available. - IUnknown* unk = m_cdac.SosInterface(); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); - } - } } ClrDataAccess::~ClrDataAccess(void) @@ -5506,6 +5492,20 @@ ClrDataAccess::Initialize(void) IfFailRet(GetDacGlobalValues()); IfFailRet(DacGetHostVtPtrs()); + // TODO: [cdac] Get contract descriptor from exported symbol + uint64_t contractDescriptorAddr = 0; + //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) + { + m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); + if (m_cdac.IsValid()) + { + // Get SOS interfaces from the cDAC if available. + IUnknown* unk = m_cdac.SosInterface(); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + } + } + // // DAC is now setup and ready to use // From 72af466681061f757b91f942452385bd00822165 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 15 Apr 2024 20:32:08 -0700 Subject: [PATCH 14/17] Put cdac use under DOTNET_ENABLE_CDAC --- src/coreclr/debug/daccess/daccess.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 0fa167d0aa7b9..be76508f63c79 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -5492,17 +5492,22 @@ ClrDataAccess::Initialize(void) IfFailRet(GetDacGlobalValues()); IfFailRet(DacGetHostVtPtrs()); - // TODO: [cdac] Get contract descriptor from exported symbol - uint64_t contractDescriptorAddr = 0; - //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) + PathString envVar; + DWORD len = WszGetEnvironmentVariable(W("DOTNET_ENABLE_CDAC"), envVar); + if (len != 0 && u16_strcmp(envVar, W("1")) == 0) { - m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); - if (m_cdac.IsValid()) + // TODO: [cdac] Get contract descriptor from exported symbol + uint64_t contractDescriptorAddr = 0; + //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) { - // Get SOS interfaces from the cDAC if available. - IUnknown* unk = m_cdac.SosInterface(); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); + if (m_cdac.IsValid()) + { + // Get SOS interfaces from the cDAC if available. + IUnknown* unk = m_cdac.SosInterface(); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + } } } From 7d0a7810ba98fa0853dc1e4cb04dd0d9bddefbb7 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 16 Apr 2024 09:57:25 -0700 Subject: [PATCH 15/17] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aaron Robinson Co-authored-by: Aleksey Kliger (λgeek) --- src/coreclr/debug/daccess/cdac.cpp | 2 +- src/coreclr/debug/daccess/cdac.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index ea54b66da3e64..56eb415ce21f0 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -81,5 +81,5 @@ int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count) if (FAILED(hr)) return hr; - return 0; + return S_OK; } diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index 3350a8aa07d43..54418dc549f1f 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -15,6 +15,9 @@ class CDAC final } public: + CDAC(const CDAC&) = delete; + CDAC& operator=(const CDAC&) = delete; + CDAC(CDAC&& other) : m_module{ other.m_module } , m_cdac_handle{ other.m_cdac_handle } From 49915e5acd10fd1e173898f2a96b9945e2a39e71 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 16 Apr 2024 10:06:47 -0700 Subject: [PATCH 16/17] Update src/coreclr/debug/daccess/cdac.cpp --- src/coreclr/debug/daccess/cdac.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index 56eb415ce21f0..78625bf67f2d7 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -47,7 +47,10 @@ CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) , m_target{target} { if (m_module == NULL) + { + m_cdac_handle = NULL; return; + } decltype(&cdac_reader_init) init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init")); decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); From ce4de2717e5121d6762b481320614a760f2a8575 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 16 Apr 2024 13:59:30 -0700 Subject: [PATCH 17/17] Use clrconfignocache --- src/coreclr/debug/daccess/daccess.cpp | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index be76508f63c79..f9a221007c277 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -24,6 +24,7 @@ #include "primitives.h" #include "dbgutil.h" #include "cdac.h" +#include #ifdef USE_DAC_TABLE_RVA #include @@ -5492,21 +5493,24 @@ ClrDataAccess::Initialize(void) IfFailRet(GetDacGlobalValues()); IfFailRet(DacGetHostVtPtrs()); - PathString envVar; - DWORD len = WszGetEnvironmentVariable(W("DOTNET_ENABLE_CDAC"), envVar); - if (len != 0 && u16_strcmp(envVar, W("1")) == 0) + CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC"); + if (enable.IsSet()) { - // TODO: [cdac] Get contract descriptor from exported symbol - uint64_t contractDescriptorAddr = 0; - //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) + DWORD val; + if (enable.TryAsInteger(10, val) && val == 1) { - m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); - if (m_cdac.IsValid()) + // TODO: [cdac] Get contract descriptor from exported symbol + uint64_t contractDescriptorAddr = 0; + //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) { - // Get SOS interfaces from the cDAC if available. - IUnknown* unk = m_cdac.SosInterface(); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); - (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); + if (m_cdac.IsValid()) + { + // Get SOS interfaces from the cDAC if available. + IUnknown* unk = m_cdac.SosInterface(); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); + } } } }