Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions docs/design/datacontracts/ExecutionManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ struct CodeBlockHandle
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle);
// Gets information about the EEJitManager: its address, code type, and head of the code heap list.
JitManagerInfo GetEEJitManagerInfo();
// Walks the linked list of CodeHeapListNodes starting from the EEJitManager's AllCodeHeaps head
// and returns information about each code heap.
IEnumerable<ICodeHeapInfo> GetCodeHeapInfos();

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

```csharp
public struct JitManagerInfo
{
public TargetPointer ManagerAddress;
public uint CodeType;
public TargetPointer HeapListAddress;
}
```

```csharp
public interface ICodeHeapInfo { }

public sealed class LoaderCodeHeapInfo : ICodeHeapInfo
{
public TargetPointer HeapAddress { get; }
public TargetPointer LoaderHeapAddress { get; }
}

public sealed class HostCodeHeapInfo : ICodeHeapInfo
{
public TargetPointer HeapAddress { get; }
public TargetPointer BaseAddress { get; }
public TargetPointer CurrentAddress { get; }
}

public sealed class UnknownCodeHeapInfo : ICodeHeapInfo {}

// mirrors native enum that distinguishes code heap types
private enum CodeHeapType : byte
{
LoaderCodeHeap = 0,
HostCodeHeap = 1,
UnknownCodeHeap = 0xff
}
```

```csharp
public struct ExceptionClauseInfo
{
Expand Down Expand Up @@ -109,6 +148,11 @@ Data descriptors used:
| `CodeHeapListNode` | `EndAddress` | End address of the used portion of the code heap |
| `CodeHeapListNode` | `MapBase` | Start of the map - start address rounded down based on OS page size |
| `CodeHeapListNode` | `HeaderMap` | Bit array used to find the start of methods - relative to `MapBase` |
| `CodeHeapListNode` | `Heap` | Pointer to the `CodeHeap` object managed by this node |
| `CodeHeap` | `HeapType` | `uint8` discriminant identifying the concrete heap type |
| `LoaderCodeHeap` | `LoaderHeap` | Offset of the embedded `ExplicitControlLoaderHeap` within the `LoaderCodeHeap` object; adding this to the object's base address yields the loader heap address |
| `HostCodeHeap` | `BaseAddress` | Pointer to the base of the committed memory region |
| `HostCodeHeap` | `CurrentAddress` | Pointer to the last available committed byte in the region |
| `EEJitManager` | `StoreRichDebugInfo` | Boolean value determining if debug info associated with the JitManager contains rich info. |
| `EEJitManager` | `AllCodeHeaps` | Pointer to the head of the linked list of all code heaps managed by the EEJitManager. |
| `RealCodeHeader` | `MethodDesc` | Pointer to the corresponding `MethodDesc` |
Expand Down Expand Up @@ -457,6 +501,52 @@ After obtaining the clause array bounds, the common iteration logic classifies e

`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.

### EE JIT Manager and Code Heap Info

```csharp
JitManagerInfo IExecutionManager.GetEEJitManagerInfo()
{
TargetPointer eeJitManagerPtr = Target.ReadGlobalPointer("EEJitManagerAddress");
TargetPointer eeJitManagerAddr = Target.ReadPointer(eeJitManagerPtr);
TargetPointer allCodeHeaps = Target.ReadPointer(eeJitManagerAddr + /* EEJitManager::AllCodeHeaps offset */);

return new JitManagerInfo
{
ManagerAddress = eeJitManagerAddr,
CodeType = 0, // miManaged | miIL
HeapListAddress = allCodeHeaps,
};
}

private ICodeHeapInfo GetCodeHeapInfo(TargetPointer codeHeapAddress)
{
byte heapType = Target.Read<byte>(codeHeapAddress + /* CodeHeap::HeapType offset */);
return heapType switch
{
0 /* CodeHeapType.LoaderCodeHeap */ => new LoaderCodeHeapInfo(
codeHeapAddress,
codeHeapAddress + /* LoaderCodeHeap::LoaderHeap offset */),
1 /* CodeHeapType.HostCodeHeap */ => new HostCodeHeapInfo(
codeHeapAddress,
Target.ReadPointer(codeHeapAddress + /* HostCodeHeap::BaseAddress offset */),
Target.ReadPointer(codeHeapAddress + /* HostCodeHeap::CurrentAddress offset */)),
_ => new UnknownCodeHeapInfo(),
};
}

IEnumerable<ICodeHeapInfo> IExecutionManager.GetCodeHeapInfos()
{
TargetPointer heapListHead = GetEEJitManagerInfo().HeapListAddress;
TargetPointer nodeAddr = heapListHead;
while (nodeAddr != TargetPointer.Null)
{
TargetPointer heapAddr = Target.ReadPointer(nodeAddr + /* CodeHeapListNode::Heap offset */);
yield return GetCodeHeapInfo(heapAddr);
nodeAddr = Target.ReadPointer(nodeAddr + /* CodeHeapListNode::Next offset */);
}
}
```

### RangeSectionMap

The range section map logically partitions the entire 32-bit or 64-bit addressable space into chunks.
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/codeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2268,6 +2268,7 @@ LoaderCodeHeap::LoaderCodeHeap(bool fMakeExecutable)
m_cbMinNextPad(0)
{
WRAPPER_NO_CONTRACT;
m_heapType = CodeHeapType::LoaderCodeHeap;
}

void ThrowOutOfMemoryWithinRange()
Expand Down
27 changes: 27 additions & 0 deletions src/coreclr/vm/codeman.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,17 @@ class CodeHeap
{
VPTR_BASE_VTABLE_CLASS(CodeHeap)

friend struct ::cdac_data<CodeHeap>;

public:
// [cDAC] [ExecutionManager] : Contract depends on these values.
enum class CodeHeapType : uint8_t
{
LoaderCodeHeap = 0,
HostCodeHeap = 1,
UnknownCodeHeap = 0xff,
};

CodeHeap() = default;

// virtual dtor. Clean up heap
Expand All @@ -486,6 +496,9 @@ class CodeHeap
#ifdef DACCESS_COMPILE
virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
#endif

protected:
CodeHeapType m_heapType = CodeHeapType::UnknownCodeHeap;
};

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -551,6 +564,8 @@ class LoaderCodeHeap final : public CodeHeap

VPTR_VTABLE_CLASS(LoaderCodeHeap, CodeHeap)

friend struct ::cdac_data<LoaderCodeHeap>;

private:
ExplicitControlLoaderHeap m_LoaderHeap;
SSIZE_T m_cbMinNextPad;
Expand Down Expand Up @@ -2277,6 +2292,18 @@ struct cdac_data<EEJitManager>
static constexpr size_t AllCodeHeaps = offsetof(EEJitManager, m_pAllCodeHeaps);
};

template<>
struct cdac_data<CodeHeap>
{
static constexpr size_t HeapType = offsetof(CodeHeap, m_heapType);
};

template<>
struct cdac_data<LoaderCodeHeap>
{
static constexpr size_t LoaderHeap = offsetof(LoaderCodeHeap, m_LoaderHeap);
};


//*****************************************************************************
//
Expand Down
17 changes: 17 additions & 0 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,25 @@ CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, StartAddress, offsetof(HeapList,
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, EndAddress, offsetof(HeapList, endAddress))
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, MapBase, offsetof(HeapList, mapBase))
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, HeaderMap, offsetof(HeapList, pHdrMap))
CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, Heap, offsetof(HeapList, pHeap))
CDAC_TYPE_END(CodeHeapListNode)

CDAC_TYPE_BEGIN(CodeHeap)
CDAC_TYPE_INDETERMINATE(CodeHeap)
CDAC_TYPE_FIELD(CodeHeap, /*uint8*/, HeapType, cdac_data<CodeHeap>::HeapType)
CDAC_TYPE_END(CodeHeap)

CDAC_TYPE_BEGIN(LoaderCodeHeap)
CDAC_TYPE_INDETERMINATE(LoaderCodeHeap)
CDAC_TYPE_FIELD(LoaderCodeHeap, /*pointer*/, LoaderHeap, cdac_data<LoaderCodeHeap>::LoaderHeap)
CDAC_TYPE_END(LoaderCodeHeap)

CDAC_TYPE_BEGIN(HostCodeHeap)
CDAC_TYPE_INDETERMINATE(HostCodeHeap)
CDAC_TYPE_FIELD(HostCodeHeap, /*pointer*/, BaseAddress, cdac_data<HostCodeHeap>::BaseAddress)
CDAC_TYPE_FIELD(HostCodeHeap, /*pointer*/, CurrentAddress, cdac_data<HostCodeHeap>::CurrentAddress)
CDAC_TYPE_END(HostCodeHeap)

#ifdef FEATURE_CODE_VERSIONING
CDAC_TYPE_BEGIN(ILCodeVersioningState)
CDAC_TYPE_INDETERMINATE(ILCodeVersioningState)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/dynamicmethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ HostCodeHeap::HostCodeHeap(EECodeGenManager *pJitManager, bool isExecutable)
m_pFreeList = NULL;
m_pAllocator = NULL;
m_pNextHeapToRelease = NULL;
m_heapType = CodeHeapType::HostCodeHeap;
}

HostCodeHeap::~HostCodeHeap()
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/vm/dynamicmethod.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ class HostCodeHeap final : public CodeHeap

VPTR_VTABLE_CLASS(HostCodeHeap, CodeHeap)

friend struct ::cdac_data<HostCodeHeap>;

private:
// pointer back to jit manager info
PTR_HeapList m_pHeapList;
Expand Down Expand Up @@ -373,6 +375,13 @@ class HostCodeHeap final : public CodeHeap
PTR_EECodeGenManager GetJitManager() { return m_pJitManager; }
}; // class HostCodeHeap

template<>
struct cdac_data<HostCodeHeap>
{
static constexpr size_t BaseAddress = offsetof(HostCodeHeap, m_pBaseAddr);
static constexpr size_t CurrentAddress = offsetof(HostCodeHeap, m_pLastAvailableCommittedAddr);
};

//---------------------------------------------------------------------------------------
//
#include "ilstubresolver.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,38 @@ public struct JitManagerInfo
public TargetPointer HeapListAddress;
}

public interface ICodeHeapInfo
{
}

public sealed class LoaderCodeHeapInfo : ICodeHeapInfo
{
public TargetPointer HeapAddress { get; }
public TargetPointer LoaderHeapAddress { get; }

public LoaderCodeHeapInfo(TargetPointer heapAddress, TargetPointer loaderHeapAddress)
{
HeapAddress = heapAddress;
LoaderHeapAddress = loaderHeapAddress;
}
}

public sealed class HostCodeHeapInfo : ICodeHeapInfo
{
public TargetPointer HeapAddress { get; }
public TargetPointer BaseAddress { get; }
public TargetPointer CurrentAddress { get; }

public HostCodeHeapInfo(TargetPointer heapAddress, TargetPointer baseAddress, TargetPointer currentAddress)
{
HeapAddress = heapAddress;
BaseAddress = baseAddress;
CurrentAddress = currentAddress;
}
}

public sealed class UnknownCodeHeapInfo : ICodeHeapInfo {}

public enum JitType : uint
{
Unknown = 0,
Expand All @@ -68,6 +100,7 @@ public interface IExecutionManager : IContract
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
List<ExceptionClauseInfo> GetExceptionClauses(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException();
Comment thread
rcj1 marked this conversation as resolved.
IEnumerable<ICodeHeapInfo> GetCodeHeapInfos() => throw new NotImplementedException();
}

public readonly struct ExecutionManager : IExecutionManager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ public enum DataType
RangeSection,
RealCodeHeader,
CodeHeapListNode,
CodeHeap,
LoaderCodeHeap,
HostCodeHeap,
Comment thread
rcj1 marked this conversation as resolved.
MethodDescVersioningState,
ILCodeVersioningState,
NativeCodeVersionNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ private enum RangeSectionFlags : int
RangeList = 0x04,
}

// Mirrors the native CodeHeap::CodeHeapType enum in codeman.h.
// Used to interpret the raw byte stored in the target process.
private enum CodeHeapType : byte
{
LoaderCodeHeap = 0,
HostCodeHeap = 1,
UnknownCodeHeap = 0xff,
}

private enum ExceptionClauseFlags_1 : uint
{
Filter = 0x1,
Expand Down Expand Up @@ -396,6 +405,32 @@ JitManagerInfo IExecutionManager.GetEEJitManagerInfo()
};
}

private ICodeHeapInfo GetCodeHeapInfo(TargetPointer codeHeapAddress)
{
Data.CodeHeap codeHeap = _target.ProcessedData.GetOrAdd<Data.CodeHeap>(codeHeapAddress);
return (CodeHeapType)codeHeap.HeapType switch
{
CodeHeapType.LoaderCodeHeap => new Contracts.LoaderCodeHeapInfo(codeHeapAddress,
_target.ProcessedData.GetOrAdd<Data.LoaderCodeHeap>(codeHeapAddress).LoaderHeap),
CodeHeapType.HostCodeHeap => new Contracts.HostCodeHeapInfo(codeHeapAddress,
_target.ProcessedData.GetOrAdd<Data.HostCodeHeap>(codeHeapAddress).BaseAddress,
_target.ProcessedData.GetOrAdd<Data.HostCodeHeap>(codeHeapAddress).CurrentAddress),
_ => new Contracts.UnknownCodeHeapInfo(),
};
Comment thread
rcj1 marked this conversation as resolved.
}

Comment thread
rcj1 marked this conversation as resolved.
IEnumerable<ICodeHeapInfo> IExecutionManager.GetCodeHeapInfos()
{
TargetPointer heapListAddress = ((IExecutionManager)this).GetEEJitManagerInfo().HeapListAddress;
TargetPointer nodeAddr = heapListAddress;
while (nodeAddr != TargetPointer.Null)
{
Data.CodeHeapListNode node = _target.ProcessedData.GetOrAdd<Data.CodeHeapListNode>(nodeAddr);
yield return GetCodeHeapInfo(node.Heap);
nodeAddr = node.Next;
}
Comment thread
rcj1 marked this conversation as resolved.
}

private RangeSection RangeSectionFromCodeBlockHandle(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ internal ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionM
public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle);
public List<ExceptionClauseInfo> GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle);
public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo();
public IEnumerable<ICodeHeapInfo> GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos();
public void Flush() => _executionManagerCore.Flush();
Comment thread
rcj1 marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ internal ExecutionManager_2(Target target, Data.RangeSectionMap topRangeSectionM
public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle);
public List<ExceptionClauseInfo> GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle);
public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo();
public IEnumerable<ICodeHeapInfo> GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos();
public void Flush() => _executionManagerCore.Flush();
Comment thread
rcj1 marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -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.

namespace Microsoft.Diagnostics.DataContractReader.Data;

internal sealed class CodeHeap : IData<CodeHeap>
{
static CodeHeap IData<CodeHeap>.Create(Target target, TargetPointer address)
=> new CodeHeap(target, address);

public CodeHeap(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.CodeHeap);
HeapType = target.Read<byte>(address + (ulong)type.Fields[nameof(HeapType)].Offset);
}

public byte HeapType { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public CodeHeapListNode(Target target, TargetPointer address)
EndAddress = target.ReadPointer(address + (ulong)type.Fields[nameof(EndAddress)].Offset);
MapBase = target.ReadPointer(address + (ulong)type.Fields[nameof(MapBase)].Offset);
HeaderMap = target.ReadPointer(address + (ulong)type.Fields[nameof(HeaderMap)].Offset);
Heap = target.ReadPointer(address + (ulong)type.Fields[nameof(Heap)].Offset);
Comment thread
rcj1 marked this conversation as resolved.
}

public TargetPointer Next { get; init; }
Expand All @@ -25,4 +26,6 @@ public CodeHeapListNode(Target target, TargetPointer address)
public TargetPointer MapBase { get; init; }

public TargetPointer HeaderMap { get; init; }

public TargetPointer Heap { get; init; }
}
Loading
Loading