diff --git a/docs/design/datacontracts/Debugger.md b/docs/design/datacontracts/Debugger.md new file mode 100644 index 00000000000000..d53d2e75c0f52b --- /dev/null +++ b/docs/design/datacontracts/Debugger.md @@ -0,0 +1,72 @@ +# Contract Debugger + +This contract is for reading debugger state from the target process, including initialization status, configuration flags, metadata update state, and JIT attach state. + +## APIs of contract + +```csharp +bool IsLeftSideInitialized(); +uint GetDefinesBitField(); +uint GetMDStructuresVersion(); +int GetAttachStateFlags(); +bool MetadataUpdatesApplied(); +``` + +## Version 1 + +### Globals + +| Global Name | Type | Description | +| --- | --- | --- | +| `Debugger` | TargetPointer | Pointer to the Debugger instance | +| `CLRJitAttachState` | TargetPointer | Pointer to the CLR JIT attach state flags | +| `MetadataUpdatesApplied` | TargetPointer | Pointer to the g_metadataUpdatesApplied flag | + +### Data Descriptors + +| Data Descriptor Name | Field | Meaning | +| --- | --- | --- | +| `Debugger` | `LeftSideInitialized` | Whether the left-side debugger infrastructure is initialized | +| `Debugger` | `Defines` | Bitfield of compile-time debugger feature defines | +| `Debugger` | `MDStructuresVersion` | Version of metadata data structures | + +### Algorithm + +```csharp +bool IsLeftSideInitialized() +{ + TargetPointer debuggerPtr = target.ReadGlobalPointer("Debugger"); + if (debuggerPtr == TargetPointer.Null) + return false; + Data.Debugger debugger = target.ProcessedData.GetOrAdd(debuggerPtr); + return debugger.LeftSideInitialized != 0; +} + +uint GetDefinesBitField() +{ + TargetPointer debuggerPtr = target.ReadGlobalPointer("Debugger"); + Data.Debugger debugger = target.ProcessedData.GetOrAdd(debuggerPtr); + return debugger.Defines; +} + +uint GetMDStructuresVersion() +{ + TargetPointer debuggerPtr = target.ReadGlobalPointer("Debugger"); + Data.Debugger debugger = target.ProcessedData.GetOrAdd(debuggerPtr); + return debugger.MDStructuresVersion; +} + +int GetAttachStateFlags() +{ + if (target.TryReadGlobalPointer("CLRJitAttachState", out TargetPointer addr)) + return (int)target.Read(addr); + return 0; +} + +bool MetadataUpdatesApplied() +{ + if (target.TryReadGlobalPointer("MetadataUpdatesApplied", out TargetPointer addr)) + return target.Read(addr) != 0; + return false; +} +``` diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 9e368c4d99ded0..947805987dc6d1 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -222,7 +222,7 @@ template void DeleteDbiArrayMemory(T *p, int count) // pAllocator - pointer to client allocator object. This lets DD allocate objects and // pass them out back to the client, which can then delete them. // DD takes a weak ref to this, so client must keep it alive until it -// calls Destroy. +// calls Release. // pMetadataLookup - callback interface to do internal metadata lookup. This is because // metadata is not dac-ized. // ppInterface - mandatory out-parameter @@ -238,7 +238,7 @@ template void DeleteDbiArrayMemory(T *p, int count) // This will yield an IDacDbiInterface to provide structured access to the // data-target. // -// Must call Destroy to on interface to free its resources. +// Must call Release on interface to free its resources. // //--------------------------------------------------------------------------------------- STDAPI @@ -295,7 +295,7 @@ DacDbiInterfaceInstance( // pAllocator - pointer to client allocator object. This lets DD allocate objects and // pass them out back to the client, which can then delete them. // DD takes a weak ref to this, so client must keep it alive until it -// calls Destroy. +// calls Release. // pMetadataLookup - callback interface to do internal metadata lookup. This is because // metadata is not dac-ized. // @@ -333,7 +333,7 @@ DacDbiInterfaceImpl::DacDbiInterfaceImpl( // Destructor. // // Notes: -// This gets invoked after Destroy(). +// This gets invoked when the ref count drops to 0 via Release(). //----------------------------------------------------------------------------- DacDbiInterfaceImpl::~DacDbiInterfaceImpl() { @@ -441,19 +441,30 @@ interface IMDInternalImport* DacDbiInterfaceImpl::GetMDImport( // See DacDbiInterface.h for full descriptions of all of these functions //----------------------------------------------------------------------------- -// Destroy the connection, freeing up any resources. -HRESULT DacDbiInterfaceImpl::Destroy() +// IUnknown implementation for DacDbiInterfaceImpl. +// Delegates to ClrDataAccess's ref-counting and adds support for IDacDbiInterface IID. +STDMETHODIMP +DacDbiInterfaceImpl::QueryInterface(THIS_ IN REFIID interfaceId, OUT PVOID* iface) { - HRESULT hr = S_OK; - EX_TRY + if (IsEqualIID(interfaceId, __uuidof(IDacDbiInterface))) { - m_pAllocator = NULL; - - this->Release(); - // Memory is deleted, don't access this object any more + AddRef(); + *iface = static_cast(this); + return S_OK; } - EX_CATCH_HRESULT(hr); - return hr; + return ClrDataAccess::QueryInterface(interfaceId, iface); +} + +STDMETHODIMP_(ULONG) +DacDbiInterfaceImpl::AddRef(THIS) +{ + return ClrDataAccess::AddRef(); +} + +STDMETHODIMP_(ULONG) +DacDbiInterfaceImpl::Release(THIS) +{ + return ClrDataAccess::Release(); } // Check whether the version of the DBI matches the version of the runtime. @@ -495,7 +506,7 @@ HRESULT DacDbiInterfaceImpl::FlushCache() } // enable or disable DAC target consistency checks -HRESULT DacDbiInterfaceImpl::DacSetTargetConsistencyChecks(bool fEnableAsserts) +HRESULT DacDbiInterfaceImpl::DacSetTargetConsistencyChecks(BOOL fEnableAsserts) { HRESULT hr = S_OK; EX_TRY @@ -1172,8 +1183,11 @@ mdSignature DacDbiInterfaceImpl::GetILCodeAndSigHelper(Module * pModule, } -HRESULT DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly, DWORD & dwTimeStamp, DWORD & dwImageSize, IStringHolder* pStrFilename, OUT bool * pResult) +HRESULT DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly, DWORD * pTimeStamp, DWORD * pImageSize, IStringHolder* pStrFilename, OUT BOOL * pResult) { + if (pTimeStamp == NULL || pImageSize == NULL || pStrFilename == NULL || pResult == NULL) + return E_POINTER; + DD_ENTER_MAY_THROW; HRESULT hr = S_OK; @@ -1186,15 +1200,15 @@ HRESULT DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPE _ASSERTE(pPEAssembly != NULL); if (pPEAssembly == NULL) { - *pResult = false; + *pResult = FALSE; } else { WCHAR wszFilePath[MAX_LONGPATH] = {0}; DWORD cchFilePath = MAX_LONGPATH; bool ret = ClrDataAccess::GetMetaDataFileInfoFromPEFile(pPEAssembly, - dwTimeStamp, - dwImageSize, + *pTimeStamp, + *pImageSize, dwDataSize, dwRvaHint, wszFilePath, @@ -2743,8 +2757,11 @@ HRESULT DacDbiInterfaceImpl::GetApproxTypeHandle(TypeInfoList * pTypeData, OUT V // DacDbiInterface API: Get the exact type handle from type data HRESULT DacDbiInterfaceImpl::GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData * pTypeData, ArgInfoList * pArgInfo, - VMPTR_TypeHandle& vmTypeHandle) + VMPTR_TypeHandle * pVmTypeHandle) { + if (pVmTypeHandle == NULL) + return E_POINTER; + DD_ENTER_MAY_THROW; LOG((LF_CORDB, LL_INFO10000, "D::GETH: getting info.\n")); @@ -2753,12 +2770,12 @@ HRESULT DacDbiInterfaceImpl::GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData * EX_TRY { - vmTypeHandle = vmTypeHandle.NullPtr(); + *pVmTypeHandle = VMPTR_TypeHandle::NullPtr(); // convert the type information to a type handle TypeHandle typeHandle = ExpandedTypeInfoToTypeHandle(pTypeData, pArgInfo); _ASSERTE(!typeHandle.IsNull()); - vmTypeHandle.SetDacTargetPtr(typeHandle.AsTAddr()); + pVmTypeHandle->SetDacTargetPtr(typeHandle.AsTAddr()); } EX_CATCH_HRESULT(hr); @@ -3732,8 +3749,11 @@ HRESULT DacDbiInterfaceImpl::GetLoaderHeapMemoryRanges(DacDbiArrayList& dacStackFrames) +HRESULT DacDbiInterfaceImpl::GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList* pDacStackFrames) { + if (pDacStackFrames == NULL) + return E_POINTER; + DD_ENTER_MAY_THROW; HRESULT hr = S_OK; @@ -3761,12 +3781,12 @@ HRESULT DacDbiInterfaceImpl::GetStackFramesFromException(VMPTR_Object vmObject, if (dacStackFramesLength > 0) { - dacStackFrames.Alloc(dacStackFramesLength); + pDacStackFrames->Alloc(dacStackFramesLength); for (INT32 index = 0; index < dacStackFramesLength; ++index) { DebugStackTrace::Element const& currentElement = stackFramesData.pElements[index]; - DacExceptionCallStackData& currentFrame = dacStackFrames[index]; + DacExceptionCallStackData& currentFrame = (*pDacStackFrames)[index]; AppDomain* pDomain = AppDomain::GetCurrentDomain(); _ASSERTE(pDomain != NULL); @@ -3882,8 +3902,11 @@ HRESULT DacDbiInterfaceImpl::GetRcwCachedInterfacePointers(VMPTR_Object vmObject #endif // FEATURE_COMINTEROP } -HRESULT DacDbiInterfaceImpl::GetCachedWinRTTypesForIIDs(VMPTR_AppDomain vmAppDomain, DacDbiArrayList & iids, OUT DacDbiArrayList * pTypes) +HRESULT DacDbiInterfaceImpl::GetCachedWinRTTypesForIIDs(VMPTR_AppDomain vmAppDomain, DacDbiArrayList * pIids, OUT DacDbiArrayList * pTypes) { + if (pIids == NULL || pTypes == NULL) + return E_POINTER; + HRESULT hr = S_OK; EX_TRY { @@ -4319,7 +4342,7 @@ HRESULT DacDbiInterfaceImpl::IsModuleMapped(VMPTR_Module pModule, OUT BOOL *isMo return hr; } -HRESULT DacDbiInterfaceImpl::MetadataUpdatesApplied(OUT bool * pResult) +HRESULT DacDbiInterfaceImpl::MetadataUpdatesApplied(OUT BOOL * pResult) { DD_ENTER_MAY_THROW; @@ -4329,7 +4352,7 @@ HRESULT DacDbiInterfaceImpl::MetadataUpdatesApplied(OUT bool * pResult) #ifdef FEATURE_METADATA_UPDATER *pResult = g_metadataUpdatesApplied; #else - *pResult = false; + *pResult = FALSE; #endif } EX_CATCH_HRESULT(hr); @@ -4843,7 +4866,7 @@ HRESULT DacDbiInterfaceImpl::EnumerateThreads(FP_THREAD_ENUMERATION_CALLBACK fpC } // public implementation of IsThreadMarkedDead -HRESULT DacDbiInterfaceImpl::IsThreadMarkedDead(VMPTR_Thread vmThread, OUT bool * pResult) +HRESULT DacDbiInterfaceImpl::IsThreadMarkedDead(VMPTR_Thread vmThread, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; @@ -6247,12 +6270,15 @@ HRESULT DacDbiInterfaceImpl::IsVmObjectHandleValid(VMPTR_OBJECTHANDLE vmHandle, } // determines if the specified module is a WinRT module -HRESULT DacDbiInterfaceImpl::IsWinRTModule(VMPTR_Module vmModule, BOOL& isWinRT) +HRESULT DacDbiInterfaceImpl::IsWinRTModule(VMPTR_Module vmModule, BOOL * pIsWinRT) { + if (pIsWinRT == NULL) + return E_POINTER; + DD_ENTER_MAY_THROW; HRESULT hr = S_OK; - isWinRT = FALSE; + *pIsWinRT = FALSE; return hr; } @@ -6733,12 +6759,12 @@ HRESULT DacDbiInterfaceImpl::EnumerateMonitorEventWaitList(VMPTR_Object vmObject } -HRESULT DacDbiInterfaceImpl::AreGCStructuresValid(OUT bool * pResult) +HRESULT DacDbiInterfaceImpl::AreGCStructuresValid(OUT BOOL * pResult) { HRESULT hr = S_OK; EX_TRY { - *pResult = true; + *pResult = TRUE; } EX_CATCH_HRESULT(hr); return hr; @@ -7457,7 +7483,7 @@ HRESULT DacDbiInterfaceImpl::GetHeapSegments(OUT DacDbiArrayList *p return hr; } -HRESULT DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS obj, OUT bool * pResult) +HRESULT DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS obj, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; @@ -7465,7 +7491,7 @@ HRESULT DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS obj, OUT bool * pResult EX_TRY { - bool isValid = false; + BOOL isValid = FALSE; if (obj != 0 && obj != (CORDB_ADDRESS)-1) { @@ -7477,13 +7503,13 @@ HRESULT DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS obj, OUT bool * pResult PTR_EEClass cls = mt->GetClass(); if (mt == cls->GetMethodTable()) - isValid = true; + isValid = TRUE; else if (!mt->IsCanonicalMethodTable() || mt->IsContinuation()) isValid = cls->GetMethodTable()->GetClass() == cls; } EX_CATCH { - isValid = false; + isValid = FALSE; } EX_END_CATCH } @@ -7494,7 +7520,7 @@ HRESULT DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS obj, OUT bool * pResult return hr; } -HRESULT DacDbiInterfaceImpl::GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_AppDomain * pApp, OUT VMPTR_Module * pModule, OUT VMPTR_DomainAssembly * pDomainAssembly, OUT bool * pResult) +HRESULT DacDbiInterfaceImpl::GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_AppDomain * pApp, OUT VMPTR_Module * pModule, OUT VMPTR_DomainAssembly * pDomainAssembly, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; @@ -7504,7 +7530,7 @@ HRESULT DacDbiInterfaceImpl::GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_ if (obj == 0 || obj == (CORDB_ADDRESS)-1) { - *pResult = false; + *pResult = FALSE; } else { @@ -7516,7 +7542,7 @@ HRESULT DacDbiInterfaceImpl::GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_ pModule->SetDacTargetPtr(PTR_HOST_TO_TADDR(module)); pDomainAssembly->SetDacTargetPtr(PTR_HOST_TO_TADDR(module->GetDomainAssembly())); - *pResult = true; + *pResult = TRUE; } } EX_CATCH_HRESULT(hr); diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index 5ddf9013a2f228..e989f03528c8e4 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -51,6 +51,14 @@ class DacDbiInterfaceImpl : // Destructor. virtual ~DacDbiInterfaceImpl(void); + // IUnknown. + // IDacDbiInterface now extends IUnknown, so DacDbiInterfaceImpl must resolve the + // diamond inheritance by delegating to ClrDataAccess's existing IUnknown implementation + // and adding support for the IDacDbiInterface IID. + STDMETHOD(QueryInterface)(THIS_ IN REFIID interfaceId, OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + // Overridden from ClrDataAccess. Gets an internal metadata importer for the file. virtual IMDInternalImport* GetMDImport( const PEAssembly* pPEAssembly, @@ -65,11 +73,7 @@ class DacDbiInterfaceImpl : HRESULT FlushCache(); // enable or disable DAC target consistency checks - HRESULT DacSetTargetConsistencyChecks(bool fEnableAsserts); - - // Destroy the interface object. The client should call this when it's done - // with the IDacDbiInterface to free up any resources. - HRESULT Destroy(); + HRESULT DacSetTargetConsistencyChecks(BOOL fEnableAsserts); IAllocator * GetAllocator() { @@ -110,10 +114,10 @@ class DacDbiInterfaceImpl : // Initialize the native/IL sequence points and native var info for a function. HRESULT GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc, CORDB_ADDRESS startAddress, BOOL fCodeAvailable, OUT NativeVarData * pNativeVarData, OUT SequencePoints * pSequencePoints); - HRESULT IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, OUT bool * pResult); + HRESULT IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, OUT BOOL * pResult); - HRESULT AreGCStructuresValid(OUT bool * pResult); + HRESULT AreGCStructuresValid(OUT BOOL * pResult); HRESULT CreateHeapWalk(HeapWalkHandle *pHandle); HRESULT DeleteHeapWalk(HeapWalkHandle handle); @@ -125,9 +129,9 @@ class DacDbiInterfaceImpl : HRESULT GetHeapSegments(OUT DacDbiArrayList *pSegments); - HRESULT IsValidObject(CORDB_ADDRESS obj, OUT bool * pResult); + HRESULT IsValidObject(CORDB_ADDRESS obj, OUT BOOL * pResult); - HRESULT GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_AppDomain * pApp, OUT VMPTR_Module * pModule, OUT VMPTR_DomainAssembly * pDomainAssembly, OUT bool * pResult); + HRESULT GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_AppDomain * pApp, OUT VMPTR_Module * pModule, OUT VMPTR_DomainAssembly * pDomainAssembly, OUT BOOL * pResult); @@ -274,7 +278,7 @@ class DacDbiInterfaceImpl : // Get the exact type handle from type data HRESULT GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData * pTypeData, ArgInfoList * pArgInfo, - VMPTR_TypeHandle& vmTypeHandle); + VMPTR_TypeHandle * pVmTypeHandle); // Retrieve the generic type params for a given MethodDesc. This function is specifically // for stackwalking because it requires the generic type token on the stack. @@ -302,7 +306,7 @@ class DacDbiInterfaceImpl : HRESULT IsExceptionObject(VMPTR_Object vmObject, OUT BOOL * pResult); - HRESULT GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList& dacStackFrames); + HRESULT GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList* pDacStackFrames); // Returns true if the argument is a runtime callable wrapper HRESULT IsRcw(VMPTR_Object vmObject, OUT BOOL * pResult); @@ -327,7 +331,7 @@ class DacDbiInterfaceImpl : HRESULT IsModuleMapped(VMPTR_Module pModule, OUT BOOL *isModuleMapped); - HRESULT MetadataUpdatesApplied(OUT bool * pResult); + HRESULT MetadataUpdatesApplied(OUT BOOL * pResult); // retrieves the list of COM interfaces implemented by vmObject, as it is known at // the time of the call (the list may change as new interface types become available @@ -343,7 +347,7 @@ class DacDbiInterfaceImpl : // list of IIDs. the interface types are retrieved from an app domain // IID / Type cache, that is updated as new types are loaded. will // have NULL entries corresponding to unknown IIDs in "iids" - HRESULT GetCachedWinRTTypesForIIDs(VMPTR_AppDomain vmAppDomain, DacDbiArrayList & iids, OUT DacDbiArrayList * pTypes); + HRESULT GetCachedWinRTTypesForIIDs(VMPTR_AppDomain vmAppDomain, DacDbiArrayList * pIids, OUT DacDbiArrayList * pTypes); // retrieves the whole app domain cache of IID / Type mappings. HRESULT GetCachedWinRTTypes(VMPTR_AppDomain vmAppDomain, OUT DacDbiArrayList * piids, OUT DacDbiArrayList * pTypes); @@ -703,7 +707,7 @@ class DacDbiInterfaceImpl : HRESULT EnumerateThreads(FP_THREAD_ENUMERATION_CALLBACK fpCallback, CALLBACK_DATA pUserData); - HRESULT IsThreadMarkedDead(VMPTR_Thread vmThread, OUT bool * pResult); + HRESULT IsThreadMarkedDead(VMPTR_Thread vmThread, OUT BOOL * pResult); // Return the handle of the specified thread. HRESULT GetThreadHandle(VMPTR_Thread vmThread, OUT HANDLE * pRetVal); @@ -923,7 +927,7 @@ class DacDbiInterfaceImpl : HRESULT IsVmObjectHandleValid(VMPTR_OBJECTHANDLE vmHandle, OUT BOOL * pResult); // if the specified module is a WinRT module then isWinRT will equal TRUE - HRESULT IsWinRTModule(VMPTR_Module vmModule, BOOL& isWinRT); + HRESULT IsWinRTModule(VMPTR_Module vmModule, BOOL * pIsWinRT); // Determines the app domain id for the object referred to by a given VMPTR_OBJECTHANDLE HRESULT GetAppDomainIdFromVmObjectHandle(VMPTR_OBJECTHANDLE vmHandle, OUT ULONG * pRetVal); @@ -1002,7 +1006,7 @@ class DacDbiInterfaceImpl : public: // API for picking up the info needed for a debugger to look up an image from its search path. - HRESULT GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly, DWORD & dwTimeStamp, DWORD & dwImageSize, IStringHolder* pStrFilename, OUT bool * pResult); + HRESULT GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly, DWORD * pTimeStamp, DWORD * pImageSize, IStringHolder* pStrFilename, OUT BOOL * pResult); }; diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index 50a8771a21a6f1..68dd02ffc875e7 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -1396,7 +1396,7 @@ BOOL DacDbiInterfaceImpl::UnwindRuntimeStackFrame(StackFrameIterator * pIter) // Return true iff TS_SyncSuspended or TS_Hijacked is set on the specified thread. // -HRESULT DacDbiInterfaceImpl::IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, OUT bool * pResult) +HRESULT DacDbiInterfaceImpl::IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; @@ -1408,17 +1408,17 @@ HRESULT DacDbiInterfaceImpl::IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, Thread::ThreadState ts = pThread->GetSnapshotState(); if ((ts & Thread::TS_SyncSuspended) != 0) { - *pResult = true; + *pResult = TRUE; } #ifdef FEATURE_HIJACK else if ((ts & Thread::TS_Hijacked) != 0) { - *pResult = true; + *pResult = TRUE; } #endif else { - *pResult = false; + *pResult = FALSE; } } EX_CATCH_HRESULT(hr); diff --git a/src/coreclr/debug/di/divalue.cpp b/src/coreclr/debug/di/divalue.cpp index 0ca91a172f4257..f1ca7ff2f5bca2 100644 --- a/src/coreclr/debug/di/divalue.cpp +++ b/src/coreclr/debug/di/divalue.cpp @@ -2460,7 +2460,7 @@ HRESULT CordbObjectValue::EnumerateExceptionCallStack(ICorDebugExceptionObjectCa DacDbiArrayList dacStackFrames; - IfFailThrow(pDAC->GetStackFramesFromException(vmObj, dacStackFrames)); + IfFailThrow(pDAC->GetStackFramesFromException(vmObj, &dacStackFrames)); int stackFramesLength = dacStackFrames.Count(); if (stackFramesLength > 0) diff --git a/src/coreclr/debug/di/module.cpp b/src/coreclr/debug/di/module.cpp index 5cda8918098b2a..f7fb4083db2e32 100644 --- a/src/coreclr/debug/di/module.cpp +++ b/src/coreclr/debug/di/module.cpp @@ -797,10 +797,10 @@ HRESULT CordbModule::InitPublicMetaDataFromFile(const WCHAR * pszFullPathName, _ASSERTE(!m_vmPEFile.IsNull()); // MetaData lookup favors the NGEN image, which is what we want here. - bool _mdFileInfoResult; + BOOL _mdFileInfoResult; IfFailThrow(this->GetProcess()->GetDAC()->GetMetaDataFileInfoFromPEFile(m_vmPEFile, - dwImageTimeStamp, - dwImageSize, + &dwImageTimeStamp, + &dwImageSize, &filePath, &_mdFileInfoResult)); if (!_mdFileInfoResult) @@ -1187,10 +1187,10 @@ HRESULT CordbModule::GetName(ULONG32 cchName, ULONG32 *pcchName, _Out_writes_to_ StringCopyHolder filePath; _ASSERTE(!m_vmPEFile.IsNull()); - bool _mdFileInfoResult; + BOOL _mdFileInfoResult; IfFailThrow(this->GetProcess()->GetDAC()->GetMetaDataFileInfoFromPEFile(m_vmPEFile, - dwImageTimeStamp, - dwImageSize, + &dwImageTimeStamp, + &dwImageSize, &filePath, &_mdFileInfoResult)); if (_mdFileInfoResult) diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index db73aaa7f3fb35..dd3b83dc998406 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -416,8 +416,8 @@ IMDInternalImport * CordbProcess::LookupMetaDataFromDebugger( IMDInternalImport * pMDII = NULL; // First, see if the debugger can locate the exact metadata we want. - bool _metaDataFileInfoResult; - IfFailThrow(this->GetDAC()->GetMetaDataFileInfoFromPEFile(vmPEAssembly, dwImageTimeStamp, dwImageSize, &filePath, &_metaDataFileInfoResult)); + BOOL _metaDataFileInfoResult; + IfFailThrow(this->GetDAC()->GetMetaDataFileInfoFromPEFile(vmPEAssembly, &dwImageTimeStamp, &dwImageSize, &filePath, &_metaDataFileInfoResult)); if (_metaDataFileInfoResult) { _ASSERTE(filePath.IsSet()); @@ -1626,7 +1626,7 @@ void CordbProcess::FreeDac() if (m_pDacPrimitives != NULL) { - m_pDacPrimitives->Destroy(); + m_pDacPrimitives->Release(); m_pDacPrimitives = NULL; } @@ -2250,7 +2250,7 @@ HRESULT CordbProcess::EnumerateHeap(ICorDebugHeapEnum **ppObjects) EX_TRY { - bool gcValid; + BOOL gcValid; IfFailThrow(m_pDacPrimitives->AreGCStructuresValid(&gcValid)); if (gcValid) { @@ -2333,7 +2333,7 @@ HRESULT CordbProcess::GetObjectInternal(CORDB_ADDRESS addr, ICorDebugObjectValue EX_TRY { - bool validObj; + BOOL validObj; IfFailThrow(m_pDacPrimitives->IsValidObject(addr, &validObj)); if (!validObj) { @@ -2601,7 +2601,7 @@ COM_METHOD CordbProcess::GetAsyncStack(CORDB_ADDRESS continuationAddress, ICorDe EX_TRY { - bool validObj; + BOOL validObj; IfFailThrow(m_pDacPrimitives->IsValidObject(continuationAddress, &validObj)); if (!validObj) { @@ -2637,7 +2637,7 @@ HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbType **ppType, C VMPTR_DomainAssembly domainAssembly; HRESULT hr = E_FAIL; - bool _appDomainResult; + BOOL _appDomainResult; IfFailThrow(GetDAC()->GetAppDomainForObject(addr, &appDomain, &mod, &domainAssembly, &_appDomainResult)); if (_appDomainResult) { @@ -14579,7 +14579,7 @@ void CordbWin32EventThread::AttachProcess() EX_TRY { // Don't allow attach if any metadata/IL updates have been applied - bool _metadataUpdatesApplied; + BOOL _metadataUpdatesApplied; IfFailThrow(pProcess->GetDAC()->MetadataUpdatesApplied(&_metadataUpdatesApplied)); if (_metadataUpdatesApplied) { @@ -15754,7 +15754,7 @@ bool CordbProcess::IsThreadSuspendedOrHijacked(ICorDebugThread * pICorDebugThrea PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(this); CordbThread * pCordbThread = static_cast (pICorDebugThread); - bool _isSuspendedOrHijacked; + BOOL _isSuspendedOrHijacked; IfFailThrow(GetDAC()->IsThreadSuspendedOrHijacked(pCordbThread->m_vmThreadToken, &_isSuspendedOrHijacked)); return _isSuspendedOrHijacked; } diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index 22274d2d3cb712..c0cd937112c5a9 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -117,7 +117,7 @@ class CordbEval; class RSLock; class NeuterList; -class IDacDbiInterface; +struct IDacDbiInterface; #if defined(FEATURE_DBGIPC_TRANSPORT_DI) class DbgTransportTarget; diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index f152b5f66c34b6..66f88f534a1750 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -912,7 +912,7 @@ bool CordbThread::IsThreadWaitingOrSleeping() // bool CordbThread::IsThreadDead() { - bool _isDead; + BOOL _isDead; IfFailThrow(GetProcess()->GetDAC()->IsThreadMarkedDead(m_vmThreadToken, &_isDead)); return _isDead; } diff --git a/src/coreclr/debug/di/rstype.cpp b/src/coreclr/debug/di/rstype.cpp index de6922416706ef..612f90583beff0 100644 --- a/src/coreclr/debug/di/rstype.cpp +++ b/src/coreclr/debug/di/rstype.cpp @@ -1569,7 +1569,7 @@ HRESULT CordbType::InitInstantiationTypeHandle(BOOL fForceInit) { // Get the TypeHandle based on the type data RSLockHolder lockHolder(GetProcess()->GetProcessLock()); - hr = pProcess->GetDAC()->GetExactTypeHandle(&typeData, &argInfo, m_typeHandleExact); + hr = pProcess->GetDAC()->GetExactTypeHandle(&typeData, &argInfo, &m_typeHandleExact); } } EX_CATCH_HRESULT(hr); diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h index f1ed7e1ea70960..51862b7564f4c5 100644 --- a/src/coreclr/debug/ee/debugger.h +++ b/src/coreclr/debug/ee/debugger.h @@ -76,6 +76,7 @@ class DebuggerFrame; class DebuggerModule; class DebuggerModuleTable; class Debugger; +template struct cdac_data; class DebuggerBreakpoint; class DebuggerPendingFuncEvalTable; class DebuggerRCThread; @@ -2998,6 +2999,8 @@ class Debugger : public DebugInterface // Used by Debugger::FirstChanceNativeException to update the context from out of process void SendSetThreadContextNeeded(CONTEXT *context, DebuggerSteppingInfo *pDebuggerSteppingInfo = NULL, bool fHasActivePatchSkip = false, bool fClearSetIP = false); BOOL IsOutOfProcessSetContextEnabled(); + + friend struct ::cdac_data; }; @@ -3030,8 +3033,16 @@ void ApcActivationCallbackStubEnd(); #endif // FEATURE_SPECIAL_USER_MODE_APC }; +template<> +struct cdac_data +{ + static constexpr size_t LeftSideInitialized = offsetof(Debugger, m_fLeftSideInitialized); + static constexpr size_t Defines = offsetof(Debugger, m_defines); + static constexpr size_t MDStructuresVersion = offsetof(Debugger, m_mdDataStructureVersion); +}; + -// CNewZeroData is the allocator used by the all the hash tables that the helper thread could possibly alter. It uses +// CNewZeroDatais the allocator used by the all the hash tables that the helper thread could possibly alter. It uses // the interop safe allocator. class CNewZeroData { diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index 1d19b32907de75..35596f56cdcd24 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -163,7 +163,10 @@ const DWORD kCurrentDbiVersionFormat = 1; // // //----------------------------------------------------------------------------- -class IDacDbiInterface + +// {DB505C1B-A327-4A46-8C32-AF55A56F8E09} +MIDL_INTERFACE("DB505C1B-A327-4A46-8C32-AF55A56F8E09") +IDacDbiInterface : public IUnknown { public: class IStringHolder; @@ -200,7 +203,7 @@ class IDacDbiInterface // Notes: // If this fails, the interface is in an undefined state. // This must be called anytime target memory changes, else all other functions - // (besides Destroy) may yield out-of-date or semantically incorrect results. + // (besides Release) may yield out-of-date or semantically incorrect results. // virtual HRESULT FlushCache() = 0; @@ -226,19 +229,7 @@ class IDacDbiInterface // consistency failures exceptions (this is independent from asserts - there are legitimate // scenarios for all 4 combinations). // - virtual HRESULT DacSetTargetConsistencyChecks(bool fEnableAsserts) = 0; - - // - // Destroy the interface object. The client should call this when it's done - // with the IDacDbiInterface to free up any resources. - // - // Return Value: - // S_OK on success; otherwise, an appropriate failure HRESULT. - // - // Notes: - // The client should not call anything else on this interface after Destroy. - // - virtual HRESULT Destroy() = 0; + virtual HRESULT DacSetTargetConsistencyChecks(BOOL fEnableAsserts) = 0; //----------------------------------------------------------------------------- // General purpose target inspection functions @@ -957,7 +948,7 @@ class IDacDbiInterface // Whether a thread is dead can be inferred from the ICorDebug API. However, we have this // on DacDbi to ensure that this definition is consistent with the other DacDbi methods, // especially the enumeration and discovery rules. - virtual HRESULT IsThreadMarkedDead(VMPTR_Thread vmThread, OUT bool * pResult) = 0; + virtual HRESULT IsThreadMarkedDead(VMPTR_Thread vmThread, OUT BOOL * pResult) = 0; // @@ -1742,13 +1733,13 @@ class IDacDbiInterface // for generics or they may represent the element type or referent // type. // pGenericArgData - list of type parameters - // vmTypeHandle - the exact type handle derived from the type information + // pVmTypeHandle - [out] the exact type handle derived from the type information // Return Value: // S_OK on success; otherwise, an appropriate failure HRESULT. virtual HRESULT GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData * pTypeData, ArgInfoList * pArgInfo, - VMPTR_TypeHandle& vmTypeHandle) = 0; + VMPTR_TypeHandle * pVmTypeHandle) = 0; // // Retrieve the generic type params for a given MethodDesc. This function is specifically @@ -1857,7 +1848,7 @@ class IDacDbiInterface virtual HRESULT IsExceptionObject(VMPTR_Object vmObject, OUT BOOL * pResult) = 0; // Get the list of raw stack frames for the specified exception object. - virtual HRESULT GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList& dacStackFrames) = 0; + virtual HRESULT GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList* pDacStackFrames) = 0; // Check whether the argument is a runtime callable wrapper. virtual HRESULT IsRcw(VMPTR_Object vmObject, OUT BOOL * pResult) = 0; @@ -1876,7 +1867,7 @@ class IDacDbiInterface // list of IIDs. the interface types are retrieved from an app domain // IID / Type cache, that is updated as new types are loaded. will // have NULL entries corresponding to unknown IIDs in "iids" - virtual HRESULT GetCachedWinRTTypesForIIDs(VMPTR_AppDomain vmAppDomain, DacDbiArrayList & iids, OUT DacDbiArrayList * pTypes) = 0; + virtual HRESULT GetCachedWinRTTypesForIIDs(VMPTR_AppDomain vmAppDomain, DacDbiArrayList * pIids, OUT DacDbiArrayList * pTypes) = 0; // retrieves the whole app domain cache of IID / Type mappings. virtual HRESULT GetCachedWinRTTypes(VMPTR_AppDomain vmAppDomain, OUT DacDbiArrayList * piids, OUT DacDbiArrayList * pTypes) = 0; @@ -2081,13 +2072,13 @@ class IDacDbiInterface // // Arguments: // vmModule: the module to check - // isWinRT: out parameter indicating state of module + // pIsWinRT: [out] indicating state of module // // Return value: // S_OK on success; otherwise, an appropriate failure HRESULT. // virtual - HRESULT IsWinRTModule(VMPTR_Module vmModule, BOOL& isWinRT) = 0; + HRESULT IsWinRTModule(VMPTR_Module vmModule, BOOL * pIsWinRT) = 0; // Determines the app domain id for the object referred to by a given VMPTR_OBJECTHANDLE // @@ -2165,9 +2156,9 @@ class IDacDbiInterface // to terminate the process when the attach is canceled. virtual HRESULT GetAttachStateFlags(OUT CLR_DEBUGGING_PROCESS_FLAGS * pRetVal) = 0; - virtual HRESULT GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly, DWORD & dwTimeStamp, DWORD & dwImageSize, IStringHolder* pStrFilename, OUT bool * pResult) = 0; + virtual HRESULT GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly, DWORD * pTimeStamp, DWORD * pImageSize, IStringHolder* pStrFilename, OUT BOOL * pResult) = 0; - virtual HRESULT IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, OUT bool * pResult) = 0; + virtual HRESULT IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, OUT BOOL * pResult) = 0; typedef void* * HeapWalkHandle; @@ -2175,7 +2166,7 @@ class IDacDbiInterface // Returns true if it is safe to walk the heap. If this function returns false, // you could still create a heap walk and attempt to walk it, but there's no // telling how much of the heap will be available. - virtual HRESULT AreGCStructuresValid(OUT bool * pResult) = 0; + virtual HRESULT AreGCStructuresValid(OUT BOOL * pResult) = 0; // Creates a HeapWalkHandle which can be used to walk the managed heap with the // WalkHeap function. Note if this function completes successfully you will need @@ -2225,9 +2216,9 @@ class IDacDbiInterface virtual HRESULT GetHeapSegments(OUT DacDbiArrayList * pSegments) = 0; - virtual HRESULT IsValidObject(CORDB_ADDRESS obj, OUT bool * pResult) = 0; + virtual HRESULT IsValidObject(CORDB_ADDRESS obj, OUT BOOL * pResult) = 0; - virtual HRESULT GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_AppDomain * pApp, OUT VMPTR_Module * pModule, OUT VMPTR_DomainAssembly * pDomainAssembly, OUT bool * pResult) = 0; + virtual HRESULT GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_AppDomain * pApp, OUT VMPTR_Module * pModule, OUT VMPTR_DomainAssembly * pDomainAssembly, OUT BOOL * pResult) = 0; // Reference Walking. @@ -2311,6 +2302,7 @@ class IDacDbiInterface // DEPRECATED - use GetNativeCodeVersionNode // Retrieves the ReJitInfo for a given MethodDesc/code address, if it exists. + // Note: Named GetReJitInfoByAddress in dacdbi.idl because COM does not support overloads. // // // Arguments: @@ -2533,7 +2525,7 @@ class IDacDbiInterface virtual HRESULT IsModuleMapped(VMPTR_Module pModule, OUT BOOL *isModuleMapped) = 0; - virtual HRESULT MetadataUpdatesApplied(OUT bool * pResult) = 0; + virtual HRESULT MetadataUpdatesApplied(OUT BOOL * pResult) = 0; virtual HRESULT GetDomainAssemblyFromModule(VMPTR_Module vmModule, OUT VMPTR_DomainAssembly *pVmDomainAssembly) = 0; @@ -2644,5 +2636,8 @@ class IDacDbiInterface }; // end IDacDbiInterface +// IID declaration for non-Windows platforms where __uuidof() expands to IID_##type. +// The actual IID is defined in corguids (via dacdbi_i.cpp). +EXTERN_C const IID IID_IDacDbiInterface; #endif // _DACDBI_INTERFACE_H_ diff --git a/src/coreclr/inc/CMakeLists.txt b/src/coreclr/inc/CMakeLists.txt index 4edac3b4f1ed9c..827f917c0157ce 100644 --- a/src/coreclr/inc/CMakeLists.txt +++ b/src/coreclr/inc/CMakeLists.txt @@ -7,6 +7,7 @@ set( CORGUIDS_IDL_SOURCES corprof.idl corsym.idl sospriv.idl + dacdbi.idl ) if(CLR_CMAKE_HOST_WIN32) diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl new file mode 100644 index 00000000000000..2a2eca68b4b690 --- /dev/null +++ b/src/coreclr/inc/dacdbi.idl @@ -0,0 +1,496 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +/***************************************************************************** + ** ** + ** dacdbi.idl - The interface used for DAC to DBI communication in the ** + ** .NET runtime debugger. ** + ** ** + *****************************************************************************/ +import "unknwn.idl"; + +// +// Forward-declared structs defined in other headers. +// +struct DbiVersion; +struct TypeRefData; +struct TargetBuffer; +struct ModuleInfo; +struct DomainAssemblyInfo; +struct DacThreadAllocInfo; +struct NativeVarData; +struct SequencePoints; +struct DebuggerIPCE_STRData; +struct DebuggerREGDISPLAY; +struct NativeCodeFunctionData; +struct ClassInfo; +struct FieldData; +struct DebuggerIPCE_ExpandedTypeData; +struct DebuggerIPCE_BasicTypeData; +struct EnCHangingFieldInfo; +struct DacExceptionCallStackData; +struct DebuggerIPCE_ObjectData; +struct MonitorLockInfo; +struct DacGcReference; +struct DacSharedReJitInfo; +struct AsyncLocalData; + +// +// Types MIDL cannot handle natively. These dummy definitions satisfy the MIDL +// parser; the real definitions come from C++ headers at compile time. +// +cpp_quote("#if 0") + +// FramePointer - wrapper around a single pointer (LPVOID m_sp in native code) +// Passed by value in IsMatchingParentFrame, GetFramePointer, and the internal frame callback. +typedef struct { UINT_PTR m_sp; } FramePointer; + +// VMPTR types - opaque pointer-sized wrappers +typedef ULONG64 VMPTR_AppDomain; +typedef ULONG64 VMPTR_OBJECTHANDLE; +typedef ULONG64 VMPTR_DomainAssembly; +typedef ULONG64 VMPTR_Assembly; +typedef ULONG64 VMPTR_Module; +typedef ULONG64 VMPTR_Thread; +typedef ULONG64 VMPTR_MethodDesc; +typedef ULONG64 VMPTR_CONTEXT; +typedef ULONG64 VMPTR_TypeHandle; +typedef ULONG64 VMPTR_FieldDesc; +typedef ULONG64 VMPTR_Object; +typedef ULONG64 VMPTR_PEAssembly; +typedef ULONG64 VMPTR_Crst; +typedef ULONG64 VMPTR_SimpleRWLock; +typedef ULONG64 VMPTR_ReJitInfo; +typedef ULONG64 VMPTR_SharedReJitInfo; +typedef ULONG64 VMPTR_ILCodeVersionNode; +typedef ULONG64 VMPTR_NativeCodeVersionNode; + +// Address and token types +typedef ULONG64 CORDB_ADDRESS; +typedef ULONG64 GENERICS_TYPE_TOKEN; +typedef ULONG64 PCODE; +typedef ULONG64 TADDR; +typedef int CONNID; +typedef ULONG64 TASKID; +typedef int mdToken; +typedef int mdTypeDef; +typedef int mdMethodDef; + +// Context types +typedef int T_CONTEXT; +typedef int DT_CONTEXT; +typedef int EXCEPTION_RECORD; + +// Metadata interface +typedef int IMDInternalImport; + +// Enum types +typedef int CorDebugThreadState; +typedef int CorDebugUserState; +typedef int CorDebugSetContextFlag; +typedef int CorDebugNGENPolicy; +typedef int CorElementType; +typedef int AddressType; +typedef int SymbolFormat; +typedef int AreValueTypesBoxed; +typedef int DelegateType; +typedef int DynamicMethodType; +typedef int FrameType; +typedef int EHijackReason; +typedef int CLR_DEBUGGING_PROCESS_FLAGS; + +// Size type +typedef unsigned int SIZE_T; + +// HANDLE type (void* in native header) +typedef UINT_PTR HANDLE; + +// Handle types (void** in native header, use UINT_PTR for pointer-sized IDL compatibility) +typedef UINT_PTR StackWalkHandle; +typedef UINT_PTR HeapWalkHandle; +typedef UINT_PTR RefWalkHandle; + +// Callback data +typedef LPVOID CALLBACK_DATA; + +// Cordebug types +typedef int COR_HEAPOBJECT; +typedef int COR_SEGMENT; +typedef int COR_TYPEID; +typedef int COR_FIELD; +typedef int COR_TYPE_LAYOUT; +typedef int COR_ARRAY_LAYOUT; +typedef int COR_HEAPINFO; +typedef int COR_MEMORY_RANGE; + +// DacDbiArrayList type params +typedef int TypeInfoList; +typedef int ArgInfoList; +typedef int TypeParamsList; + +// DacDbiArrayList instantiations +typedef struct { void *pList; int nEntries; } DacDbiArrayList_FieldData; +typedef struct { void *pList; int nEntries; } DacDbiArrayList_DacExceptionCallStackData; +typedef struct { void *pList; int nEntries; } DacDbiArrayList_ExpandedTypeData; +typedef struct { void *pList; int nEntries; } DacDbiArrayList_CORDB_ADDRESS; +typedef struct { void *pList; int nEntries; } DacDbiArrayList_GUID; +typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_SEGMENT; +typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_MEMORY_RANGE; +typedef struct { void *pList; int nEntries; } DacDbiArrayList_AsyncLocalData; + +cpp_quote("#endif") + +// +// Callback function pointer typedefs +// +typedef void (*FP_APPDOMAIN_ENUMERATION_CALLBACK)(VMPTR_AppDomain vmAppDomain, CALLBACK_DATA pUserData); +typedef void (*FP_ASSEMBLY_ENUMERATION_CALLBACK)(VMPTR_DomainAssembly vmDomainAssembly, CALLBACK_DATA pUserData); +typedef void (*FP_MODULE_ENUMERATION_CALLBACK)(VMPTR_Module vmModule, CALLBACK_DATA pUserData); +typedef void (*FP_THREAD_ENUMERATION_CALLBACK)(VMPTR_Thread vmThread, CALLBACK_DATA pUserData); +typedef BOOL (*FP_INTERNAL_FRAME_ENUMERATION_CALLBACK)(FramePointer fpFrame, CALLBACK_DATA pUserData); + + +// +// Inner callback interfaces +// + +// IStringHolder - utility for passing strings out of DAC to DBI. +[ + object, + local, + uuid(F2F195B2-C9F1-4164-B76D-CF4669956ED9) +] +interface IDacDbiStringHolder : IUnknown +{ + HRESULT AssignCopy([in] const WCHAR * psz); +}; + +// IAllocator - utility for DAC to allocate buffers in DBI memory space. +[ + object, + local, + uuid(97441D33-C82F-4106-B025-A912CB507526) +] +interface IDacDbiAllocator : IUnknown +{ + void * Alloc([in] SIZE_T lenBytes); + void Free([in] void * p); +}; + +// IMetaDataLookup - callback for DAC to obtain metadata importers from DBI. +[ + object, + local, + uuid(EF037312-925C-4A13-A9B5-3C1BB07B56FD) +] +interface IDacDbiMetaDataLookup : IUnknown +{ + IMDInternalImport * LookupMetaData([in] VMPTR_PEAssembly addressPEAssembly); +}; + + +// +// IDacDbiInterface - The main DAC to DBI communication interface. +// +// This interface provides the contract between the debugger's right-side (DBI) +// and the data access component (DAC). All methods return HRESULT. +// +[ + object, + local, + uuid(DB505C1B-A327-4A46-8C32-AF55A56F8E09) +] +interface IDacDbiInterface : IUnknown +{ + // Initialization + HRESULT CheckDbiVersion([in] const struct DbiVersion * pVersion); + HRESULT FlushCache(); + HRESULT DacSetTargetConsistencyChecks([in] BOOL fEnableAsserts); + + // Process State + HRESULT IsLeftSideInitialized([out] BOOL * pResult); + + // App Domains + HRESULT GetAppDomainFromId([in] ULONG appdomainId, [out] VMPTR_AppDomain * pRetVal); + HRESULT GetAppDomainId([in] VMPTR_AppDomain vmAppDomain, [out] ULONG * pRetVal); + HRESULT GetAppDomainObject([in] VMPTR_AppDomain vmAppDomain, [out] VMPTR_OBJECTHANDLE * pRetVal); + HRESULT GetAssemblyFromDomainAssembly([in] VMPTR_DomainAssembly vmDomainAssembly, [out] VMPTR_Assembly * vmAssembly); + HRESULT IsAssemblyFullyTrusted([in] VMPTR_DomainAssembly vmDomainAssembly, [out] BOOL * pResult); + HRESULT GetAppDomainFullName([in] VMPTR_AppDomain vmAppDomain, [in] IDacDbiStringHolder * pStrName); + HRESULT GetModuleSimpleName([in] VMPTR_Module vmModule, [in] IDacDbiStringHolder * pStrFilename); + HRESULT GetAssemblyPath([in] VMPTR_Assembly vmAssembly, [in] IDacDbiStringHolder * pStrFilename, [out] BOOL * pResult); + + // Module + HRESULT ResolveTypeReference([in] const struct TypeRefData * pTypeRefInfo, [out] struct TypeRefData * pTargetRefInfo); + HRESULT GetModulePath([in] VMPTR_Module vmModule, [in] IDacDbiStringHolder * pStrFilename, [out] BOOL * pResult); + HRESULT GetMetadata([in] VMPTR_Module vmModule, [out] struct TargetBuffer * pTargetBuffer); + HRESULT GetSymbolsBuffer([in] VMPTR_Module vmModule, [out] struct TargetBuffer * pTargetBuffer, [out] SymbolFormat * pSymbolFormat); + HRESULT GetModuleData([in] VMPTR_Module vmModule, [out] struct ModuleInfo * pData); + HRESULT GetDomainAssemblyData([in] VMPTR_DomainAssembly vmDomainAssembly, [out] struct DomainAssemblyInfo * pData); + HRESULT GetModuleForDomainAssembly([in] VMPTR_DomainAssembly vmDomainAssembly, [out] VMPTR_Module * pModule); + + // Address + HRESULT GetAddressType([in] CORDB_ADDRESS address, [out] AddressType * pRetVal); + HRESULT IsTransitionStub([in] CORDB_ADDRESS address, [out] BOOL * pResult); + + // Compiler + HRESULT GetCompilerFlags([in] VMPTR_DomainAssembly vmDomainAssembly, [out] BOOL * pfAllowJITOpts, [out] BOOL * pfEnableEnC); + HRESULT SetCompilerFlags([in] VMPTR_DomainAssembly vmDomainAssembly, [in] BOOL fAllowJitOpts, [in] BOOL fEnableEnC); + + // Enumeration + HRESULT EnumerateAppDomains([in] FP_APPDOMAIN_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); + HRESULT EnumerateAssembliesInAppDomain([in] VMPTR_AppDomain vmAppDomain, [in] FP_ASSEMBLY_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); + HRESULT EnumerateModulesInAssembly([in] VMPTR_DomainAssembly vmAssembly, [in] FP_MODULE_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); + + // Debug Events + HRESULT RequestSyncAtEvent(); + HRESULT SetSendExceptionsOutsideOfJMC([in] BOOL sendExceptionsOutsideOfJMC); + HRESULT MarkDebuggerAttachPending(); + HRESULT MarkDebuggerAttached([in] BOOL fAttached); + HRESULT Hijack( + [in] VMPTR_Thread vmThread, + [in] ULONG32 dwThreadId, + [in] const EXCEPTION_RECORD * pRecord, + [in] T_CONTEXT * pOriginalContext, + [in] ULONG32 cbSizeContext, + [in] EHijackReason reason, + [in] void * pUserData, + [out] CORDB_ADDRESS * pRemoteContextAddr); + + // Thread + HRESULT EnumerateThreads([in] FP_THREAD_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); + HRESULT IsThreadMarkedDead([in] VMPTR_Thread vmThread, [out] BOOL * pResult); + HRESULT GetThreadHandle([in] VMPTR_Thread vmThread, [out] HANDLE * pRetVal); + HRESULT GetThreadObject([in] VMPTR_Thread vmThread, [out] VMPTR_OBJECTHANDLE * pRetVal); + HRESULT GetThreadAllocInfo([in] VMPTR_Thread vmThread, [out] struct DacThreadAllocInfo * threadAllocInfo); + HRESULT SetDebugState([in] VMPTR_Thread vmThread, [in] CorDebugThreadState debugState); + HRESULT HasUnhandledException([in] VMPTR_Thread vmThread, [out] BOOL * pResult); + HRESULT GetUserState([in] VMPTR_Thread vmThread, [out] CorDebugUserState * pRetVal); + HRESULT GetPartialUserState([in] VMPTR_Thread vmThread, [out] CorDebugUserState * pRetVal); + HRESULT GetConnectionID([in] VMPTR_Thread vmThread, [out] CONNID * pRetVal); + HRESULT GetTaskID([in] VMPTR_Thread vmThread, [out] TASKID * pRetVal); + HRESULT TryGetVolatileOSThreadID([in] VMPTR_Thread vmThread, [out] DWORD * pRetVal); + HRESULT GetUniqueThreadID([in] VMPTR_Thread vmThread, [out] DWORD * pRetVal); + HRESULT GetCurrentException([in] VMPTR_Thread vmThread, [out] VMPTR_OBJECTHANDLE * pRetVal); + HRESULT GetObjectForCCW([in] CORDB_ADDRESS ccwPtr, [out] VMPTR_OBJECTHANDLE * pRetVal); + HRESULT GetCurrentCustomDebuggerNotification([in] VMPTR_Thread vmThread, [out] VMPTR_OBJECTHANDLE * pRetVal); + HRESULT GetCurrentAppDomain([out] VMPTR_AppDomain * pRetVal); + + // Assembly + HRESULT ResolveAssembly([in] VMPTR_DomainAssembly vmScope, [in] mdToken tkAssemblyRef, [out] VMPTR_DomainAssembly * pRetVal); + + // Code and Debugging Info + HRESULT GetNativeCodeSequencePointsAndVarInfo( + [in] VMPTR_MethodDesc vmMethodDesc, + [in] CORDB_ADDRESS startAddress, + [in] BOOL fCodeAvailable, + [out] struct NativeVarData * pNativeVarData, + [out] struct SequencePoints * pSequencePoints); + + // Context and Stack Walking + HRESULT GetManagedStoppedContext([in] VMPTR_Thread vmThread, [out] VMPTR_CONTEXT * pRetVal); + HRESULT CreateStackWalk([in] VMPTR_Thread vmThread, [in, out] DT_CONTEXT * pInternalContextBuffer, [out] StackWalkHandle * ppSFIHandle); + HRESULT DeleteStackWalk([in] StackWalkHandle ppSFIHandle); + HRESULT GetStackWalkCurrentContext([in] StackWalkHandle pSFIHandle, [out] DT_CONTEXT * pContext); + HRESULT SetStackWalkCurrentContext([in] VMPTR_Thread vmThread, [in] StackWalkHandle pSFIHandle, [in] CorDebugSetContextFlag flag, [in] DT_CONTEXT * pContext); + HRESULT UnwindStackWalkFrame([in] StackWalkHandle pSFIHandle, [out] BOOL * pResult); + HRESULT CheckContext([in] VMPTR_Thread vmThread, [in] const DT_CONTEXT * pContext); + HRESULT GetStackWalkCurrentFrameInfo([in] StackWalkHandle pSFIHandle, [out] struct DebuggerIPCE_STRData * pFrameData, [out] FrameType * pRetVal); + HRESULT GetCountOfInternalFrames([in] VMPTR_Thread vmThread, [out] ULONG32 * pRetVal); + HRESULT EnumerateInternalFrames([in] VMPTR_Thread vmThread, [in] FP_INTERNAL_FRAME_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); + HRESULT IsMatchingParentFrame([in] FramePointer fpToCheck, [in] FramePointer fpParent, [out] BOOL * pResult); + HRESULT GetStackParameterSize([in] CORDB_ADDRESS controlPC, [out] ULONG32 * pRetVal); + HRESULT GetFramePointer([in] StackWalkHandle pSFIHandle, [out] FramePointer * pRetVal); + HRESULT IsLeafFrame([in] VMPTR_Thread vmThread, [in] const DT_CONTEXT * pContext, [out] BOOL * pResult); + HRESULT GetContext([in] VMPTR_Thread vmThread, [out] DT_CONTEXT * pContextBuffer); + HRESULT ConvertContextToDebuggerRegDisplay([in] const DT_CONTEXT * pInContext, [out] struct DebuggerREGDISPLAY * pOutDRD, [in] BOOL fActive); + + // Method + HRESULT IsDiagnosticsHiddenOrLCGMethod([in] VMPTR_MethodDesc vmMethodDesc, [out] DynamicMethodType * pRetVal); + HRESULT GetVarArgSig([in] CORDB_ADDRESS VASigCookieAddr, [out] CORDB_ADDRESS * pArgBase, [out] struct TargetBuffer * pRetVal); + HRESULT RequiresAlign8([in] VMPTR_TypeHandle thExact, [out] BOOL * pResult); + HRESULT ResolveExactGenericArgsToken([in] DWORD dwExactGenericArgsTokenIndex, [in] GENERICS_TYPE_TOKEN rawToken, [out] GENERICS_TYPE_TOKEN * pRetVal); + HRESULT GetILCodeAndSig([in] VMPTR_DomainAssembly vmDomainAssembly, [in] mdToken functionToken, [out] struct TargetBuffer * pCodeInfo, [out] mdToken * pLocalSigToken); + HRESULT GetNativeCodeInfo([in] VMPTR_DomainAssembly vmDomainAssembly, [in] mdToken functionToken, [out] struct NativeCodeFunctionData * pCodeInfo); + HRESULT GetNativeCodeInfoForAddr( + [in] CORDB_ADDRESS codeAddress, + [out] struct NativeCodeFunctionData * pCodeInfo, + [out] VMPTR_Module * pVmModule, + [out] mdToken * pFunctionToken); + + // Type + HRESULT IsValueType([in] VMPTR_TypeHandle th, [out] BOOL * pResult); + HRESULT HasTypeParams([in] VMPTR_TypeHandle th, [out] BOOL * pResult); + HRESULT GetClassInfo([in] VMPTR_AppDomain vmAppDomain, [in] VMPTR_TypeHandle thExact, [out] struct ClassInfo * pData); + HRESULT GetInstantiationFieldInfo( + [in] VMPTR_DomainAssembly vmDomainAssembly, + [in] VMPTR_TypeHandle vmThExact, + [in] VMPTR_TypeHandle vmThApprox, + [out] DacDbiArrayList_FieldData * pFieldList, + [out] SIZE_T * pObjectSize); + HRESULT TypeHandleToExpandedTypeInfo([in] AreValueTypesBoxed boxed, [in] VMPTR_AppDomain vmAppDomain, [in] VMPTR_TypeHandle vmTypeHandle, [out] struct DebuggerIPCE_ExpandedTypeData * pTypeInfo); + HRESULT GetObjectExpandedTypeInfo([in] AreValueTypesBoxed boxed, [in] VMPTR_AppDomain vmAppDomain, [in] CORDB_ADDRESS addr, [out] struct DebuggerIPCE_ExpandedTypeData * pTypeInfo); + HRESULT GetObjectExpandedTypeInfoFromID([in] AreValueTypesBoxed boxed, [in] VMPTR_AppDomain vmAppDomain, [in] COR_TYPEID id, [out] struct DebuggerIPCE_ExpandedTypeData * pTypeInfo); + HRESULT GetTypeHandle([in] VMPTR_Module vmModule, [in] mdTypeDef metadataToken, [out] VMPTR_TypeHandle * pRetVal); + HRESULT GetApproxTypeHandle([in] TypeInfoList * pTypeData, [out] VMPTR_TypeHandle * pRetVal); + HRESULT GetExactTypeHandle([in] struct DebuggerIPCE_ExpandedTypeData * pTypeData, [in] ArgInfoList * pArgInfo, [out] VMPTR_TypeHandle * pVmTypeHandle); + HRESULT GetMethodDescParams( + [in] VMPTR_AppDomain vmAppDomain, + [in] VMPTR_MethodDesc vmMethodDesc, + [in] GENERICS_TYPE_TOKEN genericsToken, + [out] UINT32 * pcGenericClassTypeParams, + [out] TypeParamsList * pGenericTypeParams); + + // Field + HRESULT GetThreadStaticAddress([in] VMPTR_FieldDesc vmField, [in] VMPTR_Thread vmRuntimeThread, [out] CORDB_ADDRESS * pRetVal); + HRESULT GetCollectibleTypeStaticAddress([in] VMPTR_FieldDesc vmField, [in] VMPTR_AppDomain vmAppDomain, [out] CORDB_ADDRESS * pRetVal); + HRESULT GetEnCHangingFieldInfo([in] const struct EnCHangingFieldInfo * pEnCFieldInfo, [out] struct FieldData * pFieldData, [out] BOOL * pfStatic); + HRESULT GetTypeHandleParams([in] VMPTR_AppDomain vmAppDomain, [in] VMPTR_TypeHandle vmTypeHandle, [out] TypeParamsList * pParams); + HRESULT GetSimpleType( + [in] VMPTR_AppDomain vmAppDomain, + [in] CorElementType simpleType, + [out] mdTypeDef * pMetadataToken, + [out] VMPTR_Module * pVmModule, + [out] VMPTR_DomainAssembly * pVmDomainAssembly); + + // Exception and COM Interop + HRESULT IsExceptionObject([in] VMPTR_Object vmObject, [out] BOOL * pResult); + HRESULT GetStackFramesFromException([in] VMPTR_Object vmObject, [out] DacDbiArrayList_DacExceptionCallStackData * pDacStackFrames); + HRESULT IsRcw([in] VMPTR_Object vmObject, [out] BOOL * pResult); + HRESULT GetRcwCachedInterfaceTypes([in] VMPTR_Object vmObject, [in] VMPTR_AppDomain vmAppDomain, [in] BOOL bIInspectableOnly, [out] DacDbiArrayList_ExpandedTypeData * pDacInterfaces); + HRESULT GetRcwCachedInterfacePointers([in] VMPTR_Object vmObject, [in] BOOL bIInspectableOnly, [out] DacDbiArrayList_CORDB_ADDRESS * pDacItfPtrs); + HRESULT GetCachedWinRTTypesForIIDs([in] VMPTR_AppDomain vmAppDomain, [in] DacDbiArrayList_GUID * pIids, [out] DacDbiArrayList_ExpandedTypeData * pTypes); + HRESULT GetCachedWinRTTypes([in] VMPTR_AppDomain vmAppDomain, [out] DacDbiArrayList_GUID * piids, [out] DacDbiArrayList_ExpandedTypeData * pTypes); + + // Object Data + HRESULT GetTypedByRefInfo([in] CORDB_ADDRESS pTypedByRef, [in] VMPTR_AppDomain vmAppDomain, [out] struct DebuggerIPCE_ObjectData * pObjectData); + HRESULT GetStringData([in] CORDB_ADDRESS objectAddress, [out] struct DebuggerIPCE_ObjectData * pObjectData); + HRESULT GetArrayData([in] CORDB_ADDRESS objectAddress, [out] struct DebuggerIPCE_ObjectData * pObjectData); + HRESULT GetBasicObjectInfo([in] CORDB_ADDRESS objectAddress, [in] CorElementType type, [in] VMPTR_AppDomain vmAppDomain, [out] struct DebuggerIPCE_ObjectData * pObjectData); + + // Data Consistency (TEST_DATA_CONSISTENCY only) + HRESULT TestCrst([in] VMPTR_Crst vmCrst); + HRESULT TestRWLock([in] VMPTR_SimpleRWLock vmRWLock); + + // Debugger Control Block + HRESULT GetDebuggerControlBlockAddress([out] CORDB_ADDRESS * pRetVal); + + // Object Handles + HRESULT GetObjectFromRefPtr([in] CORDB_ADDRESS ptr, [out] VMPTR_Object * pRetVal); + HRESULT GetObject([in] CORDB_ADDRESS ptr, [out] VMPTR_Object * pRetVal); + + // NGEN + HRESULT EnableNGENPolicy([in] CorDebugNGENPolicy ePolicy); + HRESULT SetNGENCompilerFlags([in] DWORD dwFlags); + HRESULT GetNGENCompilerFlags([out] DWORD * pdwFlags); + + // VM Object Handle + HRESULT GetVmObjectHandle([in] CORDB_ADDRESS handleAddress, [out] VMPTR_OBJECTHANDLE * pRetVal); + HRESULT IsVmObjectHandleValid([in] VMPTR_OBJECTHANDLE vmHandle, [out] BOOL * pResult); + HRESULT IsWinRTModule([in] VMPTR_Module vmModule, [out] BOOL * pIsWinRT); + HRESULT GetAppDomainIdFromVmObjectHandle([in] VMPTR_OBJECTHANDLE vmHandle, [out] ULONG * pRetVal); + HRESULT GetHandleAddressFromVmHandle([in] VMPTR_OBJECTHANDLE vmHandle, [out] CORDB_ADDRESS * pRetVal); + + // Object Contents and Monitor + HRESULT GetObjectContents([in] VMPTR_Object obj, [out] struct TargetBuffer * pRetVal); + HRESULT GetThreadOwningMonitorLock([in] VMPTR_Object vmObject, [out] struct MonitorLockInfo * pRetVal); + HRESULT EnumerateMonitorEventWaitList([in] VMPTR_Object vmObject, [in] FP_THREAD_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); + + // Attach State + HRESULT GetAttachStateFlags([out] CLR_DEBUGGING_PROCESS_FLAGS * pRetVal); + + // Metadata + HRESULT GetMetaDataFileInfoFromPEFile( + [in] VMPTR_PEAssembly vmPEAssembly, + [out] DWORD * pTimeStamp, + [out] DWORD * pImageSize, + [in] IDacDbiStringHolder * pStrFilename, + [out] BOOL * pResult); + + // Thread State + HRESULT IsThreadSuspendedOrHijacked([in] VMPTR_Thread vmThread, [out] BOOL * pResult); + + // GC + HRESULT AreGCStructuresValid([out] BOOL * pResult); + HRESULT CreateHeapWalk([out] HeapWalkHandle * pHandle); + HRESULT DeleteHeapWalk([in] HeapWalkHandle handle); + HRESULT WalkHeap([in] HeapWalkHandle handle, [in] ULONG count, [out] COR_HEAPOBJECT * objects, [out] ULONG * pFetched); + HRESULT GetHeapSegments([out] DacDbiArrayList_COR_SEGMENT * pSegments); + HRESULT IsValidObject([in] CORDB_ADDRESS obj, [out] BOOL * pResult); + HRESULT GetAppDomainForObject( + [in] CORDB_ADDRESS obj, + [out] VMPTR_AppDomain * pApp, + [out] VMPTR_Module * pModule, + [out] VMPTR_DomainAssembly * pDomainAssembly, + [out] BOOL * pResult); + + // Reference Walking + HRESULT CreateRefWalk([out] RefWalkHandle * pHandle, [in] BOOL walkStacks, [in] BOOL walkFQ, [in] UINT32 handleWalkMask); + HRESULT DeleteRefWalk([in] RefWalkHandle handle); + HRESULT WalkRefs([in] RefWalkHandle handle, [in] ULONG count, [out] struct DacGcReference * refs, [out] ULONG * pFetched); + + // Type ID + HRESULT GetTypeID([in] CORDB_ADDRESS obj, [out] COR_TYPEID * pType); + HRESULT GetTypeIDForType([in] VMPTR_TypeHandle vmTypeHandle, [out] COR_TYPEID * pId); + HRESULT GetObjectFields([in] COR_TYPEID id, [in] ULONG32 celt, [out] COR_FIELD * layout, [out] ULONG32 * pceltFetched); + HRESULT GetTypeLayout([in] COR_TYPEID id, [out] COR_TYPE_LAYOUT * pLayout); + HRESULT GetArrayLayout([in] COR_TYPEID id, [out] COR_ARRAY_LAYOUT * pLayout); + HRESULT GetGCHeapInformation([out] COR_HEAPINFO * pHeapInfo); + + // PE File + HRESULT GetPEFileMDInternalRW([in] VMPTR_PEAssembly vmPEAssembly, [out] TADDR * pAddrMDInternalRW); + + // ReJit + HRESULT GetReJitInfo([in] VMPTR_Module vmModule, [in] mdMethodDef methodTk, [out] VMPTR_ReJitInfo * pReJitInfo); + // Note: Named GetReJitInfoByAddress in IDL because COM does not support overloads. + // Corresponds to the second GetReJitInfo overload in dacdbiinterface.h. + HRESULT GetReJitInfoByAddress([in] VMPTR_MethodDesc vmMethod, [in] CORDB_ADDRESS codeStartAddress, [out] VMPTR_ReJitInfo * pReJitInfo); + HRESULT GetSharedReJitInfo([in] VMPTR_ReJitInfo vmReJitInfo, [out] VMPTR_SharedReJitInfo * pSharedReJitInfo); + HRESULT GetSharedReJitInfoData([in] VMPTR_SharedReJitInfo sharedReJitInfo, [out] struct DacSharedReJitInfo * pData); + HRESULT AreOptimizationsDisabled([in] VMPTR_Module vmModule, [in] mdMethodDef methodTk, [out] BOOL * pOptimizationsDisabled); + + // Defines + HRESULT GetDefinesBitField([out] ULONG32 * pDefines); + HRESULT GetMDStructuresVersion([out] ULONG32 * pMDStructuresVersion); + + // Code Versioning (FEATURE_CODE_VERSIONING only) + HRESULT GetActiveRejitILCodeVersionNode([in] VMPTR_Module vmModule, [in] mdMethodDef methodTk, [out] VMPTR_ILCodeVersionNode * pVmILCodeVersionNode); + HRESULT GetNativeCodeVersionNode([in] VMPTR_MethodDesc vmMethod, [in] CORDB_ADDRESS codeStartAddress, [out] VMPTR_NativeCodeVersionNode * pVmNativeCodeVersionNode); + HRESULT GetILCodeVersionNode([in] VMPTR_NativeCodeVersionNode vmNativeCodeVersionNode, [out] VMPTR_ILCodeVersionNode * pVmILCodeVersionNode); + HRESULT GetILCodeVersionNodeData([in] VMPTR_ILCodeVersionNode ilCodeVersionNode, [out] struct DacSharedReJitInfo * pData); + + // Miscellaneous + HRESULT EnableGCNotificationEvents([in] BOOL fEnable); + + // Delegate + HRESULT IsDelegate([in] VMPTR_Object vmObject, [out] BOOL * pResult); + HRESULT GetDelegateType([in] VMPTR_Object delegateObject, [out] DelegateType * delegateType); + HRESULT GetDelegateFunctionData( + [in] DelegateType delegateType, + [in] VMPTR_Object delegateObject, + [out] VMPTR_DomainAssembly * ppFunctionDomainAssembly, + [out] mdMethodDef * pMethodDef); + HRESULT GetDelegateTargetObject( + [in] DelegateType delegateType, + [in] VMPTR_Object delegateObject, + [out] VMPTR_Object * ppTargetObj, + [out] VMPTR_AppDomain * ppTargetAppDomain); + + // Loader Heap + HRESULT GetLoaderHeapMemoryRanges([out] DacDbiArrayList_COR_MEMORY_RANGE * pRanges); + + // Module Mapping + HRESULT IsModuleMapped([in] VMPTR_Module pModule, [out] BOOL * isModuleMapped); + HRESULT MetadataUpdatesApplied([out] BOOL * pResult); + HRESULT GetDomainAssemblyFromModule([in] VMPTR_Module vmModule, [out] VMPTR_DomainAssembly * pVmDomainAssembly); + + // Async and Continuations + HRESULT ParseContinuation( + [in] CORDB_ADDRESS continuationAddress, + [out] PCODE * pDiagnosticIP, + [out] CORDB_ADDRESS * pNextContinuation, + [out] UINT32 * pState); + HRESULT GetAsyncLocals([in] VMPTR_MethodDesc vmMethod, [in] CORDB_ADDRESS codeAddr, [in] UINT32 state, [out] DacDbiArrayList_AsyncLocalData * pAsyncLocals); + + // Generic Arg Token + HRESULT GetGenericArgTokenIndex([in] VMPTR_MethodDesc vmMethod, [out] UINT32 * pTokenIndex); +}; diff --git a/src/coreclr/pal/prebuilt/idl/dacdbi_i.cpp b/src/coreclr/pal/prebuilt/idl/dacdbi_i.cpp new file mode 100644 index 00000000000000..8d0e7f75532a43 --- /dev/null +++ b/src/coreclr/pal/prebuilt/idl/dacdbi_i.cpp @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ + +/* link this file in with the server and any clients */ + + + /* File created by MIDL compiler version 8.01.0628 */ +/* Compiler settings for dacdbi.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0628 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +#ifdef __cplusplus +extern "C"{ +#endif + + +#include +#include + +#ifdef _MIDL_USE_GUIDDEF_ + +#ifndef INITGUID +#define INITGUID +#include +#undef INITGUID +#else +#include +#endif + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) + +#else // !_MIDL_USE_GUIDDEF_ + +#ifndef __IID_DEFINED__ +#define __IID_DEFINED__ + +typedef struct _IID +{ + unsigned long x; + unsigned short s1; + unsigned short s2; + unsigned char c[8]; +} IID; + +#endif // __IID_DEFINED__ + +#ifndef CLSID_DEFINED +#define CLSID_DEFINED +typedef IID CLSID; +#endif // CLSID_DEFINED + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + EXTERN_C __declspec(selectany) const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} + +#endif // !_MIDL_USE_GUIDDEF_ + +// IDacDbiStringHolder: {F2F195B2-C9F1-4164-B76D-CF4669956ED9} +MIDL_DEFINE_GUID(IID, IID_IDacDbiStringHolder,0xf2f195b2,0xc9f1,0x4164,0xb7,0x6d,0xcf,0x46,0x69,0x95,0x6e,0xd9); + + +// IDacDbiAllocator: {97441D33-C82F-4106-B025-A912CB507526} +MIDL_DEFINE_GUID(IID, IID_IDacDbiAllocator,0x97441d33,0xc82f,0x4106,0xb0,0x25,0xa9,0x12,0xcb,0x50,0x75,0x26); + + +// IDacDbiMetaDataLookup: {EF037312-925C-4A13-A9B5-3C1BB07B56FD} +MIDL_DEFINE_GUID(IID, IID_IDacDbiMetaDataLookup,0xef037312,0x925c,0x4a13,0xa9,0xb5,0x3c,0x1b,0xb0,0x7b,0x56,0xfd); + + +// IDacDbiInterface: {DB505C1B-A327-4A46-8C32-AF55A56F8E09} +MIDL_DEFINE_GUID(IID, IID_IDacDbiInterface,0xdb505c1b,0xa327,0x4a46,0x8c,0x32,0xaf,0x55,0xa5,0x6f,0x8e,0x09); + +#undef MIDL_DEFINE_GUID + +#ifdef __cplusplus +} +#endif + + diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index b6cd256d09dc32..d386098492ef4c 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -332,6 +332,13 @@ CDAC_TYPE_FIELD(SystemDomain, /*GlobalLoaderAllocator*/, GlobalLoaderAllocator, CDAC_TYPE_FIELD(SystemDomain, /*pointer*/, SystemAssembly, cdac_data::SystemAssembly) CDAC_TYPE_END(SystemDomain) +CDAC_TYPE_BEGIN(Debugger) +CDAC_TYPE_INDETERMINATE(Debugger) +CDAC_TYPE_FIELD(Debugger, /*int32*/, LeftSideInitialized, cdac_data::LeftSideInitialized) +CDAC_TYPE_FIELD(Debugger, /*uint32*/, Defines, cdac_data::Defines) +CDAC_TYPE_FIELD(Debugger, /*uint32*/, MDStructuresVersion, cdac_data::MDStructuresVersion) +CDAC_TYPE_END(Debugger) + CDAC_TYPE_BEGIN(ArrayListBase) CDAC_TYPE_INDETERMINATE(ArrayListBase) CDAC_TYPE_FIELD(ArrayListBase, /*uint32*/, Count, cdac_data::Count) @@ -1266,6 +1273,9 @@ CDAC_GLOBAL_POINTER(SystemDomain, cdac_data::SystemDomainPtr) CDAC_GLOBAL_POINTER(ThreadStore, &ThreadStore::s_pThreadStore) CDAC_GLOBAL_POINTER(FinalizerThread, &::g_pFinalizerThread) CDAC_GLOBAL_POINTER(GCThread, &::g_pSuspensionThread) +CDAC_GLOBAL_POINTER(Debugger, &::g_pDebugger) +CDAC_GLOBAL_POINTER(CLRJitAttachState, &::CLRJitAttachState) +CDAC_GLOBAL_POINTER(MetadataUpdatesApplied, &::g_metadataUpdatesApplied) // Add FrameIdentifier for all defined Frame types. Used to differentiate Frame objects. #define FRAME_TYPE_NAME(frameType) \ @@ -1410,6 +1420,7 @@ CDAC_GLOBAL_CONTRACT(CodeVersions, 1) CDAC_GLOBAL_CONTRACT(ComWrappers, 1) #endif // FEATURE_COMWRAPPERS CDAC_GLOBAL_CONTRACT(DacStreams, 1) +CDAC_GLOBAL_CONTRACT(Debugger, 1) CDAC_GLOBAL_CONTRACT(DebugInfo, 2) CDAC_GLOBAL_CONTRACT(EcmaMetadata, 1) CDAC_GLOBAL_CONTRACT(Exception, 1) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs index a4e33db17c7fcf..5f9c6138344046 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs @@ -102,6 +102,10 @@ public abstract class ContractRegistry /// Gets an instance of the BuiltInCOM contract for the target. /// public virtual IBuiltInCOM BuiltInCOM => GetContract(); + /// + /// Gets an instance of the Debugger contract for the target. + /// + public virtual IDebugger Debugger => GetContract(); public abstract TContract GetContract() where TContract : IContract; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs new file mode 100644 index 00000000000000..05d6f61a12e91b --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +public interface IDebugger : IContract +{ + static string IContract.Name { get; } = nameof(Debugger); + + bool IsLeftSideInitialized() => throw new NotImplementedException(); + uint GetDefinesBitField() => throw new NotImplementedException(); + uint GetMDStructuresVersion() => throw new NotImplementedException(); + int GetAttachStateFlags() => throw new NotImplementedException(); + bool MetadataUpdatesApplied() => throw new NotImplementedException(); +} + +public readonly struct Debugger : IDebugger +{ + // Everything throws NotImplementedException +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs index 089e49ee17591c..3c4cc3687e2dc2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs @@ -5,5 +5,6 @@ namespace Microsoft.Diagnostics.DataContractReader; public static class CorDbgHResults { + public const int CORDBG_E_NOTREADY = unchecked((int)0x80131c10); public const int CORDBG_E_READVIRTUAL_FAILURE = unchecked((int)0x80131c49); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index 2a49c5a0d11569..2fc5b4dddde1ef 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -42,6 +42,7 @@ public enum DataType Module, ModuleLookupMap, AppDomain, + Debugger, SystemDomain, Assembly, LoaderAllocator, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 2585e72902f7ac..0bd6672f802eb8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -13,6 +13,9 @@ public static class Globals public const string ThreadStore = nameof(ThreadStore); public const string FinalizerThread = nameof(FinalizerThread); public const string GCThread = nameof(GCThread); + public const string Debugger = nameof(Debugger); + public const string CLRJitAttachState = nameof(CLRJitAttachState); + public const string MetadataUpdatesApplied = nameof(MetadataUpdatesApplied); public const string FeatureCOMInterop = nameof(FeatureCOMInterop); public const string FeatureComWrappers = nameof(FeatureComWrappers); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/DebuggerFactory.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/DebuggerFactory.cs new file mode 100644 index 00000000000000..58bd60ac94c5c7 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/DebuggerFactory.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +public sealed class DebuggerFactory : IContractFactory +{ + IDebugger IContractFactory.CreateContract(Target target, int version) + { + return version switch + { + 1 => new Debugger_1(target), + _ => default(Debugger), + }; + } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs new file mode 100644 index 00000000000000..7768cf0898d987 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly struct Debugger_1 : IDebugger +{ + private readonly Target _target; + + internal Debugger_1(Target target) + { + _target = target; + } + + bool IDebugger.IsLeftSideInitialized() + { + TargetPointer debuggerPtr = _target.ReadGlobalPointer(Constants.Globals.Debugger); + if (debuggerPtr == TargetPointer.Null) + return false; + + Data.Debugger debugger = _target.ProcessedData.GetOrAdd(debuggerPtr); + return debugger.LeftSideInitialized != 0; + } + + uint IDebugger.GetDefinesBitField() + { + TargetPointer debuggerPtr = _target.ReadGlobalPointer(Constants.Globals.Debugger); + if (debuggerPtr == TargetPointer.Null) + throw new System.Runtime.InteropServices.COMException(null, CorDbgHResults.CORDBG_E_NOTREADY); + + Data.Debugger debugger = _target.ProcessedData.GetOrAdd(debuggerPtr); + return debugger.Defines; + } + + uint IDebugger.GetMDStructuresVersion() + { + TargetPointer debuggerPtr = _target.ReadGlobalPointer(Constants.Globals.Debugger); + if (debuggerPtr == TargetPointer.Null) + throw new System.Runtime.InteropServices.COMException(null, CorDbgHResults.CORDBG_E_NOTREADY); + + Data.Debugger debugger = _target.ProcessedData.GetOrAdd(debuggerPtr); + return debugger.MDStructuresVersion; + } + + int IDebugger.GetAttachStateFlags() + { + if (_target.TryReadGlobalPointer(Constants.Globals.CLRJitAttachState, out TargetPointer? addr)) + { + return (int)_target.Read(addr.Value.Value); + } + return 0; + } + + bool IDebugger.MetadataUpdatesApplied() + { + if (_target.TryReadGlobalPointer(Constants.Globals.MetadataUpdatesApplied, out TargetPointer? addr)) + { + return _target.Read(addr.Value.Value) != 0; + } + return false; + } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Debugger.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Debugger.cs new file mode 100644 index 00000000000000..3165d480333a8e --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Debugger.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class Debugger : IData +{ + static Debugger IData.Create(Target target, TargetPointer address) + => new Debugger(target, address); + + public Debugger(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.Debugger); + + LeftSideInitialized = target.Read(address + (ulong)type.Fields[nameof(LeftSideInitialized)].Offset); + Defines = target.Read(address + (ulong)type.Fields[nameof(Defines)].Offset); + MDStructuresVersion = target.Read(address + (ulong)type.Fields[nameof(MDStructuresVersion)].Offset); + } + + public int LeftSideInitialized { get; init; } + public uint Defines { get; init; } + public uint MDStructuresVersion { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs new file mode 100644 index 00000000000000..1172acaf464a8f --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -0,0 +1,1331 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices.Marshalling; +using Microsoft.Diagnostics.DataContractReader.Contracts; + +namespace Microsoft.Diagnostics.DataContractReader.Legacy; + +[GeneratedComClass] +public sealed unsafe partial class DacDbiImpl : IDacDbiInterface +{ + private readonly Target _target; + private readonly IDacDbiInterface? _legacy; + + public DacDbiImpl(Target target, object? legacyObj) + { + _target = target; + _legacy = legacyObj as IDacDbiInterface; + } + + public int CheckDbiVersion(DbiVersion* pVersion) + => _legacy is not null ? _legacy.CheckDbiVersion(pVersion) : HResults.E_NOTIMPL; + + public int FlushCache() + => _legacy is not null ? _legacy.FlushCache() : HResults.E_NOTIMPL; + + public int DacSetTargetConsistencyChecks(Interop.BOOL fEnableAsserts) + => _legacy is not null ? _legacy.DacSetTargetConsistencyChecks(fEnableAsserts) : HResults.E_NOTIMPL; + + public int IsLeftSideInitialized(int* pResult) + { + *pResult = 0; + int hr = HResults.S_OK; + try + { + *pResult = _target.Contracts.Debugger.IsLeftSideInitialized() ? 1 : 0; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + int resultLocal; + int hrLocal = _legacy.IsLeftSideInitialized(&resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal); + } +#endif + + return hr; + } + + public int GetAppDomainFromId(uint appdomainId, ulong* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + if (appdomainId != 1) + throw new ArgumentException(null, nameof(appdomainId)); + TargetPointer appDomainPtr = _target.ReadGlobalPointer(Constants.Globals.AppDomain); + *pRetVal = _target.ReadPointer(appDomainPtr); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetAppDomainFromId(appdomainId, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}"); + } +#endif + return hr; + } + + public int GetAppDomainId(ulong vmAppDomain, uint* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + *pRetVal = vmAppDomain == 0 ? 0u : 1u; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + uint retValLocal; + int hrLocal = _legacy.GetAppDomainId(vmAppDomain, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal}, DAC: {retValLocal}"); + } +#endif + return hr; + } + + public int GetAppDomainObject(ulong vmAppDomain, ulong* pRetVal) + => _legacy is not null ? _legacy.GetAppDomainObject(vmAppDomain, pRetVal) : HResults.E_NOTIMPL; + + public int GetAssemblyFromDomainAssembly(ulong vmDomainAssembly, ulong* vmAssembly) + { + *vmAssembly = 0; + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmDomainAssembly)); + *vmAssembly = loader.GetAssembly(handle).Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong assemblyLocal; + int hrLocal = _legacy.GetAssemblyFromDomainAssembly(vmDomainAssembly, &assemblyLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*vmAssembly == assemblyLocal, $"cDAC: {*vmAssembly:x}, DAC: {assemblyLocal:x}"); + } +#endif + return hr; + } + + public int IsAssemblyFullyTrusted(ulong vmDomainAssembly, int* pResult) + { + *pResult = 1; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + int resultLocal; + int hrLocal = _legacy.IsAssemblyFullyTrusted(vmDomainAssembly, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int GetAppDomainFullName(ulong vmAppDomain, IStringHolder pStrName) + { + int hr = HResults.S_OK; + try + { + string name = _target.Contracts.Loader.GetAppDomainFriendlyName(); + pStrName.AssignCopy(name); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int GetModuleSimpleName(ulong vmModule, IStringHolder pStrFilename) + { + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmModule)); + string name = loader.GetFileName(handle); + pStrFilename.AssignCopy(name); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int GetAssemblyPath(ulong vmAssembly, IStringHolder pStrFilename, int* pResult) + { + *pResult = 0; + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + Contracts.ModuleHandle handle = loader.GetModuleHandleFromAssemblyPtr(new TargetPointer(vmAssembly)); + string path = loader.GetPath(handle); + if (string.IsNullOrEmpty(path)) + { + *pResult = 0; + } + else + { + pStrFilename.AssignCopy(path); + *pResult = 1; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int ResolveTypeReference(DacDbiTypeRefData* pTypeRefInfo, DacDbiTypeRefData* pTargetRefInfo) + => _legacy is not null ? _legacy.ResolveTypeReference(pTypeRefInfo, pTargetRefInfo) : HResults.E_NOTIMPL; + + public int GetModulePath(ulong vmModule, IStringHolder pStrFilename, int* pResult) + { + *pResult = 0; + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmModule)); + string path = loader.GetPath(handle); + if (string.IsNullOrEmpty(path)) + { + *pResult = 0; + } + else + { + pStrFilename.AssignCopy(path); + *pResult = 1; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int GetMetadata(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer) + => _legacy is not null ? _legacy.GetMetadata(vmModule, pTargetBuffer) : HResults.E_NOTIMPL; + + public int GetSymbolsBuffer(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer, int* pSymbolFormat) + => _legacy is not null ? _legacy.GetSymbolsBuffer(vmModule, pTargetBuffer, pSymbolFormat) : HResults.E_NOTIMPL; + + public int GetModuleData(ulong vmModule, DacDbiModuleInfo* pData) + => _legacy is not null ? _legacy.GetModuleData(vmModule, pData) : HResults.E_NOTIMPL; + + public int GetDomainAssemblyData(ulong vmDomainAssembly, DacDbiDomainAssemblyInfo* pData) + => _legacy is not null ? _legacy.GetDomainAssemblyData(vmDomainAssembly, pData) : HResults.E_NOTIMPL; + + public int GetModuleForDomainAssembly(ulong vmDomainAssembly, ulong* pModule) + { + *pModule = 0; + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + Contracts.ModuleHandle handle = loader.GetModuleHandleFromModulePtr(new TargetPointer(vmDomainAssembly)); + *pModule = loader.GetModule(handle).Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong moduleLocal; + int hrLocal = _legacy.GetModuleForDomainAssembly(vmDomainAssembly, &moduleLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pModule == moduleLocal, $"cDAC: {*pModule:x}, DAC: {moduleLocal:x}"); + } +#endif + return hr; + } + + public int GetAddressType(ulong address, int* pRetVal) + => _legacy is not null ? _legacy.GetAddressType(address, pRetVal) : HResults.E_NOTIMPL; + + public int IsTransitionStub(ulong address, int* pResult) + => _legacy is not null ? _legacy.IsTransitionStub(address, pResult) : HResults.E_NOTIMPL; + + public int GetCompilerFlags(ulong vmDomainAssembly, int* pfAllowJITOpts, int* pfEnableEnC) + => _legacy is not null ? _legacy.GetCompilerFlags(vmDomainAssembly, pfAllowJITOpts, pfEnableEnC) : HResults.E_NOTIMPL; + + public int SetCompilerFlags(ulong vmDomainAssembly, int fAllowJitOpts, int fEnableEnC) + => _legacy is not null ? _legacy.SetCompilerFlags(vmDomainAssembly, fAllowJitOpts, fEnableEnC) : HResults.E_NOTIMPL; + + public int EnumerateAppDomains(nint fpCallback, nint pUserData) + { + int hr = HResults.S_OK; + try + { + TargetPointer appDomainPtr = _target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = _target.ReadPointer(appDomainPtr); + var callback = (delegate* unmanaged)fpCallback; + callback(appDomain, pUserData); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int EnumerateAssembliesInAppDomain(ulong vmAppDomain, nint fpCallback, nint pUserData) + { + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + var callback = (delegate* unmanaged)fpCallback; + IEnumerable modules = loader.GetModuleHandles( + new TargetPointer(vmAppDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeLoading | AssemblyIterationFlags.IncludeExecution); + foreach (Contracts.ModuleHandle module in modules) + { + TargetPointer assemblyPtr = loader.GetAssembly(module); + callback(assemblyPtr.Value, pUserData); + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int EnumerateModulesInAssembly(ulong vmAssembly, nint fpCallback, nint pUserData) + { + int hr = HResults.S_OK; + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + var callback = (delegate* unmanaged)fpCallback; + Contracts.ModuleHandle handle = loader.GetModuleHandleFromAssemblyPtr(new TargetPointer(vmAssembly)); + TargetPointer modulePtr = loader.GetModule(handle); + callback(modulePtr.Value, pUserData); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int RequestSyncAtEvent() + => _legacy is not null ? _legacy.RequestSyncAtEvent() : HResults.E_NOTIMPL; + + public int SetSendExceptionsOutsideOfJMC(int sendExceptionsOutsideOfJMC) + => _legacy is not null ? _legacy.SetSendExceptionsOutsideOfJMC(sendExceptionsOutsideOfJMC) : HResults.E_NOTIMPL; + + public int MarkDebuggerAttachPending() + => _legacy is not null ? _legacy.MarkDebuggerAttachPending() : HResults.E_NOTIMPL; + + public int MarkDebuggerAttached(int fAttached) + => _legacy is not null ? _legacy.MarkDebuggerAttached(fAttached) : HResults.E_NOTIMPL; + + public int Hijack(ulong vmThread, uint dwThreadId, nint pRecord, nint pOriginalContext, uint cbSizeContext, int reason, nint pUserData, ulong* pRemoteContextAddr) + => _legacy is not null ? _legacy.Hijack(vmThread, dwThreadId, pRecord, pOriginalContext, cbSizeContext, reason, pUserData, pRemoteContextAddr) : HResults.E_NOTIMPL; + + public int EnumerateThreads(nint fpCallback, nint pUserData) + { + int hr = HResults.S_OK; + try + { + Contracts.IThread threadContract = _target.Contracts.Thread; + Contracts.ThreadStoreData threadStore = threadContract.GetThreadStoreData(); + var callback = (delegate* unmanaged)fpCallback; + TargetPointer currentThread = threadStore.FirstThread; + while (currentThread != TargetPointer.Null) + { + callback(currentThread.Value, pUserData); + Contracts.ThreadData threadData = threadContract.GetThreadData(currentThread); + currentThread = threadData.NextThread; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + return hr; + } + + public int IsThreadMarkedDead(ulong vmThread, Interop.BOOL* pResult) + { + *pResult = Interop.BOOL.FALSE; + int hr = HResults.S_OK; + try + { + Contracts.ThreadData threadData = _target.Contracts.Thread.GetThreadData(new TargetPointer(vmThread)); + *pResult = (threadData.State & Contracts.ThreadState.Dead) != 0 ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + Interop.BOOL resultLocal; + int hrLocal = _legacy.IsThreadMarkedDead(vmThread, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int GetThreadHandle(ulong vmThread, nint pRetVal) + => _legacy is not null ? _legacy.GetThreadHandle(vmThread, pRetVal) : HResults.E_NOTIMPL; + + public int GetThreadObject(ulong vmThread, ulong* pRetVal) + => _legacy is not null ? _legacy.GetThreadObject(vmThread, pRetVal) : HResults.E_NOTIMPL; + + public int GetThreadAllocInfo(ulong vmThread, DacDbiThreadAllocInfo* pThreadAllocInfo) + => _legacy is not null ? _legacy.GetThreadAllocInfo(vmThread, pThreadAllocInfo) : HResults.E_NOTIMPL; + + public int SetDebugState(ulong vmThread, int debugState) + => _legacy is not null ? _legacy.SetDebugState(vmThread, debugState) : HResults.E_NOTIMPL; + + public int HasUnhandledException(ulong vmThread, int* pResult) + => _legacy is not null ? _legacy.HasUnhandledException(vmThread, pResult) : HResults.E_NOTIMPL; + + public int GetUserState(ulong vmThread, int* pRetVal) + => _legacy is not null ? _legacy.GetUserState(vmThread, pRetVal) : HResults.E_NOTIMPL; + + public int GetPartialUserState(ulong vmThread, int* pRetVal) + => _legacy is not null ? _legacy.GetPartialUserState(vmThread, pRetVal) : HResults.E_NOTIMPL; + + public int GetConnectionID(ulong vmThread, uint* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + uint retValLocal; + int hrLocal = _legacy.GetConnectionID(vmThread, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal}, DAC: {retValLocal}"); + } +#endif + return hr; + } + + public int GetTaskID(ulong vmThread, ulong* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetTaskID(vmThread, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal}, DAC: {retValLocal}"); + } +#endif + return hr; + } + + public int TryGetVolatileOSThreadID(ulong vmThread, uint* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + Contracts.ThreadData threadData = _target.Contracts.Thread.GetThreadData(new TargetPointer(vmThread)); + *pRetVal = (uint)threadData.OSId.Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + uint retValLocal; + int hrLocal = _legacy.TryGetVolatileOSThreadID(vmThread, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal}, DAC: {retValLocal}"); + } +#endif + return hr; + } + + public int GetUniqueThreadID(ulong vmThread, uint* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + Contracts.ThreadData threadData = _target.Contracts.Thread.GetThreadData(new TargetPointer(vmThread)); + *pRetVal = threadData.Id; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + uint retValLocal; + int hrLocal = _legacy.GetUniqueThreadID(vmThread, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal}, DAC: {retValLocal}"); + } +#endif + return hr; + } + + public int GetCurrentException(ulong vmThread, ulong* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + TargetPointer throwable = _target.Contracts.Thread.GetThrowableObject(new TargetPointer(vmThread)); + *pRetVal = throwable.Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetCurrentException(vmThread, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}"); + } +#endif + return hr; + } + + public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal) + => _legacy is not null ? _legacy.GetObjectForCCW(ccwPtr, pRetVal) : HResults.E_NOTIMPL; + + public int GetCurrentCustomDebuggerNotification(ulong vmThread, ulong* pRetVal) + => _legacy is not null ? _legacy.GetCurrentCustomDebuggerNotification(vmThread, pRetVal) : HResults.E_NOTIMPL; + + public int GetCurrentAppDomain(ulong* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + TargetPointer appDomainPtr = _target.ReadGlobalPointer(Constants.Globals.AppDomain); + *pRetVal = _target.ReadPointer(appDomainPtr); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetCurrentAppDomain(&retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}"); + } +#endif + return hr; + } + + public int ResolveAssembly(ulong vmScope, uint tkAssemblyRef, ulong* pRetVal) + => _legacy is not null ? _legacy.ResolveAssembly(vmScope, tkAssemblyRef, pRetVal) : HResults.E_NOTIMPL; + + public int GetNativeCodeSequencePointsAndVarInfo(ulong vmMethodDesc, ulong startAddress, int fCodeAvailable, nint pNativeVarData, nint pSequencePoints) + => _legacy is not null ? _legacy.GetNativeCodeSequencePointsAndVarInfo(vmMethodDesc, startAddress, fCodeAvailable, pNativeVarData, pSequencePoints) : HResults.E_NOTIMPL; + + public int GetManagedStoppedContext(ulong vmThread, ulong* pRetVal) + => _legacy is not null ? _legacy.GetManagedStoppedContext(vmThread, pRetVal) : HResults.E_NOTIMPL; + + public int CreateStackWalk(ulong vmThread, nint pInternalContextBuffer, nuint* ppSFIHandle) + => _legacy is not null ? _legacy.CreateStackWalk(vmThread, pInternalContextBuffer, ppSFIHandle) : HResults.E_NOTIMPL; + + public int DeleteStackWalk(nuint ppSFIHandle) + => _legacy is not null ? _legacy.DeleteStackWalk(ppSFIHandle) : HResults.E_NOTIMPL; + + public int GetStackWalkCurrentContext(nuint pSFIHandle, nint pContext) + => _legacy is not null ? _legacy.GetStackWalkCurrentContext(pSFIHandle, pContext) : HResults.E_NOTIMPL; + + public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, nint pContext) + => _legacy is not null ? _legacy.SetStackWalkCurrentContext(vmThread, pSFIHandle, flag, pContext) : HResults.E_NOTIMPL; + + public int UnwindStackWalkFrame(nuint pSFIHandle, int* pResult) + => _legacy is not null ? _legacy.UnwindStackWalkFrame(pSFIHandle, pResult) : HResults.E_NOTIMPL; + + public int CheckContext(ulong vmThread, nint pContext) + => _legacy is not null ? _legacy.CheckContext(vmThread, pContext) : HResults.E_NOTIMPL; + + public int GetStackWalkCurrentFrameInfo(nuint pSFIHandle, nint pFrameData, int* pRetVal) + => _legacy is not null ? _legacy.GetStackWalkCurrentFrameInfo(pSFIHandle, pFrameData, pRetVal) : HResults.E_NOTIMPL; + + public int GetCountOfInternalFrames(ulong vmThread, uint* pRetVal) + => _legacy is not null ? _legacy.GetCountOfInternalFrames(vmThread, pRetVal) : HResults.E_NOTIMPL; + + public int EnumerateInternalFrames(ulong vmThread, nint fpCallback, nint pUserData) + => _legacy is not null ? _legacy.EnumerateInternalFrames(vmThread, fpCallback, pUserData) : HResults.E_NOTIMPL; + + public int IsMatchingParentFrame(ulong fpToCheck, ulong fpParent, int* pResult) + => _legacy is not null ? _legacy.IsMatchingParentFrame(fpToCheck, fpParent, pResult) : HResults.E_NOTIMPL; + + public int GetStackParameterSize(ulong controlPC, uint* pRetVal) + => _legacy is not null ? _legacy.GetStackParameterSize(controlPC, pRetVal) : HResults.E_NOTIMPL; + + public int GetFramePointer(nuint pSFIHandle, ulong* pRetVal) + => _legacy is not null ? _legacy.GetFramePointer(pSFIHandle, pRetVal) : HResults.E_NOTIMPL; + + public int IsLeafFrame(ulong vmThread, nint pContext, int* pResult) + => _legacy is not null ? _legacy.IsLeafFrame(vmThread, pContext, pResult) : HResults.E_NOTIMPL; + + public int GetContext(ulong vmThread, nint pContextBuffer) + => _legacy is not null ? _legacy.GetContext(vmThread, pContextBuffer) : HResults.E_NOTIMPL; + + public int ConvertContextToDebuggerRegDisplay(nint pInContext, nint pOutDRD, int fActive) + => _legacy is not null ? _legacy.ConvertContextToDebuggerRegDisplay(pInContext, pOutDRD, fActive) : HResults.E_NOTIMPL; + + public int IsDiagnosticsHiddenOrLCGMethod(ulong vmMethodDesc, int* pRetVal) + => _legacy is not null ? _legacy.IsDiagnosticsHiddenOrLCGMethod(vmMethodDesc, pRetVal) : HResults.E_NOTIMPL; + + public int GetVarArgSig(ulong VASigCookieAddr, ulong* pArgBase, DacDbiTargetBuffer* pRetVal) + => _legacy is not null ? _legacy.GetVarArgSig(VASigCookieAddr, pArgBase, pRetVal) : HResults.E_NOTIMPL; + + public int RequiresAlign8(ulong thExact, int* pResult) + => _legacy is not null ? _legacy.RequiresAlign8(thExact, pResult) : HResults.E_NOTIMPL; + + public int ResolveExactGenericArgsToken(uint dwExactGenericArgsTokenIndex, ulong rawToken, ulong* pRetVal) + => _legacy is not null ? _legacy.ResolveExactGenericArgsToken(dwExactGenericArgsTokenIndex, rawToken, pRetVal) : HResults.E_NOTIMPL; + + public int GetILCodeAndSig(ulong vmDomainAssembly, uint functionToken, DacDbiTargetBuffer* pTargetBuffer, uint* pLocalSigToken) + => _legacy is not null ? _legacy.GetILCodeAndSig(vmDomainAssembly, functionToken, pTargetBuffer, pLocalSigToken) : HResults.E_NOTIMPL; + + public int GetNativeCodeInfo(ulong vmDomainAssembly, uint functionToken, nint pJitManagerList) + => _legacy is not null ? _legacy.GetNativeCodeInfo(vmDomainAssembly, functionToken, pJitManagerList) : HResults.E_NOTIMPL; + + public int GetNativeCodeInfoForAddr(ulong codeAddress, nint pCodeInfo, ulong* pVmModule, uint* pFunctionToken) + => _legacy is not null ? _legacy.GetNativeCodeInfoForAddr(codeAddress, pCodeInfo, pVmModule, pFunctionToken) : HResults.E_NOTIMPL; + + public int IsValueType(ulong vmTypeHandle, int* pResult) + { + *pResult = 0; + int hr = HResults.S_OK; + try + { + Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + Contracts.TypeHandle th = rts.GetTypeHandle(new TargetPointer(vmTypeHandle)); + CorElementType corType = rts.GetSignatureCorElementType(th); + *pResult = corType == CorElementType.ValueType ? 1 : 0; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + int resultLocal; + int hrLocal = _legacy.IsValueType(vmTypeHandle, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int HasTypeParams(ulong vmTypeHandle, int* pResult) + { + *pResult = 0; + int hr = HResults.S_OK; + try + { + Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + Contracts.TypeHandle th = rts.GetTypeHandle(new TargetPointer(vmTypeHandle)); + *pResult = rts.HasTypeParam(th) ? 1 : 0; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + int resultLocal; + int hrLocal = _legacy.HasTypeParams(vmTypeHandle, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int GetClassInfo(ulong vmAppDomain, ulong thExact, nint pData) + => _legacy is not null ? _legacy.GetClassInfo(vmAppDomain, thExact, pData) : HResults.E_NOTIMPL; + + public int GetInstantiationFieldInfo(ulong vmDomainAssembly, ulong vmTypeHandle, ulong vmExactMethodTable, nint pFieldList, nuint* pObjectSize) + => _legacy is not null ? _legacy.GetInstantiationFieldInfo(vmDomainAssembly, vmTypeHandle, vmExactMethodTable, pFieldList, pObjectSize) : HResults.E_NOTIMPL; + + public int TypeHandleToExpandedTypeInfo(int boxed, ulong vmAppDomain, ulong vmTypeHandle, nint pData) + => _legacy is not null ? _legacy.TypeHandleToExpandedTypeInfo(boxed, vmAppDomain, vmTypeHandle, pData) : HResults.E_NOTIMPL; + + public int GetObjectExpandedTypeInfo(int boxed, ulong vmAppDomain, ulong addr, nint pTypeInfo) + => _legacy is not null ? _legacy.GetObjectExpandedTypeInfo(boxed, vmAppDomain, addr, pTypeInfo) : HResults.E_NOTIMPL; + + public int GetObjectExpandedTypeInfoFromID(int boxed, ulong vmAppDomain, COR_TYPEID id, nint pTypeInfo) + => _legacy is not null ? _legacy.GetObjectExpandedTypeInfoFromID(boxed, vmAppDomain, id, pTypeInfo) : HResults.E_NOTIMPL; + + public int GetTypeHandle(ulong vmModule, uint metadataToken, ulong* pRetVal) + => _legacy is not null ? _legacy.GetTypeHandle(vmModule, metadataToken, pRetVal) : HResults.E_NOTIMPL; + + public int GetApproxTypeHandle(nint pTypeData, ulong* pRetVal) + => _legacy is not null ? _legacy.GetApproxTypeHandle(pTypeData, pRetVal) : HResults.E_NOTIMPL; + + public int GetExactTypeHandle(nint pTypeData, nint pArgInfo, ulong* pVmTypeHandle) + => _legacy is not null ? _legacy.GetExactTypeHandle(pTypeData, pArgInfo, pVmTypeHandle) : HResults.E_NOTIMPL; + + public int GetMethodDescParams(ulong vmAppDomain, ulong vmMethodDesc, ulong genericsToken, uint* pcGenericClassTypeParams, nint pGenericTypeParams) + => _legacy is not null ? _legacy.GetMethodDescParams(vmAppDomain, vmMethodDesc, genericsToken, pcGenericClassTypeParams, pGenericTypeParams) : HResults.E_NOTIMPL; + + public int GetThreadStaticAddress(ulong vmField, ulong vmRuntimeThread, ulong* pRetVal) + => _legacy is not null ? _legacy.GetThreadStaticAddress(vmField, vmRuntimeThread, pRetVal) : HResults.E_NOTIMPL; + + public int GetCollectibleTypeStaticAddress(ulong vmField, ulong vmAppDomain, ulong* pRetVal) + => _legacy is not null ? _legacy.GetCollectibleTypeStaticAddress(vmField, vmAppDomain, pRetVal) : HResults.E_NOTIMPL; + + public int GetEnCHangingFieldInfo(nint pEnCFieldInfo, nint pFieldData, int* pfStatic) + => _legacy is not null ? _legacy.GetEnCHangingFieldInfo(pEnCFieldInfo, pFieldData, pfStatic) : HResults.E_NOTIMPL; + + public int GetTypeHandleParams(ulong vmAppDomain, ulong vmTypeHandle, nint pParams) + => _legacy is not null ? _legacy.GetTypeHandleParams(vmAppDomain, vmTypeHandle, pParams) : HResults.E_NOTIMPL; + + public int GetSimpleType(ulong vmAppDomain, int simpleType, uint* pMetadataToken, ulong* pVmModule, ulong* pVmDomainAssembly) + => _legacy is not null ? _legacy.GetSimpleType(vmAppDomain, simpleType, pMetadataToken, pVmModule, pVmDomainAssembly) : HResults.E_NOTIMPL; + + public int IsExceptionObject(ulong vmObject, int* pResult) + => _legacy is not null ? _legacy.IsExceptionObject(vmObject, pResult) : HResults.E_NOTIMPL; + + public int GetStackFramesFromException(ulong vmObject, nint pDacStackFrames) + => _legacy is not null ? _legacy.GetStackFramesFromException(vmObject, pDacStackFrames) : HResults.E_NOTIMPL; + + public int IsRcw(ulong vmObject, int* pResult) + => _legacy is not null ? _legacy.IsRcw(vmObject, pResult) : HResults.E_NOTIMPL; + + public int GetRcwCachedInterfaceTypes(ulong vmObject, ulong vmAppDomain, int bIInspectableOnly, nint pDacInterfaces) + => _legacy is not null ? _legacy.GetRcwCachedInterfaceTypes(vmObject, vmAppDomain, bIInspectableOnly, pDacInterfaces) : HResults.E_NOTIMPL; + + public int GetRcwCachedInterfacePointers(ulong vmObject, int bIInspectableOnly, nint pDacItfPtrs) + => _legacy is not null ? _legacy.GetRcwCachedInterfacePointers(vmObject, bIInspectableOnly, pDacItfPtrs) : HResults.E_NOTIMPL; + + public int GetCachedWinRTTypesForIIDs(ulong vmAppDomain, nint pIids, nint pTypes) + => _legacy is not null ? _legacy.GetCachedWinRTTypesForIIDs(vmAppDomain, pIids, pTypes) : HResults.E_NOTIMPL; + + public int GetCachedWinRTTypes(ulong vmAppDomain, nint piids, nint pTypes) + => _legacy is not null ? _legacy.GetCachedWinRTTypes(vmAppDomain, piids, pTypes) : HResults.E_NOTIMPL; + + public int GetTypedByRefInfo(ulong pTypedByRef, ulong vmAppDomain, nint pObjectData) + => _legacy is not null ? _legacy.GetTypedByRefInfo(pTypedByRef, vmAppDomain, pObjectData) : HResults.E_NOTIMPL; + + public int GetStringData(ulong objectAddress, nint pObjectData) + => _legacy is not null ? _legacy.GetStringData(objectAddress, pObjectData) : HResults.E_NOTIMPL; + + public int GetArrayData(ulong objectAddress, nint pObjectData) + => _legacy is not null ? _legacy.GetArrayData(objectAddress, pObjectData) : HResults.E_NOTIMPL; + + public int GetBasicObjectInfo(ulong objectAddress, int type, ulong vmAppDomain, nint pObjectData) + => _legacy is not null ? _legacy.GetBasicObjectInfo(objectAddress, type, vmAppDomain, pObjectData) : HResults.E_NOTIMPL; + + public int TestCrst(ulong vmCrst) + => _legacy is not null ? _legacy.TestCrst(vmCrst) : HResults.E_NOTIMPL; + + public int TestRWLock(ulong vmRWLock) + => _legacy is not null ? _legacy.TestRWLock(vmRWLock) : HResults.E_NOTIMPL; + + public int GetDebuggerControlBlockAddress(ulong* pRetVal) + => _legacy is not null ? _legacy.GetDebuggerControlBlockAddress(pRetVal) : HResults.E_NOTIMPL; + + public int GetObjectFromRefPtr(ulong ptr, ulong* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + *pRetVal = _target.ReadPointer(new TargetPointer(ptr)).Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetObjectFromRefPtr(ptr, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}"); + } +#endif + return hr; + } + + public int GetObject(ulong ptr, ulong* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + TargetPointer objRef = _target.ReadPointer(new TargetPointer(ptr)); + if (objRef == TargetPointer.Null) + throw new ArgumentException(null, nameof(ptr)); + *pRetVal = objRef.Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetObject(ptr, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}"); + } +#endif + return hr; + } + + public int EnableNGENPolicy(int ePolicy) + { + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + int hrLocal = _legacy.EnableNGENPolicy(ePolicy); + Debug.ValidateHResult(hr, hrLocal); + } +#endif + return hr; + } + + public int SetNGENCompilerFlags(uint dwFlags) + => _legacy is not null ? _legacy.SetNGENCompilerFlags(dwFlags) : HResults.E_NOTIMPL; + + public int GetNGENCompilerFlags(uint* pdwFlags) + => _legacy is not null ? _legacy.GetNGENCompilerFlags(pdwFlags) : HResults.E_NOTIMPL; + + public int GetVmObjectHandle(ulong handleAddress, ulong* pRetVal) + { + *pRetVal = handleAddress; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetVmObjectHandle(handleAddress, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}"); + } +#endif + return hr; + } + + public int IsVmObjectHandleValid(ulong vmHandle, int* pResult) + { + *pResult = 0; + int hr = HResults.S_OK; + try + { + TargetPointer obj = _target.ReadPointer(new TargetPointer(vmHandle)); + *pResult = obj != TargetPointer.Null ? 1 : 0; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + int resultLocal; + int hrLocal = _legacy.IsVmObjectHandleValid(vmHandle, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int IsWinRTModule(ulong vmModule, int* isWinRT) + { + *isWinRT = 0; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + int isWinRTLocal; + int hrLocal = _legacy.IsWinRTModule(vmModule, &isWinRTLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*isWinRT == isWinRTLocal, $"cDAC: {*isWinRT}, DAC: {isWinRTLocal}"); + } +#endif + return hr; + } + + public int GetAppDomainIdFromVmObjectHandle(ulong vmHandle, uint* pRetVal) + { + *pRetVal = vmHandle == 0 ? 0u : 1u; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + uint retValLocal; + int hrLocal = _legacy.GetAppDomainIdFromVmObjectHandle(vmHandle, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal}, DAC: {retValLocal}"); + } +#endif + return hr; + } + + public int GetHandleAddressFromVmHandle(ulong vmHandle, ulong* pRetVal) + { + *pRetVal = vmHandle; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetHandleAddressFromVmHandle(vmHandle, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal:x}, DAC: {retValLocal:x}"); + } +#endif + return hr; + } + + public int GetObjectContents(ulong obj, DacDbiTargetBuffer* pRetVal) + => _legacy is not null ? _legacy.GetObjectContents(obj, pRetVal) : HResults.E_NOTIMPL; + + public int GetThreadOwningMonitorLock(ulong vmObject, DacDbiMonitorLockInfo* pRetVal) + => _legacy is not null ? _legacy.GetThreadOwningMonitorLock(vmObject, pRetVal) : HResults.E_NOTIMPL; + + public int EnumerateMonitorEventWaitList(ulong vmObject, nint fpCallback, nint pUserData) + => _legacy is not null ? _legacy.EnumerateMonitorEventWaitList(vmObject, fpCallback, pUserData) : HResults.E_NOTIMPL; + + public int GetAttachStateFlags(int* pRetVal) + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + *pRetVal = _target.Contracts.Debugger.GetAttachStateFlags(); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + int resultLocal; + int hrLocal = _legacy.GetAttachStateFlags(&resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == resultLocal); + } +#endif + + return hr; + } + + public int GetMetaDataFileInfoFromPEFile(ulong vmPEAssembly, uint* dwTimeStamp, uint* dwImageSize, IStringHolder pStrFilename, Interop.BOOL* pResult) + => _legacy is not null ? _legacy.GetMetaDataFileInfoFromPEFile(vmPEAssembly, dwTimeStamp, dwImageSize, pStrFilename, pResult) : HResults.E_NOTIMPL; + + public int IsThreadSuspendedOrHijacked(ulong vmThread, Interop.BOOL* pResult) + => _legacy is not null ? _legacy.IsThreadSuspendedOrHijacked(vmThread, pResult) : HResults.E_NOTIMPL; + + public int AreGCStructuresValid(Interop.BOOL* pResult) + { + // Native DacDbiInterfaceImpl::AreGCStructuresValid always returns TRUE. + // DacDbi callers assume the runtime is suspended, so GC structures are always valid. + *pResult = Interop.BOOL.TRUE; + int hr = HResults.S_OK; +#if DEBUG + if (_legacy is not null) + { + Interop.BOOL resultLocal; + int hrLocal = _legacy.AreGCStructuresValid(&resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int CreateHeapWalk(nuint* pHandle) + => _legacy is not null ? _legacy.CreateHeapWalk(pHandle) : HResults.E_NOTIMPL; + + public int DeleteHeapWalk(nuint handle) + => _legacy is not null ? _legacy.DeleteHeapWalk(handle) : HResults.E_NOTIMPL; + + public int WalkHeap(nuint handle, uint count, COR_HEAPOBJECT* objects, uint* fetched) + => _legacy is not null ? _legacy.WalkHeap(handle, count, objects, fetched) : HResults.E_NOTIMPL; + + public int GetHeapSegments(nint pSegments) + => _legacy is not null ? _legacy.GetHeapSegments(pSegments) : HResults.E_NOTIMPL; + + public int IsValidObject(ulong obj, Interop.BOOL* pResult) + => _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL; + + public int GetAppDomainForObject(ulong obj, ulong* pApp, ulong* pModule, ulong* pDomainAssembly, Interop.BOOL* pResult) + => _legacy is not null ? _legacy.GetAppDomainForObject(obj, pApp, pModule, pDomainAssembly, pResult) : HResults.E_NOTIMPL; + + public int CreateRefWalk(nuint* pHandle, int walkStacks, int walkFQ, uint handleWalkMask) + => _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL; + + public int DeleteRefWalk(nuint handle) + => _legacy is not null ? _legacy.DeleteRefWalk(handle) : HResults.E_NOTIMPL; + + public int WalkRefs(nuint handle, uint count, nint refs, uint* pFetched) + => _legacy is not null ? _legacy.WalkRefs(handle, count, refs, pFetched) : HResults.E_NOTIMPL; + + public int GetTypeID(ulong obj, COR_TYPEID* pType) + { + *pType = default; + int hr = HResults.S_OK; + try + { + TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj)); + pType->token1 = mt.Value; + pType->token2 = 0; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + COR_TYPEID resultLocal; + int hrLocal = _legacy.GetTypeID(obj, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(pType->token1 == resultLocal.token1); + Debug.Assert(pType->token2 == resultLocal.token2); + } + } +#endif + + return hr; + } + + public int GetTypeIDForType(ulong vmTypeHandle, COR_TYPEID* pId) + { + *pId = default; + int hr = HResults.S_OK; + try + { + pId->token1 = vmTypeHandle; + pId->token2 = 0; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + COR_TYPEID resultLocal; + int hrLocal = _legacy.GetTypeIDForType(vmTypeHandle, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(pId->token1 == resultLocal.token1); + Debug.Assert(pId->token2 == resultLocal.token2); + } + } +#endif + + return hr; + } + + public int GetObjectFields(nint id, uint celt, COR_FIELD* layout, uint* pceltFetched) + => _legacy is not null ? _legacy.GetObjectFields(id, celt, layout, pceltFetched) : HResults.E_NOTIMPL; + + public int GetTypeLayout(nint id, COR_TYPE_LAYOUT* pLayout) + => _legacy is not null ? _legacy.GetTypeLayout(id, pLayout) : HResults.E_NOTIMPL; + + public int GetArrayLayout(nint id, nint pLayout) + => _legacy is not null ? _legacy.GetArrayLayout(id, pLayout) : HResults.E_NOTIMPL; + + public int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo) + { + *pHeapInfo = default; + int hr = HResults.S_OK; + try + { + Contracts.IGC gc = _target.Contracts.GC; + pHeapInfo->areGCStructuresValid = gc.GetGCStructuresValid() ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + pHeapInfo->numHeaps = gc.GetGCHeapCount(); + pHeapInfo->pointerSize = (uint)_target.PointerSize; + + string[] identifiers = gc.GetGCIdentifiers(); + bool isServer = System.Array.Exists(identifiers, static id => id == "server"); + pHeapInfo->gcType = isServer ? 1 : 0; // CorDebugServerGC = 1, CorDebugWorkstationGC = 0 + pHeapInfo->concurrent = System.Array.Exists(identifiers, static id => id == "background") ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + COR_HEAPINFO resultLocal; + int hrLocal = _legacy.GetGCHeapInformation(&resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(pHeapInfo->areGCStructuresValid == resultLocal.areGCStructuresValid); + Debug.Assert(pHeapInfo->numHeaps == resultLocal.numHeaps); + Debug.Assert(pHeapInfo->pointerSize == resultLocal.pointerSize); + Debug.Assert(pHeapInfo->gcType == resultLocal.gcType); + } + } +#endif + + return hr; + } + + public int GetPEFileMDInternalRW(ulong vmPEAssembly, ulong* pAddrMDInternalRW) + => _legacy is not null ? _legacy.GetPEFileMDInternalRW(vmPEAssembly, pAddrMDInternalRW) : HResults.E_NOTIMPL; + + public int GetReJitInfo(ulong vmModule, uint methodTk, ulong* pReJitInfo) + => _legacy is not null ? _legacy.GetReJitInfo(vmModule, methodTk, pReJitInfo) : HResults.E_NOTIMPL; + + public int GetReJitInfoByCodeStartAddr(ulong vmMethod, ulong codeStartAddress, ulong* pReJitInfo) + => _legacy is not null ? _legacy.GetReJitInfoByCodeStartAddr(vmMethod, codeStartAddress, pReJitInfo) : HResults.E_NOTIMPL; + + public int GetSharedReJitInfo(ulong vmReJitInfo, ulong* pSharedReJitInfo) + => _legacy is not null ? _legacy.GetSharedReJitInfo(vmReJitInfo, pSharedReJitInfo) : HResults.E_NOTIMPL; + + public int GetSharedReJitInfoData(ulong sharedReJitInfo, DacDbiSharedReJitInfo* pData) + => _legacy is not null ? _legacy.GetSharedReJitInfoData(sharedReJitInfo, pData) : HResults.E_NOTIMPL; + + public int AreOptimizationsDisabled(ulong vmModule, uint methodTk, int* pOptimizationsDisabled) + => _legacy is not null ? _legacy.AreOptimizationsDisabled(vmModule, methodTk, pOptimizationsDisabled) : HResults.E_NOTIMPL; + + public int GetDefinesBitField(uint* pDefines) + { + *pDefines = 0; + int hr = HResults.S_OK; + try + { + *pDefines = _target.Contracts.Debugger.GetDefinesBitField(); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + uint resultLocal; + int hrLocal = _legacy.GetDefinesBitField(&resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pDefines == resultLocal); + } +#endif + + return hr; + } + + public int GetMDStructuresVersion(uint* pMDStructuresVersion) + { + *pMDStructuresVersion = 0; + int hr = HResults.S_OK; + try + { + *pMDStructuresVersion = _target.Contracts.Debugger.GetMDStructuresVersion(); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + uint resultLocal; + int hrLocal = _legacy.GetMDStructuresVersion(&resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pMDStructuresVersion == resultLocal); + } +#endif + + return hr; + } + + public int GetActiveRejitILCodeVersionNode(ulong vmModule, uint methodTk, ulong* pVmILCodeVersionNode) + => _legacy is not null ? _legacy.GetActiveRejitILCodeVersionNode(vmModule, methodTk, pVmILCodeVersionNode) : HResults.E_NOTIMPL; + + public int GetNativeCodeVersionNode(ulong vmMethod, ulong codeStartAddress, ulong* pVmNativeCodeVersionNode) + => _legacy is not null ? _legacy.GetNativeCodeVersionNode(vmMethod, codeStartAddress, pVmNativeCodeVersionNode) : HResults.E_NOTIMPL; + + public int GetILCodeVersionNode(ulong vmNativeCodeVersionNode, ulong* pVmILCodeVersionNode) + => _legacy is not null ? _legacy.GetILCodeVersionNode(vmNativeCodeVersionNode, pVmILCodeVersionNode) : HResults.E_NOTIMPL; + + public int GetILCodeVersionNodeData(ulong ilCodeVersionNode, DacDbiSharedReJitInfo* pData) + => _legacy is not null ? _legacy.GetILCodeVersionNodeData(ilCodeVersionNode, pData) : HResults.E_NOTIMPL; + + public int EnableGCNotificationEvents(int fEnable) + => _legacy is not null ? _legacy.EnableGCNotificationEvents(fEnable) : HResults.E_NOTIMPL; + + public int IsDelegate(ulong vmObject, int* pResult) + => _legacy is not null ? _legacy.IsDelegate(vmObject, pResult) : HResults.E_NOTIMPL; + + public int GetDelegateType(ulong delegateObject, int* delegateType) + => _legacy is not null ? _legacy.GetDelegateType(delegateObject, delegateType) : HResults.E_NOTIMPL; + + public int GetDelegateFunctionData(int delegateType, ulong delegateObject, ulong* ppFunctionDomainAssembly, uint* pMethodDef) + => _legacy is not null ? _legacy.GetDelegateFunctionData(delegateType, delegateObject, ppFunctionDomainAssembly, pMethodDef) : HResults.E_NOTIMPL; + + public int GetDelegateTargetObject(int delegateType, ulong delegateObject, ulong* ppTargetObj, ulong* ppTargetAppDomain) + => _legacy is not null ? _legacy.GetDelegateTargetObject(delegateType, delegateObject, ppTargetObj, ppTargetAppDomain) : HResults.E_NOTIMPL; + + public int GetLoaderHeapMemoryRanges(nint pRanges) + => _legacy is not null ? _legacy.GetLoaderHeapMemoryRanges(pRanges) : HResults.E_NOTIMPL; + + public int IsModuleMapped(ulong pModule, int* isModuleMapped) + => _legacy is not null ? _legacy.IsModuleMapped(pModule, isModuleMapped) : HResults.E_NOTIMPL; + + public int MetadataUpdatesApplied(Interop.BOOL* pResult) + { + *pResult = Interop.BOOL.FALSE; + int hr = HResults.S_OK; + try + { + *pResult = _target.Contracts.Debugger.MetadataUpdatesApplied() ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + Interop.BOOL resultLocal; + int hrLocal = _legacy.MetadataUpdatesApplied(&resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal); + } +#endif + + return hr; + } + + public int GetDomainAssemblyFromModule(ulong vmModule, ulong* pVmDomainAssembly) + { + *pVmDomainAssembly = 0; + int hr = HResults.S_OK; + try + { + // In modern .NET, Module and DomainAssembly are the same object + *pVmDomainAssembly = vmModule; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong daLocal; + int hrLocal = _legacy.GetDomainAssemblyFromModule(vmModule, &daLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pVmDomainAssembly == daLocal, $"cDAC: {*pVmDomainAssembly:x}, DAC: {daLocal:x}"); + } +#endif + return hr; + } + + public int ParseContinuation(ulong continuationAddress, ulong* pDiagnosticIP, ulong* pNextContinuation, uint* pState) + => _legacy is not null ? _legacy.ParseContinuation(continuationAddress, pDiagnosticIP, pNextContinuation, pState) : HResults.E_NOTIMPL; + + public int GetAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, nint pAsyncLocals) + => _legacy is not null ? _legacy.GetAsyncLocals(vmMethod, codeAddr, state, pAsyncLocals) : HResults.E_NOTIMPL; + + public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) + => _legacy is not null ? _legacy.GetGenericArgTokenIndex(vmMethod, pIndex) : HResults.E_NOTIMPL; +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs new file mode 100644 index 00000000000000..9c6b5f6ba81c9c --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -0,0 +1,631 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Microsoft.Diagnostics.DataContractReader.Legacy; + +[StructLayout(LayoutKind.Sequential)] +public struct DbiVersion +{ + public uint m_dwFormat; + public uint m_dwDbiVersion; + public uint m_dwProtocolBreakingChangeCounter; + public uint m_dwReservedMustBeZero1; +} + +[StructLayout(LayoutKind.Sequential)] +public struct COR_TYPEID +{ + public ulong token1; + public ulong token2; +} + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiTargetBuffer +{ + public ulong pAddress; + public uint cbSize; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiDomainAssemblyInfo +{ + public ulong vmAppDomain; + public ulong vmDomainAssembly; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiModuleInfo +{ + public ulong vmAssembly; + public ulong pPEBaseAddress; + public ulong vmPEAssembly; + public uint nPESize; + public Interop.BOOL fIsDynamic; + public Interop.BOOL fInMemory; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiMonitorLockInfo +{ + public ulong lockOwner; + public uint acquisitionCount; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiThreadAllocInfo +{ + public ulong allocBytesSOH; + public ulong allocBytesUOH; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiTypeRefData +{ + public ulong vmDomainAssembly; + public uint typeToken; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiSharedReJitInfo +{ + public uint state; + public ulong pbIL; + public uint dwCodegenFlags; + public uint cInstrumentedMapEntries; + public ulong rgInstrumentedMapEntries; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DacDbiExceptionCallStackData +{ + public ulong vmAppDomain; + public ulong vmDomainAssembly; + public ulong ip; + public uint methodDef; + public Interop.BOOL isLastForeignExceptionFrame; +} + +[StructLayout(LayoutKind.Sequential)] +public struct COR_HEAPINFO +{ + public Interop.BOOL areGCStructuresValid; + public uint pointerSize; + public uint numHeaps; + public Interop.BOOL concurrent; + public int gcType; +} + +[StructLayout(LayoutKind.Sequential)] +public struct COR_HEAPOBJECT +{ + public ulong address; + public ulong size; + public COR_TYPEID type; +} + +[StructLayout(LayoutKind.Sequential)] +public struct COR_SEGMENT +{ + public ulong start; + public ulong end; + public int type; + public uint heap; +} + +[StructLayout(LayoutKind.Sequential)] +public struct COR_TYPE_LAYOUT +{ + public COR_TYPEID parentID; + public uint objectSize; + public uint numFields; + public uint boxOffset; + public int type; +} + +[StructLayout(LayoutKind.Sequential)] +public struct COR_FIELD +{ + public uint token; + public uint offset; + public COR_TYPEID id; + public int fieldType; +} + +#pragma warning restore CS0649 + +// Name-surface projection of IDacDbiInterface in native method order for COM binding validation. +// Parameter shapes are intentionally coarse placeholders and will be refined with method implementation work. +[GeneratedComInterface] +[Guid("B7A6D3F5-6B46-4DD4-8AF1-0D4A2AFB98C1")] +public unsafe partial interface IDacDbiInterface +{ + [PreserveSig] + int CheckDbiVersion(DbiVersion* pVersion); + + [PreserveSig] + int FlushCache(); + + [PreserveSig] + int DacSetTargetConsistencyChecks(Interop.BOOL fEnableAsserts); + + [PreserveSig] + int IsLeftSideInitialized(int* pResult); + + [PreserveSig] + int GetAppDomainFromId(uint appdomainId, ulong* pRetVal); + + [PreserveSig] + int GetAppDomainId(ulong vmAppDomain, uint* pRetVal); + + [PreserveSig] + int GetAppDomainObject(ulong vmAppDomain, ulong* pRetVal); + + [PreserveSig] + int GetAssemblyFromDomainAssembly(ulong vmDomainAssembly, ulong* vmAssembly); + + [PreserveSig] + int IsAssemblyFullyTrusted(ulong vmDomainAssembly, int* pResult); + + [PreserveSig] + int GetAppDomainFullName(ulong vmAppDomain, IStringHolder pStrName); + + [PreserveSig] + int GetModuleSimpleName(ulong vmModule, IStringHolder pStrFilename); + + [PreserveSig] + int GetAssemblyPath(ulong vmAssembly, IStringHolder pStrFilename, int* pResult); + + [PreserveSig] + int ResolveTypeReference(DacDbiTypeRefData* pTypeRefInfo, DacDbiTypeRefData* pTargetRefInfo); + + [PreserveSig] + int GetModulePath(ulong vmModule, IStringHolder pStrFilename, int* pResult); + + [PreserveSig] + int GetMetadata(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer); + + [PreserveSig] + int GetSymbolsBuffer(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer, int* pSymbolFormat); + + [PreserveSig] + int GetModuleData(ulong vmModule, DacDbiModuleInfo* pData); + + [PreserveSig] + int GetDomainAssemblyData(ulong vmDomainAssembly, DacDbiDomainAssemblyInfo* pData); + + [PreserveSig] + int GetModuleForDomainAssembly(ulong vmDomainAssembly, ulong* pModule); + + [PreserveSig] + int GetAddressType(ulong address, int* pRetVal); + + [PreserveSig] + int IsTransitionStub(ulong address, int* pResult); + + [PreserveSig] + int GetCompilerFlags(ulong vmDomainAssembly, int* pfAllowJITOpts, int* pfEnableEnC); + + [PreserveSig] + int SetCompilerFlags(ulong vmDomainAssembly, int fAllowJitOpts, int fEnableEnC); + + [PreserveSig] + int EnumerateAppDomains(nint fpCallback, nint pUserData); + + [PreserveSig] + int EnumerateAssembliesInAppDomain(ulong vmAppDomain, nint fpCallback, nint pUserData); + + [PreserveSig] + int EnumerateModulesInAssembly(ulong vmAssembly, nint fpCallback, nint pUserData); + + [PreserveSig] + int RequestSyncAtEvent(); + + [PreserveSig] + int SetSendExceptionsOutsideOfJMC(int sendExceptionsOutsideOfJMC); + + [PreserveSig] + int MarkDebuggerAttachPending(); + + [PreserveSig] + int MarkDebuggerAttached(int fAttached); + + [PreserveSig] + int Hijack(ulong vmThread, uint dwThreadId, nint pRecord, nint pOriginalContext, uint cbSizeContext, int reason, nint pUserData, ulong* pRemoteContextAddr); + + [PreserveSig] + int EnumerateThreads(nint fpCallback, nint pUserData); + + [PreserveSig] + int IsThreadMarkedDead(ulong vmThread, Interop.BOOL* pResult); + + [PreserveSig] + int GetThreadHandle(ulong vmThread, nint pRetVal); + + [PreserveSig] + int GetThreadObject(ulong vmThread, ulong* pRetVal); + + [PreserveSig] + int GetThreadAllocInfo(ulong vmThread, DacDbiThreadAllocInfo* pThreadAllocInfo); + + [PreserveSig] + int SetDebugState(ulong vmThread, int debugState); + + [PreserveSig] + int HasUnhandledException(ulong vmThread, int* pResult); + + [PreserveSig] + int GetUserState(ulong vmThread, int* pRetVal); + + [PreserveSig] + int GetPartialUserState(ulong vmThread, int* pRetVal); + + [PreserveSig] + int GetConnectionID(ulong vmThread, uint* pRetVal); + + [PreserveSig] + int GetTaskID(ulong vmThread, ulong* pRetVal); + + [PreserveSig] + int TryGetVolatileOSThreadID(ulong vmThread, uint* pRetVal); + + [PreserveSig] + int GetUniqueThreadID(ulong vmThread, uint* pRetVal); + + [PreserveSig] + int GetCurrentException(ulong vmThread, ulong* pRetVal); + + [PreserveSig] + int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal); + + [PreserveSig] + int GetCurrentCustomDebuggerNotification(ulong vmThread, ulong* pRetVal); + + [PreserveSig] + int GetCurrentAppDomain(ulong* pRetVal); + + [PreserveSig] + int ResolveAssembly(ulong vmScope, uint tkAssemblyRef, ulong* pRetVal); + + [PreserveSig] + int GetNativeCodeSequencePointsAndVarInfo(ulong vmMethodDesc, ulong startAddress, int fCodeAvailable, nint pNativeVarData, nint pSequencePoints); + + [PreserveSig] + int GetManagedStoppedContext(ulong vmThread, ulong* pRetVal); + + [PreserveSig] + int CreateStackWalk(ulong vmThread, nint pInternalContextBuffer, nuint* ppSFIHandle); + + [PreserveSig] + int DeleteStackWalk(nuint ppSFIHandle); + + [PreserveSig] + int GetStackWalkCurrentContext(nuint pSFIHandle, nint pContext); + + [PreserveSig] + int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, nint pContext); + + [PreserveSig] + int UnwindStackWalkFrame(nuint pSFIHandle, int* pResult); + + [PreserveSig] + int CheckContext(ulong vmThread, nint pContext); + + [PreserveSig] + int GetStackWalkCurrentFrameInfo(nuint pSFIHandle, nint pFrameData, int* pRetVal); + + [PreserveSig] + int GetCountOfInternalFrames(ulong vmThread, uint* pRetVal); + + [PreserveSig] + int EnumerateInternalFrames(ulong vmThread, nint fpCallback, nint pUserData); + + [PreserveSig] + int IsMatchingParentFrame(ulong fpToCheck, ulong fpParent, int* pResult); + + [PreserveSig] + int GetStackParameterSize(ulong controlPC, uint* pRetVal); + + [PreserveSig] + int GetFramePointer(nuint pSFIHandle, ulong* pRetVal); + + [PreserveSig] + int IsLeafFrame(ulong vmThread, nint pContext, int* pResult); + + [PreserveSig] + int GetContext(ulong vmThread, nint pContextBuffer); + + [PreserveSig] + int ConvertContextToDebuggerRegDisplay(nint pInContext, nint pOutDRD, int fActive); + + [PreserveSig] + int IsDiagnosticsHiddenOrLCGMethod(ulong vmMethodDesc, int* pRetVal); + + [PreserveSig] + int GetVarArgSig(ulong VASigCookieAddr, ulong* pArgBase, DacDbiTargetBuffer* pRetVal); + + [PreserveSig] + int RequiresAlign8(ulong thExact, int* pResult); + + [PreserveSig] + int ResolveExactGenericArgsToken(uint dwExactGenericArgsTokenIndex, ulong rawToken, ulong* pRetVal); + + [PreserveSig] + int GetILCodeAndSig(ulong vmDomainAssembly, uint functionToken, DacDbiTargetBuffer* pTargetBuffer, uint* pLocalSigToken); + + [PreserveSig] + int GetNativeCodeInfo(ulong vmDomainAssembly, uint functionToken, nint pJitManagerList); + + [PreserveSig] + int GetNativeCodeInfoForAddr(ulong codeAddress, nint pCodeInfo, ulong* pVmModule, uint* pFunctionToken); + + [PreserveSig] + int IsValueType(ulong vmTypeHandle, int* pResult); + + [PreserveSig] + int HasTypeParams(ulong vmTypeHandle, int* pResult); + + [PreserveSig] + int GetClassInfo(ulong vmAppDomain, ulong thExact, nint pData); + + [PreserveSig] + int GetInstantiationFieldInfo(ulong vmDomainAssembly, ulong vmTypeHandle, ulong vmExactMethodTable, nint pFieldList, nuint* pObjectSize); + + [PreserveSig] + int TypeHandleToExpandedTypeInfo(int boxed, ulong vmAppDomain, ulong vmTypeHandle, nint pData); + + [PreserveSig] + int GetObjectExpandedTypeInfo(int boxed, ulong vmAppDomain, ulong addr, nint pTypeInfo); + + [PreserveSig] + int GetObjectExpandedTypeInfoFromID(int boxed, ulong vmAppDomain, COR_TYPEID id, nint pTypeInfo); + + [PreserveSig] + int GetTypeHandle(ulong vmModule, uint metadataToken, ulong* pRetVal); + + [PreserveSig] + int GetApproxTypeHandle(nint pTypeData, ulong* pRetVal); + + [PreserveSig] + int GetExactTypeHandle(nint pTypeData, nint pArgInfo, ulong* pVmTypeHandle); + + [PreserveSig] + int GetMethodDescParams(ulong vmAppDomain, ulong vmMethodDesc, ulong genericsToken, uint* pcGenericClassTypeParams, nint pGenericTypeParams); + + [PreserveSig] + int GetThreadStaticAddress(ulong vmField, ulong vmRuntimeThread, ulong* pRetVal); + + [PreserveSig] + int GetCollectibleTypeStaticAddress(ulong vmField, ulong vmAppDomain, ulong* pRetVal); + + [PreserveSig] + int GetEnCHangingFieldInfo(nint pEnCFieldInfo, nint pFieldData, int* pfStatic); + + [PreserveSig] + int GetTypeHandleParams(ulong vmAppDomain, ulong vmTypeHandle, nint pParams); + + [PreserveSig] + int GetSimpleType(ulong vmAppDomain, int simpleType, uint* pMetadataToken, ulong* pVmModule, ulong* pVmDomainAssembly); + + [PreserveSig] + int IsExceptionObject(ulong vmObject, int* pResult); + + [PreserveSig] + int GetStackFramesFromException(ulong vmObject, nint pDacStackFrames); + + [PreserveSig] + int IsRcw(ulong vmObject, int* pResult); + + [PreserveSig] + int GetRcwCachedInterfaceTypes(ulong vmObject, ulong vmAppDomain, int bIInspectableOnly, nint pDacInterfaces); + + [PreserveSig] + int GetRcwCachedInterfacePointers(ulong vmObject, int bIInspectableOnly, nint pDacItfPtrs); + + [PreserveSig] + int GetCachedWinRTTypesForIIDs(ulong vmAppDomain, nint pIids, nint pTypes); + + [PreserveSig] + int GetCachedWinRTTypes(ulong vmAppDomain, nint piids, nint pTypes); + + [PreserveSig] + int GetTypedByRefInfo(ulong pTypedByRef, ulong vmAppDomain, nint pObjectData); + + [PreserveSig] + int GetStringData(ulong objectAddress, nint pObjectData); + + [PreserveSig] + int GetArrayData(ulong objectAddress, nint pObjectData); + + [PreserveSig] + int GetBasicObjectInfo(ulong objectAddress, int type, ulong vmAppDomain, nint pObjectData); + + [PreserveSig] + int TestCrst(ulong vmCrst); + + [PreserveSig] + int TestRWLock(ulong vmRWLock); + + [PreserveSig] + int GetDebuggerControlBlockAddress(ulong* pRetVal); + + [PreserveSig] + int GetObjectFromRefPtr(ulong ptr, ulong* pRetVal); + + [PreserveSig] + int GetObject(ulong ptr, ulong* pRetVal); + + [PreserveSig] + int EnableNGENPolicy(int ePolicy); + + [PreserveSig] + int SetNGENCompilerFlags(uint dwFlags); + + [PreserveSig] + int GetNGENCompilerFlags(uint* pdwFlags); + + [PreserveSig] + int GetVmObjectHandle(ulong handleAddress, ulong* pRetVal); + + [PreserveSig] + int IsVmObjectHandleValid(ulong vmHandle, int* pResult); + + [PreserveSig] + int IsWinRTModule(ulong vmModule, int* isWinRT); + + [PreserveSig] + int GetAppDomainIdFromVmObjectHandle(ulong vmHandle, uint* pRetVal); + + [PreserveSig] + int GetHandleAddressFromVmHandle(ulong vmHandle, ulong* pRetVal); + + [PreserveSig] + int GetObjectContents(ulong obj, DacDbiTargetBuffer* pRetVal); + + [PreserveSig] + int GetThreadOwningMonitorLock(ulong vmObject, DacDbiMonitorLockInfo* pRetVal); + + [PreserveSig] + int EnumerateMonitorEventWaitList(ulong vmObject, nint fpCallback, nint pUserData); + + [PreserveSig] + int GetAttachStateFlags(int* pRetVal); + + [PreserveSig] + int GetMetaDataFileInfoFromPEFile(ulong vmPEAssembly, uint* dwTimeStamp, uint* dwImageSize, IStringHolder pStrFilename, Interop.BOOL* pResult); + + [PreserveSig] + int IsThreadSuspendedOrHijacked(ulong vmThread, Interop.BOOL* pResult); + + [PreserveSig] + int AreGCStructuresValid(Interop.BOOL* pResult); + + [PreserveSig] + int CreateHeapWalk(nuint* pHandle); + + [PreserveSig] + int DeleteHeapWalk(nuint handle); + + [PreserveSig] + int WalkHeap(nuint handle, uint count, COR_HEAPOBJECT* objects, uint* fetched); + + [PreserveSig] + int GetHeapSegments(nint pSegments); + + [PreserveSig] + int IsValidObject(ulong obj, Interop.BOOL* pResult); + + [PreserveSig] + int GetAppDomainForObject(ulong obj, ulong* pApp, ulong* pModule, ulong* pDomainAssembly, Interop.BOOL* pResult); + + [PreserveSig] + int CreateRefWalk(nuint* pHandle, int walkStacks, int walkFQ, uint handleWalkMask); + + [PreserveSig] + int DeleteRefWalk(nuint handle); + + [PreserveSig] + int WalkRefs(nuint handle, uint count, nint refs, uint* pFetched); + + [PreserveSig] + int GetTypeID(ulong obj, COR_TYPEID* pType); + + [PreserveSig] + int GetTypeIDForType(ulong vmTypeHandle, COR_TYPEID* pId); + + [PreserveSig] + int GetObjectFields(nint id, uint celt, COR_FIELD* layout, uint* pceltFetched); + + [PreserveSig] + int GetTypeLayout(nint id, COR_TYPE_LAYOUT* pLayout); + + [PreserveSig] + int GetArrayLayout(nint id, nint pLayout); + + [PreserveSig] + int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo); + + [PreserveSig] + int GetPEFileMDInternalRW(ulong vmPEAssembly, ulong* pAddrMDInternalRW); + + [PreserveSig] + int GetReJitInfo(ulong vmModule, uint methodTk, ulong* pReJitInfo); + + [PreserveSig] + int GetReJitInfoByCodeStartAddr(ulong vmMethod, ulong codeStartAddress, ulong* pReJitInfo); + + [PreserveSig] + int GetSharedReJitInfo(ulong vmReJitInfo, ulong* pSharedReJitInfo); + + [PreserveSig] + int GetSharedReJitInfoData(ulong sharedReJitInfo, DacDbiSharedReJitInfo* pData); + + [PreserveSig] + int AreOptimizationsDisabled(ulong vmModule, uint methodTk, int* pOptimizationsDisabled); + + [PreserveSig] + int GetDefinesBitField(uint* pDefines); + + [PreserveSig] + int GetMDStructuresVersion(uint* pMDStructuresVersion); + + [PreserveSig] + int GetActiveRejitILCodeVersionNode(ulong vmModule, uint methodTk, ulong* pVmILCodeVersionNode); + + [PreserveSig] + int GetNativeCodeVersionNode(ulong vmMethod, ulong codeStartAddress, ulong* pVmNativeCodeVersionNode); + + [PreserveSig] + int GetILCodeVersionNode(ulong vmNativeCodeVersionNode, ulong* pVmILCodeVersionNode); + + [PreserveSig] + int GetILCodeVersionNodeData(ulong ilCodeVersionNode, DacDbiSharedReJitInfo* pData); + + [PreserveSig] + int EnableGCNotificationEvents(int fEnable); + + [PreserveSig] + int IsDelegate(ulong vmObject, int* pResult); + + [PreserveSig] + int GetDelegateType(ulong delegateObject, int* delegateType); + + [PreserveSig] + int GetDelegateFunctionData(int delegateType, ulong delegateObject, ulong* ppFunctionDomainAssembly, uint* pMethodDef); + + [PreserveSig] + int GetDelegateTargetObject(int delegateType, ulong delegateObject, ulong* ppTargetObj, ulong* ppTargetAppDomain); + + [PreserveSig] + int GetLoaderHeapMemoryRanges(nint pRanges); + + [PreserveSig] + int IsModuleMapped(ulong pModule, int* isModuleMapped); + + [PreserveSig] + int MetadataUpdatesApplied(Interop.BOOL* pResult); + + [PreserveSig] + int GetDomainAssemblyFromModule(ulong vmModule, ulong* pVmDomainAssembly); + + [PreserveSig] + int ParseContinuation(ulong continuationAddress, ulong* pDiagnosticIP, ulong* pNextContinuation, uint* pState); + + [PreserveSig] + int GetAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, nint pAsyncLocals); + + [PreserveSig] + int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex); +} + +[GeneratedComInterface] +[Guid("1D83B63E-D0C1-4473-9E6D-E53BFB3CF9A3")] +public partial interface IStringHolder +{ + [PreserveSig] + int AssignCopy([MarshalAs(UnmanagedType.LPWStr)] string psz); +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs index 1a29993494081f..a136a324f22b2e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs @@ -49,6 +49,7 @@ public CachingContractRegistry(Target target, TryGetContractVersionDelegate tryG [typeof(ISignatureDecoder)] = new SignatureDecoderFactory(), [typeof(ISyncBlock)] = new SyncBlockFactory(), [typeof(IBuiltInCOM)] = new BuiltInCOMFactory(), + [typeof(IDebugger)] = new DebuggerFactory(), }; foreach (IContractFactory factory in additionalFactories) diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index acc5dec4a18775..c9333b3cef12da 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -86,6 +86,43 @@ private static unsafe int CreateSosInterface(IntPtr handle, IntPtr legacyImplPtr return 0; } + /// + /// Create the DacDbi interface implementation. + /// + /// Handle created via cdac initialization + /// Optional. Pointer to legacy implementation of IDacDbiInterface + /// IUnknown pointer that can be queried for IDacDbiInterface + [UnmanagedCallersOnly(EntryPoint = $"{CDAC}create_dacdbi_interface")] + private static unsafe int CreateDacDbiInterface(IntPtr handle, IntPtr legacyImplPtr, nint* obj) + { + if (obj == null) + return HResults.E_INVALIDARG; + if (handle == IntPtr.Zero || legacyImplPtr == IntPtr.Zero) + { + *obj = IntPtr.Zero; + return HResults.E_NOTIMPL; + } + + Target? target = GCHandle.FromIntPtr(handle).Target as Target; + if (target is null) + { + *obj = IntPtr.Zero; + return HResults.E_INVALIDARG; + } + + ComWrappers cw = new StrategyBasedComWrappers(); + object legacyObj = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); + if (legacyObj is not Legacy.IDacDbiInterface) + { + *obj = IntPtr.Zero; + return HResults.COR_E_INVALIDCAST; // E_NOINTERFACE + } + + Legacy.DacDbiImpl impl = new(target, legacyObj); + *obj = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); + return HResults.S_OK; + } + [UnmanagedCallersOnly(EntryPoint = "CLRDataCreateInstanceWithFallback")] private static unsafe int CLRDataCreateInstanceWithFallback(Guid* pIID, IntPtr /*ICLRDataTarget*/ pLegacyTarget, IntPtr pLegacyImpl, void** iface) { diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiAppDomainDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiAppDomainDumpTests.cs new file mode 100644 index 00000000000000..ed433217e7593a --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiAppDomainDumpTests.cs @@ -0,0 +1,217 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for DacDbiImpl AppDomain, misc policy, and simple thread +/// property methods. Uses the BasicThreads debuggee (heap dump). +/// +public class DacDbiAppDomainDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "BasicThreads"; + + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetAppDomainId_ReturnsOneForValidAppDomain(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + + uint id; + int hr = dbi.GetAppDomainId(appDomain, &id); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(1u, id); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetAppDomainId_ReturnsZeroForNull(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + uint id; + int hr = dbi.GetAppDomainId(0, &id); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(0u, id); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetAppDomainFromId_ReturnsAppDomain(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ulong appDomain; + int hr = dbi.GetAppDomainFromId(1, &appDomain); + Assert.Equal(System.HResults.S_OK, hr); + Assert.NotEqual(0UL, appDomain); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetAppDomainFromId_FailsForInvalidId(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ulong appDomain; + int hr = dbi.GetAppDomainFromId(99, &appDomain); + Assert.True(hr < 0, "Expected failure HRESULT for invalid AppDomain ID"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetCurrentAppDomain_ReturnsNonNull(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ulong appDomain; + int hr = dbi.GetCurrentAppDomain(&appDomain); + Assert.Equal(System.HResults.S_OK, hr); + Assert.NotEqual(0UL, appDomain); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetCurrentAppDomain_MatchesGetAppDomainFromId(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ulong currentAD; + int hr1 = dbi.GetCurrentAppDomain(¤tAD); + Assert.Equal(System.HResults.S_OK, hr1); + + ulong fromId; + int hr2 = dbi.GetAppDomainFromId(1, &fromId); + Assert.Equal(System.HResults.S_OK, hr2); + + Assert.Equal(currentAD, fromId); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void EnumerateAppDomains_CallsCallbackOnce(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + int count = 0; + delegate* unmanaged callback = &CountCallback; + int hr = dbi.EnumerateAppDomains((nint)callback, (nint)(&count)); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(1, count); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void IsAssemblyFullyTrusted_ReturnsTrue(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ILoader loader = Target.Contracts.Loader; + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + IEnumerable modules = loader.GetModuleHandles(new TargetPointer(appDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution); + + foreach (ModuleHandle module in modules) + { + TargetPointer moduleAddr = loader.GetModule(module); + int result; + int hr = dbi.IsAssemblyFullyTrusted(moduleAddr, &result); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(1, result); + break; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetConnectionID_ReturnsZero(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + IThread threadContract = Target.Contracts.Thread; + ThreadStoreData storeData = threadContract.GetThreadStoreData(); + + uint connId; + int hr = dbi.GetConnectionID(storeData.FirstThread, &connId); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(0u, connId); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetTaskID_ReturnsZero(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + IThread threadContract = Target.Contracts.Thread; + ThreadStoreData storeData = threadContract.GetThreadStoreData(); + + ulong taskId; + int hr = dbi.GetTaskID(storeData.FirstThread, &taskId); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(0UL, taskId); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void IsWinRTModule_ReturnsFalse(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ILoader loader = Target.Contracts.Loader; + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + IEnumerable modules = loader.GetModuleHandles(new TargetPointer(appDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution); + + foreach (ModuleHandle module in modules) + { + TargetPointer moduleAddr = loader.GetModule(module); + int isWinRT; + int hr = dbi.IsWinRTModule(moduleAddr, &isWinRT); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(0, isWinRT); + break; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void EnableNGENPolicy_ReturnsSOK(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + int hr = dbi.EnableNGENPolicy(0); + Assert.Equal(System.HResults.S_OK, hr); + } + + [UnmanagedCallersOnly] + private static unsafe void CountCallback(ulong addr, nint userData) + { + (*(int*)userData)++; + } +} diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiGCDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiGCDumpTests.cs new file mode 100644 index 00000000000000..13b8d03d1f6897 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiGCDumpTests.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for DacDbiImpl GC methods. +/// Uses the BasicThreads debuggee (heap dump). +/// +public class DacDbiGCDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "BasicThreads"; + + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void AreGCStructuresValid_CrossValidateWithContract(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + Interop.BOOL result; + int hr = dbi.AreGCStructuresValid(&result); + Assert.Equal(System.HResults.S_OK, hr); + + bool contractResult = Target.Contracts.GC.GetGCStructuresValid(); + Assert.Equal(contractResult, result == Interop.BOOL.TRUE); + } +} diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs new file mode 100644 index 00000000000000..23eaa482fe15e2 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs @@ -0,0 +1,211 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for DacDbiImpl loader, assembly, and module methods. +/// Uses the MultiModule debuggee (full dump), which loads assemblies from multiple ALCs. +/// +public class DacDbiLoaderDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "MultiModule"; + protected override string DumpType => "full"; + + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public void GetAppDomainFullName_ReturnsNonEmpty(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + + var holder = new TestStringHolder(); + int hr = dbi.GetAppDomainFullName(appDomain, holder); + Assert.Equal(System.HResults.S_OK, hr); + Assert.False(string.IsNullOrEmpty(holder.Value), "AppDomain name should not be empty"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "Assembly type does not include IsDynamic/IsLoaded fields in .NET 10")] + public unsafe void GetModuleSimpleName_ReturnsNonEmpty(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ILoader loader = Target.Contracts.Loader; + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + IEnumerable modules = loader.GetModuleHandles(new TargetPointer(appDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution); + + int checkedCount = 0; + foreach (ModuleHandle module in modules) + { + TargetPointer moduleAddr = loader.GetModule(module); + var holder = new TestStringHolder(); + int hr = dbi.GetModuleSimpleName(moduleAddr, holder); + Assert.Equal(System.HResults.S_OK, hr); + Assert.False(string.IsNullOrEmpty(holder.Value), $"Module name should not be empty for module at {moduleAddr}"); + checkedCount++; + } + Assert.True(checkedCount > 0, "Should have checked at least one module"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "Assembly type does not include IsDynamic/IsLoaded fields in .NET 10")] + public unsafe void GetAssemblyFromDomainAssembly_CrossValidate(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ILoader loader = Target.Contracts.Loader; + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + IEnumerable modules = loader.GetModuleHandles(new TargetPointer(appDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution); + + foreach (ModuleHandle module in modules) + { + TargetPointer moduleAddr = loader.GetModule(module); + TargetPointer expectedAssembly = loader.GetAssembly(module); + + ulong assembly; + int hr = dbi.GetAssemblyFromDomainAssembly(moduleAddr, &assembly); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(expectedAssembly.Value, assembly); + break; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "Assembly type does not include IsDynamic/IsLoaded fields in .NET 10")] + public unsafe void GetModuleForDomainAssembly_CrossValidate(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ILoader loader = Target.Contracts.Loader; + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + IEnumerable modules = loader.GetModuleHandles(new TargetPointer(appDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution); + + foreach (ModuleHandle module in modules) + { + TargetPointer expectedModule = loader.GetModule(module); + + ulong result; + int hr = dbi.GetModuleForDomainAssembly(expectedModule, &result); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(expectedModule.Value, result); + break; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "Assembly type does not include IsDynamic/IsLoaded fields in .NET 10")] + public unsafe void GetDomainAssemblyFromModule_IsIdentity(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ILoader loader = Target.Contracts.Loader; + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + IEnumerable modules = loader.GetModuleHandles(new TargetPointer(appDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution); + + foreach (ModuleHandle module in modules) + { + TargetPointer moduleAddr = loader.GetModule(module); + + ulong domainAssembly; + int hr = dbi.GetDomainAssemblyFromModule(moduleAddr, &domainAssembly); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(moduleAddr.Value, domainAssembly); + break; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "Assembly type does not include IsDynamic/IsLoaded fields in .NET 10")] + public unsafe void EnumerateAssembliesInAppDomain_HasAssemblies(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + + int count = 0; + delegate* unmanaged callback = &CountCallback; + int hr = dbi.EnumerateAssembliesInAppDomain(appDomain, (nint)callback, (nint)(&count)); + Assert.Equal(System.HResults.S_OK, hr); + Assert.True(count > 0, "Should have at least one assembly"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "Assembly type does not include IsDynamic/IsLoaded fields in .NET 10")] + public unsafe void EnumerateModulesInAssembly_ReturnsOneModule(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ILoader loader = Target.Contracts.Loader; + TargetPointer appDomainPtr = Target.ReadGlobalPointer(Constants.Globals.AppDomain); + ulong appDomain = Target.ReadPointer(appDomainPtr); + IEnumerable modules = loader.GetModuleHandles(new TargetPointer(appDomain), + AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution); + + foreach (ModuleHandle module in modules) + { + TargetPointer assemblyAddr = loader.GetAssembly(module); + int count = 0; + delegate* unmanaged callback = &CountCallback; + int hr = dbi.EnumerateModulesInAssembly(assemblyAddr, (nint)callback, (nint)(&count)); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(1, count); + break; + } + } + + [UnmanagedCallersOnly] + private static unsafe void CountCallback(ulong addr, nint userData) + { + (*(int*)userData)++; + } + + /// + /// Managed implementation of for testing string-returning + /// DacDbiImpl methods. Works because DacDbiImpl is called directly (not via COM interop), + /// so the interface parameter is a regular managed interface reference. + /// + private class TestStringHolder : IStringHolder + { + public string? Value { get; private set; } + + public int AssignCopy(string psz) + { + Value = psz; + + return System.HResults.S_OK; + } + } +} diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs new file mode 100644 index 00000000000000..e47021a41484e2 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for DacDbiImpl object handle methods. +/// Uses the BasicThreads debuggee (heap dump). +/// +public class DacDbiObjectDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "BasicThreads"; + + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetVmObjectHandle_IsIdentity(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ulong testAddr = 0x12345678; + ulong result; + int hr = dbi.GetVmObjectHandle(testAddr, &result); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(testAddr, result); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetHandleAddressFromVmHandle_IsIdentity(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + ulong testAddr = 0xABCDEF00; + ulong result; + int hr = dbi.GetHandleAddressFromVmHandle(testAddr, &result); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(testAddr, result); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetAppDomainIdFromVmObjectHandle_ReturnsOneForNonZero(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + uint id; + int hr = dbi.GetAppDomainIdFromVmObjectHandle(0x12345678, &id); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(1u, id); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetAppDomainIdFromVmObjectHandle_ReturnsZeroForNull(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + uint id; + int hr = dbi.GetAppDomainIdFromVmObjectHandle(0, &id); + Assert.Equal(System.HResults.S_OK, hr); + Assert.Equal(0u, id); + } +} diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiThreadDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiThreadDumpTests.cs new file mode 100644 index 00000000000000..f86953765af348 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiThreadDumpTests.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for DacDbiImpl thread methods. +/// Uses the BasicThreads debuggee (heap dump), which spawns 5 named threads then crashes. +/// +public class DacDbiThreadDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "BasicThreads"; + + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void EnumerateThreads_CountMatchesContract(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + IThread threadContract = Target.Contracts.Thread; + ThreadStoreData storeData = threadContract.GetThreadStoreData(); + + int dbiCount = 0; + delegate* unmanaged callback = &CountThreadCallback; + int hr = dbi.EnumerateThreads((nint)callback, (nint)(&dbiCount)); + Assert.Equal(System.HResults.S_OK, hr); + + Assert.Equal(storeData.ThreadCount, dbiCount); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void IsThreadMarkedDead_CrossValidateWithContract(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + IThread threadContract = Target.Contracts.Thread; + ThreadStoreData storeData = threadContract.GetThreadStoreData(); + + TargetPointer current = storeData.FirstThread; + while (current != TargetPointer.Null) + { + Interop.BOOL isDead; + int hr = dbi.IsThreadMarkedDead(current, &isDead); + Assert.Equal(System.HResults.S_OK, hr); + + ThreadData data = threadContract.GetThreadData(current); + bool contractSaysDead = (data.State & ThreadState.Dead) != 0; + Assert.Equal(contractSaysDead, isDead == Interop.BOOL.TRUE); + + current = data.NextThread; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void TryGetVolatileOSThreadID_MatchesContract(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + IThread threadContract = Target.Contracts.Thread; + ThreadStoreData storeData = threadContract.GetThreadStoreData(); + + TargetPointer current = storeData.FirstThread; + while (current != TargetPointer.Null) + { + uint osId; + int hr = dbi.TryGetVolatileOSThreadID(current, &osId); + Assert.Equal(System.HResults.S_OK, hr); + + ThreadData data = threadContract.GetThreadData(current); + Assert.Equal((uint)data.OSId.Value, osId); + + current = data.NextThread; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetUniqueThreadID_MatchesContract(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + IThread threadContract = Target.Contracts.Thread; + ThreadStoreData storeData = threadContract.GetThreadStoreData(); + + TargetPointer current = storeData.FirstThread; + HashSet seenIds = new(); + + while (current != TargetPointer.Null) + { + uint uniqueId; + int hr = dbi.GetUniqueThreadID(current, &uniqueId); + Assert.Equal(System.HResults.S_OK, hr); + + ThreadData data = threadContract.GetThreadData(current); + Assert.Equal(data.Id, uniqueId); + Assert.True(seenIds.Add(uniqueId), $"Duplicate thread ID: {uniqueId}"); + + current = data.NextThread; + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public unsafe void GetCurrentException_CrossValidateWithContract(TestConfiguration config) + { + InitializeDumpTest(config); + DacDbiImpl dbi = CreateDacDbi(); + + IThread threadContract = Target.Contracts.Thread; + ThreadStoreData storeData = threadContract.GetThreadStoreData(); + + TargetPointer current = storeData.FirstThread; + int checkedCount = 0; + + while (current != TargetPointer.Null) + { + ulong exception; + int hr = dbi.GetCurrentException(current, &exception); + Assert.Equal(System.HResults.S_OK, hr); + + TargetPointer contractException = threadContract.GetThrowableObject(current); + Assert.Equal(contractException.Value, exception); + checkedCount++; + + ThreadData data = threadContract.GetThreadData(current); + current = data.NextThread; + } + + Assert.True(checkedCount > 0, "Should have checked at least one thread"); + } + + [UnmanagedCallersOnly] + private static unsafe void CountThreadCallback(ulong addr, nint userData) + { + (*(int*)userData)++; + } +}