mirror of https://github.com/dotnet/runtime
Adding GetAssemblyLoadContext cDAC API (#117939)
* adding GetAssemblyLoadContext cDAC API * simplifying field access * restructuring etc * comments
This commit is contained in:
parent
2d3bf386a5
commit
2db9fdf5b4
|
@ -68,6 +68,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);
|
||||
|
@ -107,6 +108,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 |
|
||||
|
@ -384,6 +387,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(
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
```
|
||||
|
|
|
@ -266,8 +266,14 @@ CDAC_TYPE_END(LoaderAllocator)
|
|||
CDAC_TYPE_BEGIN(PEAssembly)
|
||||
CDAC_TYPE_INDETERMINATE(PEAssembly)
|
||||
CDAC_TYPE_FIELD(PEAssembly, /*pointer*/, PEImage, cdac_data<PEAssembly>::PEImage)
|
||||
CDAC_TYPE_FIELD(PEAssembly, /*pointer*/, AssemblyBinder, cdac_data<PEAssembly>::AssemblyBinder)
|
||||
CDAC_TYPE_END(PEAssembly)
|
||||
|
||||
CDAC_TYPE_BEGIN(AssemblyBinder)
|
||||
CDAC_TYPE_INDETERMINATE(AssemblyBinder)
|
||||
CDAC_TYPE_FIELD(AssemblyBinder, /*pointer*/, ManagedAssemblyLoadContext, cdac_data<AssemblyBinder>::ManagedAssemblyLoadContext)
|
||||
CDAC_TYPE_END(AssemblyBinder)
|
||||
|
||||
CDAC_TYPE_BEGIN(PEImage)
|
||||
CDAC_TYPE_INDETERMINATE(PEImage)
|
||||
CDAC_TYPE_FIELD(PEImage, /*pointer*/, LoadedImageLayout, cdac_data<PEImage>::LoadedImageLayout)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -128,6 +128,12 @@ private:
|
|||
INT_PTR m_ptrManagedAssemblyLoadContext;
|
||||
|
||||
SArray<Assembly*> m_loadedAssemblies;
|
||||
friend struct cdac_data<AssemblyBinder>;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct cdac_data<AssemblyBinder>
|
||||
{
|
||||
static constexpr size_t ManagedAssemblyLoadContext = offsetof(AssemblyBinder, m_ptrManagedAssemblyLoadContext);
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -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<IMetaDataEmit> 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;
|
||||
}
|
||||
|
|
|
@ -312,20 +312,18 @@ public:
|
|||
// 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 @@ public:
|
|||
|
||||
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 @@ private:
|
|||
BINDER_SPACE::Assembly* pBindResultInfo,
|
||||
IMetaDataEmit* pEmit,
|
||||
BOOL isSystem,
|
||||
AssemblyBinder* pFallbackBinder = NULL,
|
||||
PEImage* pPEImageIL = NULL,
|
||||
BINDER_SPACE::Assembly* pHostAssembly = NULL
|
||||
);
|
||||
|
@ -425,15 +424,7 @@ private:
|
|||
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<PEAssembly>;
|
||||
}; // class PEAssembly
|
||||
|
@ -442,6 +433,7 @@ template<>
|
|||
struct cdac_data<PEAssembly>
|
||||
{
|
||||
static constexpr size_t PEImage = offsetof(PEAssembly, m_PEImage);
|
||||
static constexpr size_t AssemblyBinder = offsetof(PEAssembly, m_pAssemblyBinder);
|
||||
};
|
||||
|
||||
typedef ReleaseHolder<PEAssembly> PEAssemblyHolder;
|
||||
|
|
|
@ -91,6 +91,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();
|
||||
|
|
|
@ -35,6 +35,7 @@ public enum DataType
|
|||
Assembly,
|
||||
LoaderAllocator,
|
||||
PEAssembly,
|
||||
AssemblyBinder,
|
||||
PEImage,
|
||||
PEImageLayout,
|
||||
CGrowableSymbolStream,
|
||||
|
|
|
@ -306,6 +306,15 @@ internal readonly struct Loader_1 : ILoader
|
|||
return module.Base;
|
||||
}
|
||||
|
||||
TargetPointer ILoader.GetAssemblyLoadContext(ModuleHandle handle)
|
||||
{
|
||||
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
|
||||
Data.PEAssembly peAssembly = _target.ProcessedData.GetOrAdd<Data.PEAssembly>(module.PEAssembly);
|
||||
Data.AssemblyBinder binder = _target.ProcessedData.GetOrAdd<Data.AssemblyBinder>(peAssembly.AssemblyBinder);
|
||||
Data.ObjectHandle objectHandle = _target.ProcessedData.GetOrAdd<Data.ObjectHandle>(binder.ManagedAssemblyLoadContext);
|
||||
return objectHandle.Object;
|
||||
}
|
||||
|
||||
ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle)
|
||||
{
|
||||
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
|
||||
|
|
|
@ -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<AssemblyBinder>
|
||||
{
|
||||
static AssemblyBinder IData<AssemblyBinder>.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; }
|
||||
}
|
|
@ -13,7 +13,9 @@ internal sealed class PEAssembly : IData<PEAssembly>
|
|||
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; }
|
||||
}
|
||||
|
|
|
@ -2284,7 +2284,40 @@ internal sealed unsafe partial class SOSDacImpl
|
|||
=> _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
|
||||
|
|
Loading…
Reference in New Issue