Skip to content

Commit

Permalink
[cdac] Make DAC load and use cDAC when available (dotnet#100946)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
elinor-fung authored and matouskozak committed Apr 30, 2024
1 parent 6f15c2b commit 152598d
Show file tree
Hide file tree
Showing 15 changed files with 753 additions and 70 deletions.
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
88 changes: 88 additions & 0 deletions src/coreclr/debug/daccess/cdac.cpp
Original file line number Diff line number Diff line change
@@ -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 <sospriv.h>
#include <sstring.h>
#include "dbgutil.h"
#include <cdac_reader.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());
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 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<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"));
_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<decltype(&cdac_reader_free)>(::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;
}
69 changes: 69 additions & 0 deletions src/coreclr/debug/daccess/cdac.h
Original file line number Diff line number Diff line change
@@ -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<IUnknown> m_sos;
};

#endif // CDAC_H
26 changes: 25 additions & 1 deletion src/coreclr/debug/daccess/daccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "dwreport.h"
#include "primitives.h"
#include "dbgutil.h"
#include "cdac.h"
#include <clrconfignocache.h>

#ifdef USE_DAC_TABLE_RVA
#include <dactablerva.h>
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -3123,7 +3126,6 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe
// see ClrDataAccess::VerifyDlls for details.
m_fEnableDllVerificationAsserts = false;
#endif

}

ClrDataAccess::~ClrDataAccess(void)
Expand Down Expand Up @@ -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
//
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

#include "cdac.h"

//----------------------------------------------------------------------------
//
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
Loading

0 comments on commit 152598d

Please sign in to comment.