From e126f8ff2e635ef104b8f1212ec76420f114e99d Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 16 Apr 2024 21:37:28 -0700 Subject: [PATCH] [cdac] Make DAC load and use cDAC when available (#100946) - If `DOTNET_ENABLE_CDAC` environment variable is `1`, Look for `cdacreader` next to DAC and load it if found - Implement `ISOSDacInterface` in cDAC - currently returns `E_NOTIMPL` for everything - Make DAC delegate to cDAC (if available) for GetThreadStoreData and GetBreakingChangeVersion - Initialize cDAC with function for reading from the target --- src/coreclr/debug/daccess/CMakeLists.txt | 4 + src/coreclr/debug/daccess/cdac.cpp | 88 ++++++ src/coreclr/debug/daccess/cdac.h | 69 +++++ src/coreclr/debug/daccess/daccess.cpp | 26 +- src/coreclr/debug/daccess/dacimpl.h | 13 +- src/coreclr/debug/daccess/request.cpp | 83 +++-- src/libraries/externals.csproj | 4 + .../managed/cdacreader/inc/cdac_reader.h | 14 +- .../managed/cdacreader/src/Entrypoints.cs | 6 +- .../cdacreader/src/Legacy/ISOSDacInterface.cs | 293 ++++++++++++++++++ .../cdacreader/src/Legacy/SOSDacImpl.cs | 119 +++++++ .../managed/cdacreader/src/SOSDacImpl.cs | 36 --- src/native/managed/cdacreader/src/Target.cs | 57 +++- .../managed/cdacreader/src/cdacreader.csproj | 5 + src/native/managed/compile-native.proj | 6 +- 15 files changed, 753 insertions(+), 70 deletions(-) create mode 100644 src/coreclr/debug/daccess/cdac.cpp create mode 100644 src/coreclr/debug/daccess/cdac.h 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/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..78625bf67f2d7 --- /dev/null +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "cdac.h" +#include +#include +#include "dbgutil.h" +#include + +#define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader")) + +namespace +{ + 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; + } + + int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context) + { + CDAC* cdac = reinterpret_cast(context); + return cdac->ReadFromTarget(addr, dest, count); + } +} + +CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target) +{ + HMODULE cdacLib; + if (!TryLoadCDACLibrary(&cdacLib)) + return CDAC::Invalid(); + + return CDAC{cdacLib, descriptorAddr, target}; +} + +CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) + : m_module(module) + , 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")); + _ASSERTE(init != nullptr && getSosInterface != nullptr); + + init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle); + getSosInterface(m_cdac_handle, &m_sos); +} + +CDAC::~CDAC() +{ + if (m_cdac_handle != NULL) + { + 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); +} + +IUnknown* CDAC::SosInterface() +{ + return m_sos; +} + +int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count) +{ + HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count); + if (FAILED(hr)) + return hr; + + return S_OK; +} diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h new file mode 100644 index 0000000000000..54418dc549f1f --- /dev/null +++ b/src/coreclr/debug/daccess/cdac.h @@ -0,0 +1,69 @@ +// 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 + +class CDAC final +{ +public: // static + static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); + + static CDAC Invalid() + { + return CDAC{nullptr, 0, nullptr}; + } + +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 } + , 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: + CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); + +private: + HMODULE m_module; + intptr_t m_cdac_handle; + ICorDebugDataTarget* m_target; + NonVMComHolder m_sos; +}; + +#endif // CDAC_H diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index ca8c76bf5b81f..66ddb02f888ee 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -23,6 +23,8 @@ #include "dwreport.h" #include "primitives.h" #include "dbgutil.h" +#include "cdac.h" +#include #ifdef USE_DAC_TABLE_RVA #include @@ -3034,6 +3036,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 @@ -3123,7 +3126,6 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe // see ClrDataAccess::VerifyDlls for details. m_fEnableDllVerificationAsserts = false; #endif - } ClrDataAccess::~ClrDataAccess(void) @@ -5491,6 +5493,28 @@ ClrDataAccess::Initialize(void) IfFailRet(GetDacGlobalValues()); IfFailRet(DacGetHostVtPtrs()); + CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC"); + if (enable.IsSet()) + { + DWORD val; + if (enable.TryAsInteger(10, val) && val == 1) + { + // 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 // diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index e698eed4c1803..081ff88da8157 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 +#include "cdac.h" //---------------------------------------------------------------------------- // @@ -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,13 +1222,15 @@ 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. // HRESULT Initialize(void); + HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data); + BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord); #ifndef TARGET_UNIX HRESULT GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM); @@ -1414,6 +1417,10 @@ class ClrDataAccess ULONG32 m_instanceAge; bool m_debugMode; + CDAC m_cdac; + NonVMComHolder m_cdacSos; + NonVMComHolder m_cdacSos9; + #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS protected: @@ -1964,7 +1971,7 @@ class DacMemoryEnumerator : public DefaultCOMImplGetThreadStoreData(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) { @@ -4951,7 +4986,15 @@ HRESULT ClrDataAccess::GetBreakingChangeVersion(int* pVersion) if (pVersion == nullptr) return E_INVALIDARG; - *pVersion = SOS_BREAKING_CHANGE_VERSION; + if (m_cdacSos9 != nullptr && SUCCEEDED(m_cdacSos9->GetBreakingChangeVersion(pVersion))) + { + _ASSERTE(*pVersion == SOS_BREAKING_CHANGE_VERSION); + } + else + { + *pVersion = SOS_BREAKING_CHANGE_VERSION; + } + return S_OK; } @@ -5406,10 +5449,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 +5483,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/cdacreader/inc/cdac_reader.h b/src/native/managed/cdacreader/inc/cdac_reader.h index b6c71b671a6ed..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(intptr_t descriptor, 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/Entrypoints.cs b/src/native/managed/cdacreader/src/Entrypoints.cs index a65ba9c5fa5ea..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; @@ -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..bd0d20e65b77c --- /dev/null +++ b/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs @@ -0,0 +1,293 @@ +// 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; + +// 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 +{ + 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 +{ + // 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); + + // 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/Target.cs b/src/native/managed/cdacreader/src/Target.cs index 1590984f017c3..898cab774bfb5 100644 --- a/src/native/managed/cdacreader/src/Target.cs +++ b/src/native/managed/cdacreader/src/Target.cs @@ -1,11 +1,64 @@ // 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; -internal sealed class Target +public struct TargetPointer +{ + public static TargetPointer Null = new(0); + + public ulong Value; + public TargetPointer(ulong value) => Value = value; +} + +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; } + + 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); } diff --git a/src/native/managed/cdacreader/src/cdacreader.csproj b/src/native/managed/cdacreader/src/cdacreader.csproj index 37e77c1221eac..253bb3c6c27e0 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,6 +11,9 @@ true + + + diff --git a/src/native/managed/compile-native.proj b/src/native/managed/compile-native.proj index 769954456f346..d227466bfcebd 100644 --- a/src/native/managed/compile-native.proj +++ b/src/native/managed/compile-native.proj @@ -1,8 +1,6 @@ - - Release - + shared @@ -39,7 +37,7 @@ - +