diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index 9964998eb51172..dc56b8e33b7303 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -66,12 +66,15 @@ ModuleFlags GetFlags(ModuleHandle handle); string GetPath(ModuleHandle handle); string GetFileName(ModuleHandle handle); TargetPointer GetLoaderAllocator(ModuleHandle handle); -TargetPointer GetThunkHeap(ModuleHandle handle); TargetPointer GetILBase(ModuleHandle handle); ModuleLookupTables GetLookupTables(ModuleHandle handle); TargetPointer GetModuleLookupMapElement(TargetPointer table, uint token, out TargetNUInt flags); bool IsCollectible(ModuleHandle handle); bool IsAssemblyLoaded(ModuleHandle handle); +TargetPointer GetGlobalLoaderAllocator(); +TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer); +TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer); +TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer); ``` ## Version 1 @@ -84,7 +87,6 @@ bool IsAssemblyLoaded(ModuleHandle handle); | `Module` | `Base` | Pointer to start of PE file in memory | | `Module` | `Flags` | Assembly of the Module | | `Module` | `LoaderAllocator` | LoaderAllocator of the Module | -| `Module` | `ThunkHeap` | Pointer to the thunk heap | | `Module` | `Path` | Path of the Module (UTF-16, null-terminated) | | `Module` | `FileName` | File name of the Module (UTF-16, null-terminated) | | `Module` | `GrowableSymbolStream` | Pointer to the in memory symbol stream | @@ -115,17 +117,22 @@ bool IsAssemblyLoaded(ModuleHandle handle); | `AppDomain` | `RootAssembly` | Pointer to the root assembly | | `AppDomain` | `DomainAssemblyList` | ArrayListBase of assemblies in the AppDomain | | `LoaderAllocator` | `ReferenceCount` | Reference count of LoaderAllocator | +| `LoaderAllocator` | `HighFrequencyHeap` | High-frequency heap of LoaderAllocator | +| `LoaderAllocator` | `LowFrequencyHeap` | Low-frequency heap of LoaderAllocator | +| `LoaderAllocator` | `StubHeap` | Stub heap of LoaderAllocator | | `ArrayListBase` | `Count` | Total number of elements in the ArrayListBase | | `ArrayListBase` | `FirstBlock` | First ArrayListBlock | | `ArrayListBlock` | `Next` | Next ArrayListBlock in chain | | `ArrayListBlock` | `Size` | Size of data section in block | | `ArrayListBlock` | `ArrayStart` | Start of data section in block | +| `SystemDomain` | `GlobalLoaderAllocator` | global LoaderAllocator | ### Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | | `AppDomain` | TargetPointer | Pointer to the global AppDomain | +| `SystemDomain` | TargetPointer | Pointer to the global SystemDomain | ### Contract Constants: @@ -361,11 +368,6 @@ TargetPointer GetLoaderAllocator(ModuleHandle handle) return target.ReadPointer(handle.Address + /* Module::LoaderAllocator offset */); } -TargetPointer GetThunkHeap(ModuleHandle handle) -{ - return target.ReadPointer(handle.Address + /* Module::ThunkHeap offset */); -} - TargetPointer GetILBase(ModuleHandle handle) { return target.ReadPointer(handle.Address + /* Module::Base offset */); @@ -411,20 +413,41 @@ TargetPointer GetModuleLookupMapElement(TargetPointer table, uint token, out Tar } while (table != TargetPointer.Null); return TargetPointer.Null; } -``` -```csharp -bool ILoader.IsCollectible(ModuleHandle handle) +bool IsCollectible(ModuleHandle handle) { - TargetPointer assembly = _target.ReadPointer(handle.Address + /*Module::Assembly*/); - byte isCollectible = _target.Read(assembly + /* Assembly::IsCollectible*/); + TargetPointer assembly = target.ReadPointer(handle.Address + /*Module::Assembly*/); + byte isCollectible = target.Read(assembly + /* Assembly::IsCollectible*/); return isCollectible != 0; } -bool ILoader.IsAssemblyLoaded(ModuleHandle handle) +bool IsAssemblyLoaded(ModuleHandle handle) { - TargetPointer assembly = _target.ReadPointer(handle.Address + /*Module::Assembly*/); - uint loadLevel = _target.Read(assembly + /* Assembly::Level*/); + TargetPointer assembly = target.ReadPointer(handle.Address + /*Module::Assembly*/); + uint loadLevel = target.Read(assembly + /* Assembly::Level*/); return assembly.Level >= ASSEMBLY_LEVEL_LOADED; } + +TargetPointer GetGlobalLoaderAllocator() +{ + TargetPointer systemDomainPointer = target.ReadGlobalPointer(Constants.Globals.SystemDomain); + TargetPointer systemDomain = target.ReadPointer(systemDomainPointer); + return target.ReadPointer(systemDomain + /* SystemDomain::GlobalLoaderAllocator offset */); +} + +TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer) +{ + return target.ReadPointer(loaderAllocatorPointer + /* LoaderAllocator::HighFrequencyHeap offset */); +} + +TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer) +{ + return target.ReadPointer(loaderAllocatorPointer + /* LoaderAllocator::LowFrequencyHeap offset */); +} + +TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer) +{ + return target.ReadPointer(loaderAllocatorPointer + /* LoaderAllocator::StubHeap offset */); +} + ``` diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index a47ddaeb7ee94a..7b67aef397ca9b 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -258,6 +258,9 @@ CDAC_TYPE_END(Assembly) CDAC_TYPE_BEGIN(LoaderAllocator) CDAC_TYPE_INDETERMINATE(LoaderAllocator) CDAC_TYPE_FIELD(LoaderAllocator, /*uint32*/, ReferenceCount, cdac_data::ReferenceCount) +CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, HighFrequencyHeap, cdac_data::HighFrequencyHeap) +CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, LowFrequencyHeap, cdac_data::LowFrequencyHeap) +CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, StubHeap, cdac_data::StubHeap) CDAC_TYPE_END(LoaderAllocator) CDAC_TYPE_BEGIN(PEAssembly) @@ -294,6 +297,11 @@ CDAC_TYPE_FIELD(AppDomain, /*pointer*/, RootAssembly, cdac_data::Root CDAC_TYPE_FIELD(AppDomain, /*DomainAssemblyList*/, DomainAssemblyList, cdac_data::DomainAssemblyList) CDAC_TYPE_END(AppDomain) +CDAC_TYPE_BEGIN(SystemDomain) +CDAC_TYPE_INDETERMINATE(SystemDomain) +CDAC_TYPE_FIELD(SystemDomain, /*GlobalLoaderAllocator*/, GlobalLoaderAllocator, cdac_data::GlobalLoaderAllocator) +CDAC_TYPE_END(SystemDomain) + CDAC_TYPE_BEGIN(ArrayListBase) CDAC_TYPE_INDETERMINATE(ArrayListBase) CDAC_TYPE_FIELD(ArrayListBase, /*uint32*/, Count, cdac_data::Count) @@ -963,6 +971,7 @@ CDAC_GLOBAL(MethodDescAlignment, uint64, MethodDesc::ALIGNMENT) CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE) CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data::SyncBlockValue) CDAC_GLOBAL(StubCodeBlockLast, uint8, STUB_CODE_BLOCK_LAST) +CDAC_GLOBAL(DefaultADID, uint32, DefaultADID) CDAC_GLOBAL(MaxClrNotificationArgs, uint32, MAX_CLR_NOTIFICATION_ARGS) CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 958ed38105bb57..4a9ee03c857821 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1881,6 +1881,7 @@ template<> struct cdac_data { static constexpr PTR_SystemDomain* SystemDomainPtr = &SystemDomain::m_pSystemDomain; + static constexpr size_t GlobalLoaderAllocator = offsetof(SystemDomain, m_GlobalAllocator); }; #endif // DACCESS_COMPILE diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 3b7e0833fa883b..e38808d9cc69e1 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -885,6 +885,9 @@ template<> struct cdac_data { static constexpr size_t ReferenceCount = offsetof(LoaderAllocator, m_cReferences); + static constexpr size_t HighFrequencyHeap = offsetof(LoaderAllocator, m_pHighFrequencyHeap); + static constexpr size_t LowFrequencyHeap = offsetof(LoaderAllocator, m_pLowFrequencyHeap); + static constexpr size_t StubHeap = offsetof(LoaderAllocator, m_pStubHeap); }; typedef VPTR(LoaderAllocator) PTR_LoaderAllocator; 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 ea748dffda1cc2..384cb9e20c84a2 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 @@ -41,15 +41,6 @@ public enum ModuleFlags BeingUnloaded = 0x100000, } -public record struct ModuleLookupTables( - TargetPointer FieldDefToDesc, - TargetPointer ManifestModuleReferences, - TargetPointer MemberRefToDesc, - TargetPointer MethodDefToDesc, - TargetPointer TypeDefToMethodTable, - TargetPointer TypeRefToMethodTable, - TargetPointer MethodDefToILCodeVersioningState); - [Flags] public enum AssemblyIterationFlags { @@ -71,6 +62,15 @@ public enum AssemblyIterationFlags IncludeCollected = 0x00000080, // Include all collectible assemblies that have been collected } +public record struct ModuleLookupTables( + TargetPointer FieldDefToDesc, + TargetPointer ManifestModuleReferences, + TargetPointer MemberRefToDesc, + TargetPointer MethodDefToDesc, + TargetPointer TypeDefToMethodTable, + TargetPointer TypeRefToMethodTable, + TargetPointer MethodDefToILCodeVersioningState); + public interface ILoader : IContract { static string IContract.Name => nameof(Loader); @@ -88,14 +88,17 @@ public interface ILoader : IContract ModuleFlags GetFlags(ModuleHandle handle) => throw new NotImplementedException(); string GetPath(ModuleHandle handle) => throw new NotImplementedException(); string GetFileName(ModuleHandle handle) => throw new NotImplementedException(); - TargetPointer GetLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetILBase(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(); bool IsAssemblyLoaded(ModuleHandle handle) => throw new NotImplementedException(); + + TargetPointer GetGlobalLoaderAllocator() => throw new NotImplementedException(); + TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); + TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); + TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); } public readonly struct Loader : ILoader 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 805ccd7c85f69f..009813b1eb5e03 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -31,6 +31,7 @@ public enum DataType Module, ModuleLookupMap, AppDomain, + SystemDomain, Assembly, LoaderAllocator, PEAssembly, 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 b3db24b4e387a3..5f42826a3b7adf 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -54,6 +54,7 @@ public static class Globals public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); public const string StubCodeBlockLast = nameof(StubCodeBlockLast); + public const string DefaultADID = nameof(DefaultADID); public const string MaxClrNotificationArgs = nameof(MaxClrNotificationArgs); public const string ClrNotificationArguments = nameof(ClrNotificationArguments); public const string PlatformMetadata = nameof(PlatformMetadata); 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 c03a42e840c5e7..cb0cc5a66c977a 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 @@ -143,6 +143,7 @@ TargetPointer ILoader.GetModule(ModuleHandle handle) { return handle.Address; } + TargetPointer ILoader.GetAssembly(ModuleHandle handle) { Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); @@ -353,4 +354,29 @@ bool ILoader.IsAssemblyLoaded(ModuleHandle handle) Data.Assembly assembly = _target.ProcessedData.GetOrAdd(module.Assembly); return assembly.Level >= ASSEMBLY_LEVEL_LOADED /* IsLoaded */; } + + TargetPointer ILoader.GetGlobalLoaderAllocator() + { + TargetPointer systemDomainPointer = _target.ReadGlobalPointer(Constants.Globals.SystemDomain); + Data.SystemDomain systemDomain = _target.ProcessedData.GetOrAdd(_target.ReadPointer(systemDomainPointer)); + return systemDomain.GlobalLoaderAllocator; + } + + TargetPointer ILoader.GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer) + { + Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd(loaderAllocatorPointer); + return loaderAllocator.HighFrequencyHeap; + } + + TargetPointer ILoader.GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer) + { + Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd(loaderAllocatorPointer); + return loaderAllocator.LowFrequencyHeap; + } + + TargetPointer ILoader.GetStubHeap(TargetPointer loaderAllocatorPointer) + { + Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd(loaderAllocatorPointer); + return loaderAllocator.StubHeap; + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs index 6a7ba15a630a8f..2a933ff2ace452 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs @@ -13,10 +13,16 @@ public LoaderAllocator(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.LoaderAllocator); ReferenceCount = target.Read(address + (ulong)type.Fields[nameof(ReferenceCount)].Offset); + HighFrequencyHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(HighFrequencyHeap)].Offset); + LowFrequencyHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(LowFrequencyHeap)].Offset); + StubHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(StubHeap)].Offset); } public uint ReferenceCount { get; init; } + public TargetPointer HighFrequencyHeap { get; init; } + public TargetPointer LowFrequencyHeap { get; init; } + public TargetPointer StubHeap { get; init; } public bool IsAlive => ReferenceCount != 0; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/SystemDomain.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/SystemDomain.cs new file mode 100644 index 00000000000000..e3596be4def1bb --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/SystemDomain.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.Data; + +internal sealed class SystemDomain : IData +{ + static SystemDomain IData.Create(Target target, TargetPointer address) => new SystemDomain(target, address); + public SystemDomain(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.SystemDomain); + GlobalLoaderAllocator = address + (ulong)type.Fields[nameof(GlobalLoaderAllocator)].Offset; + } + + public TargetPointer GlobalLoaderAllocator { get; init; } +} diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index b587023128f56f..0b4f5cc0279393 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -24,6 +24,41 @@ internal struct DacpThreadStoreData public int fHostConfig; // Uses hosting flags defined above }; +internal enum DacpAppDomainDataStage : uint +{ + STAGE_CREATING, + STAGE_READYFORMANAGEDCODE, + STAGE_ACTIVE, + STAGE_OPEN, + STAGE_UNLOAD_REQUESTED, + STAGE_EXITING, + STAGE_EXITED, + STAGE_FINALIZING, + STAGE_FINALIZED, + STAGE_HANDLETABLE_NOACCESS, + STAGE_CLEARED, + STAGE_COLLECTED, + STAGE_CLOSED +}; + +internal struct DacpAppDomainData +{ + // The pointer to the AppDomain or SystemDomain. + // It's useful to keep this around in the structure + public ClrDataAddress AppDomainPtr; + public ClrDataAddress AppSecDesc; + public ClrDataAddress pLowFrequencyHeap; + public ClrDataAddress pHighFrequencyHeap; + public ClrDataAddress pStubHeap; + public ClrDataAddress DomainLocalBlock; + public ClrDataAddress pDomainLocalModules; + // The creation sequence number of this app domain (starting from 1) + public uint dwId; + public int AssemblyCount; + public int FailedAssemblyCount; + public DacpAppDomainDataStage appDomainStage; +}; + internal struct DacpAppDomainStoreData { public ClrDataAddress sharedDomain; @@ -210,7 +245,7 @@ internal unsafe partial interface ISOSDacInterface [PreserveSig] int GetAppDomainList(uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ClrDataAddress[] values, uint* pNeeded); [PreserveSig] - int GetAppDomainData(ClrDataAddress addr, /*struct DacpAppDomainData*/ void* data); + int GetAppDomainData(ClrDataAddress addr, DacpAppDomainData* data); [PreserveSig] int GetAppDomainName(ClrDataAddress addr, uint count, char* name, uint* pNeeded); [PreserveSig] diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index d05994d1c30026..8cfc4f07780c25 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -110,8 +110,81 @@ int ISOSDacInterface.GetAppDomainConfigFile(ClrDataAddress appDomain, int count, return hr; } - int ISOSDacInterface.GetAppDomainData(ClrDataAddress addr, void* data) - => _legacyImpl is not null ? _legacyImpl.GetAppDomainData(addr, data) : HResults.E_NOTIMPL; + int ISOSDacInterface.GetAppDomainData(ClrDataAddress addr, DacpAppDomainData* data) + { + int hr = HResults.S_OK; + try + { + if (addr == 0) + { + hr = HResults.E_INVALIDARG; + } + else + { + *data = default; + data->AppDomainPtr = addr; + TargetPointer systemDomainPointer = _target.ReadGlobalPointer(Constants.Globals.SystemDomain); + ClrDataAddress systemDomain = _target.ReadPointer(systemDomainPointer).ToClrDataAddress(_target); + Contracts.ILoader loader = _target.Contracts.Loader; + TargetPointer globalLoaderAllocator = loader.GetGlobalLoaderAllocator(); + data->pHighFrequencyHeap = loader.GetHighFrequencyHeap(globalLoaderAllocator).ToClrDataAddress(_target); + data->pLowFrequencyHeap = loader.GetLowFrequencyHeap(globalLoaderAllocator).ToClrDataAddress(_target); + data->pStubHeap = loader.GetStubHeap(globalLoaderAllocator).ToClrDataAddress(_target); + data->appDomainStage = DacpAppDomainDataStage.STAGE_OPEN; + if (addr != systemDomain) + { + TargetPointer pAppDomain = addr.ToTargetPointer(_target); + data->dwId = _target.ReadGlobal(Constants.Globals.DefaultADID); + + IEnumerable modules = loader.GetModuleHandles( + pAppDomain, + AssemblyIterationFlags.IncludeLoading | + AssemblyIterationFlags.IncludeLoaded | + AssemblyIterationFlags.IncludeExecution); + + foreach (Contracts.ModuleHandle module in modules) + { + if (loader.IsAssemblyLoaded(module)) + { + data->AssemblyCount++; + } + } + + IEnumerable failedModules = loader.GetModuleHandles( + pAppDomain, + AssemblyIterationFlags.IncludeFailedToLoad); + data->FailedAssemblyCount = failedModules.Count(); + } + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl is not null) + { + DacpAppDomainData dataLocal = default; + int hrLocal = _legacyImpl.GetAppDomainData(addr, &dataLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK) + { + Debug.Assert(data->AppDomainPtr == dataLocal.AppDomainPtr); + Debug.Assert(data->pHighFrequencyHeap == dataLocal.pHighFrequencyHeap); + Debug.Assert(data->pLowFrequencyHeap == dataLocal.pLowFrequencyHeap); + Debug.Assert(data->pStubHeap == dataLocal.pStubHeap); + Debug.Assert(data->DomainLocalBlock == dataLocal.DomainLocalBlock); + Debug.Assert(data->pDomainLocalModules == dataLocal.pDomainLocalModules); + Debug.Assert(data->dwId == dataLocal.dwId); + Debug.Assert(data->appDomainStage == dataLocal.appDomainStage); + Debug.Assert(data->AssemblyCount == dataLocal.AssemblyCount); + Debug.Assert(data->FailedAssemblyCount == dataLocal.FailedAssemblyCount); + } + } +#endif + return hr; + + } int ISOSDacInterface.GetAppDomainList(uint count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[] values, uint* pNeeded) { int hr = HResults.S_OK;