From 6055dcda2ea59b0d8fc342d57d48705a36bd6769 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:22:07 +0000 Subject: [PATCH 1/6] Initial plan From 758ddcb6dc2a908f65faadaf24484ad867fecb5f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:52:12 +0000 Subject: [PATCH 2/6] Implement ISOSDacInterface::GetJitManagerList in cDAC SOSDacImpl - Add AllCodeHeaps field to cdac_data and EEJitManagerAddress global pointer - Update datadescriptor.inc with new type field and global pointer - Add JitManagerInfo struct and GetJitManagerInfo() to IExecutionManager contract - Implement GetJitManagerInfo in ExecutionManagerCore, ExecutionManager_1, ExecutionManager_2 - Define DacpJitManagerInfo struct in ISOSDacInterface.cs - Implement GetJitManagerList in SOSDacImpl.cs with DEBUG comparison - Add unit tests for GetJitManagerInfo (16 new tests, all pass) - Update MockDescriptors.ExecutionManager with EEJitManager type and global Co-authored-by: max-charlamb <44248479+max-charlamb@users.noreply.github.com> --- src/coreclr/vm/codeman.h | 4 ++ .../vm/datadescriptor/datadescriptor.inc | 2 + .../Contracts/IExecutionManager.cs | 8 +++ .../Constants.cs | 1 + .../ExecutionManager/ExecutionManagerCore.cs | 15 +++++ .../ExecutionManager/ExecutionManager_1.cs | 1 + .../ExecutionManager/ExecutionManager_2.cs | 1 + .../Data/EEJitManager.cs | 2 + .../ISOSDacInterface.cs | 9 ++- .../SOSDacImpl.cs | 56 ++++++++++++++++++- .../ExecutionManager/ExecutionManagerTests.cs | 34 +++++++++++ .../MockDescriptors.ExecutionManager.cs | 34 ++++++++++- 12 files changed, 161 insertions(+), 6 deletions(-) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 1f13e6e71c0f92..967940da4bd66f 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2005,6 +2005,8 @@ class EECodeGenManager : public IJitManager Crst m_CodeHeapLock; ULONG m_iteratorCount; bool m_storeRichDebugInfo; + + friend struct ::cdac_data; }; //----------------------------------------------------------------------------- @@ -2263,6 +2265,7 @@ template<> struct cdac_data { static constexpr size_t StoreRichDebugInfo = offsetof(EEJitManager, m_storeRichDebugInfo); + static constexpr size_t AllCodeHeaps = offsetof(EEJitManager, m_pAllCodeHeaps); }; @@ -2580,6 +2583,7 @@ template<> struct cdac_data { static constexpr void* const CodeRangeMapAddress = (void*)&ExecutionManager::g_codeRangeMap.Data[0]; + static constexpr void* const EEJitManagerPtr = (void*)&ExecutionManager::m_pEEJitManager; }; #endif diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 4799a56f287703..ab42e6019bdb7e 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -672,6 +672,7 @@ CDAC_TYPE_END(RangeSection) CDAC_TYPE_BEGIN(EEJitManager) CDAC_TYPE_INDETERMINATE(EEJitManager) CDAC_TYPE_FIELD(EEJitManager, /*bool*/, StoreRichDebugInfo, cdac_data::StoreRichDebugInfo) +CDAC_TYPE_FIELD(EEJitManager, /*pointer*/, AllCodeHeaps, cdac_data::AllCodeHeaps) CDAC_TYPE_END(EEJitManager) CDAC_TYPE_BEGIN(RealCodeHeader) @@ -1153,6 +1154,7 @@ CDAC_GLOBAL(StressLogMaxMessageSize, uint64, (uint64_t)StressMsg::maxMsgSize) CDAC_GLOBAL(StressLogEnabled, uint8, 0) #endif CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_data::CodeRangeMapAddress) +CDAC_GLOBAL_POINTER(EEJitManagerAddress, cdac_data::EEJitManagerPtr) CDAC_GLOBAL_POINTER(PlatformMetadata, &::g_cdacPlatformMetadata) CDAC_GLOBAL_POINTER(ProfilerControlBlock, &::g_profControlBlock) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs index 8a9653e17e7618..b563137afd8f02 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs @@ -12,6 +12,13 @@ public struct CodeBlockHandle public CodeBlockHandle(TargetPointer address) => Address = address; } +public struct JitManagerInfo +{ + public TargetPointer ManagerAddress; + public uint CodeType; + public TargetPointer HeapListAddress; +} + public interface IExecutionManager : IContract { static string IContract.Name { get; } = nameof(ExecutionManager); @@ -25,6 +32,7 @@ public interface IExecutionManager : IContract // **Currently GetGCInfo only supports X86** void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => throw new NotImplementedException(); TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException(); + JitManagerInfo GetJitManagerInfo() => throw new NotImplementedException(); } public readonly struct ExecutionManager : IExecutionManager 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 68a4ac621aca3a..22eac6f1f968d6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -60,6 +60,7 @@ public static class Globals public const string DirectorySeparator = nameof(DirectorySeparator); public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); + public const string EEJitManagerAddress = nameof(EEJitManagerAddress); public const string StubCodeBlockLast = nameof(StubCodeBlockLast); public const string DefaultADID = nameof(DefaultADID); public const string StaticsPointerMask = nameof(StaticsPointerMask); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs index 7161eae75e3840..d8a8c560b8bf36 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs @@ -269,4 +269,19 @@ TargetNUInt IExecutionManager.GetRelativeOffset(CodeBlockHandle codeInfoHandle) return info.RelativeOffset; } + + JitManagerInfo IExecutionManager.GetJitManagerInfo() + { + TargetPointer eeJitManagerPtr = _target.ReadGlobalPointer(Constants.Globals.EEJitManagerAddress); + TargetPointer eeJitManagerAddr = _target.ReadPointer(eeJitManagerPtr); + + Data.EEJitManager jitManager = _target.ProcessedData.GetOrAdd(eeJitManagerAddr); + + return new JitManagerInfo + { + ManagerAddress = eeJitManagerAddr, + CodeType = 0, // miManaged | miIL + HeapListAddress = jitManager.AllCodeHeaps, + }; + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs index 551c664237096c..f2ab607ce0619e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs @@ -23,4 +23,5 @@ internal ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionM public TargetPointer GetDebugInfo(CodeBlockHandle codeInfoHandle, out bool hasFlagByte) => _executionManagerCore.GetDebugInfo(codeInfoHandle, out hasFlagByte); public void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => _executionManagerCore.GetGCInfo(codeInfoHandle, out gcInfo, out gcVersion); public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle); + public JitManagerInfo GetJitManagerInfo() => _executionManagerCore.GetJitManagerInfo(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs index ab1fda5e329640..13458cf315303e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs @@ -23,4 +23,5 @@ internal ExecutionManager_2(Target target, Data.RangeSectionMap topRangeSectionM public TargetPointer GetDebugInfo(CodeBlockHandle codeInfoHandle, out bool hasFlagByte) => _executionManagerCore.GetDebugInfo(codeInfoHandle, out hasFlagByte); public void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => _executionManagerCore.GetGCInfo(codeInfoHandle, out gcInfo, out gcVersion); public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle); + public JitManagerInfo GetJitManagerInfo() => _executionManagerCore.GetJitManagerInfo(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEJitManager.cs index 58eae2a2cf67d1..7d2e2d074dd52c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEJitManager.cs @@ -11,7 +11,9 @@ public EEJitManager(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.EEJitManager); StoreRichDebugInfo = target.Read(address + (ulong)type.Fields[nameof(StoreRichDebugInfo)].Offset) != 0; + AllCodeHeaps = target.ReadPointer(address + (ulong)type.Fields[nameof(AllCodeHeaps)].Offset); } public bool StoreRichDebugInfo { get; init; } + public TargetPointer AllCodeHeaps { get; init; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs index 6851ade98cdffa..63f3ea2ada6052 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs @@ -411,6 +411,13 @@ public struct DacpFieldDescData public ClrDataAddress NextField; }; +public struct DacpJitManagerInfo +{ + public ClrDataAddress managerAddr; + public uint codeType; + public ClrDataAddress ptrHeapList; +}; + [GeneratedComInterface] [Guid("436f00f2-b42a-4b9f-870c-e73db66ae930")] public unsafe partial interface ISOSDacInterface @@ -480,7 +487,7 @@ public unsafe partial interface ISOSDacInterface [PreserveSig] int GetCodeHeaderData(ClrDataAddress ip, /*struct DacpCodeHeaderData*/ void* data); [PreserveSig] - int GetJitManagerList(uint count, /*struct DacpJitManagerInfo*/ void* managers, uint* pNeeded); + int GetJitManagerList(uint count, DacpJitManagerInfo* managers, uint* pNeeded); [PreserveSig] int GetJitHelperFunctionName(ClrDataAddress ip, uint count, byte* name, uint* pNeeded); [PreserveSig] diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index f1ee4780f5968e..ca7a082c37ce66 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -1537,8 +1537,60 @@ int ISOSDacInterface.GetILForModule(ClrDataAddress moduleAddr, int rva, ClrDataA } int ISOSDacInterface.GetJitHelperFunctionName(ClrDataAddress ip, uint count, byte* name, uint* pNeeded) => _legacyImpl is not null ? _legacyImpl.GetJitHelperFunctionName(ip, count, name, pNeeded) : HResults.E_NOTIMPL; - int ISOSDacInterface.GetJitManagerList(uint count, void* managers, uint* pNeeded) - => _legacyImpl is not null ? _legacyImpl.GetJitManagerList(count, managers, pNeeded) : HResults.E_NOTIMPL; + int ISOSDacInterface.GetJitManagerList(uint count, DacpJitManagerInfo* managers, uint* pNeeded) + { + int hr = HResults.S_OK; + try + { + if (managers is not null) + { + if (count >= 1) + { + *managers = default; + Contracts.JitManagerInfo jitManagerInfo = _target.Contracts.ExecutionManager.GetJitManagerInfo(); + managers->managerAddr = jitManagerInfo.ManagerAddress.ToClrDataAddress(_target); + managers->codeType = jitManagerInfo.CodeType; + managers->ptrHeapList = jitManagerInfo.HeapListAddress.ToClrDataAddress(_target); + } + } + else if (pNeeded is not null) + { + *pNeeded = 1; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl is not null) + { + if (managers is not null) + { + DacpJitManagerInfo managerLocal = default; + int hrLocal = _legacyImpl.GetJitManagerList(count, &managerLocal, null); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK && count >= 1) + { + Debug.Assert(managers->managerAddr == managerLocal.managerAddr); + Debug.Assert(managers->codeType == managerLocal.codeType); + Debug.Assert(managers->ptrHeapList == managerLocal.ptrHeapList); + } + } + else + { + uint neededLocal; + int hrLocal = _legacyImpl.GetJitManagerList(0, null, &neededLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK && pNeeded is not null) + { + Debug.Assert(*pNeeded == neededLocal); + } + } + } +#endif + return hr; + } private bool IsJumpRel64(TargetPointer pThunk) => 0x48 == _target.Read(pThunk) && diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index b4c858f5a6e573..28bd7e54319e66 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -396,6 +396,40 @@ public void GetUnwindInfoBaseAddress_R2R_ManyRuntimeFunction(int version, MockTa Assert.Equal(new TargetPointer(codeRangeStart), actualBaseAddress); } + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void GetJitManagerInfo_ReturnsManagerAddress(int version, MockTarget.Architecture arch) + { + MockDescriptors.ExecutionManager emBuilder = new(version, arch, MockDescriptors.ExecutionManager.DefaultAllocationRange); + var target = CreateTarget(emBuilder); + + var em = target.Contracts.ExecutionManager; + Assert.NotNull(em); + + JitManagerInfo info = em.GetJitManagerInfo(); + Assert.Equal(emBuilder.EEJitManagerAddress, info.ManagerAddress); + Assert.Equal(0u, info.CodeType); + Assert.Equal(TargetPointer.Null, info.HeapListAddress); + } + + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void GetJitManagerInfo_WithCodeHeaps(int version, MockTarget.Architecture arch) + { + TargetPointer expectedHeapList = new(0x0099_aa00); + + MockDescriptors.ExecutionManager emBuilder = new(version, arch, MockDescriptors.ExecutionManager.DefaultAllocationRange, allCodeHeaps: expectedHeapList); + var target = CreateTarget(emBuilder); + + var em = target.Contracts.ExecutionManager; + Assert.NotNull(em); + + JitManagerInfo info = em.GetJitManagerInfo(); + Assert.Equal(emBuilder.EEJitManagerAddress, info.ManagerAddress); + Assert.Equal(0u, info.CodeType); + Assert.Equal(expectedHeapList, info.HeapListAddress); + } + public static IEnumerable StdArchAllVersions() { const int highestVersion = 2; diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs index 85efb7fd191203..c95ee0ff813634 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs @@ -256,6 +256,16 @@ public static RangeSectionMapTestBuilder CreateRangeSection(MockTarget.Architect ] }; + private static readonly MockDescriptors.TypeFields EEJitManagerFields = new() + { + DataType = DataType.EEJitManager, + Fields = + [ + new(nameof(Data.EEJitManager.StoreRichDebugInfo), DataType.uint8), + new(nameof(Data.EEJitManager.AllCodeHeaps), DataType.pointer), + ] + }; + internal int Version { get; } internal MockMemorySpace.Builder Builder { get; } @@ -269,11 +279,13 @@ public static RangeSectionMapTestBuilder CreateRangeSection(MockTarget.Architect private readonly MockMemorySpace.BumpAllocator _nibbleMapAllocator; private readonly MockMemorySpace.BumpAllocator _allocator; - internal ExecutionManager(int version, MockTarget.Architecture arch, AllocationRange allocationRange) - : this(version, new MockMemorySpace.Builder(new TargetTestHelpers(arch)), allocationRange) + internal TargetPointer EEJitManagerAddress { get; } + + internal ExecutionManager(int version, MockTarget.Architecture arch, AllocationRange allocationRange, TargetPointer allCodeHeaps = default) + : this(version, new MockMemorySpace.Builder(new TargetTestHelpers(arch)), allocationRange, allCodeHeaps) { } - internal ExecutionManager(int version, MockMemorySpace.Builder builder, AllocationRange allocationRange) + internal ExecutionManager(int version, MockMemorySpace.Builder builder, AllocationRange allocationRange, TargetPointer allCodeHeaps = default) { Version = version; Builder = builder; @@ -292,14 +304,30 @@ internal ExecutionManager(int version, MockMemorySpace.Builder builder, Allocati RealCodeHeaderFields, ReadyToRunInfoFields(Builder.TargetTestHelpers), MockDescriptors.ModuleFields, + EEJitManagerFields, ]).Concat(MockDescriptors.HashMap.GetTypes(Builder.TargetTestHelpers)) .Concat(_rfBuilder.Types) .ToDictionary(); + // Allocate and populate the EEJitManager instance + var jitManagerTypeInfo = Types[DataType.EEJitManager]; + MockMemorySpace.HeapFragment eeJitManagerFragment = _allocator.Allocate(jitManagerTypeInfo.Size.Value, "EEJitManager"); + Builder.AddHeapFragment(eeJitManagerFragment); + EEJitManagerAddress = eeJitManagerFragment.Address; + int pointerSize = Builder.TargetTestHelpers.PointerSize; + Span jmData = Builder.BorrowAddressRange(eeJitManagerFragment.Address, (int)jitManagerTypeInfo.Size.Value); + Builder.TargetTestHelpers.WritePointer(jmData.Slice(jitManagerTypeInfo.Fields[nameof(Data.EEJitManager.AllCodeHeaps)].Offset, pointerSize), allCodeHeaps); + + // Allocate the global pointer that holds the EEJitManager address + MockMemorySpace.HeapFragment eeJitManagerGlobalPointer = _allocator.Allocate((ulong)pointerSize, "EEJitManagerGlobalPointer"); + Builder.AddHeapFragment(eeJitManagerGlobalPointer); + Builder.TargetTestHelpers.WritePointer(eeJitManagerGlobalPointer.Data, EEJitManagerAddress); + Globals = [ (nameof(Constants.Globals.ExecutionManagerCodeRangeMapAddress), ExecutionManagerCodeRangeMapAddress), (nameof(Constants.Globals.StubCodeBlockLast), 0x0Fu), + (nameof(Constants.Globals.EEJitManagerAddress), eeJitManagerGlobalPointer.Address), ]; Globals = Globals .Concat(MockDescriptors.HashMap.GetGlobals(Builder.TargetTestHelpers)) From 8c9dae472b5b818cd76179d73d9994c6fca9bb7a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:57:25 +0000 Subject: [PATCH 3/6] Update ExecutionManager contract documentation with new APIs and data descriptors Co-authored-by: max-charlamb <44248479+max-charlamb@users.noreply.github.com> --- docs/design/datacontracts/ExecutionManager.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index 103aac455a2a48..56203e20b45ca6 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -37,6 +37,8 @@ struct CodeBlockHandle void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion); // Gets the offset of the codeInfoHandle inside of the code block TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle); + // Gets information about the EEJitManager: its address, code type, and head of the code heap list. + JitManagerInfo GetJitManagerInfo(); // Extension Methods (implemented in terms of other APIs) bool IsFunclet(CodeBlockHandle codeInfoHandle); @@ -70,6 +72,7 @@ Data descriptors used: | `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` | | `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` | | `RealCodeHeader` | `NumUnwindInfos` | Number of Unwind Infos | | `RealCodeHeader` | `UnwindInfos` | Start address of Unwind Infos | @@ -101,6 +104,7 @@ Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | | `ExecutionManagerCodeRangeMapAddress` | TargetPointer | Pointer to the global RangeSectionMap | +| `EEJitManagerAddress` | TargetPointer | Pointer to the EEJitManager instance | | `StubCodeBlockLast` | uint8 | Maximum sentinel code header value indentifying a stub code block | | `HashMapSlotsPerBucket` | uint32 | Number of slots in each bucket of a `HashMap` | | `HashMapValueMask` | uint64 | Bitmask used when storing values in a `HashMap` | From 0c9e08974295b6f52c801cd2ae4253f9487b6bb7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 21:31:47 +0000 Subject: [PATCH 4/6] Rename GetJitManagerInfo to GetEEJitManagerInfo per review feedback Co-authored-by: max-charlamb <44248479+max-charlamb@users.noreply.github.com> --- docs/design/datacontracts/ExecutionManager.md | 2 +- .../Contracts/IExecutionManager.cs | 2 +- .../Contracts/ExecutionManager/ExecutionManagerCore.cs | 2 +- .../Contracts/ExecutionManager/ExecutionManager_1.cs | 2 +- .../Contracts/ExecutionManager/ExecutionManager_2.cs | 2 +- .../SOSDacImpl.cs | 2 +- .../cdac/tests/ExecutionManager/ExecutionManagerTests.cs | 8 ++++---- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index 56203e20b45ca6..565f54c01df284 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -38,7 +38,7 @@ struct CodeBlockHandle // Gets the offset of the codeInfoHandle inside of the code block TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle); // Gets information about the EEJitManager: its address, code type, and head of the code heap list. - JitManagerInfo GetJitManagerInfo(); + JitManagerInfo GetEEJitManagerInfo(); // Extension Methods (implemented in terms of other APIs) bool IsFunclet(CodeBlockHandle codeInfoHandle); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs index b563137afd8f02..6582a36deb8ef5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs @@ -32,7 +32,7 @@ public interface IExecutionManager : IContract // **Currently GetGCInfo only supports X86** void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => throw new NotImplementedException(); TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException(); - JitManagerInfo GetJitManagerInfo() => throw new NotImplementedException(); + JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException(); } public readonly struct ExecutionManager : IExecutionManager diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs index d8a8c560b8bf36..5577cba635ad58 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs @@ -270,7 +270,7 @@ TargetNUInt IExecutionManager.GetRelativeOffset(CodeBlockHandle codeInfoHandle) return info.RelativeOffset; } - JitManagerInfo IExecutionManager.GetJitManagerInfo() + JitManagerInfo IExecutionManager.GetEEJitManagerInfo() { TargetPointer eeJitManagerPtr = _target.ReadGlobalPointer(Constants.Globals.EEJitManagerAddress); TargetPointer eeJitManagerAddr = _target.ReadPointer(eeJitManagerPtr); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs index f2ab607ce0619e..5ea76dd484d03e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs @@ -23,5 +23,5 @@ internal ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionM public TargetPointer GetDebugInfo(CodeBlockHandle codeInfoHandle, out bool hasFlagByte) => _executionManagerCore.GetDebugInfo(codeInfoHandle, out hasFlagByte); public void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => _executionManagerCore.GetGCInfo(codeInfoHandle, out gcInfo, out gcVersion); public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle); - public JitManagerInfo GetJitManagerInfo() => _executionManagerCore.GetJitManagerInfo(); + public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs index 13458cf315303e..f103302d42374e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs @@ -23,5 +23,5 @@ internal ExecutionManager_2(Target target, Data.RangeSectionMap topRangeSectionM public TargetPointer GetDebugInfo(CodeBlockHandle codeInfoHandle, out bool hasFlagByte) => _executionManagerCore.GetDebugInfo(codeInfoHandle, out hasFlagByte); public void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => _executionManagerCore.GetGCInfo(codeInfoHandle, out gcInfo, out gcVersion); public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle); - public JitManagerInfo GetJitManagerInfo() => _executionManagerCore.GetJitManagerInfo(); + public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index ca7a082c37ce66..a91915f5768369 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -1547,7 +1547,7 @@ int ISOSDacInterface.GetJitManagerList(uint count, DacpJitManagerInfo* managers, if (count >= 1) { *managers = default; - Contracts.JitManagerInfo jitManagerInfo = _target.Contracts.ExecutionManager.GetJitManagerInfo(); + Contracts.JitManagerInfo jitManagerInfo = _target.Contracts.ExecutionManager.GetEEJitManagerInfo(); managers->managerAddr = jitManagerInfo.ManagerAddress.ToClrDataAddress(_target); managers->codeType = jitManagerInfo.CodeType; managers->ptrHeapList = jitManagerInfo.HeapListAddress.ToClrDataAddress(_target); diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index 28bd7e54319e66..05e6d96b48533b 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -398,7 +398,7 @@ public void GetUnwindInfoBaseAddress_R2R_ManyRuntimeFunction(int version, MockTa [Theory] [MemberData(nameof(StdArchAllVersions))] - public void GetJitManagerInfo_ReturnsManagerAddress(int version, MockTarget.Architecture arch) + public void GetEEJitManagerInfo_ReturnsManagerAddress(int version, MockTarget.Architecture arch) { MockDescriptors.ExecutionManager emBuilder = new(version, arch, MockDescriptors.ExecutionManager.DefaultAllocationRange); var target = CreateTarget(emBuilder); @@ -406,7 +406,7 @@ public void GetJitManagerInfo_ReturnsManagerAddress(int version, MockTarget.Arch var em = target.Contracts.ExecutionManager; Assert.NotNull(em); - JitManagerInfo info = em.GetJitManagerInfo(); + JitManagerInfo info = em.GetEEJitManagerInfo(); Assert.Equal(emBuilder.EEJitManagerAddress, info.ManagerAddress); Assert.Equal(0u, info.CodeType); Assert.Equal(TargetPointer.Null, info.HeapListAddress); @@ -414,7 +414,7 @@ public void GetJitManagerInfo_ReturnsManagerAddress(int version, MockTarget.Arch [Theory] [MemberData(nameof(StdArchAllVersions))] - public void GetJitManagerInfo_WithCodeHeaps(int version, MockTarget.Architecture arch) + public void GetEEJitManagerInfo_WithCodeHeaps(int version, MockTarget.Architecture arch) { TargetPointer expectedHeapList = new(0x0099_aa00); @@ -424,7 +424,7 @@ public void GetJitManagerInfo_WithCodeHeaps(int version, MockTarget.Architecture var em = target.Contracts.ExecutionManager; Assert.NotNull(em); - JitManagerInfo info = em.GetJitManagerInfo(); + JitManagerInfo info = em.GetEEJitManagerInfo(); Assert.Equal(emBuilder.EEJitManagerAddress, info.ManagerAddress); Assert.Equal(0u, info.CodeType); Assert.Equal(expectedHeapList, info.HeapListAddress); From f4859c68f1f6cea5bc1035390dbc3859c364dfae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 22:47:06 +0000 Subject: [PATCH 5/6] Change EEJitManagerPtr to use typed pointer instead of void* in cdac_data Co-authored-by: max-charlamb <44248479+max-charlamb@users.noreply.github.com> --- src/coreclr/vm/codeman.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 967940da4bd66f..28c47c49e66fc5 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2583,7 +2583,7 @@ template<> struct cdac_data { static constexpr void* const CodeRangeMapAddress = (void*)&ExecutionManager::g_codeRangeMap.Data[0]; - static constexpr void* const EEJitManagerPtr = (void*)&ExecutionManager::m_pEEJitManager; + static constexpr PTR_EEJitManager* EEJitManagerPtr = &ExecutionManager::m_pEEJitManager; }; #endif From ad57c13ffafdfcea7b1d3625af783e0d8f393636 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:52:43 -0500 Subject: [PATCH 6/6] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/design/datacontracts/ExecutionManager.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index 565f54c01df284..cb3406190f4ed3 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -104,7 +104,7 @@ Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | | `ExecutionManagerCodeRangeMapAddress` | TargetPointer | Pointer to the global RangeSectionMap | -| `EEJitManagerAddress` | TargetPointer | Pointer to the EEJitManager instance | +| `EEJitManagerAddress` | TargetPointer | Address of the global pointer to the EEJitManager instance (read a TargetPointer from this address to obtain the instance address) | | `StubCodeBlockLast` | uint8 | Maximum sentinel code header value indentifying a stub code block | | `HashMapSlotsPerBucket` | uint32 | Number of slots in each bucket of a `HashMap` | | `HashMapValueMask` | uint64 | Bitmask used when storing values in a `HashMap` |