Skip to content

Commit e126f8f

Browse files
authored
[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
1 parent e6f1fd8 commit e126f8f

File tree

15 files changed

+753
-70
lines changed

15 files changed

+753
-70
lines changed

src/coreclr/debug/daccess/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
add_definitions(-DFEATURE_NO_HOST)
22

3+
add_subdirectory(${CLR_SRC_NATIVE_DIR}/managed/cdacreader/cmake ${CLR_ARTIFACTS_OBJ_DIR}/cdacreader)
4+
35
include_directories(BEFORE ${VM_DIR})
46
include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
57
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
@@ -12,6 +14,7 @@ if(CLR_CMAKE_HOST_UNIX)
1214
endif(CLR_CMAKE_HOST_UNIX)
1315

1416
set(DACCESS_SOURCES
17+
cdac.cpp
1518
dacdbiimpl.cpp
1619
dacdbiimpllocks.cpp
1720
dacdbiimplstackwalk.cpp
@@ -40,6 +43,7 @@ convert_to_absolute_path(DACCESS_SOURCES ${DACCESS_SOURCES})
4043
add_library_clr(daccess ${DACCESS_SOURCES})
4144
set_target_properties(daccess PROPERTIES DAC_COMPONENT TRUE)
4245
target_precompile_headers(daccess PRIVATE [["stdafx.h"]])
46+
target_link_libraries(daccess PRIVATE cdacreader_api)
4347

4448
add_dependencies(daccess eventing_headers)
4549

src/coreclr/debug/daccess/cdac.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#include "cdac.h"
5+
#include <sospriv.h>
6+
#include <sstring.h>
7+
#include "dbgutil.h"
8+
#include <cdac_reader.h>
9+
10+
#define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader"))
11+
12+
namespace
13+
{
14+
bool TryLoadCDACLibrary(HMODULE *phCDAC)
15+
{
16+
// Load cdacreader from next to DAC binary
17+
PathString path;
18+
if (FAILED(GetClrModuleDirectory(path)))
19+
return false;
20+
21+
path.Append(CDAC_LIB_NAME);
22+
*phCDAC = CLRLoadLibrary(path.GetUnicode());
23+
if (*phCDAC == NULL)
24+
return false;
25+
26+
return true;
27+
}
28+
29+
int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context)
30+
{
31+
CDAC* cdac = reinterpret_cast<CDAC*>(context);
32+
return cdac->ReadFromTarget(addr, dest, count);
33+
}
34+
}
35+
36+
CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target)
37+
{
38+
HMODULE cdacLib;
39+
if (!TryLoadCDACLibrary(&cdacLib))
40+
return CDAC::Invalid();
41+
42+
return CDAC{cdacLib, descriptorAddr, target};
43+
}
44+
45+
CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target)
46+
: m_module(module)
47+
, m_target{target}
48+
{
49+
if (m_module == NULL)
50+
{
51+
m_cdac_handle = NULL;
52+
return;
53+
}
54+
55+
decltype(&cdac_reader_init) init = reinterpret_cast<decltype(&cdac_reader_init)>(::GetProcAddress(m_module, "cdac_reader_init"));
56+
decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast<decltype(&cdac_reader_get_sos_interface)>(::GetProcAddress(m_module, "cdac_reader_get_sos_interface"));
57+
_ASSERTE(init != nullptr && getSosInterface != nullptr);
58+
59+
init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle);
60+
getSosInterface(m_cdac_handle, &m_sos);
61+
}
62+
63+
CDAC::~CDAC()
64+
{
65+
if (m_cdac_handle != NULL)
66+
{
67+
decltype(&cdac_reader_free) free = reinterpret_cast<decltype(&cdac_reader_free)>(::GetProcAddress(m_module, "cdac_reader_free"));
68+
_ASSERTE(free != nullptr);
69+
free(m_cdac_handle);
70+
}
71+
72+
if (m_module != NULL)
73+
::FreeLibrary(m_module);
74+
}
75+
76+
IUnknown* CDAC::SosInterface()
77+
{
78+
return m_sos;
79+
}
80+
81+
int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count)
82+
{
83+
HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count);
84+
if (FAILED(hr))
85+
return hr;
86+
87+
return S_OK;
88+
}

src/coreclr/debug/daccess/cdac.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#ifndef CDAC_H
5+
#define CDAC_H
6+
7+
class CDAC final
8+
{
9+
public: // static
10+
static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget);
11+
12+
static CDAC Invalid()
13+
{
14+
return CDAC{nullptr, 0, nullptr};
15+
}
16+
17+
public:
18+
CDAC(const CDAC&) = delete;
19+
CDAC& operator=(const CDAC&) = delete;
20+
21+
CDAC(CDAC&& other)
22+
: m_module{ other.m_module }
23+
, m_cdac_handle{ other.m_cdac_handle }
24+
, m_target{ other.m_target }
25+
, m_sos{ other.m_sos.Extract() }
26+
{
27+
other.m_module = NULL;
28+
other.m_cdac_handle = 0;
29+
other.m_target = NULL;
30+
other.m_sos = NULL;
31+
}
32+
33+
CDAC& operator=(CDAC&& other)
34+
{
35+
m_module = other.m_module;
36+
m_cdac_handle = other.m_cdac_handle;
37+
m_target = other.m_target;
38+
m_sos = other.m_sos.Extract();
39+
40+
other.m_module = NULL;
41+
other.m_cdac_handle = 0;
42+
other.m_target = NULL;
43+
other.m_sos = NULL;
44+
45+
return *this;
46+
}
47+
48+
~CDAC();
49+
50+
bool IsValid() const
51+
{
52+
return m_module != NULL && m_cdac_handle != 0;
53+
}
54+
55+
// This does not AddRef the returned interface
56+
IUnknown* SosInterface();
57+
int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count);
58+
59+
private:
60+
CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target);
61+
62+
private:
63+
HMODULE m_module;
64+
intptr_t m_cdac_handle;
65+
ICorDebugDataTarget* m_target;
66+
NonVMComHolder<IUnknown> m_sos;
67+
};
68+
69+
#endif // CDAC_H

src/coreclr/debug/daccess/daccess.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "dwreport.h"
2424
#include "primitives.h"
2525
#include "dbgutil.h"
26+
#include "cdac.h"
27+
#include <clrconfignocache.h>
2628

2729
#ifdef USE_DAC_TABLE_RVA
2830
#include <dactablerva.h>
@@ -3034,6 +3036,7 @@ class DacStreamManager
30343036
//----------------------------------------------------------------------------
30353037

30363038
ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget/*=0*/)
3039+
: m_cdac{CDAC::Invalid()}
30373040
{
30383041
SUPPORTS_DAC_HOST_ONLY; // ctor does no marshalling - don't check with DacCop
30393042

@@ -3123,7 +3126,6 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe
31233126
// see ClrDataAccess::VerifyDlls for details.
31243127
m_fEnableDllVerificationAsserts = false;
31253128
#endif
3126-
31273129
}
31283130

31293131
ClrDataAccess::~ClrDataAccess(void)
@@ -5491,6 +5493,28 @@ ClrDataAccess::Initialize(void)
54915493
IfFailRet(GetDacGlobalValues());
54925494
IfFailRet(DacGetHostVtPtrs());
54935495

5496+
CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
5497+
if (enable.IsSet())
5498+
{
5499+
DWORD val;
5500+
if (enable.TryAsInteger(10, val) && val == 1)
5501+
{
5502+
// TODO: [cdac] Get contract descriptor from exported symbol
5503+
uint64_t contractDescriptorAddr = 0;
5504+
//if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
5505+
{
5506+
m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget);
5507+
if (m_cdac.IsValid())
5508+
{
5509+
// Get SOS interfaces from the cDAC if available.
5510+
IUnknown* unk = m_cdac.SosInterface();
5511+
(void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos);
5512+
(void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9);
5513+
}
5514+
}
5515+
}
5516+
}
5517+
54945518
//
54955519
// DAC is now setup and ready to use
54965520
//

src/coreclr/debug/daccess/dacimpl.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ class DacStreamManager;
794794

795795
#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
796796

797+
#include "cdac.h"
797798

798799
//----------------------------------------------------------------------------
799800
//
@@ -1208,7 +1209,7 @@ class ClrDataAccess
12081209
CLRDATA_ADDRESS *allocLimit);
12091210

12101211
// ISOSDacInterface13
1211-
virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
1212+
virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
12121213
virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator);
12131214
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded);
12141215
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded);
@@ -1221,13 +1222,15 @@ class ClrDataAccess
12211222
virtual HRESULT STDMETHODCALLTYPE GetStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
12221223
virtual HRESULT STDMETHODCALLTYPE GetThreadStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS thread, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
12231224
virtual HRESULT STDMETHODCALLTYPE GetMethodTableInitializationFlags(CLRDATA_ADDRESS methodTable, MethodTableInitializationFlags *initializationStatus);
1224-
1225+
12251226
//
12261227
// ClrDataAccess.
12271228
//
12281229

12291230
HRESULT Initialize(void);
12301231

1232+
HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data);
1233+
12311234
BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
12321235
#ifndef TARGET_UNIX
12331236
HRESULT GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM);
@@ -1414,6 +1417,10 @@ class ClrDataAccess
14141417
ULONG32 m_instanceAge;
14151418
bool m_debugMode;
14161419

1420+
CDAC m_cdac;
1421+
NonVMComHolder<ISOSDacInterface> m_cdacSos;
1422+
NonVMComHolder<ISOSDacInterface9> m_cdacSos9;
1423+
14171424
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
14181425

14191426
protected:
@@ -1964,7 +1971,7 @@ class DacMemoryEnumerator : public DefaultCOMImpl<ISOSMemoryEnum, IID_ISOSMemory
19641971

19651972
virtual ~DacMemoryEnumerator() {}
19661973
virtual HRESULT Init() = 0;
1967-
1974+
19681975
HRESULT STDMETHODCALLTYPE Skip(unsigned int count);
19691976
HRESULT STDMETHODCALLTYPE Reset();
19701977
HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount);

0 commit comments

Comments
 (0)