Skip to content

Commit adba54d

Browse files
authored
[cdac] Make cDAC delegate to the DAC instead of the other way around (#108772)
- `SOSDacImpl` in cDAC implements all the interfaces implemented by `ClrDataAccess` - `CLRDataCreateInstance` returns cDAC if it is enabled - `cdac_reader_get_sos_interface` takes the legacy DAC implementation - Legacy DAC no longer calls into cDAC for its `ISOSDac*` implementations - cDAC delegates to legacy DAC (if it has one) for APIs it has not implemented and asserts that the results are the same for APIs it has implemented Behavioural differences of note: - Since asserts comparing results are in the cDAC instead of DAC now, they will come through as a fail fast with or without a debugger attached - as opposed to before, when they were silently ignored when a debugger was attached. The assert message will print to the debugger output (if attached) or OutputDebugString/syslog. - If the cDAC implementation of an API errors, it does not fall back to calling the legacy DAC. I think this is reasonable given that we plan to put the ability to choose cDAC vs legacy DAC at a higher level. If cDAC implementation fails, it should fail and not try to hide it. - `ClrDataAccess` lifetime is handled by cDAC (when enabled), so actual release is dependent on finalization of the COM object. I ran the SOS tests in diagnostics repo against this change locally both with and without the cDAC enabled.
1 parent 8a7fa48 commit adba54d

14 files changed

+1503
-947
lines changed

src/coreclr/debug/daccess/cdac.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace
4343
}
4444
}
4545

46-
CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target)
46+
CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target, IUnknown* legacyImpl)
4747
{
4848
HMODULE cdacLib;
4949
if (!TryLoadCDACLibrary(&cdacLib))
@@ -59,20 +59,18 @@ CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target)
5959
return {};
6060
}
6161

62-
return CDAC{cdacLib, handle, target};
62+
return CDAC{cdacLib, handle, target, legacyImpl};
6363
}
6464

65-
CDAC::CDAC(HMODULE module, intptr_t handle, ICorDebugDataTarget* target)
65+
CDAC::CDAC(HMODULE module, intptr_t handle, ICorDebugDataTarget* target, IUnknown* legacyImpl)
6666
: m_module{module}
6767
, m_cdac_handle{handle}
6868
, m_target{target}
69+
, m_legacyImpl{legacyImpl}
6970
{
7071
_ASSERTE(m_module != NULL && m_cdac_handle != 0 && m_target != NULL);
7172

7273
m_target->AddRef();
73-
decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast<decltype(&cdac_reader_get_sos_interface)>(::GetProcAddress(m_module, "cdac_reader_get_sos_interface"));
74-
_ASSERTE(getSosInterface != nullptr);
75-
getSosInterface(m_cdac_handle, &m_sos);
7674
}
7775

7876
CDAC::~CDAC()
@@ -88,7 +86,10 @@ CDAC::~CDAC()
8886
::FreeLibrary(m_module);
8987
}
9088

91-
IUnknown* CDAC::SosInterface()
89+
void CDAC::CreateSosInterface(IUnknown** sos)
9290
{
93-
return m_sos;
91+
decltype(&cdac_reader_create_sos_interface) createSosInterface = reinterpret_cast<decltype(&cdac_reader_create_sos_interface)>(::GetProcAddress(m_module, "cdac_reader_create_sos_interface"));
92+
_ASSERTE(createSosInterface != nullptr);
93+
int ret = createSosInterface(m_cdac_handle, m_legacyImpl, sos);
94+
_ASSERTE(ret == 0);
9495
}

src/coreclr/debug/daccess/cdac.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class CDAC final
88
{
99
public: // static
10-
static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget);
10+
static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget, IUnknown* legacyImpl);
1111

1212
public:
1313
CDAC() = default;
@@ -19,25 +19,25 @@ class CDAC final
1919
: m_module{ other.m_module }
2020
, m_cdac_handle{ other.m_cdac_handle }
2121
, m_target{ other.m_target.Extract() }
22-
, m_sos{ other.m_sos.Extract() }
22+
, m_legacyImpl{ other.m_legacyImpl }
2323
{
2424
other.m_module = NULL;
2525
other.m_cdac_handle = 0;
2626
other.m_target = NULL;
27-
other.m_sos = NULL;
27+
other.m_legacyImpl = NULL;
2828
}
2929

3030
CDAC& operator=(CDAC&& other)
3131
{
3232
m_module = other.m_module;
3333
m_cdac_handle = other.m_cdac_handle;
3434
m_target = other.m_target.Extract();
35-
m_sos = other.m_sos.Extract();
35+
m_legacyImpl = other.m_legacyImpl;
3636

3737
other.m_module = NULL;
3838
other.m_cdac_handle = 0;
3939
other.m_target = NULL;
40-
other.m_sos = NULL;
40+
other.m_legacyImpl = NULL;
4141

4242
return *this;
4343
}
@@ -49,17 +49,18 @@ class CDAC final
4949
return m_module != NULL && m_cdac_handle != 0;
5050
}
5151

52-
// This does not AddRef the returned interface
53-
IUnknown* SosInterface();
52+
void CreateSosInterface(IUnknown** sos);
5453

5554
private:
56-
CDAC(HMODULE module, intptr_t handle, ICorDebugDataTarget* target);
55+
CDAC(HMODULE module, intptr_t handle, ICorDebugDataTarget* target, IUnknown* legacyImpl);
5756

5857
private:
5958
HMODULE m_module;
6059
intptr_t m_cdac_handle;
6160
NonVMComHolder<ICorDebugDataTarget> m_target;
62-
NonVMComHolder<IUnknown> m_sos;
61+
62+
// Assumes the legacy impl lives for the lifetime of this class - currently ClrDataAccess, which contains this class
63+
IUnknown* m_legacyImpl;
6364
};
6465

6566
#endif // CDAC_H

src/coreclr/debug/daccess/daccess.cpp

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5501,31 +5501,6 @@ ClrDataAccess::Initialize(void)
55015501
IfFailRet(GetDacGlobalValues());
55025502
IfFailRet(DacGetHostVtPtrs());
55035503

5504-
// TODO: [cdac] TryGetSymbol is only implemented for Linux, OSX, and Windows.
5505-
#ifdef CAN_USE_CDAC
5506-
CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
5507-
if (enable.IsSet())
5508-
{
5509-
DWORD val;
5510-
if (enable.TryAsInteger(10, val) && val == 1)
5511-
{
5512-
uint64_t contractDescriptorAddr = 0;
5513-
if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
5514-
{
5515-
m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget);
5516-
if (m_cdac.IsValid())
5517-
{
5518-
// Get SOS interfaces from the cDAC if available.
5519-
IUnknown* unk = m_cdac.SosInterface();
5520-
(void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos);
5521-
(void)unk->QueryInterface(__uuidof(ISOSDacInterface2), (void**)&m_cdacSos2);
5522-
(void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9);
5523-
}
5524-
}
5525-
}
5526-
}
5527-
#endif
5528-
55295504
//
55305505
// DAC is now setup and ready to use
55315506
//
@@ -7146,9 +7121,53 @@ CLRDataCreateInstance(REFIID iid,
71467121
#ifdef LOGGING
71477122
InitializeLogging();
71487123
#endif
7149-
hr = pClrDataAccess->QueryInterface(iid, iface);
71507124

7151-
pClrDataAccess->Release();
7125+
// TODO: [cdac] Remove when cDAC deploys with SOS - https://github.com/dotnet/runtime/issues/108720
7126+
NonVMComHolder<IUnknown> cdacInterface = nullptr;
7127+
#ifdef CAN_USE_CDAC
7128+
CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
7129+
if (enable.IsSet())
7130+
{
7131+
DWORD val;
7132+
if (enable.TryAsInteger(10, val) && val == 1)
7133+
{
7134+
// TODO: [cdac] TryGetSymbol is only implemented for Linux, OSX, and Windows.
7135+
uint64_t contractDescriptorAddr = 0;
7136+
if (TryGetSymbol(pClrDataAccess->m_pTarget, pClrDataAccess->m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
7137+
{
7138+
IUnknown* thisImpl;
7139+
HRESULT qiRes = pClrDataAccess->QueryInterface(IID_IUnknown, (void**)&thisImpl);
7140+
_ASSERTE(SUCCEEDED(qiRes));
7141+
CDAC& cdac = pClrDataAccess->m_cdac;
7142+
cdac = CDAC::Create(contractDescriptorAddr, pClrDataAccess->m_pTarget, thisImpl);
7143+
if (cdac.IsValid())
7144+
{
7145+
// Get SOS interfaces from the cDAC if available.
7146+
cdac.CreateSosInterface(&cdacInterface);
7147+
_ASSERTE(cdacInterface != nullptr);
7148+
7149+
// Lifetime is now managed by cDAC implementation of SOS interfaces
7150+
pClrDataAccess->Release();
7151+
}
7152+
7153+
// Release the AddRef from the QI.
7154+
pClrDataAccess->Release();
7155+
}
7156+
}
7157+
}
7158+
#endif
7159+
if (cdacInterface != nullptr)
7160+
{
7161+
hr = cdacInterface->QueryInterface(iid, iface);
7162+
}
7163+
else
7164+
{
7165+
hr = pClrDataAccess->QueryInterface(iid, iface);
7166+
7167+
// Lifetime is now managed by caller
7168+
pClrDataAccess->Release();
7169+
}
7170+
71527171
return hr;
71537172
}
71547173

src/coreclr/debug/daccess/dacimpl.h

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,22 +1231,6 @@ class ClrDataAccess
12311231

12321232
HRESULT Initialize(void);
12331233

1234-
HRESULT GetThreadDataImpl(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData);
1235-
HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data);
1236-
HRESULT GetModuleDataImpl(CLRDATA_ADDRESS addr, struct DacpModuleData *moduleData);
1237-
HRESULT GetNestedExceptionDataImpl(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS *exceptionObject, CLRDATA_ADDRESS *nextNestedException);
1238-
HRESULT GetMethodTableDataImpl(CLRDATA_ADDRESS mt, struct DacpMethodTableData *data);
1239-
HRESULT GetMethodTableForEEClassImpl (CLRDATA_ADDRESS eeClassReallyMT, CLRDATA_ADDRESS *value);
1240-
HRESULT GetMethodTableNameImpl(CLRDATA_ADDRESS mt, unsigned int count, _Inout_updates_z_(count) WCHAR *mtName, unsigned int *pNeeded);
1241-
HRESULT GetObjectDataImpl(CLRDATA_ADDRESS addr, struct DacpObjectData *objectData);
1242-
HRESULT GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data);
1243-
HRESULT GetObjectStringDataImpl(CLRDATA_ADDRESS obj, unsigned int count, _Inout_updates_z_(count) WCHAR *stringData, unsigned int *pNeeded);
1244-
HRESULT GetPEFileBaseImpl(CLRDATA_ADDRESS moduleAddr, CLRDATA_ADDRESS *base);
1245-
HRESULT GetPEFileNameImpl(CLRDATA_ADDRESS moduleAddr, unsigned int count, _Inout_updates_z_(count) WCHAR *fileName, unsigned int *pNeeded);
1246-
HRESULT GetUsefulGlobalsImpl(struct DacpUsefulGlobalsData *globalsData);
1247-
HRESULT GetMethodDescDataImpl(CLRDATA_ADDRESS methodDesc, CLRDATA_ADDRESS ip, struct DacpMethodDescData *data, ULONG cRevertedRejitVersions, DacpReJitData * rgRevertedRejitData, ULONG * pcNeededRevertedRejitData);
1248-
HRESULT GetMethodDescNameImpl(CLRDATA_ADDRESS methodDesc, unsigned int count, _Inout_updates_z_(count) WCHAR *name, unsigned int *pNeeded);
1249-
12501234
BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
12511235
#ifndef TARGET_UNIX
12521236
HRESULT GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM);
@@ -1433,10 +1417,9 @@ class ClrDataAccess
14331417
ULONG32 m_instanceAge;
14341418
bool m_debugMode;
14351419

1420+
// This currently exists on the DAC as a way of managing lifetime of loading/freeing the cdacreader
1421+
// TODO: [cdac] Remove when cDAC deploys with SOS - https://github.com/dotnet/runtime/issues/108720
14361422
CDAC m_cdac;
1437-
NonVMComHolder<ISOSDacInterface> m_cdacSos;
1438-
NonVMComHolder<ISOSDacInterface2> m_cdacSos2;
1439-
NonVMComHolder<ISOSDacInterface9> m_cdacSos9;
14401423

14411424
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
14421425

0 commit comments

Comments
 (0)