Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cdac] Make DAC load and use cDAC when available #100946

Merged
merged 17 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/coreclr/debug/daccess/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand Down
79 changes: 79 additions & 0 deletions src/coreclr/debug/daccess/cdac.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 <sospriv.h>
#include <sstring.h>
#include "dbgutil.h"

#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());
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
if (*phCDAC == NULL)
return false;

return true;
}

int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context)
{
CDAC* cdac = reinterpret_cast<CDAC*>(context);
return cdac->ReadFromTarget(addr, dest, count);
}
}

CDAC* CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target)
{
HMODULE cdacLib;
if (!TryLoadCDACLibrary(&cdacLib))
return nullptr;

CDAC *impl = new (nothrow) CDAC{cdacLib, descriptorAddr, target};
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
return impl;
}

CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target)
: m_module(module)
, m_target{target}
{
decltype(&cdac_reader_init) init = reinterpret_cast<decltype(&cdac_reader_init)>(::GetProcAddress(m_module, "cdac_reader_init"));
decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast<decltype(&cdac_reader_get_sos_interface)>(::GetProcAddress(m_module, "cdac_reader_get_sos_interface"));
m_free = reinterpret_cast<decltype(&cdac_reader_free)>(::GetProcAddress(m_module, "cdac_reader_free"));
_ASSERTE(init != nullptr && getSosInterface != nullptr && m_free != nullptr);

init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle);
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
getSosInterface(m_cdac_handle, &m_sos);
}

CDAC::~CDAC()
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
{
if (m_cdac_handle != NULL)
m_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 0;
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
}
34 changes: 34 additions & 0 deletions src/coreclr/debug/daccess/cdac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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 CDAC final
{
public: // static
static CDAC* Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget);

public:
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
~CDAC();

// 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);
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved

private:
HMODULE m_module;
intptr_t m_cdac_handle;
ICorDebugDataTarget* m_target;
NonVMComHolder<IUnknown> m_sos;

private:
decltype(&cdac_reader_free) m_free;
};

#endif // CDAC_H
20 changes: 20 additions & 0 deletions src/coreclr/debug/daccess/daccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "dwreport.h"
#include "primitives.h"
#include "dbgutil.h"
#include "cdac.h"

#ifdef USE_DAC_TABLE_RVA
#include <dactablerva.h>
Expand Down Expand Up @@ -3124,6 +3125,19 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe
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);
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
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)
Expand Down Expand Up @@ -3160,6 +3174,12 @@ ClrDataAccess::~ClrDataAccess(void)
}
m_pTarget->Release();
m_pMutableTarget->Release();

if (m_cdac)
{
delete m_cdac;
m_cdac = NULL;
}
}

STDMETHODIMP
Expand Down
13 changes: 10 additions & 3 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ class DacStreamManager;

#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS

class CDAC;

//----------------------------------------------------------------------------
//
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -1414,6 +1417,10 @@ class ClrDataAccess
ULONG32 m_instanceAge;
bool m_debugMode;

CDAC* m_cdac;
NonVMComHolder<ISOSDacInterface> m_cdacSos;
NonVMComHolder<ISOSDacInterface9> m_cdacSos9;

#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS

protected:
Expand Down Expand Up @@ -1964,7 +1971,7 @@ class DacMemoryEnumerator : public DefaultCOMImpl<ISOSMemoryEnum, IID_ISOSMemory

virtual ~DacMemoryEnumerator() {}
virtual HRESULT Init() = 0;

HRESULT STDMETHODCALLTYPE Skip(unsigned int count);
HRESULT STDMETHODCALLTYPE Reset();
HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount);
Expand Down
83 changes: 63 additions & 20 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ typedef DPTR(InteropLib::ABI::ManagedObjectWrapperLayout) PTR_ManagedObjectWrapp
#include "rejit.h"
#include "request_common.h"

#include "cdac.h"

// GC headers define these to EE-specific stuff that we don't want.
#undef EnterCriticalSection
#undef LeaveCriticalSection
Expand Down Expand Up @@ -299,31 +301,64 @@ HRESULT ClrDataAccess::GetThreadStoreData(struct DacpThreadStoreData *threadStor
{
SOSDacEnter();

ThreadStore* threadStore = ThreadStore::s_pThreadStore;
if (!threadStore)
if (m_cdacSos != NULL)
{
hr = E_UNEXPECTED;
// 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))
{
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)
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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));
Expand Down
4 changes: 4 additions & 0 deletions src/libraries/externals.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@
<!-- CoreRun is not used for testing anymore, but we still use it for benchmarking and profiling -->
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\corerun*" />
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\PDB\corerun*" />
<!-- Include cDAC reader library
TODO: [cdac] Remove once cdacreader is added to shipping shared framework -->
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\*cdacreader*" />
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\PDB\*cdacreader*" />
</ItemGroup>
<!-- If the build has native sanitizers, copy over the non-sanitized diagnostic binaries so they can be loaded by a debugger -->
<ItemGroup Condition="'$(EnableNativeSanitizers)' != ''">
Expand Down
Loading
Loading