From 2ddca667e02aee4cc3ba16e81f575a7aae8c22c6 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 19 Jun 2020 11:07:56 +0200 Subject: [PATCH] Enhance DAC to allow getting AssemblyLoadContext for objects (#37901) * Enhance DAC to allow getting AssemblyLoadContext for objects This change adds support to DAC for getting AssemblyLoadContext for a MethodTable. The returned AsseblyLoadContext is the context into which the related type was loaded. --- .../binder/inc/clrprivbinderassemblyloadcontext.h | 7 ---- src/coreclr/src/binder/inc/clrprivbindercoreclr.h | 12 ------ src/coreclr/src/debug/daccess/dacfn.cpp | 1 - src/coreclr/src/debug/daccess/dacimpl.h | 2 + src/coreclr/src/debug/daccess/request.cpp | 26 +++++++++++++ src/coreclr/src/inc/sospriv.idl | 2 + src/coreclr/src/pal/prebuilt/inc/sospriv.h | 12 +++++- src/coreclr/src/vm/appdomain.cpp | 5 +++ src/coreclr/src/vm/assemblyloadcontext.h | 18 +++++++++ src/coreclr/src/vm/common.h | 1 + src/coreclr/src/vm/pefile.cpp | 45 +++++++++++----------- src/coreclr/src/vm/pefile.h | 31 +++++++++++---- 12 files changed, 111 insertions(+), 51 deletions(-) diff --git a/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h b/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h index 546779e..0cadffb 100644 --- a/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h +++ b/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h @@ -59,11 +59,6 @@ public: return &m_appContext; } - inline INT_PTR GetManagedAssemblyLoadContext() - { - return m_ptrManagedAssemblyLoadContext; - } - HRESULT BindUsingPEImage( /* in */ PEImage *pPEImage, /* in */ BOOL fIsNativeImage, /* [retval][out] */ ICLRPrivAssembly **ppAssembly); @@ -78,8 +73,6 @@ private: CLRPrivBinderCoreCLR *m_pTPABinder; - // A long weak GC handle to the managed AssemblyLoadContext - INT_PTR m_ptrManagedAssemblyLoadContext; // A strong GC handle to the managed AssemblyLoadContext. This handle is set when the unload of the AssemblyLoadContext is initiated // to keep the managed AssemblyLoadContext alive until the unload is finished. // We still keep the weak handle pointing to the same managed AssemblyLoadContext so that native code can use the handle above diff --git a/src/coreclr/src/binder/inc/clrprivbindercoreclr.h b/src/coreclr/src/binder/inc/clrprivbindercoreclr.h index 3779e5b..95209ad 100644 --- a/src/coreclr/src/binder/inc/clrprivbindercoreclr.h +++ b/src/coreclr/src/binder/inc/clrprivbindercoreclr.h @@ -59,23 +59,11 @@ public: BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly, bool excludeAppPaths); - INT_PTR GetManagedAssemblyLoadContext() - { - return m_ptrManagedAssemblyLoadContext; - } - - void SetManagedAssemblyLoadContext(INT_PTR ptrManagedTPABinderInstance) - { - m_ptrManagedAssemblyLoadContext = ptrManagedTPABinderInstance; - } - //========================================================================= // Internal implementation details //------------------------------------------------------------------------- private: BINDER_SPACE::ApplicationContext m_appContext; - - INT_PTR m_ptrManagedAssemblyLoadContext; }; #endif // __CLR_PRIV_BINDER_CORECLR_H__ diff --git a/src/coreclr/src/debug/daccess/dacfn.cpp b/src/coreclr/src/debug/daccess/dacfn.cpp index 1ef7bdf..43ee137 100644 --- a/src/coreclr/src/debug/daccess/dacfn.cpp +++ b/src/coreclr/src/debug/daccess/dacfn.cpp @@ -22,7 +22,6 @@ #include "gcinterface.h" #include "gcinterface.dac.h" - DacTableInfo g_dacTableInfo; DacGlobals g_dacGlobals; diff --git a/src/coreclr/src/debug/daccess/dacimpl.h b/src/coreclr/src/debug/daccess/dacimpl.h index ec26f54..0e74b28 100644 --- a/src/coreclr/src/debug/daccess/dacimpl.h +++ b/src/coreclr/src/debug/daccess/dacimpl.h @@ -1204,6 +1204,8 @@ public: virtual HRESULT STDMETHODCALLTYPE GetGenerationTableSvr(CLRDATA_ADDRESS heapAddr, unsigned int cGenerations, struct DacpGenerationData *pGenerationData, unsigned int *pNeeded); virtual HRESULT STDMETHODCALLTYPE GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr, unsigned int cFillPointers, CLRDATA_ADDRESS *pFinalizationFillPointers, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetAssemblyLoadContext(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS* assemblyLoadContext); + // // ClrDataAccess. // diff --git a/src/coreclr/src/debug/daccess/request.cpp b/src/coreclr/src/debug/daccess/request.cpp index 8bd396e..4abc51b 100644 --- a/src/coreclr/src/debug/daccess/request.cpp +++ b/src/coreclr/src/debug/daccess/request.cpp @@ -4699,3 +4699,29 @@ HRESULT ClrDataAccess::GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr, SOSDacLeave(); return hr; } + +HRESULT ClrDataAccess::GetAssemblyLoadContext(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS* assemblyLoadContext) +{ + if (methodTable == 0 || assemblyLoadContext == NULL) + return E_INVALIDARG; + + SOSDacEnter(); + PTR_MethodTable pMT = PTR_MethodTable(CLRDATA_ADDRESS_TO_TADDR(methodTable)); + PTR_Module pModule = pMT->GetModule(); + + PTR_PEFile pPEFile = pModule->GetFile(); + PTR_AssemblyLoadContext pAssemblyLoadContext = pPEFile->GetAssemblyLoadContext(); + + INT_PTR managedAssemblyLoadContextHandle = pAssemblyLoadContext->GetManagedAssemblyLoadContext(); + + TADDR managedAssemblyLoadContextAddr = 0; + if (managedAssemblyLoadContextHandle != 0) + { + DacReadAll(managedAssemblyLoadContextHandle,&managedAssemblyLoadContextAddr,sizeof(TADDR),true); + } + + *assemblyLoadContext = TO_CDADDR(managedAssemblyLoadContextAddr); + + SOSDacLeave(); + return hr; +} diff --git a/src/coreclr/src/inc/sospriv.idl b/src/coreclr/src/inc/sospriv.idl index e29ef56..4b60985 100644 --- a/src/coreclr/src/inc/sospriv.idl +++ b/src/coreclr/src/inc/sospriv.idl @@ -407,4 +407,6 @@ interface ISOSDacInterface8 : IUnknown // SVR HRESULT GetGenerationTableSvr(CLRDATA_ADDRESS heapAddr, unsigned int cGenerations, struct DacpGenerationData *pGenerationData, unsigned int *pNeeded); HRESULT GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr, unsigned int cFillPointers, CLRDATA_ADDRESS *pFinalizationFillPointers, unsigned int *pNeeded); + + HRESULT GetAssemblyLoadContext(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS* assemblyLoadContext); } diff --git a/src/coreclr/src/pal/prebuilt/inc/sospriv.h b/src/coreclr/src/pal/prebuilt/inc/sospriv.h index d06852e..d76eac0 100644 --- a/src/coreclr/src/pal/prebuilt/inc/sospriv.h +++ b/src/coreclr/src/pal/prebuilt/inc/sospriv.h @@ -2548,6 +2548,9 @@ EXTERN_C const IID IID_ISOSDacInterface8; CLRDATA_ADDRESS *pFinalizationFillPointers, unsigned int *pNeeded) = 0; + virtual HRESULT STDMETHODCALLTYPE GetAssemblyLoadContext( + CLRDATA_ADDRESS methodTable, + CLRDATA_ADDRESS* assemblyLoadContext) = 0; }; @@ -2599,6 +2602,11 @@ EXTERN_C const IID IID_ISOSDacInterface8; CLRDATA_ADDRESS *pFinalizationFillPointers, unsigned int *pNeeded); + HRESULT ( STDMETHODCALLTYPE *GetAssemblyLoadContext )( + ISOSDacInterface8 * This, + CLRDATA_ADDRESS methodTable, + CLRDATA_ADDRESS *assemblyLoadContext); + END_INTERFACE } ISOSDacInterface8Vtbl; @@ -2608,7 +2616,6 @@ EXTERN_C const IID IID_ISOSDacInterface8; }; - #ifdef COBJMACROS @@ -2637,6 +2644,9 @@ EXTERN_C const IID IID_ISOSDacInterface8; #define ISOSDacInterface8_GetFinalizationFillPointersSvr(This,heapAddr,cFillPointers,pFinalizationFillPointers,pNeeded) \ ( (This)->lpVtbl -> GetFinalizationFillPointersSvr(This,heapAddr,cFillPointers,pFinalizationFillPointers,pNeeded) ) +#define ISOSDacInterface8_GetAssemblyLoadContext(This,methodTable,assemblyLoadContext) \ + ( (This)->lpVtbl -> GetAssemblyLoadContext(This,methodTable,assemblyLoadContext) ) + #endif /* COBJMACROS */ diff --git a/src/coreclr/src/vm/appdomain.cpp b/src/coreclr/src/vm/appdomain.cpp index d8d9d09..218ed50 100644 --- a/src/coreclr/src/vm/appdomain.cpp +++ b/src/coreclr/src/vm/appdomain.cpp @@ -4492,6 +4492,11 @@ IUnknown *AppDomain::CreateBinderContext() // Initialize the assembly binder for the default context loads for CoreCLR. IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(DefaultADID, &m_pTPABinderContext)); + + // Since the PEAssembly for the System.Private.CoreLib.dll is created before the binder (the AssemblyLoadContext), + // we need to update the AssemblyLoadContext pointer in that PEAssembly now. For other assemblies, it is + // set in the PEFile constructor. + SystemDomain::SystemFile()->SetupAssemblyLoadContext(); } RETURN m_pTPABinderContext; diff --git a/src/coreclr/src/vm/assemblyloadcontext.h b/src/coreclr/src/vm/assemblyloadcontext.h index b18ecf6..06c22ee 100644 --- a/src/coreclr/src/vm/assemblyloadcontext.h +++ b/src/coreclr/src/vm/assemblyloadcontext.h @@ -23,6 +23,24 @@ public: /* [retval][out] */ UINT_PTR* pBinderId); NativeImage *LoadNativeImage(Module *componentModule, LPCUTF8 nativeImageName); + + INT_PTR GetManagedAssemblyLoadContext() + { + return m_ptrManagedAssemblyLoadContext; + } + + void SetManagedAssemblyLoadContext(INT_PTR ptrManagedTPABinderInstance) + { + m_ptrManagedAssemblyLoadContext = ptrManagedTPABinderInstance; + } + +protected: + // A GC handle to the managed AssemblyLoadContext. + // It is a long weak handle for collectible AssemblyLoadContexts and strong handle for non-collectible ones. + INT_PTR m_ptrManagedAssemblyLoadContext; + +private: + SArray m_nativeImages; }; #endif diff --git a/src/coreclr/src/vm/common.h b/src/coreclr/src/vm/common.h index 8c8a4df..7b730e1 100644 --- a/src/coreclr/src/vm/common.h +++ b/src/coreclr/src/vm/common.h @@ -112,6 +112,7 @@ typedef DPTR(class ArrayBase) PTR_ArrayBase; typedef DPTR(class Assembly) PTR_Assembly; typedef DPTR(class AssemblyBaseObject) PTR_AssemblyBaseObject; typedef DPTR(class AssemblyLoadContextBaseObject) PTR_AssemblyLoadContextBaseObject; +typedef DPTR(class AssemblyLoadContext) PTR_AssemblyLoadContext; typedef DPTR(class AssemblyNameBaseObject) PTR_AssemblyNameBaseObject; typedef VPTR(class BaseDomain) PTR_BaseDomain; typedef DPTR(class ClassLoader) PTR_ClassLoader; diff --git a/src/coreclr/src/vm/pefile.cpp b/src/coreclr/src/vm/pefile.cpp index eec038f..40f0910 100644 --- a/src/coreclr/src/vm/pefile.cpp +++ b/src/coreclr/src/vm/pefile.cpp @@ -63,6 +63,7 @@ PEFile::PEFile(PEImage *identity) : m_pMetadataLock(::new SimpleRWLock(PREEMPTIVE, LOCK_TYPE_DEFAULT)), m_refCount(1), m_flags(0), + m_pAssemblyLoadContext(nullptr), m_pHostAssembly(nullptr), m_pFallbackLoadContextBinder(nullptr) { @@ -1831,7 +1832,7 @@ void PEAssembly::Attach() STANDARD_VM_CONTRACT; } - +#ifndef DACCESS_COMPILE PEAssembly::PEAssembly( CoreBindResult* pBindResultInfo, IMetaDataEmit* pEmit, @@ -1921,8 +1922,10 @@ PEAssembly::PEAssembly( m_debugName.Normalize(); m_pDebugName = m_debugName; #endif -} + SetupAssemblyLoadContext(); +} +#endif // !DACCESS_COMPILE PEAssembly *PEAssembly::Open( @@ -2331,6 +2334,24 @@ void PEFile::EnsureImageOpened() GetILimage()->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED)->Release(); } +void PEFile::SetupAssemblyLoadContext() +{ + PTR_ICLRPrivBinder pBindingContext = GetBindingContext(); + ICLRPrivBinder* pOpaqueBinder = NULL; + + if (pBindingContext != NULL) + { + UINT_PTR assemblyBinderID = 0; + IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); + + pOpaqueBinder = reinterpret_cast(assemblyBinderID); + } + + m_pAssemblyLoadContext = (pOpaqueBinder != NULL) ? + (AssemblyLoadContext*)pOpaqueBinder : + AppDomain::GetCurrentDomain()->GetTPABinderContext(); +} + #endif // #ifndef DACCESS_COMPILE #ifdef DACCESS_COMPILE @@ -2462,23 +2483,3 @@ PTR_ICLRPrivBinder PEFile::GetBindingContext() return pBindingContext; } - -#ifndef DACCESS_COMPILE -AssemblyLoadContext* PEFile::GetAssemblyLoadContext() -{ - LIMITED_METHOD_CONTRACT; - - PTR_ICLRPrivBinder pBindingContext = GetBindingContext(); - ICLRPrivBinder* pOpaqueBinder = NULL; - - if (pBindingContext != NULL) - { - UINT_PTR assemblyBinderID = 0; - IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); - - pOpaqueBinder = reinterpret_cast(assemblyBinderID); - } - - return (pOpaqueBinder != NULL) ? (AssemblyLoadContext*)pOpaqueBinder : AppDomain::GetCurrentDomain()->GetTPABinderContext(); -} -#endif diff --git a/src/coreclr/src/vm/pefile.h b/src/coreclr/src/vm/pefile.h index c3282c4..518449d 100644 --- a/src/coreclr/src/vm/pefile.h +++ b/src/coreclr/src/vm/pefile.h @@ -479,7 +479,10 @@ protected: IMetaDataEmit *m_pEmitter; SimpleRWLock *m_pMetadataLock; Volatile m_refCount; - int m_flags; + int m_flags; + + // AssemblyLoadContext that this PEFile is associated with + PTR_AssemblyLoadContext m_pAssemblyLoadContext; #ifdef DEBUGGING_SUPPORTED #ifdef FEATURE_PREJIT @@ -566,20 +569,32 @@ public: // Returns the ICLRPrivBinder* instance associated with the PEFile PTR_ICLRPrivBinder GetBindingContext(); - AssemblyLoadContext* GetAssemblyLoadContext(); - - bool HasHostAssembly() - { STATIC_CONTRACT_WRAPPER; return GetHostAssembly() != nullptr; } - - bool CanUseWithBindingCache() - { LIMITED_METHOD_CONTRACT; return !HasHostAssembly(); } +#ifndef DACCESS_COMPILE + void SetupAssemblyLoadContext(); void SetFallbackLoadContextBinder(PTR_ICLRPrivBinder pFallbackLoadContextBinder) { LIMITED_METHOD_CONTRACT; m_pFallbackLoadContextBinder = pFallbackLoadContextBinder; + SetupAssemblyLoadContext(); + } + +#endif //!DACCESS_COMPILE + + PTR_AssemblyLoadContext GetAssemblyLoadContext() + { + LIMITED_METHOD_CONTRACT; + + _ASSERTE(m_pAssemblyLoadContext != NULL); + return m_pAssemblyLoadContext; } + bool HasHostAssembly() + { STATIC_CONTRACT_WRAPPER; return GetHostAssembly() != nullptr; } + + bool CanUseWithBindingCache() + { LIMITED_METHOD_CONTRACT; return !HasHostAssembly(); } + PTR_ICLRPrivBinder GetFallbackLoadContextBinder() { LIMITED_METHOD_CONTRACT; -- 2.7.4