Skip to content

Commit 65a2ec4

Browse files
author
Max Charlamb
committed
implement ISOSDacInterface.GetAssemblyList
1 parent 1ccc750 commit 65a2ec4

File tree

14 files changed

+294
-20
lines changed

14 files changed

+294
-20
lines changed

Diff for: src/coreclr/debug/runtimeinfo/datadescriptor.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,17 @@ CDAC_TYPE_INDETERMINATE(Assembly)
249249
#ifdef FEATURE_COLLECTIBLE_TYPES
250250
CDAC_TYPE_FIELD(Assembly, /*uint8*/, IsCollectible, cdac_data<Assembly>::IsCollectible)
251251
#endif
252+
CDAC_TYPE_FIELD(Assembly, /*pointer*/, Module, cdac_data<Assembly>::Module)
253+
CDAC_TYPE_FIELD(Assembly, /*pointer*/, Error, cdac_data<Assembly>::Error)
254+
CDAC_TYPE_FIELD(Assembly, /*uint32*/, NotifyFlags, cdac_data<Assembly>::NotifyFlags)
255+
CDAC_TYPE_FIELD(Assembly, /*uint32*/, Level, cdac_data<Assembly>::Level)
252256
CDAC_TYPE_END(Assembly)
253257

258+
CDAC_TYPE_BEGIN(LoaderAllocator)
259+
CDAC_TYPE_INDETERMINATE(LoaderAllocator)
260+
CDAC_TYPE_FIELD(LoaderAllocator, /*uint32*/, ReferenceCount, cdac_data<LoaderAllocator>::ReferenceCount)
261+
CDAC_TYPE_END(LoaderAllocator)
262+
254263
CDAC_TYPE_BEGIN(PEAssembly)
255264
CDAC_TYPE_INDETERMINATE(PEAssembly)
256265
CDAC_TYPE_FIELD(PEAssembly, /*pointer*/, PEImage, cdac_data<PEAssembly>::PEImage)
@@ -293,9 +302,9 @@ CDAC_TYPE_END(ArrayListBase)
293302

294303
CDAC_TYPE_BEGIN(ArrayListBlock)
295304
CDAC_TYPE_INDETERMINATE(ArrayListBlock)
296-
CDAC_TYPE_FIELD(ArrayListBlock, /*pointer*/, Next, cdac_data<ArrayListBlock>::Next)
297-
CDAC_TYPE_FIELD(ArrayListBlock, /*uint32*/, Size, cdac_data<ArrayListBlock>::Size)
298-
CDAC_TYPE_FIELD(ArrayListBlock, /*pointer*/, ArrayStart, cdac_data<ArrayListBlock>::ArrayStart)
305+
CDAC_TYPE_FIELD(ArrayListBlock, /*pointer*/, Next, cdac_data<ArrayListBase>::Next)
306+
CDAC_TYPE_FIELD(ArrayListBlock, /*uint32*/, Size, cdac_data<ArrayListBase>::Size)
307+
CDAC_TYPE_FIELD(ArrayListBlock, /*pointer*/, ArrayStart, cdac_data<ArrayListBase>::ArrayStart)
299308
CDAC_TYPE_END(ArrayListBlock)
300309

301310
// RuntimeTypeSystem
@@ -832,6 +841,7 @@ CDAC_GLOBAL_STRING(Architecture, riscv64)
832841
CDAC_GLOBAL_STRING(RID, RID_STRING)
833842

834843
CDAC_GLOBAL_POINTER(AppDomain, &AppDomain::m_pTheAppDomain)
844+
CDAC_GLOBAL_POINTER(SystemDomain, &SystemDomain::m_pSystemDomain)
835845
CDAC_GLOBAL_POINTER(ThreadStore, &ThreadStore::s_pThreadStore)
836846
CDAC_GLOBAL_POINTER(FinalizerThread, &::g_pFinalizerThread)
837847
CDAC_GLOBAL_POINTER(GCThread, &::g_pSuspensionThread)

Diff for: src/coreclr/inc/arraylist.h

+5-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <contract.h>
1010
#include <stddef.h> // offsetof
1111

12+
// Forward Declarations
13+
template<typename T> struct cdac_data;
14+
1215
//
1316
// ArrayList is a simple class which is used to contain a growable
1417
// list of pointers, stored in chunks. Modification is by appending
@@ -53,7 +56,6 @@ class ArrayListBase
5356
(*PTR_DWORD(addr + offsetof(ArrayListBlock, m_blockSize)) * sizeof(void*));
5457
}
5558
#endif
56-
friend struct ::cdac_data<ArrayListBlock>;
5759
};
5860
typedef SPTR(ArrayListBlock) PTR_ArrayListBlock;
5961

@@ -264,25 +266,21 @@ class ArrayListBase
264266
return BlockIterator((ArrayListBlock *) &m_firstBlock, m_count);
265267
}
266268

267-
friend struct ::cdac_data<ArrayListBase>;
268-
friend struct ::cdac_data<ArrayListBlock>;
269+
friend struct cdac_data<ArrayListBase>;
269270
};
270271

271272
template<>
272273
struct cdac_data<ArrayListBase>
273274
{
274275
static constexpr size_t Count = offsetof(ArrayListBase, m_count);
275276
static constexpr size_t FirstBlock = offsetof(ArrayListBase, m_firstBlock);
276-
};
277277

278-
template<>
279-
struct cdac_data<ArrayListBase::ArrayListBlock>
280-
{
281278
static constexpr size_t Next = offsetof(ArrayListBase::ArrayListBlock, m_next);
282279
static constexpr size_t Size = offsetof(ArrayListBase::ArrayListBlock, m_blockSize);
283280
static constexpr size_t ArrayStart = offsetof(ArrayListBase::ArrayListBlock, m_array);
284281
};
285282

283+
286284
class ArrayList : public ArrayListBase
287285
{
288286
public:

Diff for: src/coreclr/vm/appdomain.hpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,8 @@ class AppDomain final
964964
{
965965
return m_array.Iterate();
966966
}
967+
968+
friend struct cdac_data<AppDomain>;
967969
}; // class DomainAssemblyList
968970

969971
// Conceptually a list of code:Assembly structures, protected by lock code:GetAssemblyListLock
@@ -1621,6 +1623,7 @@ template<>
16211623
struct cdac_data<AppDomain>
16221624
{
16231625
static constexpr size_t RootAssembly = offsetof(AppDomain, m_pRootAssembly);
1626+
static constexpr size_t DomainAssemblyList = offsetof(AppDomain, m_Assemblies) + offsetof(AppDomain::DomainAssemblyList, m_array);
16241627
};
16251628

16261629
typedef DPTR(class SystemDomain) PTR_SystemDomain;
@@ -1913,9 +1916,10 @@ class SystemDomain final
19131916

19141917
InlineSString<100> m_SystemDirectory;
19151918

1919+
public:
19161920
// Global domain that every one uses
19171921
SPTR_DECL(SystemDomain, m_pSystemDomain);
1918-
1922+
private:
19191923
LoaderAllocator * m_pDelayedUnloadListOfLoaderAllocators;
19201924

19211925
#ifndef DACCESS_COMPILE

Diff for: src/coreclr/vm/assembly.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,10 @@ struct cdac_data<Assembly>
546546
#ifdef FEATURE_COLLECTIBLE_TYPES
547547
static constexpr size_t IsCollectible = offsetof(Assembly, m_isCollectible);
548548
#endif
549+
static constexpr size_t Module = offsetof(Assembly, m_pModule);
550+
static constexpr size_t Error = offsetof(Assembly, m_pError);
551+
static constexpr size_t NotifyFlags = offsetof(Assembly, m_notifyFlags);
552+
static constexpr size_t Level = offsetof(Assembly, m_level);
549553
};
550554

551555
#ifndef DACCESS_COMPILE

Diff for: src/coreclr/vm/loaderallocator.hpp

+14-6
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ class CodeRangeMapRangeList : public RangeList
4747
VPTR_VTABLE_CLASS(CodeRangeMapRangeList, RangeList)
4848

4949
#if defined(DACCESS_COMPILE) || !defined(TARGET_WINDOWS)
50-
CodeRangeMapRangeList() :
50+
CodeRangeMapRangeList() :
5151
_RangeListRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT),
5252
_rangeListType(STUB_CODE_BLOCK_UNKNOWN),
5353
_id(NULL),
5454
_collectible(true)
5555
{}
5656
#endif
5757

58-
CodeRangeMapRangeList(StubCodeBlockKind rangeListType, bool collectible) :
58+
CodeRangeMapRangeList(StubCodeBlockKind rangeListType, bool collectible) :
5959
_RangeListRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT),
6060
_rangeListType(rangeListType),
6161
_id(NULL),
@@ -85,15 +85,15 @@ class CodeRangeMapRangeList : public RangeList
8585

8686
_ASSERTE(id == _id || _id == NULL);
8787
_id = id;
88-
// Grow the array first, so that a failure cannot break the
88+
// Grow the array first, so that a failure cannot break the
8989

9090
RangeSection::RangeSectionFlags flags = RangeSection::RANGE_SECTION_RANGELIST;
9191
if (_collectible)
9292
{
9393
_starts.Preallocate(_starts.GetCount() + 1);
9494
flags = (RangeSection::RangeSectionFlags)(flags | RangeSection::RANGE_SECTION_COLLECTIBLE);
9595
}
96-
96+
9797
ExecutionManager::AddCodeRange(start, end, ExecutionManager::GetEEJitManager(), flags, this);
9898

9999
if (_collectible)
@@ -168,7 +168,7 @@ class CodeRangeMapRangeList : public RangeList
168168
return FALSE;
169169
if ((pRS->_flags & RangeSection::RANGE_SECTION_RANGELIST) == 0)
170170
return FALSE;
171-
171+
172172
return (pRS->_pRangeList == this);
173173
}
174174

@@ -262,7 +262,7 @@ class SegmentedHandleIndexStack
262262
public:
263263

264264
~SegmentedHandleIndexStack();
265-
265+
266266
// Push the value to the stack. If the push cannot be done due to OOM, return false;
267267
inline bool Push(DWORD value);
268268

@@ -877,8 +877,16 @@ class LoaderAllocator
877877
virtual void UnregisterDependentHandleToNativeObjectFromCleanup(LADependentHandleToNativeObject *dependentHandle) {};
878878
virtual void CleanupDependentHandlesToNativeObjects() {};
879879
#endif
880+
881+
friend struct ::cdac_data<LoaderAllocator>;
880882
}; // class LoaderAllocator
881883

884+
template<>
885+
struct cdac_data<LoaderAllocator>
886+
{
887+
static constexpr size_t ReferenceCount = offsetof(LoaderAllocator, m_cReferences);
888+
};
889+
882890
typedef VPTR(LoaderAllocator) PTR_LoaderAllocator;
883891

884892
extern "C" BOOL QCALLTYPE LoaderAllocator_Destroy(QCall::LoaderAllocatorHandle pLoaderAllocator);

Diff for: src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs

+24-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public ModuleHandle(TargetPointer address)
1919
[Flags]
2020
public enum ModuleFlags
2121
{
22+
Tenured = 0x00000001, // Set once we know for sure the Module will not be freed until the appdomain itself exits
2223
EditAndContinue = 0x00000008, // Edit and Continue is enabled for this module
2324
ReflectionEmit = 0x00000040, // Reflection.Emit was used to create this module
2425
}
@@ -32,13 +33,34 @@ public record struct ModuleLookupTables(
3233
TargetPointer TypeRefToMethodTable,
3334
TargetPointer MethodDefToILCodeVersioningState);
3435

36+
[Flags]
37+
public enum AssemblyIterationFlags
38+
{
39+
// load status flags
40+
IncludeLoaded = 0x00000001, // include assemblies that are already loaded
41+
// (m_level >= code:FILE_LOAD_DELIVER_EVENTS)
42+
IncludeLoading = 0x00000002, // include assemblies that are still in the process of loading
43+
// (all m_level values)
44+
IncludeAvailableToProfilers = 0x00000020, // include assemblies available to profilers
45+
// See comment at code:DomainAssembly::IsAvailableToProfilers
46+
47+
// Execution / introspection flags
48+
IncludeExecution = 0x00000004, // include assemblies that are loaded for execution only
49+
50+
IncludeFailedToLoad = 0x00000010, // include assemblies that failed to load
51+
52+
// Collectible assemblies flags
53+
ExcludeCollectible = 0x00000040, // Exclude all collectible assemblies
54+
IncludeCollected = 0x00000080, // Include all collectible assemblies that have been collected
55+
}
56+
3557
public interface ILoader : IContract
3658
{
3759
static string IContract.Name => nameof(Loader);
3860

3961
ModuleHandle GetModuleHandle(TargetPointer modulePointer) => throw new NotImplementedException();
4062

41-
List<TargetPointer> GetAssemblies(TargetPointer appDomain) => throw new NotImplementedException();
63+
List<ModuleHandle> GetAssemblies(TargetPointer appDomain, AssemblyIterationFlags iterationFlags) => throw new NotImplementedException();
4264
TargetPointer GetRootAssembly() => throw new NotImplementedException();
4365
TargetPointer GetAssembly(ModuleHandle handle) => throw new NotImplementedException();
4466
TargetPointer GetPEAssembly(ModuleHandle handle) => throw new NotImplementedException();
@@ -55,6 +77,7 @@ public interface ILoader : IContract
5577

5678
TargetPointer GetModuleLookupMapElement(TargetPointer table, uint token, out TargetNUInt flags) => throw new NotImplementedException();
5779
bool IsCollectible(ModuleHandle handle) => throw new NotImplementedException();
80+
bool IsAssemblyLoaded(ModuleHandle handle) => throw new NotImplementedException();
5881
}
5982

6083
public readonly struct Loader : ILoader

Diff for: src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public enum DataType
3232
ModuleLookupMap,
3333
AppDomain,
3434
Assembly,
35+
LoaderAllocator,
3536
PEAssembly,
3637
PEImage,
3738
PEImageLayout,

Diff for: src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public static class Globals
99
{
1010
// See src/coreclr/debug/runtimeinfo/datadescriptor.h
1111
public const string AppDomain = nameof(AppDomain);
12+
public const string SystemDomain = nameof(SystemDomain);
1213
public const string ThreadStore = nameof(ThreadStore);
1314
public const string FinalizerThread = nameof(FinalizerThread);
1415
public const string GCThread = nameof(GCThread);

Diff for: src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs

+73
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using Microsoft.Diagnostics.DataContractReader.Data;
67

78
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
@@ -23,6 +24,71 @@ ModuleHandle ILoader.GetModuleHandle(TargetPointer modulePointer)
2324
return new ModuleHandle(modulePointer);
2425
}
2526

27+
List<ModuleHandle> ILoader.GetAssemblies(TargetPointer appDomain, AssemblyIterationFlags iterationFlags)
28+
{
29+
if (appDomain == TargetPointer.Null)
30+
throw new ArgumentNullException(nameof(appDomain));
31+
32+
Data.AppDomain domain = _target.ProcessedData.GetOrAdd<Data.AppDomain>(appDomain);
33+
ArrayListBase arrayList = _target.ProcessedData.GetOrAdd<ArrayListBase>(domain.DomainAssemblyList);
34+
35+
List<ModuleHandle> handles = [];
36+
foreach (TargetPointer pAssembly in arrayList.Elements)
37+
{
38+
TargetPointer assemblyAddr = _target.ReadPointer(pAssembly);
39+
Data.Assembly assembly = _target.ProcessedData.GetOrAdd<Data.Assembly>(assemblyAddr);
40+
41+
// following logic is based on AppDomain::AssemblyIterator::Next_Unlocked in appdomain.cpp
42+
43+
if (assembly.IsError && !iterationFlags.HasFlag(AssemblyIterationFlags.IncludeFailedToLoad))
44+
continue; // skip assemblies with errors
45+
46+
if ((assembly.NotifyFlags & 0x1 /*PROFILER_NOTIFIED*/) != 0 && !iterationFlags.HasFlag(AssemblyIterationFlags.IncludeAvailableToProfilers))
47+
{
48+
// The assembly has reached the state at which we would notify profilers,
49+
// and we're supposed to include such assemblies in the enumeration. So
50+
// don't reject it (i.e., noop here, and don't bother with the rest of
51+
// the load status checks). Check for this first, since
52+
// IncludeAvailableToProfilers contains some loaded AND loading
53+
// assemblies.
54+
}
55+
else if (assembly.IsLoaded)
56+
{
57+
if (!iterationFlags.HasFlag(AssemblyIterationFlags.IncludeLoaded))
58+
continue; // skip loaded assemblies
59+
}
60+
else
61+
{
62+
if (!iterationFlags.HasFlag(AssemblyIterationFlags.IncludeLoading))
63+
continue; // skip loading assemblies
64+
}
65+
66+
// Next, reject assemblies whose execution status is
67+
// not to be included in the enumeration
68+
69+
if (!iterationFlags.HasFlag(AssemblyIterationFlags.IncludeExecution))
70+
continue; // skip assemblies with execution status
71+
72+
if (assembly.IsCollectible != 0)
73+
{
74+
if (iterationFlags.HasFlag(AssemblyIterationFlags.ExcludeCollectible))
75+
continue; // skip collectible assemblies
76+
77+
Module module = _target.ProcessedData.GetOrAdd<Data.Module>(assembly.Module);
78+
if (((ModuleFlags)module.Flags).HasFlag(ModuleFlags.Tenured))
79+
continue; // skip tenured modules
80+
81+
LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd<Data.LoaderAllocator>(module.LoaderAllocator);
82+
if (!loaderAllocator.IsAlive && !iterationFlags.HasFlag(AssemblyIterationFlags.IncludeCollected))
83+
continue; // skip collected assemblies
84+
}
85+
86+
handles.Add(new(assembly.Module));
87+
}
88+
89+
return handles;
90+
}
91+
2692
TargetPointer ILoader.GetRootAssembly()
2793
{
2894
TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain);
@@ -192,4 +258,11 @@ bool ILoader.IsCollectible(ModuleHandle handle)
192258
Data.Assembly la = _target.ProcessedData.GetOrAdd<Data.Assembly>(assembly);
193259
return la.IsCollectible != 0;
194260
}
261+
262+
bool ILoader.IsAssemblyLoaded(ModuleHandle handle)
263+
{
264+
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
265+
Data.Assembly assembly = _target.ProcessedData.GetOrAdd<Data.Assembly>(module.Assembly);
266+
return assembly.IsLoaded;
267+
}
195268
}

Diff for: src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/AppDomain.cs

+2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ public AppDomain(Target target, TargetPointer address)
1313
Target.TypeInfo type = target.GetTypeInfo(DataType.AppDomain);
1414

1515
RootAssembly = target.ReadPointer(address + (ulong)type.Fields[nameof(RootAssembly)].Offset);
16+
DomainAssemblyList = address + (ulong)type.Fields[nameof(DomainAssemblyList)].Offset;
1617
}
1718

1819
public TargetPointer RootAssembly { get; init; }
20+
public TargetPointer DomainAssemblyList { get; init; }
1921
}

0 commit comments

Comments
 (0)