diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index dc56b8e33b7303..bcd0fb8af3292a 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -67,6 +67,7 @@ string GetPath(ModuleHandle handle); string GetFileName(ModuleHandle handle); TargetPointer GetLoaderAllocator(ModuleHandle handle); TargetPointer GetILBase(ModuleHandle handle); +TargetPointer GetAssemblyLoadContext(ModuleHandle handle); ModuleLookupTables GetLookupTables(ModuleHandle handle); TargetPointer GetModuleLookupMapElement(TargetPointer table, uint token, out TargetNUInt flags); bool IsCollectible(ModuleHandle handle); @@ -106,6 +107,8 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer); | `Assembly` | `NotifyFlags` | Flags relating to the debugger/profiler notification state of the assembly | | `Assembly` | `Level` | File load level of the assembly | | `PEAssembly` | `PEImage` | Pointer to the PEAssembly's PEImage | +| `PEAssembly` | `AssemblyBinder` | Pointer to the PEAssembly's binder | +| `AssemblyBinder` | `ManagedAssemblyLoadContext` | Pointer to the AssemblyBinder's ManagedAssemblyLoadContext | | `PEImage` | `LoadedImageLayout` | Pointer to the PEImage's loaded PEImageLayout | | `PEImage` | `ProbeExtensionResult` | PEImage's ProbeExtensionResult | | `ProbeExtensionResult` | `Type` | Type of ProbeExtensionResult | @@ -373,6 +376,14 @@ TargetPointer GetILBase(ModuleHandle handle) return target.ReadPointer(handle.Address + /* Module::Base offset */); } +TargetPointer ILoader.GetAssemblyLoadContext(ModuleHandle handle) +{ + PEAssembly peAssembly = target.ReadPointer(handle.Address + /* Module::PEAssembly offset */); + AssemblyBinder binder = target.ReadPointer(peAssembly + /* PEAssembly::AssemblyBinder offset */); + ObjectHandle objectHandle = new ObjectHandle(binder); + return objectHandle.Object; +} + ModuleLookupTables GetLookupTables(ModuleHandle handle) { return new ModuleLookupTables( diff --git a/docs/design/datacontracts/Thread.md b/docs/design/datacontracts/Thread.md index efdd7d0bbc653a..98ccb4a9ead5eb 100644 --- a/docs/design/datacontracts/Thread.md +++ b/docs/design/datacontracts/Thread.md @@ -46,7 +46,6 @@ record struct ThreadData ( ThreadStoreData GetThreadStoreData(); ThreadStoreCounts GetThreadCounts(); ThreadData GetThreadData(TargetPointer threadPointer); -TargetPointer GetManagedThreadObject(TargetPointer threadPointer); ``` ## Version 1 @@ -128,10 +127,4 @@ ThreadData GetThreadData(TargetPointer address) NextThread: target.ReadPointer(address + /* Thread::LinkNext offset */) - threadLinkOffset; ); } - -TargetPointer GetManagedThreadObject(TargetPointer threadPointer) -{ - var runtimeThread = new Thread(Target, threadPointer); - return Contracts.GCHandle.GetObject(new DacGCHandle(runtimeThread.m_ExposedObject)); -} ``` diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.inc b/src/coreclr/debug/runtimeinfo/datadescriptor.inc index 7b67aef397ca9b..09415794b7cf9c 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.inc +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.inc @@ -266,8 +266,14 @@ CDAC_TYPE_END(LoaderAllocator) CDAC_TYPE_BEGIN(PEAssembly) CDAC_TYPE_INDETERMINATE(PEAssembly) CDAC_TYPE_FIELD(PEAssembly, /*pointer*/, PEImage, cdac_data::PEImage) +CDAC_TYPE_FIELD(PEAssembly, /*pointer*/, AssemblyBinder, cdac_data::AssemblyBinder) CDAC_TYPE_END(PEAssembly) +CDAC_TYPE_BEGIN(AssemblyBinder) +CDAC_TYPE_INDETERMINATE(AssemblyBinder) +CDAC_TYPE_FIELD(AssemblyBinder, /*pointer*/, ManagedAssemblyLoadContext, cdac_data::ManagedAssemblyLoadContext) +CDAC_TYPE_END(AssemblyBinder) + CDAC_TYPE_BEGIN(PEImage) CDAC_TYPE_INDETERMINATE(PEImage) CDAC_TYPE_FIELD(PEImage, /*pointer*/, LoadedImageLayout, cdac_data::LoadedImageLayout) diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 21f9b00f6da872..470bbfd1e23c2d 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -431,10 +431,7 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar IfFailThrow(pAssemblyEmit->DefineAssembly(pAssemblyNameParts->_pPublicKeyOrToken, pAssemblyNameParts->_cbPublicKeyOrToken, hashAlgorithm, pAssemblyNameParts->_pName, &assemData, pAssemblyNameParts->_flags, &ma)); - pPEAssembly = PEAssembly::Create(pAssemblyEmit); - - // Set it as the fallback load context binder for the dynamic assembly being created - pPEAssembly->SetFallbackBinder(pBinder); + pPEAssembly = PEAssembly::Create(pAssemblyEmit, pBinder); } AppDomain* pDomain = ::GetAppDomain(); diff --git a/src/coreclr/vm/assemblybinder.h b/src/coreclr/vm/assemblybinder.h index 8fa57302cfa401..fe9f002d3bced7 100644 --- a/src/coreclr/vm/assemblybinder.h +++ b/src/coreclr/vm/assemblybinder.h @@ -128,6 +128,12 @@ class AssemblyBinder INT_PTR m_ptrManagedAssemblyLoadContext; SArray m_loadedAssemblies; + friend struct cdac_data; }; +template<> +struct cdac_data +{ + static constexpr size_t ManagedAssemblyLoadContext = offsetof(AssemblyBinder, m_ptrManagedAssemblyLoadContext); +}; #endif diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp index 0ab24368e027c1..6551714eab7817 100644 --- a/src/coreclr/vm/peassembly.cpp +++ b/src/coreclr/vm/peassembly.cpp @@ -647,6 +647,7 @@ PEAssembly::PEAssembly( BINDER_SPACE::Assembly* pBindResultInfo, IMetaDataEmit* pEmit, BOOL isSystem, + AssemblyBinder* pFallbackBinder /*= NULL*/, PEImage * pPEImage /*= NULL*/, BINDER_SPACE::Assembly * pHostAssembly /*= NULL*/) { @@ -670,7 +671,7 @@ PEAssembly::PEAssembly( m_refCount = 1; m_isSystem = isSystem; m_pHostAssembly = nullptr; - m_pFallbackBinder = nullptr; + m_pAssemblyBinder = nullptr; pPEImage = pBindResultInfo ? pBindResultInfo->GetPEImage() : pPEImage; if (pPEImage) @@ -722,6 +723,15 @@ PEAssembly::PEAssembly( m_pHostAssembly = pBindResultInfo; } + if (m_pHostAssembly != nullptr) + { + m_pAssemblyBinder = m_pHostAssembly->GetBinder(); + } + else + { + m_pAssemblyBinder = pFallbackBinder; + } + #ifdef LOGGING GetPathOrCodeBase(m_debugName); m_pDebugName = m_debugName.GetUTF8(); @@ -740,6 +750,7 @@ PEAssembly *PEAssembly::Open( nullptr, // BindResult nullptr, // IMetaDataEmit FALSE, // isSystem + nullptr, // FallbackBinder pPEImageIL, pHostAssembly); @@ -833,7 +844,7 @@ PEAssembly* PEAssembly::Open(BINDER_SPACE::Assembly* pBindResult) }; /* static */ -PEAssembly *PEAssembly::Create(IMetaDataAssemblyEmit *pAssemblyEmit) +PEAssembly *PEAssembly::Create(IMetaDataAssemblyEmit *pAssemblyEmit, AssemblyBinder *pFallbackBinder) { CONTRACT(PEAssembly *) { @@ -847,7 +858,7 @@ PEAssembly *PEAssembly::Create(IMetaDataAssemblyEmit *pAssemblyEmit) // we have.) SafeComHolder pEmit; pAssemblyEmit->QueryInterface(IID_IMetaDataEmit, (void **)&pEmit); - RETURN new PEAssembly(NULL, pEmit, FALSE); + RETURN new PEAssembly(NULL, pEmit, FALSE, pFallbackBinder); } #endif // #ifndef DACCESS_COMPILE @@ -1083,25 +1094,5 @@ TADDR PEAssembly::GetMDInternalRWAddress() // Returns the AssemblyBinder* instance associated with the PEAssembly PTR_AssemblyBinder PEAssembly::GetAssemblyBinder() { - LIMITED_METHOD_CONTRACT; - - PTR_AssemblyBinder pBinder = NULL; - - PTR_BINDER_SPACE_Assembly pHostAssembly = GetHostAssembly(); - if (pHostAssembly) - { - pBinder = pHostAssembly->GetBinder(); - } - else - { - // If we do not have a host assembly, check if we are dealing with - // a dynamically emitted assembly and if so, use its fallback load context - // binder reference. - if (IsReflectionEmit()) - { - pBinder = GetFallbackBinder(); - } - } - - return pBinder; + return m_pAssemblyBinder; } diff --git a/src/coreclr/vm/peassembly.h b/src/coreclr/vm/peassembly.h index 43b14abe9fe41d..fe1aa193ab1970 100644 --- a/src/coreclr/vm/peassembly.h +++ b/src/coreclr/vm/peassembly.h @@ -312,20 +312,18 @@ class PEAssembly final // For Dynamic assemblies this is the fallback binder. PTR_AssemblyBinder GetAssemblyBinder(); -#ifndef DACCESS_COMPILE - void SetFallbackBinder(PTR_AssemblyBinder pFallbackBinder) - { - LIMITED_METHOD_CONTRACT; - m_pFallbackBinder = pFallbackBinder; - } - -#endif //!DACCESS_COMPILE - + // For certain assemblies, we do not have m_pHostAssembly since they are not bound using an actual binder. + // An example is Ref-Emitted assemblies. Thus, when such assemblies trigger load of their dependencies, + // we need to ensure they are loaded in appropriate load context. + // + // To enable this, we maintain a concept of "FallbackBinder", which will be set to the Binder of the + // assembly that created the dynamic assembly. If the creator assembly is dynamic itself, then its fallback + // load context would be propagated to the assembly being dynamically generated. PTR_AssemblyBinder GetFallbackBinder() { LIMITED_METHOD_CONTRACT; - return m_pFallbackBinder; + return (m_pHostAssembly != NULL) ? NULL : m_pAssemblyBinder; } // ------------------------------------------------------------ @@ -341,7 +339,7 @@ class PEAssembly final static PEAssembly* Open(BINDER_SPACE::Assembly* pBindResult); - static PEAssembly* Create(IMetaDataAssemblyEmit* pEmit); + static PEAssembly* Create(IMetaDataAssemblyEmit* pEmit, AssemblyBinder* pFallbackBinder); // ------------------------------------------------------------ // Utility functions @@ -372,6 +370,7 @@ class PEAssembly final BINDER_SPACE::Assembly* pBindResultInfo, IMetaDataEmit* pEmit, BOOL isSystem, + AssemblyBinder* pFallbackBinder = NULL, PEImage* pPEImageIL = NULL, BINDER_SPACE::Assembly* pHostAssembly = NULL ); @@ -425,15 +424,7 @@ class PEAssembly final bool m_isSystem; PTR_BINDER_SPACE_Assembly m_pHostAssembly; - - // For certain assemblies, we do not have m_pHostAssembly since they are not bound using an actual binder. - // An example is Ref-Emitted assemblies. Thus, when such assemblies trigger load of their dependencies, - // we need to ensure they are loaded in appropriate load context. - // - // To enable this, we maintain a concept of "FallbackBinder", which will be set to the Binder of the - // assembly that created the dynamic assembly. If the creator assembly is dynamic itself, then its fallback - // load context would be propagated to the assembly being dynamically generated. - PTR_AssemblyBinder m_pFallbackBinder; + PTR_AssemblyBinder m_pAssemblyBinder; friend struct cdac_data; }; // class PEAssembly @@ -442,6 +433,7 @@ template<> struct cdac_data { static constexpr size_t PEImage = offsetof(PEAssembly, m_PEImage); + static constexpr size_t AssemblyBinder = offsetof(PEAssembly, m_pAssemblyBinder); }; typedef ReleaseHolder PEAssemblyHolder; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index 384cb9e20c84a2..f43a034dcc7245 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -90,6 +90,7 @@ public interface ILoader : IContract string GetFileName(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetILBase(ModuleHandle handle) => throw new NotImplementedException(); + TargetPointer GetAssemblyLoadContext(ModuleHandle handle) => throw new NotImplementedException(); ModuleLookupTables GetLookupTables(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetModuleLookupMapElement(TargetPointer table, uint token, out TargetNUInt flags) => throw new NotImplementedException(); bool IsCollectible(ModuleHandle handle) => throw new NotImplementedException(); 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 009813b1eb5e03..af56c39e5e3a34 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -35,6 +35,7 @@ public enum DataType Assembly, LoaderAllocator, PEAssembly, + AssemblyBinder, PEImage, PEImageLayout, CGrowableSymbolStream, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index cb0cc5a66c977a..bfb2fa05818c47 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -296,6 +296,15 @@ TargetPointer ILoader.GetILBase(ModuleHandle handle) return module.Base; } + TargetPointer ILoader.GetAssemblyLoadContext(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + Data.PEAssembly peAssembly = _target.ProcessedData.GetOrAdd(module.PEAssembly); + Data.AssemblyBinder binder = _target.ProcessedData.GetOrAdd(peAssembly.AssemblyBinder); + Data.ObjectHandle objectHandle = _target.ProcessedData.GetOrAdd(binder.ManagedAssemblyLoadContext); + return objectHandle.Object; + } + ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle) { Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AssemblyBinder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AssemblyBinder.cs new file mode 100644 index 00000000000000..83e406cbb75c36 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AssemblyBinder.cs @@ -0,0 +1,17 @@ +// 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.Data; + +internal sealed class AssemblyBinder : IData +{ + static AssemblyBinder IData.Create(Target target, TargetPointer address) => new AssemblyBinder(target, address); + public AssemblyBinder(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.AssemblyBinder); + ManagedAssemblyLoadContext = target.ReadPointer(address + (ulong)type.Fields[nameof(ManagedAssemblyLoadContext)].Offset); + } + public TargetPointer ManagedAssemblyLoadContext { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PEAssembly.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PEAssembly.cs index 675c281c417bcb..09a03cb527217a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PEAssembly.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PEAssembly.cs @@ -13,7 +13,9 @@ public PEAssembly(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.PEAssembly); PEImage = target.ReadPointer(address + (ulong)type.Fields[nameof(PEImage)].Offset); + AssemblyBinder = target.ReadPointer(address + (ulong)type.Fields[nameof(AssemblyBinder)].Offset); } public TargetPointer PEImage { get; init; } + public TargetPointer AssemblyBinder { get; init; } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index f196e9a42e177c..8bf0cfb411197c 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -2229,7 +2229,40 @@ int ISOSDacInterface8.GetFinalizationFillPointersSvr(ClrDataAddress heapAddr, ui => _legacyImpl8 is not null ? _legacyImpl8.GetFinalizationFillPointersSvr(heapAddr, cFillPointers, pFinalizationFillPointers, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface8.GetAssemblyLoadContext(ClrDataAddress methodTable, ClrDataAddress* assemblyLoadContext) - => _legacyImpl8 is not null ? _legacyImpl8.GetAssemblyLoadContext(methodTable, assemblyLoadContext) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + if (methodTable == 0 || assemblyLoadContext == null) + hr = HResults.E_INVALIDARG; + else + { + Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + Contracts.ILoader loaderContract = _target.Contracts.Loader; + Contracts.TypeHandle methodTableHandle = rtsContract.GetTypeHandle(methodTable.ToTargetPointer(_target)); + Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(rtsContract.GetModule(methodTableHandle)); + TargetPointer alc = loaderContract.GetAssemblyLoadContext(moduleHandle); + *assemblyLoadContext = alc.ToClrDataAddress(_target); + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl8 is not null) + { + ClrDataAddress assemblyLoadContextLocal; + int hrLocal = _legacyImpl8.GetAssemblyLoadContext(methodTable, &assemblyLoadContextLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK) + { + Debug.Assert(*assemblyLoadContext == assemblyLoadContextLocal); + } + } +#endif + return hr; + } #endregion ISOSDacInterface8 #region ISOSDacInterface9