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 all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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());
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 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);
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)
{
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:
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
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
Loading