Skip to content

Commit 655c517

Browse files
rcj1CopilotCopilot
authored
Add GetCodeHeapList cDAC API (#126231)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 209c66f commit 655c517

File tree

22 files changed

+807
-4
lines changed

22 files changed

+807
-4
lines changed

docs/design/datacontracts/ExecutionManager.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ struct CodeBlockHandle
4545
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle);
4646
// Gets information about the EEJitManager: its address, code type, and head of the code heap list.
4747
JitManagerInfo GetEEJitManagerInfo();
48+
// Walks the linked list of CodeHeapListNodes starting from the EEJitManager's AllCodeHeaps head
49+
// and returns information about each code heap.
50+
IEnumerable<ICodeHeapInfo> GetCodeHeapInfos();
4851

4952
// Get the exception clause info for the code block
5053
List<ExceptionClauseInfo> GetExceptionClauses(CodeBlockHandle codeInfoHandle);
@@ -56,6 +59,42 @@ struct CodeBlockHandle
5659
bool IsFilterFunclet(CodeBlockHandle codeInfoHandle);
5760
```
5861

62+
```csharp
63+
public struct JitManagerInfo
64+
{
65+
public TargetPointer ManagerAddress;
66+
public uint CodeType;
67+
public TargetPointer HeapListAddress;
68+
}
69+
```
70+
71+
```csharp
72+
public interface ICodeHeapInfo { }
73+
74+
public sealed class LoaderCodeHeapInfo : ICodeHeapInfo
75+
{
76+
public TargetPointer HeapAddress { get; }
77+
public TargetPointer LoaderHeapAddress { get; }
78+
}
79+
80+
public sealed class HostCodeHeapInfo : ICodeHeapInfo
81+
{
82+
public TargetPointer HeapAddress { get; }
83+
public TargetPointer BaseAddress { get; }
84+
public TargetPointer CurrentAddress { get; }
85+
}
86+
87+
public sealed class UnknownCodeHeapInfo : ICodeHeapInfo {}
88+
89+
// mirrors native enum that distinguishes code heap types
90+
private enum CodeHeapType : byte
91+
{
92+
LoaderCodeHeap = 0,
93+
HostCodeHeap = 1,
94+
UnknownCodeHeap = 0xff
95+
}
96+
```
97+
5998
```csharp
6099
public struct ExceptionClauseInfo
61100
{
@@ -109,6 +148,11 @@ Data descriptors used:
109148
| `CodeHeapListNode` | `EndAddress` | End address of the used portion of the code heap |
110149
| `CodeHeapListNode` | `MapBase` | Start of the map - start address rounded down based on OS page size |
111150
| `CodeHeapListNode` | `HeaderMap` | Bit array used to find the start of methods - relative to `MapBase` |
151+
| `CodeHeapListNode` | `Heap` | Pointer to the `CodeHeap` object managed by this node |
152+
| `CodeHeap` | `HeapType` | `uint8` discriminant identifying the concrete heap type |
153+
| `LoaderCodeHeap` | `LoaderHeap` | Offset of the embedded `ExplicitControlLoaderHeap` within the `LoaderCodeHeap` object; adding this to the object's base address yields the loader heap address |
154+
| `HostCodeHeap` | `BaseAddress` | Pointer to the base of the committed memory region |
155+
| `HostCodeHeap` | `CurrentAddress` | Pointer to the last available committed byte in the region |
112156
| `EEJitManager` | `StoreRichDebugInfo` | Boolean value determining if debug info associated with the JitManager contains rich info. |
113157
| `EEJitManager` | `AllCodeHeaps` | Pointer to the head of the linked list of all code heaps managed by the EEJitManager. |
114158
| `RealCodeHeader` | `MethodDesc` | Pointer to the corresponding `MethodDesc` |
@@ -457,6 +501,52 @@ After obtaining the clause array bounds, the common iteration logic classifies e
457501

458502
`IsFilterFunclet` first checks `IsFunclet`. If the code block is a funclet, it retrieves the EH clauses for the method and checks whether any filter clause's handler offset matches the funclet's relative offset. If a match is found, the funclet is a filter funclet.
459503

504+
### EE JIT Manager and Code Heap Info
505+
506+
```csharp
507+
JitManagerInfo IExecutionManager.GetEEJitManagerInfo()
508+
{
509+
TargetPointer eeJitManagerPtr = Target.ReadGlobalPointer("EEJitManagerAddress");
510+
TargetPointer eeJitManagerAddr = Target.ReadPointer(eeJitManagerPtr);
511+
TargetPointer allCodeHeaps = Target.ReadPointer(eeJitManagerAddr + /* EEJitManager::AllCodeHeaps offset */);
512+
513+
return new JitManagerInfo
514+
{
515+
ManagerAddress = eeJitManagerAddr,
516+
CodeType = 0, // miManaged | miIL
517+
HeapListAddress = allCodeHeaps,
518+
};
519+
}
520+
521+
private ICodeHeapInfo GetCodeHeapInfo(TargetPointer codeHeapAddress)
522+
{
523+
byte heapType = Target.Read<byte>(codeHeapAddress + /* CodeHeap::HeapType offset */);
524+
return heapType switch
525+
{
526+
0 /* CodeHeapType.LoaderCodeHeap */ => new LoaderCodeHeapInfo(
527+
codeHeapAddress,
528+
codeHeapAddress + /* LoaderCodeHeap::LoaderHeap offset */),
529+
1 /* CodeHeapType.HostCodeHeap */ => new HostCodeHeapInfo(
530+
codeHeapAddress,
531+
Target.ReadPointer(codeHeapAddress + /* HostCodeHeap::BaseAddress offset */),
532+
Target.ReadPointer(codeHeapAddress + /* HostCodeHeap::CurrentAddress offset */)),
533+
_ => new UnknownCodeHeapInfo(),
534+
};
535+
}
536+
537+
IEnumerable<ICodeHeapInfo> IExecutionManager.GetCodeHeapInfos()
538+
{
539+
TargetPointer heapListHead = GetEEJitManagerInfo().HeapListAddress;
540+
TargetPointer nodeAddr = heapListHead;
541+
while (nodeAddr != TargetPointer.Null)
542+
{
543+
TargetPointer heapAddr = Target.ReadPointer(nodeAddr + /* CodeHeapListNode::Heap offset */);
544+
yield return GetCodeHeapInfo(heapAddr);
545+
nodeAddr = Target.ReadPointer(nodeAddr + /* CodeHeapListNode::Next offset */);
546+
}
547+
}
548+
```
549+
460550
### RangeSectionMap
461551

462552
The range section map logically partitions the entire 32-bit or 64-bit addressable space into chunks.

src/coreclr/vm/codeman.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2268,6 +2268,7 @@ LoaderCodeHeap::LoaderCodeHeap(bool fMakeExecutable)
22682268
m_cbMinNextPad(0)
22692269
{
22702270
WRAPPER_NO_CONTRACT;
2271+
m_heapType = CodeHeapType::LoaderCodeHeap;
22712272
}
22722273

22732274
void ThrowOutOfMemoryWithinRange()

src/coreclr/vm/codeman.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,17 @@ class CodeHeap
473473
{
474474
VPTR_BASE_VTABLE_CLASS(CodeHeap)
475475

476+
friend struct ::cdac_data<CodeHeap>;
477+
476478
public:
479+
// [cDAC] [ExecutionManager] : Contract depends on these values.
480+
enum class CodeHeapType : uint8_t
481+
{
482+
LoaderCodeHeap = 0,
483+
HostCodeHeap = 1,
484+
UnknownCodeHeap = 0xff,
485+
};
486+
477487
CodeHeap() = default;
478488

479489
// virtual dtor. Clean up heap
@@ -486,6 +496,9 @@ class CodeHeap
486496
#ifdef DACCESS_COMPILE
487497
virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
488498
#endif
499+
500+
protected:
501+
CodeHeapType m_heapType = CodeHeapType::UnknownCodeHeap;
489502
};
490503

491504
//-----------------------------------------------------------------------------
@@ -551,6 +564,8 @@ class LoaderCodeHeap final : public CodeHeap
551564

552565
VPTR_VTABLE_CLASS(LoaderCodeHeap, CodeHeap)
553566

567+
friend struct ::cdac_data<LoaderCodeHeap>;
568+
554569
private:
555570
ExplicitControlLoaderHeap m_LoaderHeap;
556571
SSIZE_T m_cbMinNextPad;
@@ -2277,6 +2292,18 @@ struct cdac_data<EEJitManager>
22772292
static constexpr size_t AllCodeHeaps = offsetof(EEJitManager, m_pAllCodeHeaps);
22782293
};
22792294

2295+
template<>
2296+
struct cdac_data<CodeHeap>
2297+
{
2298+
static constexpr size_t HeapType = offsetof(CodeHeap, m_heapType);
2299+
};
2300+
2301+
template<>
2302+
struct cdac_data<LoaderCodeHeap>
2303+
{
2304+
static constexpr size_t LoaderHeap = offsetof(LoaderCodeHeap, m_LoaderHeap);
2305+
};
2306+
22802307

22812308
//*****************************************************************************
22822309
//

src/coreclr/vm/datadescriptor/datadescriptor.inc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,8 +846,25 @@ CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, StartAddress, offsetof(HeapList,
846846
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, EndAddress, offsetof(HeapList, endAddress))
847847
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, MapBase, offsetof(HeapList, mapBase))
848848
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, HeaderMap, offsetof(HeapList, pHdrMap))
849+
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, Heap, offsetof(HeapList, pHeap))
849850
CDAC_TYPE_END(CodeHeapListNode)
850851

852+
CDAC_TYPE_BEGIN(CodeHeap)
853+
CDAC_TYPE_INDETERMINATE(CodeHeap)
854+
CDAC_TYPE_FIELD(CodeHeap, /*uint8*/, HeapType, cdac_data<CodeHeap>::HeapType)
855+
CDAC_TYPE_END(CodeHeap)
856+
857+
CDAC_TYPE_BEGIN(LoaderCodeHeap)
858+
CDAC_TYPE_INDETERMINATE(LoaderCodeHeap)
859+
CDAC_TYPE_FIELD(LoaderCodeHeap, /*pointer*/, LoaderHeap, cdac_data<LoaderCodeHeap>::LoaderHeap)
860+
CDAC_TYPE_END(LoaderCodeHeap)
861+
862+
CDAC_TYPE_BEGIN(HostCodeHeap)
863+
CDAC_TYPE_INDETERMINATE(HostCodeHeap)
864+
CDAC_TYPE_FIELD(HostCodeHeap, /*pointer*/, BaseAddress, cdac_data<HostCodeHeap>::BaseAddress)
865+
CDAC_TYPE_FIELD(HostCodeHeap, /*pointer*/, CurrentAddress, cdac_data<HostCodeHeap>::CurrentAddress)
866+
CDAC_TYPE_END(HostCodeHeap)
867+
851868
#ifdef FEATURE_CODE_VERSIONING
852869
CDAC_TYPE_BEGIN(ILCodeVersioningState)
853870
CDAC_TYPE_INDETERMINATE(ILCodeVersioningState)

src/coreclr/vm/dynamicmethod.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ HostCodeHeap::HostCodeHeap(EECodeGenManager *pJitManager, bool isExecutable)
366366
m_pFreeList = NULL;
367367
m_pAllocator = NULL;
368368
m_pNextHeapToRelease = NULL;
369+
m_heapType = CodeHeapType::HostCodeHeap;
369370
}
370371

371372
HostCodeHeap::~HostCodeHeap()

src/coreclr/vm/dynamicmethod.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ class HostCodeHeap final : public CodeHeap
312312

313313
VPTR_VTABLE_CLASS(HostCodeHeap, CodeHeap)
314314

315+
friend struct ::cdac_data<HostCodeHeap>;
316+
315317
private:
316318
// pointer back to jit manager info
317319
PTR_HeapList m_pHeapList;
@@ -373,6 +375,13 @@ class HostCodeHeap final : public CodeHeap
373375
PTR_EECodeGenManager GetJitManager() { return m_pJitManager; }
374376
}; // class HostCodeHeap
375377

378+
template<>
379+
struct cdac_data<HostCodeHeap>
380+
{
381+
static constexpr size_t BaseAddress = offsetof(HostCodeHeap, m_pBaseAddr);
382+
static constexpr size_t CurrentAddress = offsetof(HostCodeHeap, m_pLastAvailableCommittedAddr);
383+
};
384+
376385
//---------------------------------------------------------------------------------------
377386
//
378387
#include "ilstubresolver.h"

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,38 @@ public struct JitManagerInfo
4242
public TargetPointer HeapListAddress;
4343
}
4444

45+
public interface ICodeHeapInfo
46+
{
47+
}
48+
49+
public sealed class LoaderCodeHeapInfo : ICodeHeapInfo
50+
{
51+
public TargetPointer HeapAddress { get; }
52+
public TargetPointer LoaderHeapAddress { get; }
53+
54+
public LoaderCodeHeapInfo(TargetPointer heapAddress, TargetPointer loaderHeapAddress)
55+
{
56+
HeapAddress = heapAddress;
57+
LoaderHeapAddress = loaderHeapAddress;
58+
}
59+
}
60+
61+
public sealed class HostCodeHeapInfo : ICodeHeapInfo
62+
{
63+
public TargetPointer HeapAddress { get; }
64+
public TargetPointer BaseAddress { get; }
65+
public TargetPointer CurrentAddress { get; }
66+
67+
public HostCodeHeapInfo(TargetPointer heapAddress, TargetPointer baseAddress, TargetPointer currentAddress)
68+
{
69+
HeapAddress = heapAddress;
70+
BaseAddress = baseAddress;
71+
CurrentAddress = currentAddress;
72+
}
73+
}
74+
75+
public sealed class UnknownCodeHeapInfo : ICodeHeapInfo {}
76+
4577
public enum JitType : uint
4678
{
4779
Unknown = 0,
@@ -68,6 +100,7 @@ public interface IExecutionManager : IContract
68100
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
69101
List<ExceptionClauseInfo> GetExceptionClauses(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
70102
JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException();
103+
IEnumerable<ICodeHeapInfo> GetCodeHeapInfos() => throw new NotImplementedException();
71104
}
72105

73106
public readonly struct ExecutionManager : IExecutionManager

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ public enum DataType
106106
RangeSection,
107107
RealCodeHeader,
108108
CodeHeapListNode,
109+
CodeHeap,
110+
LoaderCodeHeap,
111+
HostCodeHeap,
109112
MethodDescVersioningState,
110113
ILCodeVersioningState,
111114
NativeCodeVersionNode,

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ private enum RangeSectionFlags : int
6262
RangeList = 0x04,
6363
}
6464

65+
// Mirrors the native CodeHeap::CodeHeapType enum in codeman.h.
66+
// Used to interpret the raw byte stored in the target process.
67+
private enum CodeHeapType : byte
68+
{
69+
LoaderCodeHeap = 0,
70+
HostCodeHeap = 1,
71+
UnknownCodeHeap = 0xff,
72+
}
73+
6574
private enum ExceptionClauseFlags_1 : uint
6675
{
6776
Filter = 0x1,
@@ -396,6 +405,32 @@ JitManagerInfo IExecutionManager.GetEEJitManagerInfo()
396405
};
397406
}
398407

408+
private ICodeHeapInfo GetCodeHeapInfo(TargetPointer codeHeapAddress)
409+
{
410+
Data.CodeHeap codeHeap = _target.ProcessedData.GetOrAdd<Data.CodeHeap>(codeHeapAddress);
411+
return (CodeHeapType)codeHeap.HeapType switch
412+
{
413+
CodeHeapType.LoaderCodeHeap => new Contracts.LoaderCodeHeapInfo(codeHeapAddress,
414+
_target.ProcessedData.GetOrAdd<Data.LoaderCodeHeap>(codeHeapAddress).LoaderHeap),
415+
CodeHeapType.HostCodeHeap => new Contracts.HostCodeHeapInfo(codeHeapAddress,
416+
_target.ProcessedData.GetOrAdd<Data.HostCodeHeap>(codeHeapAddress).BaseAddress,
417+
_target.ProcessedData.GetOrAdd<Data.HostCodeHeap>(codeHeapAddress).CurrentAddress),
418+
_ => new Contracts.UnknownCodeHeapInfo(),
419+
};
420+
}
421+
422+
IEnumerable<ICodeHeapInfo> IExecutionManager.GetCodeHeapInfos()
423+
{
424+
TargetPointer heapListAddress = ((IExecutionManager)this).GetEEJitManagerInfo().HeapListAddress;
425+
TargetPointer nodeAddr = heapListAddress;
426+
while (nodeAddr != TargetPointer.Null)
427+
{
428+
Data.CodeHeapListNode node = _target.ProcessedData.GetOrAdd<Data.CodeHeapListNode>(nodeAddr);
429+
yield return GetCodeHeapInfo(node.Heap);
430+
nodeAddr = node.Next;
431+
}
432+
}
433+
399434
private RangeSection RangeSectionFromCodeBlockHandle(CodeBlockHandle codeInfoHandle)
400435
{
401436
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ internal ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionM
3131
public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle);
3232
public List<ExceptionClauseInfo> GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle);
3333
public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo();
34+
public IEnumerable<ICodeHeapInfo> GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos();
3435
public void Flush() => _executionManagerCore.Flush();
3536
}

0 commit comments

Comments
 (0)