From 610be95662edbf46948d6665d35b9e12e4445953 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sun, 12 Apr 2026 21:46:39 -0700 Subject: [PATCH 1/8] GetRuntimeNameByAddress --- docs/design/datacontracts/ExecutionManager.md | 41 ++++ docs/design/datacontracts/PrecodeStubs.md | 20 ++ src/coreclr/debug/daccess/daccess.cpp | 2 +- src/coreclr/inc/gfunc_list.h | 8 + src/coreclr/vm/codeman.h | 1 + .../vm/datadescriptor/datadescriptor.inc | 17 ++ src/coreclr/vm/loaderallocator.hpp | 7 + .../Contracts/IExecutionManager.cs | 21 ++ .../Contracts/IPrecodeStubs.cs | 2 + .../DataType.cs | 1 + .../Constants.cs | 5 + .../ExecutionManagerCore.EEJitManager.cs | 84 +++++++- ...ecutionManagerCore.ReadyToRunJitManager.cs | 7 + .../ExecutionManager/ExecutionManagerCore.cs | 61 ++++++ .../ExecutionManager/ExecutionManager_1.cs | 1 + .../ExecutionManager/ExecutionManager_2.cs | 1 + .../Contracts/PrecodeStubs_Common.cs | 18 ++ .../Data/CodeRangeMapRangeList.cs | 18 ++ .../Data/RangeSection.cs | 2 + .../SOSDacImpl.IXCLRDataProcess.cs | 182 +++++++++++++++++- .../ExecutionManager/ExecutionManagerTests.cs | 100 ++++++++++ .../MockDescriptors.ExecutionManager.cs | 53 +++++ 22 files changed, 646 insertions(+), 6 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CodeRangeMapRangeList.cs diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index cf7163569789f9..cf430fac49d155 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -52,6 +52,10 @@ struct CodeBlockHandle // Get the exception clause info for the code block List GetExceptionClauses(CodeBlockHandle codeInfoHandle); + // Classify a code address as a known stub kind (precode, jump stub, VSD stub, etc.) + // or as managed code. Returns CodeBlockUnknown if the address is not recognized. + StubKind GetStubKind(TargetCodePointer jittedCodeAddress); + // Extension Methods (implemented in terms of other APIs) // Returns true if the code block is a funclet (exception handler, filter, or finally) bool IsFunclet(CodeBlockHandle codeInfoHandle); @@ -143,6 +147,8 @@ Data descriptors used: | `RangeSection` | `Flags` | Flags for the range section | | `RangeSection` | `HeapList` | Pointer to the heap list | | `RangeSection` | `R2RModule` | ReadyToRun module | +| `RangeSection` | `RangeList` | Pointer to the `CodeRangeMapRangeList` associated with this range section | +| `CodeRangeMapRangeList` | `RangeListType` | Integer identifying the stub code block kind for this range list | | `CodeHeapListNode` | `Next` | Next node | | `CodeHeapListNode` | `StartAddress` | Start address of the used portion of the code heap | | `CodeHeapListNode` | `EndAddress` | End address of the used portion of the code heap | @@ -219,6 +225,11 @@ Global variables used: | `GCInfoVersion` | uint32 | JITted code GCInfo version | | `FeatureOnStackReplacement` | uint8 | 1 if FEATURE_ON_STACK_REPLACEMENT is enabled, 0 otherwise | | `FeaturePortableEntrypoints` | uint8 | 1 if FEATURE_PORTABLE_ENTRYPOINTS is enabled, 0 otherwise | +| `ThePreStub` | TargetPointer | Address of the pre-stub entry point (only present when `FeaturePortableEntrypoints` is disabled) | +| `GenericPInvokeCalliHelper` | TargetPointer | Address of the generic PInvoke CALLI helper stub | +| `VarargPInvokeStub` | TargetPointer | Address of the vararg PInvoke stub | +| `VarargPInvokeStub_RetBuffArg` | TargetPointer | Address of the vararg PInvoke stub with return buffer argument (not present on x86, ARM64, LoongArch64, RISC-V) | +| `TailCallJitHelper` | TargetPointer | Address of the JIT tail call helper (only present on x86 Windows) | | `ObjectMethodTable` | TargetPointer | Pointer to the `System.Object` MethodTable, used for catch-all handler detection | Contract constants used: @@ -501,6 +512,36 @@ 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. +### Stub Kind Classification + +`GetStubKind` classifies a code address as a known stub type or managed code. It first checks the address against well-known global stub pointers (`ThePreStub`, `VarargPInvokeStub`, `VarargPInvokeStub_RetBuffArg`, `GenericPInvokeCalliHelper`, `TailCallJitHelper`). If the address matches one of these, it returns the corresponding `StubKind` immediately. + +If no global match is found, the method looks up the address in the `RangeSectionMap`. If a `RangeSection` is found, the JIT manager for that section classifies the code: + +- **EEJitManager**: If the range section is a range list, reads the `CodeRangeMapRangeList.RangeListType` to determine the stub code block kind. Otherwise, it uses the nibble map to find the method code start, reads the code header indirect pointer, and checks whether it is a stub code block (value ≤ `StubCodeBlockLast`). If so, the value identifies the specific stub kind. +- **ReadyToRunJitManager**: Checks whether the address falls within a delay-load method call thunk region. + +```csharp +StubKind GetStubKind(TargetCodePointer jittedCodeAddress) +{ + TargetPointer address = CodePointerUtils.AddressFromCodePointer(jittedCodeAddress); + + // Check well-known global stubs + if (address == ThePreStub) return StubKind.PreStub; + if (address == VarargPInvokeStub || address == VarargPInvokeStub_RetBuffArg + || address == GenericPInvokeCalliHelper) + return StubKind.InteropDispatchStub; + if (address == TailCallJitHelper) return StubKind.TailCallStub; + + // Look up in range section map + RangeSection range = FindRangeSection(jittedCodeAddress); + if (range == null) return StubKind.CodeBlockUnknown; + + JitManager jitManager = GetJitManager(range); + return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); +} +``` + ### EE JIT Manager and Code Heap Info ```csharp diff --git a/docs/design/datacontracts/PrecodeStubs.md b/docs/design/datacontracts/PrecodeStubs.md index b336b433ac2e13..31be70145bf232 100644 --- a/docs/design/datacontracts/PrecodeStubs.md +++ b/docs/design/datacontracts/PrecodeStubs.md @@ -7,6 +7,13 @@ This contract provides support for examining [precode](../coreclr/botr/method-de ```csharp // Gets a pointer to the MethodDesc for a given stub entrypoint TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint); + + // Enumerates candidate precode entry points near a given code address. + // The address is pointer-aligned and then iterated backwards in pointer-sized + // steps up to StubPrecodeSize / PointerSize candidates. This is used by + // GetRuntimeNameByAddress to resolve a code address that falls within a + // precode stub back to its entry point. + IEnumerable GetCandidateEntryPoints(TargetCodePointer address); ``` ## Version 1, 2, and 3 @@ -295,4 +302,17 @@ After the initial precode type is determined, for stub precodes a refined precod return precode.GetMethodDesc(_target, MachineDescriptor); } + + IEnumerable IPrecodeStubs.GetCandidateEntryPoints(TargetCodePointer address) + { + TargetPointer instrPointer = CodePointerReadableInstrPointer(address); + ulong aligned = instrPointer.Value & ~(ulong)(PointerSize - 1); + uint count = StubPrecodeSize / PointerSize; + + for (uint i = 0; i < count; i++) + { + TargetPointer candidateAddr = new TargetPointer(aligned - (i * PointerSize)); + yield return CodePointerFromAddress(candidateAddr); + } + } ``` diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 0c8801da35fe27..12e0ff453b1f02 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -5327,7 +5327,7 @@ static int FormatCLRStubName( // Compute the address as a string safely. WCHAR addrString[Max64BitHexString + 1]; - FormatInteger(addrString, ARRAY_SIZE(addrString), "%p", stubAddr); + FormatInteger(addrString, ARRAY_SIZE(addrString), sizeof(void*) == 8 ? "%016llX" : "%08X", stubAddr); size_t addStringLen = u16_strlen(addrString); // Compute maximum length, include the null terminator. diff --git a/src/coreclr/inc/gfunc_list.h b/src/coreclr/inc/gfunc_list.h index 9631099ff92f46..44031c75a12332 100644 --- a/src/coreclr/inc/gfunc_list.h +++ b/src/coreclr/inc/gfunc_list.h @@ -12,6 +12,14 @@ DEFINE_DACGFN(DACNotifyCompilationFinished) DEFINE_DACGFN(ThePreStub) +DEFINE_DACGFN(GenericPInvokeCalliHelper) +DEFINE_DACGFN(VarargPInvokeStub) +#if !defined(TARGET_X86) && !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64) +DEFINE_DACGFN(VarargPInvokeStub_RetBuffArg) +#endif +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) +DEFINE_DACGFN(JIT_TailCall) +#endif DEFINE_DACGFN(ThePreStubPatchLabel) #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 668b95beb9ddef..6afa441a9d3839 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -793,6 +793,7 @@ template<> struct cdac_data static constexpr size_t Flags = offsetof(RangeSection, _flags); static constexpr size_t HeapList = offsetof(RangeSection, _pHeapList); static constexpr size_t R2RModule = offsetof(RangeSection, _pR2RModule); + static constexpr size_t RangeList = offsetof(RangeSection, _pRangeList); }; enum class RangeSectionLockState diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index a13b9b275ce31c..1837c8f3e4a8a2 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -805,8 +805,14 @@ CDAC_TYPE_FIELD(RangeSection, T_POINTER, JitManager, cdac_data::Ji CDAC_TYPE_FIELD(RangeSection, T_INT32, Flags, cdac_data::Flags) CDAC_TYPE_FIELD(RangeSection, T_POINTER, HeapList, cdac_data::HeapList) CDAC_TYPE_FIELD(RangeSection, T_POINTER, R2RModule, cdac_data::R2RModule) +CDAC_TYPE_FIELD(RangeSection, T_POINTER, RangeList, cdac_data::RangeList) CDAC_TYPE_END(RangeSection) +CDAC_TYPE_BEGIN(CodeRangeMapRangeList) +CDAC_TYPE_INDETERMINATE(CodeRangeMapRangeList) +CDAC_TYPE_FIELD(CodeRangeMapRangeList, T_INT32, RangeListType, cdac_data::RangeListType) +CDAC_TYPE_END(CodeRangeMapRangeList) + CDAC_TYPE_BEGIN(EEJitManager) CDAC_TYPE_INDETERMINATE(EEJitManager) CDAC_TYPE_FIELD(EEJitManager, T_BOOL, StoreRichDebugInfo, cdac_data::StoreRichDebugInfo) @@ -1412,6 +1418,17 @@ CDAC_GLOBAL(ArrayBaseSize, T_UINT32, ARRAYBASE_BASESIZE) CDAC_GLOBAL(SyncBlockValueToObjectOffset, T_UINT16, OBJHEADER_SIZE - cdac_data::SyncBlockValue) CDAC_GLOBAL(StubCodeBlockLast, T_UINT8, STUB_CODE_BLOCK_LAST) CDAC_GLOBAL(DefaultADID, T_UINT32, DefaultADID) +#ifndef FEATURE_PORTABLE_ENTRYPOINTS +CDAC_GLOBAL_POINTER(ThePreStub, &ThePreStub) +#endif // !FEATURE_PORTABLE_ENTRYPOINTS +CDAC_GLOBAL_POINTER(GenericPInvokeCalliHelper, &GenericPInvokeCalliHelper) +CDAC_GLOBAL_POINTER(VarargPInvokeStub, &VarargPInvokeStub) +#if !defined(TARGET_X86) && !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64) +CDAC_GLOBAL_POINTER(VarargPInvokeStub_RetBuffArg, &VarargPInvokeStub_RetBuffArg) +#endif +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) +CDAC_GLOBAL_POINTER(TailCallJitHelper, &JIT_TailCall) +#endif // TARGET_X86 && !UNIX_X86_ABI #ifndef TARGET_UNIX CDAC_GLOBAL(SizeOfGenericModeBlock, T_UINT32, sizeof(GenericModeBlock)) #endif diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 68c372185b4723..23b2da9157727f 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -182,6 +182,13 @@ class CodeRangeMapRangeList : public RangeList SArray _starts; void* _id; bool _collectible; + friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + static constexpr size_t RangeListType = offsetof(CodeRangeMapRangeList, _rangeListType); }; // Iterator over Assemblies in the same ALC 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 0dddd31417e5ad..16678ce332e712 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 @@ -46,6 +46,26 @@ public interface ICodeHeapInfo { } +public enum StubKind : uint +{ + CodeBlockUnknown = 0, + CodeBlockJumpStub = 1, + CodeBlockDynamicHelper = 3, + CodeBlockPrecode = 4, + CodeBlockVSDDispatchStub = 5, + CodeBlockVSDResolveStub = 6, + CodeBlockVSDLookupStub = 7, + CodeBlockVSDVTableStub = 8, + CodeBlockCallCounting = 9, + CodeBlockStubLinkStub = 10, + CodeBlockMethodCallThunk = 11, + CodeBlockNoCode = 12, + CodeBlockManaged = 13, + PreStub = 14, + InteropDispatchStub = 15, + TailCallStub = 16, +} + public sealed class LoaderCodeHeapInfo : ICodeHeapInfo { public TargetPointer HeapAddress { get; } @@ -101,6 +121,7 @@ public interface IExecutionManager : IContract List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException(); JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException(); IEnumerable GetCodeHeapInfos() => throw new NotImplementedException(); + StubKind GetStubKind(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); } public readonly struct ExecutionManager : IExecutionManager diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs index aced1d2316dd08..fce6ee7d12a874 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -9,6 +10,7 @@ public interface IPrecodeStubs : IContract { static string IContract.Name { get; } = nameof(PrecodeStubs); TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint) => throw new NotImplementedException(); + IEnumerable GetCandidateEntryPoints(TargetCodePointer address) => throw new NotImplementedException(); } public readonly struct PrecodeStubs : IPrecodeStubs 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 521d3b56783f2d..190e85f07043fe 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -168,6 +168,7 @@ public enum DataType ComInterfaceEntry, InternalComInterfaceDispatch, AuxiliarySymbolInfo, + CodeRangeMapRangeList, /* GC Data Types */ 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 41eccea4c65d96..56985d783e3173 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -82,6 +82,11 @@ public static class Globals public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); public const string EEJitManagerAddress = nameof(EEJitManagerAddress); public const string StubCodeBlockLast = nameof(StubCodeBlockLast); + public const string ThePreStub = nameof(ThePreStub); + public const string VarargPInvokeStub = nameof(VarargPInvokeStub); + public const string VarargPInvokeStub_RetBuffArg = nameof(VarargPInvokeStub_RetBuffArg); + public const string GenericPInvokeCalliHelper = nameof(GenericPInvokeCalliHelper); + public const string TailCallJitHelper = nameof(TailCallJitHelper); public const string DefaultADID = nameof(DefaultADID); public const string StaticsPointerMask = nameof(StaticsPointerMask); public const string PtrArrayOffsetToDataArray = nameof(PtrArrayOffsetToDataArray); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs index a3e73ed437a098..d0f5abf60856ad 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs @@ -20,6 +20,20 @@ public EEJitManager(Target target, INibbleMap nibbleMap) : base(target) _runtimeFunctions = RuntimeFunctionLookup.Create(target); } + private enum StubCodeBlockKind : int + { + Unknown = 0, + JumpStub = 1, + DynamicHelper = 3, + StubPrecode = 4, + FixupPrecode = 5, + VSDDispatchStub = 6, + VSDResolveStub = 7, + VSDLookupStub = 8, + VSDVTableStub = 9, + CallCountingStub = 10, + } + public override bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out CodeBlock? info) { info = null; @@ -117,6 +131,19 @@ public override TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCode return realCodeHeader.DebugInfo; } + public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) + { + if (rangeSection.IsRangeList) + { + Data.CodeRangeMapRangeList rangeList = Target.ProcessedData.GetOrAdd(rangeSection.Data!.RangeList); + return GetStubKind((StubCodeBlockKind)rangeList.RangeListType); + } + TargetPointer startAddr = FindMethodCode(rangeSection, jittedCodeAddress); // validate that the code address is within the method's code range + if (startAddr == TargetPointer.Null) + return StubKind.CodeBlockNoCode; + return GetCodeHeaderStubKind(rangeSection, startAddr); + } + public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion) { gcInfo = TargetPointer.Null; @@ -154,9 +181,9 @@ private TargetPointer FindMethodCode(RangeSection rangeSection, TargetCodePointe return _nibbleMap.FindMethodCode(heapListNode, jittedCodeAddress); } - private bool GetRealCodeHeader(RangeSection rangeSection, TargetPointer codeStart, [NotNullWhen(true)] out Data.RealCodeHeader? realCodeHeader) + private bool GetCodeHeaderAddress(RangeSection rangeSection, TargetPointer codeStart, out TargetPointer codeHeaderAddress) { - realCodeHeader = null; + codeHeaderAddress = TargetPointer.Null; // EEJitManager::JitCodeToMethodInfo if (rangeSection.IsRangeList) return false; @@ -170,15 +197,64 @@ private bool GetRealCodeHeader(RangeSection rangeSection, TargetPointer codeStar // See EEJitManager::GetCodeHeaderFromStartAddress in vm/codeman.h int codeHeaderOffset = Target.PointerSize; TargetPointer codeHeaderIndirect = new TargetPointer(codeStart - (ulong)codeHeaderOffset); - if (RangeSection.IsStubCodeBlock(Target, codeHeaderIndirect)) + codeHeaderAddress = Target.ReadPointer(codeHeaderIndirect); + return true; + } + + private bool GetRealCodeHeader(RangeSection rangeSection, TargetPointer codeStart, [NotNullWhen(true)] out Data.RealCodeHeader? realCodeHeader) + { + realCodeHeader = null; + if (!GetCodeHeaderAddress(rangeSection, codeStart, out TargetPointer codeHeaderAddress)) + { + return false; + } + if (RangeSection.IsStubCodeBlock(Target, codeHeaderAddress)) { return false; } - TargetPointer codeHeaderAddress = Target.ReadPointer(codeHeaderIndirect); realCodeHeader = Target.ProcessedData.GetOrAdd(codeHeaderAddress); return true; } + private static StubKind GetStubKind(StubCodeBlockKind stubCodeBlockKind) + { + switch (stubCodeBlockKind) + { + case StubCodeBlockKind.JumpStub: + return StubKind.CodeBlockJumpStub; + case StubCodeBlockKind.DynamicHelper: + return StubKind.CodeBlockDynamicHelper; + case StubCodeBlockKind.StubPrecode: + case StubCodeBlockKind.FixupPrecode: + return StubKind.CodeBlockPrecode; + case StubCodeBlockKind.VSDDispatchStub: + return StubKind.CodeBlockVSDDispatchStub; + case StubCodeBlockKind.VSDResolveStub: + return StubKind.CodeBlockVSDResolveStub; + case StubCodeBlockKind.VSDLookupStub: + return StubKind.CodeBlockVSDLookupStub; + case StubCodeBlockKind.VSDVTableStub: + return StubKind.CodeBlockVSDVTableStub; + case StubCodeBlockKind.CallCountingStub: + return StubKind.CodeBlockCallCounting; + default: + return StubKind.CodeBlockUnknown; + } + } + + private StubKind GetCodeHeaderStubKind(RangeSection rangeSection, TargetPointer codeStart) + { + if (GetCodeHeaderAddress(rangeSection, codeStart, out TargetPointer codeHeaderAddress)) + { + if (RangeSection.IsStubCodeBlock(Target, codeHeaderAddress)) + { + return GetStubKind((StubCodeBlockKind)codeHeaderAddress.Value); + } + return StubKind.CodeBlockManaged; + } + return StubKind.CodeBlockUnknown; + } + public override void GetExceptionClauses(RangeSection rangeSection, CodeBlockHandle codeInfoHandle, out TargetPointer startAddr, out TargetPointer endAddr) { startAddr = TargetPointer.Null; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs index ff05f37b6c6628..af13dd60d354c4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs @@ -142,6 +142,13 @@ public override TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCode return imageBase + debugInfoOffset; } + public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) + { + if (rangeSection.Data == null) + return StubKind.CodeBlockUnknown; + return IsStubCodeBlockThunk(rangeSection.Data, GetReadyToRunInfo(rangeSection), jittedCodeAddress) ? StubKind.CodeBlockMethodCallThunk : StubKind.CodeBlockUnknown; + } + public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion) { gcInfo = TargetPointer.Null; 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 43e89fbe2237e7..17e60ce099882d 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 @@ -21,6 +21,11 @@ internal sealed partial class ExecutionManagerCore : IExecutionManager private readonly ExecutionManagerHelpers.RangeSectionMap _rangeSectionMapLookup; private readonly EEJitManager _eeJitManager; private readonly ReadyToRunJitManager _r2rJitManager; + private readonly TargetPointer _thePreStub; + private readonly TargetPointer _varargPInvokeStub; + private readonly TargetPointer _varargPInvokeStub_RetBuffArg; + private readonly TargetPointer _genericPInvokeCalliHelper; + private readonly TargetPointer _tailCallJitHelper; public ExecutionManagerCore(Target target, Data.RangeSectionMap topRangeSectionMap) { @@ -30,6 +35,18 @@ public ExecutionManagerCore(Target target, Data.RangeSectionMap topRangeSectionM INibbleMap nibbleMap = T.Create(_target); _eeJitManager = new EEJitManager(_target, nibbleMap); _r2rJitManager = new ReadyToRunJitManager(_target); + _thePreStub = ReadOptionalGlobalPointer(_target, Constants.Globals.ThePreStub); + _varargPInvokeStub = ReadOptionalGlobalPointer(_target, Constants.Globals.VarargPInvokeStub); + _varargPInvokeStub_RetBuffArg = ReadOptionalGlobalPointer(_target, Constants.Globals.VarargPInvokeStub_RetBuffArg); + _genericPInvokeCalliHelper = ReadOptionalGlobalPointer(_target, Constants.Globals.GenericPInvokeCalliHelper); + _tailCallJitHelper = ReadOptionalGlobalPointer(_target, Constants.Globals.TailCallJitHelper); + } + + private static TargetPointer ReadOptionalGlobalPointer(Target target, string name) + { + return target.TryReadGlobalPointer(name, out TargetPointer? ptr) + ? ptr.Value + : TargetPointer.Null; } public void Flush() @@ -99,6 +116,7 @@ public abstract void GetMethodRegionInfo( public abstract TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out bool hasFlagByte); public abstract void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion); public abstract void GetExceptionClauses(RangeSection rangeSection, CodeBlockHandle codeInfoHandle, out TargetPointer startAddr, out TargetPointer endAddr); + public abstract StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress); } private sealed class RangeSection @@ -539,4 +557,47 @@ List IExecutionManager.GetExceptionClauses(CodeBlockHandle } return exceptionClauses; } + + private bool TryGetStubKindFromConstants(TargetPointer jittedCodeAddress, out StubKind stubKind) + { + stubKind = StubKind.CodeBlockUnknown; + if (jittedCodeAddress == TargetPointer.Null) + { + return false; + } + if (jittedCodeAddress == _thePreStub) + { + stubKind = StubKind.PreStub; + return true; + } + else if (jittedCodeAddress == _varargPInvokeStub + || jittedCodeAddress == _varargPInvokeStub_RetBuffArg + || jittedCodeAddress == _genericPInvokeCalliHelper) + { + stubKind = StubKind.InteropDispatchStub; + return true; + } + else if (jittedCodeAddress == _tailCallJitHelper) + { + stubKind = StubKind.TailCallStub; + return true; + } + return false; + } + + public StubKind GetStubKind(TargetCodePointer jittedCodeAddress) + { + TargetPointer jittedPtr = CodePointerUtils.AddressFromCodePointer(jittedCodeAddress, _target); + if (TryGetStubKindFromConstants(jittedPtr, out StubKind stubKind)) + { + return stubKind; + } + + RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, jittedCodeAddress); + if (range.Data == null) + return StubKind.CodeBlockUnknown; + + JitManager jitManager = GetJitManager(range.Data); + return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); + } } 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 b636a2914c36ec..c23094f8c88c93 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 @@ -34,5 +34,6 @@ internal ExecutionManager_1(Target target) public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); public IEnumerable GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos(); + public StubKind GetStubKind(TargetCodePointer entryPoint) => _executionManagerCore.GetStubKind(entryPoint); public void Flush() => _executionManagerCore.Flush(); } 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 6b84fda982ab5e..ee17e586860b31 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 @@ -34,5 +34,6 @@ internal ExecutionManager_2(Target target) public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); public IEnumerable GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos(); + public StubKind GetStubKind(TargetCodePointer entryPoint) => _executionManagerCore.GetStubKind(entryPoint); public void Flush() => _executionManagerCore.Flush(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs index c8b76481107e5c..7c3c78067ab5a1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Collections.Generic; using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -146,4 +147,21 @@ TargetPointer IPrecodeStubs.GetMethodDescFromStubAddress(TargetCodePointer entry return precode.GetMethodDesc(_target, MachineDescriptor); } + + IEnumerable IPrecodeStubs.GetCandidateEntryPoints(TargetCodePointer address) + { + uint pointerSize = (uint)_target.PointerSize; + TargetPointer instrPointer = CodePointerReadableInstrPointer(address); + ulong aligned = instrPointer.Value & ~(ulong)(pointerSize - 1); + + if (MachineDescriptor.StubPrecodeSize is not byte maxPrecodeSize) + throw new InvalidOperationException("StubPrecodeSize is required to enumerate candidate entry points"); + uint count = maxPrecodeSize / pointerSize; + + for (uint i = 0; i < count; i++) + { + TargetPointer candidateAddr = new TargetPointer(aligned - (i * pointerSize)); + yield return CodePointerUtils.CodePointerFromAddress(candidateAddr, _target); + } + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CodeRangeMapRangeList.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CodeRangeMapRangeList.cs new file mode 100644 index 00000000000000..edcefc8f8d5114 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CodeRangeMapRangeList.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. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class CodeRangeMapRangeList : IData +{ + static CodeRangeMapRangeList IData.Create(Target target, TargetPointer address) + => new CodeRangeMapRangeList(target, address); + + public CodeRangeMapRangeList(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.CodeRangeMapRangeList); + RangeListType = target.ReadField(address, type, nameof(RangeListType)); + } + + public int RangeListType { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RangeSection.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RangeSection.cs index cf54d9ddcef9d6..f104ca8df6bae1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RangeSection.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RangeSection.cs @@ -18,6 +18,7 @@ public RangeSection(Target target, TargetPointer address) Flags = target.ReadField(address, type, nameof(Flags)); HeapList = target.ReadPointerField(address, type, nameof(HeapList)); R2RModule = target.ReadPointerField(address, type, nameof(R2RModule)); + RangeList = target.ReadPointerField(address, type, nameof(RangeList)); } public TargetPointer RangeBegin { get; init; } @@ -27,4 +28,5 @@ public RangeSection(Target target, TargetPointer address) public TargetPointer HeapList { get; init; } public int Flags { get; init; } public TargetPointer R2RModule { get; init; } + public TargetPointer RangeList { get; init; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index 590e529ffc480f..1f0e7c9652f455 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Text; using Microsoft.Diagnostics.DataContractReader.Contracts; using Microsoft.Diagnostics.DataContractReader.Contracts.Extensions; @@ -101,7 +102,186 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( uint* nameLen, char* nameBuf, ClrDataAddress* displacement) - => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetRuntimeNameByAddress(address, flags, bufLen, nameLen, nameBuf, displacement) : HResults.E_NOTIMPL; + { + if (displacement is not null) + *displacement = default; + int hr = HResults.S_OK; + try + { + if (flags != 0) + throw new ArgumentException("Flags are not supported", nameof(flags)); + + TargetCodePointer codeAddr = address.ToTargetCodePointer(_target); + + // IsPossibleCodeAddress - validate the address is readable + if (!_target.TryRead(codeAddr, out byte _)) + throw new ArgumentException("Address is not readable", nameof(address)); + + IExecutionManager eman = _target.Contracts.ExecutionManager; + string? resultName = null; + + // First, try to find it as managed code (equivalent of EECodeInfo path in legacy DAC) + CodeBlockHandle? cbh = eman.GetCodeBlockHandle(codeAddr); + if (cbh is CodeBlockHandle codeBlock) + { + TargetPointer methodDescPtr = eman.GetMethodDesc(codeBlock); + if (displacement is not null) + { + TargetNUInt relOffset = eman.GetRelativeOffset(codeBlock); + *displacement = relOffset.Value; + } + + resultName = GetNameFromMethodDesc(methodDescPtr, address); + } + else + { + // Try stub classification + StubKind stubKind = eman.GetStubKind(codeAddr); + + if (stubKind == StubKind.CodeBlockPrecode) + { + // For precode stubs, resolve the MethodDesc from the precode entry point + IPrecodeStubs precodeStubs = _target.Contracts.PrecodeStubs; + foreach (TargetCodePointer potentialEntryPoint in precodeStubs.GetCandidateEntryPoints(codeAddr)) + { + TargetPointer methodDescPtr = eman.NonVirtualEntry2MethodDesc(potentialEntryPoint); + if (methodDescPtr != TargetPointer.Null) + { + if (displacement is not null) + *displacement = codeAddr.Value - potentialEntryPoint.Value; + + resultName = GetNameFromMethodDesc(methodDescPtr, address); + break; + } + } + resultName ??= FormatCLRStubName(GetStubName(stubKind)!, address); + } + else + { + // Known stub type - format as CLRStub[]@ + string? stubName = GetStubName(stubKind); + + if (stubName is not null) + resultName = FormatCLRStubName(stubName, address); + else if (_target.Contracts.AuxiliarySymbols.TryGetAuxiliarySymbolName(address.ToTargetPointer(_target), out string? auxSymbolName)) + { + resultName = auxSymbolName; + } + } + if (resultName is null) + { + throw new InvalidCastException(); + } + } + + OutputBufferHelpers.CopyStringToBuffer(nameBuf, bufLen, nameLen, resultName); + + if (nameBuf is not null && bufLen < resultName.Length + 1) + hr = HResults.S_FALSE; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacyProcess is not null) + { + uint nameLenLocal = 0; + char[] nameBufLocal = new char[bufLen > 0 ? bufLen : 1]; + ClrDataAddress displacementLocal = default; + int hrLocal; + fixed (char* pNameBufLocal = nameBufLocal) + { + hrLocal = _legacyProcess.GetRuntimeNameByAddress( + address, flags, bufLen, + &nameLenLocal, + nameBuf is null ? null : pNameBufLocal, + displacement is null ? null : &displacementLocal); + } + + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK || hr == HResults.S_FALSE) + { + Debug.Assert(nameLen is null || *nameLen == nameLenLocal); + if (nameBuf is not null) + { + Debug.Assert(new ReadOnlySpan(nameBuf, (int)nameLenLocal) + .SequenceEqual(nameBufLocal.AsSpan(0, (int)nameLenLocal))); + } + if (displacement is not null) + { + Debug.Assert(*displacement == displacementLocal); + } + } + } +#endif + + return hr; + } + + private static string? GetStubName(Contracts.StubKind stubKind) + { + return stubKind switch + { + Contracts.StubKind.CodeBlockJumpStub => "JumpStub", + Contracts.StubKind.CodeBlockPrecode => "MethodDescPrestub", + Contracts.StubKind.CodeBlockVSDDispatchStub => "VSD_DispatchStub", + Contracts.StubKind.CodeBlockVSDResolveStub => "VSD_ResolveStub", + Contracts.StubKind.CodeBlockVSDLookupStub => "VSD_LookupStub", + Contracts.StubKind.CodeBlockVSDVTableStub => "VSD_VTableStub", + Contracts.StubKind.CodeBlockCallCounting => "CallCountingStub", + Contracts.StubKind.CodeBlockStubLinkStub => "StubLinkStub", + Contracts.StubKind.CodeBlockMethodCallThunk => "MethodCallThunk", + Contracts.StubKind.PreStub => "ThePreStub", + Contracts.StubKind.InteropDispatchStub => "InteropDispatchStub", + Contracts.StubKind.TailCallStub => "TailCallStub", + _ => null, + }; + } + + private string GetNameFromMethodDesc(TargetPointer methodDescPtr, ClrDataAddress address) + { + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle mdHandle = rts.GetMethodDescHandle(methodDescPtr); + + // Dynamic methods with no stored signature get formatted as CLRStub@ + if (rts.IsNoMetadataMethod(mdHandle, out _) + && rts.IsStoredSigMethodDesc(mdHandle, out ReadOnlySpan signature) + && signature.IsEmpty) + { + return FormatCLRStubName(null, address); + } + + // Get the full method name + StringBuilder sb = new(); + TypeNameBuilder.AppendMethodInternal( + _target, + sb, + mdHandle, + TypeNameFormat.FormatSignature | + TypeNameFormat.FormatNamespace | + TypeNameFormat.FormatFullInst); + + return sb.ToString(); + } + + private string FormatCLRStubName(string? stubName, ClrDataAddress address) + { + // Format: "CLRStub[]@" or "CLRStub@" + StringBuilder sb = new(); + sb.Append("CLRStub"); + if (!string.IsNullOrEmpty(stubName)) + { + sb.Append('['); + sb.Append(stubName); + sb.Append(']'); + } + sb.Append('@'); + sb.Append(address.Value.ToString($"X{_target.PointerSize * 2}")); + + return sb.ToString(); + } int IXCLRDataProcess.StartEnumAppDomains(ulong* handle) => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index 7f8b5cff5b5603..a4bf40160359c4 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -29,6 +29,7 @@ public class ExecutionManagerTests [DataType.ReadyToRunInfo] = TargetTestHelpers.CreateTypeInfo(emBuilder.ReadyToRunInfoLayout), [DataType.EEJitManager] = TargetTestHelpers.CreateTypeInfo(emBuilder.EEJitManagerLayout), [DataType.Module] = TargetTestHelpers.CreateTypeInfo(emBuilder.ModuleLayout), + [DataType.CodeRangeMapRangeList] = TargetTestHelpers.CreateTypeInfo(emBuilder.CodeRangeMapRangeListLayout), [DataType.HashMap] = TargetTestHelpers.CreateTypeInfo(MockHashMap.CreateLayout(helpers.Arch)), [DataType.Bucket] = TargetTestHelpers.CreateTypeInfo(MockHashMapBucket.CreateLayout(helpers.Arch)), }; @@ -655,6 +656,105 @@ public void GetCodeHeapList_LinkedList_TwoNodes(string version, MockTarget.Archi Assert.Equal(currentAddr, hostInfo.CurrentAddress); } + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void TryGetStubKind_GlobalConstants(string version, MockTarget.Architecture arch) + { + IExecutionManager em = CreateExecutionManagerContract(version, arch); + + Assert.Equal(StubKind.PreStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_1000))); + Assert.Equal(StubKind.InteropDispatchStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_2000))); + Assert.Equal(StubKind.InteropDispatchStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_3000))); + Assert.Equal(StubKind.InteropDispatchStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_4000))); + Assert.Equal(StubKind.TailCallStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_5000))); + Assert.Equal(StubKind.CodeBlockUnknown, em.TryGetStubKind(new TargetCodePointer(0x00aa_9000))); + } + + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void TryGetStubKind_RangeListStubs(string version, MockTarget.Architecture arch) + { + const ulong codeRangeStart = 0x0a0a_0000u; + const uint codeRangeSize = 0x4000u; + const ulong jitManagerAddress = 0x000b_ff00; + const int stubCodeBlockKindPrecode = 4; // STUB_CODE_BLOCK_STUBPRECODE + + IExecutionManager em = CreateExecutionManagerContract( + version, + arch, + emBuilder => + { + var jittedCode = emBuilder.AllocateJittedCodeRange(codeRangeStart, codeRangeSize); + MockRangeSection rangeSection = emBuilder.AddRangeListRangeSection(jittedCode, jitManagerAddress, stubCodeBlockKindPrecode); + _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); + }); + + StubKind kind = em.TryGetStubKind(new TargetCodePointer(codeRangeStart + 0x100)); + Assert.Equal(StubKind.CodeBlockPrecode, kind); + } + + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void TryGetStubKind_CodeHeapStubs(string version, MockTarget.Architecture arch) + { + const ulong codeRangeStart = 0x0a0a_0000u; + const uint codeRangeSize = 0xc000u; + const uint stubSize = 0x20; + const ulong jitManagerAddress = 0x000b_ff00; + const int stubCodeBlockKindJumpStub = 1; // STUB_CODE_BLOCK_JUMPSTUB + ulong stubCodeAddress = 0; + + IExecutionManager em = CreateExecutionManagerContract( + version, + arch, + emBuilder => + { + var jittedCode = emBuilder.AllocateJittedCodeRange(codeRangeStart, codeRangeSize); + stubCodeAddress = emBuilder.AddStubCodeBlock(jittedCode, stubSize, stubCodeBlockKindJumpStub).CodeAddress; + + NibbleMapTestBuilderBase nibBuilder = emBuilder.CreateNibbleMap(codeRangeStart, codeRangeSize); + nibBuilder.AllocateCodeChunk(new TargetCodePointer(stubCodeAddress), stubSize); + + MockCodeHeapListNode codeHeapListNode = emBuilder.AddCodeHeapListNode(0, codeRangeStart, codeRangeStart + codeRangeSize, codeRangeStart, nibBuilder.NibbleMapFragment.Address); + MockRangeSection rangeSection = emBuilder.AddRangeSection(jittedCode, jitManagerAddress, codeHeapListNode.Address); + _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); + }); + + StubKind kind = em.TryGetStubKind(new TargetCodePointer(stubCodeAddress)); + Assert.Equal(StubKind.CodeBlockJumpStub, kind); + } + + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void TryGetStubKind_ManagedCode(string version, MockTarget.Architecture arch) + { + const ulong codeRangeStart = 0x0a0a_0000u; + const uint codeRangeSize = 0xc000u; + const uint methodSize = 0x450; + const ulong jitManagerAddress = 0x000b_ff00; + const ulong expectedMethodDescAddress = 0x0101_aaa0; + ulong methodStart = 0; + + IExecutionManager em = CreateExecutionManagerContract( + version, + arch, + emBuilder => + { + var jittedCode = emBuilder.AllocateJittedCodeRange(codeRangeStart, codeRangeSize); + methodStart = emBuilder.AddJittedMethod(jittedCode, methodSize, expectedMethodDescAddress).CodeAddress; + + NibbleMapTestBuilderBase nibBuilder = emBuilder.CreateNibbleMap(codeRangeStart, codeRangeSize); + nibBuilder.AllocateCodeChunk(new TargetCodePointer(methodStart), methodSize); + + MockCodeHeapListNode codeHeapListNode = emBuilder.AddCodeHeapListNode(0, codeRangeStart, codeRangeStart + codeRangeSize, codeRangeStart, nibBuilder.NibbleMapFragment.Address); + MockRangeSection rangeSection = emBuilder.AddRangeSection(jittedCode, jitManagerAddress, codeHeapListNode.Address); + _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); + }); + + StubKind kind = em.TryGetStubKind(new TargetCodePointer(methodStart)); + Assert.Equal(StubKind.CodeBlockManaged, kind); + } + 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 c72126d962f939..772477d988b8e1 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs @@ -99,6 +99,7 @@ internal sealed class MockRangeSection : TypedView private const string FlagsFieldName = "Flags"; private const string HeapListFieldName = "HeapList"; private const string R2RModuleFieldName = "R2RModule"; + private const string RangeListFieldName = "RangeList"; public static Layout CreateLayout(MockTarget.Architecture architecture) => new SequentialLayoutBuilder("RangeSection", architecture) @@ -109,6 +110,7 @@ public static Layout CreateLayout(MockTarget.Architecture arch .AddUInt32Field(FlagsFieldName) .AddPointerField(HeapListFieldName) .AddPointerField(R2RModuleFieldName) + .AddPointerField(RangeListFieldName) .Build(); public ulong RangeBegin @@ -146,6 +148,28 @@ public ulong R2RModule get => ReadPointerField(R2RModuleFieldName); set => WritePointerField(R2RModuleFieldName, value); } + + public ulong RangeList + { + get => ReadPointerField(RangeListFieldName); + set => WritePointerField(RangeListFieldName, value); + } +} + +internal sealed class MockCodeRangeMapRangeList : TypedView +{ + private const string RangeListTypeFieldName = "RangeListType"; + + public static Layout CreateLayout(MockTarget.Architecture architecture) + => new SequentialLayoutBuilder("CodeRangeMapRangeList", architecture) + .AddUInt32Field(RangeListTypeFieldName) + .Build(); + + public int RangeListType + { + get => (int)ReadUInt32Field(RangeListTypeFieldName); + set => WriteUInt32Field(RangeListTypeFieldName, (uint)value); + } } internal sealed class MockCodeHeapListNode : TypedView @@ -442,6 +466,7 @@ public Memory CodeBytes internal sealed class MockExecutionManagerBuilder { private const uint CodeHeapRangeSectionFlag = 0x02; + private const uint RangeListRangeSectionFlag = 0x04; private const string EEJitManagerGlobalName = "EEJitManagerGlobalPointer"; private const int RangeSectionMapBitsPerLevel = 8; @@ -501,6 +526,7 @@ internal readonly struct JittedCodeRange internal Layout ReadyToRunInfoLayout { get; } internal Layout EEJitManagerLayout { get; } internal Layout ModuleLayout { get; } + internal Layout CodeRangeMapRangeListLayout { get; } internal Layout RuntimeFunctionLayout => _runtimeFunctions.RuntimeFunctionLayout; internal Layout UnwindInfoLayout => _runtimeFunctions.UnwindInfoLayout; internal (string Name, ulong Value)[] Globals { get; } @@ -555,6 +581,7 @@ internal MockExecutionManagerBuilder(string version, MockMemorySpace.Builder bui ReadyToRunInfoLayout = MockReadyToRunInfo.CreateLayout(architecture, hashMapStride); EEJitManagerLayout = MockEEJitManager.CreateLayout(architecture); ModuleLayout = MockLoaderModule.CreateLayout(architecture); + CodeRangeMapRangeListLayout = MockCodeRangeMapRangeList.CreateLayout(architecture); _eeJitManager = AllocateAndCreate(EEJitManagerLayout, "EEJitManager"); _eeJitManager.AllCodeHeaps = allCodeHeaps; @@ -569,6 +596,11 @@ internal MockExecutionManagerBuilder(string version, MockMemorySpace.Builder bui }; globals.Add((nameof(Constants.Globals.HashMapSlotsPerBucket), MockHashMapBucket.SlotsPerBucket)); globals.Add((nameof(Constants.Globals.HashMapValueMask), Builder.TargetTestHelpers.MaxSignedTargetAddress)); + globals.Add((nameof(Constants.Globals.ThePreStub), 0x00aa_1000)); + globals.Add((nameof(Constants.Globals.GenericPInvokeCalliHelper), 0x00aa_2000)); + globals.Add((nameof(Constants.Globals.VarargPInvokeStub), 0x00aa_3000)); + globals.Add((nameof(Constants.Globals.VarargPInvokeStub_RetBuffArg), 0x00aa_4000)); + globals.Add((nameof(Constants.Globals.TailCallJitHelper), 0x00aa_5000)); Globals = [.. globals]; } @@ -614,6 +646,27 @@ public MockRangeSection AddReadyToRunRangeSection(JittedCodeRange jittedCodeRang return rangeSection; } + public MockRangeSection AddRangeListRangeSection(JittedCodeRange jittedCodeRange, ulong jitManagerAddress, int rangeListType) + { + MockCodeRangeMapRangeList rangeList = AllocateAndCreate(CodeRangeMapRangeListLayout, "CodeRangeMapRangeList"); + rangeList.RangeListType = rangeListType; + + MockRangeSection rangeSection = AllocateAndCreate(RangeSectionLayout, "RangeSection (RangeList)", _rangeSectionMapAllocator); + rangeSection.RangeBegin = jittedCodeRange.RangeStart; + rangeSection.RangeEndOpen = jittedCodeRange.RangeEnd; + rangeSection.Flags = RangeListRangeSectionFlag; + rangeSection.RangeList = rangeList.Address; + rangeSection.JitManager = jitManagerAddress; + return rangeSection; + } + + public MockJittedMethod AddStubCodeBlock(JittedCodeRange jittedCodeRange, uint codeSize, int stubCodeBlockKind) + { + MockJittedMethod stub = AllocateJittedMethod(jittedCodeRange, codeSize, "Stub Code Block"); + stub.CodeHeader = (ulong)stubCodeBlockKind; + return stub; + } + public MockRangeSectionFragment AddRangeSectionFragment(JittedCodeRange jittedCodeRange, ulong rangeSectionAddress) => AddRangeSectionFragment(jittedCodeRange, rangeSectionAddress, insertIntoMap: true); From 1b691c22cbfc5ea686a5a8ad353e2da9eb95c5b9 Mon Sep 17 00:00:00 2001 From: Rachel Date: Sun, 19 Apr 2026 22:50:45 -0700 Subject: [PATCH 2/8] Update PrecodeStubs.md --- docs/design/datacontracts/PrecodeStubs.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/design/datacontracts/PrecodeStubs.md b/docs/design/datacontracts/PrecodeStubs.md index 31be70145bf232..a664e3b759a2ea 100644 --- a/docs/design/datacontracts/PrecodeStubs.md +++ b/docs/design/datacontracts/PrecodeStubs.md @@ -9,9 +9,7 @@ This contract provides support for examining [precode](../coreclr/botr/method-de TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint); // Enumerates candidate precode entry points near a given code address. - // The address is pointer-aligned and then iterated backwards in pointer-sized - // steps up to StubPrecodeSize / PointerSize candidates. This is used by - // GetRuntimeNameByAddress to resolve a code address that falls within a + // This is used to resolve a code address that falls within a // precode stub back to its entry point. IEnumerable GetCandidateEntryPoints(TargetCodePointer address); ``` From f01a100c17687f07304008db394b8f44e5cd50db Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Sun, 19 Apr 2026 23:12:53 -0700 Subject: [PATCH 3/8] Update src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../cdac/tests/ExecutionManager/ExecutionManagerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index a4bf40160359c4..7f1beb7c2cee25 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -751,7 +751,7 @@ public void TryGetStubKind_ManagedCode(string version, MockTarget.Architecture a _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - StubKind kind = em.TryGetStubKind(new TargetCodePointer(methodStart)); + StubKind kind = em.GetStubKind(new TargetCodePointer(methodStart)); Assert.Equal(StubKind.CodeBlockManaged, kind); } From 71221612889603c973fd7b077d19d76d30eb8287 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Mon, 20 Apr 2026 10:36:36 -0700 Subject: [PATCH 4/8] fix build and comments --- src/coreclr/vm/cgensys.h | 7 +++++++ src/coreclr/vm/class.h | 3 +++ src/coreclr/vm/datadescriptor/datadescriptor.inc | 10 +++++----- src/coreclr/vm/jitinterface.h | 4 ++++ .../ExecutionManager/ExecutionManagerCore.cs | 7 ++++--- .../Contracts/PrecodeStubs_Common.cs | 5 ++++- .../Data/PrecodeMachineDescriptor.cs | 6 +++--- .../ExecutionManager/ExecutionManagerTests.cs | 16 ++++++++-------- .../MockDescriptors.ExecutionManager.cs | 10 +++++----- 9 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/coreclr/vm/cgensys.h b/src/coreclr/vm/cgensys.h index 59c451b0a90ba7..38e82565cead5c 100644 --- a/src/coreclr/vm/cgensys.h +++ b/src/coreclr/vm/cgensys.h @@ -56,6 +56,13 @@ extern "C" void STDCALL GenericPInvokeCalliHelper(void); extern "C" PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBlock, TADDR pIndirection, DWORD sectionIndex, Module * pModule); +// cDAC-visible TADDR wrappers for function entrypoints. +inline const TADDR g_cdacGenericPInvokeCalliHelper = (TADDR)(void*)GenericPInvokeCalliHelper; +inline const TADDR g_cdacVarargPInvokeStub = (TADDR)(void*)VarargPInvokeStub; +#if !defined(TARGET_X86) && !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64) +inline const TADDR g_cdacVarargPInvokeStub_RetBuffArg = (TADDR)(void*)VarargPInvokeStub_RetBuffArg; +#endif + extern "C" void STDCALL VirtualMethodFixupStub(void); extern "C" void STDCALL VirtualMethodFixupPatchLabel(void); diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 13d1ee37a8d3cd..917394985901ed 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -1955,6 +1955,9 @@ inline BOOL EEClass::IsInt128OrHasInt128Fields() VOID InitPreStubManager(); EXTERN_C void STDCALL ThePreStub(); +#ifndef FEATURE_PORTABLE_ENTRYPOINTS +inline const TADDR g_cdacThePreStub = (TADDR)(void*)ThePreStub; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS inline PCODE GetPreStubEntryPoint() { diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 1837c8f3e4a8a2..dd0ab088a5f58b 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1419,15 +1419,15 @@ CDAC_GLOBAL(SyncBlockValueToObjectOffset, T_UINT16, OBJHEADER_SIZE - cdac_data IPrecodeStubs.GetCandidateEntryPoints(TargetCodeP for (uint i = 0; i < count; i++) { - TargetPointer candidateAddr = new TargetPointer(aligned - (i * pointerSize)); + ulong offset = i * pointerSize; + if (aligned < offset) + yield break; + TargetPointer candidateAddr = new TargetPointer(aligned - offset); yield return CodePointerUtils.CodePointerFromAddress(candidateAddr, _target); } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs index 840059e1511c95..4413f639c3f02c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs @@ -43,7 +43,7 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) if (type.Fields.ContainsKey(nameof(StubPrecodeSize))) { - StubPrecodeSize = target.ReadField(address, type, nameof(FixupStubPrecodeSize)); + StubPrecodeSize = target.ReadField(address, type, nameof(StubPrecodeSize)); StubBytes = new byte[StubPrecodeSize.Value]; target.ReadBuffer(address + (ulong)type.Fields[nameof(StubBytes)].Offset, StubBytes); StubIgnoredBytes = new byte[StubPrecodeSize.Value]; @@ -52,8 +52,8 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) else { StubPrecodeSize = null; - FixupBytes = null; - FixupIgnoredBytes = null; + StubBytes = null; + StubIgnoredBytes = null; } PInvokeImportPrecodeType = MaybeGetPrecodeType(target, address, nameof(PInvokeImportPrecodeType)); diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index 7f1beb7c2cee25..3effcbbe31190f 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -662,12 +662,12 @@ public void TryGetStubKind_GlobalConstants(string version, MockTarget.Architectu { IExecutionManager em = CreateExecutionManagerContract(version, arch); - Assert.Equal(StubKind.PreStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_1000))); - Assert.Equal(StubKind.InteropDispatchStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_2000))); - Assert.Equal(StubKind.InteropDispatchStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_3000))); - Assert.Equal(StubKind.InteropDispatchStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_4000))); - Assert.Equal(StubKind.TailCallStub, em.TryGetStubKind(new TargetCodePointer(0x00aa_5000))); - Assert.Equal(StubKind.CodeBlockUnknown, em.TryGetStubKind(new TargetCodePointer(0x00aa_9000))); + Assert.Equal(StubKind.PreStub, em.GetStubKind(new TargetCodePointer(0x00aa_1000))); + Assert.Equal(StubKind.InteropDispatchStub, em.GetStubKind(new TargetCodePointer(0x00aa_2000))); + Assert.Equal(StubKind.InteropDispatchStub, em.GetStubKind(new TargetCodePointer(0x00aa_3000))); + Assert.Equal(StubKind.InteropDispatchStub, em.GetStubKind(new TargetCodePointer(0x00aa_4000))); + Assert.Equal(StubKind.TailCallStub, em.GetStubKind(new TargetCodePointer(0x00aa_5000))); + Assert.Equal(StubKind.CodeBlockUnknown, em.GetStubKind(new TargetCodePointer(0x00aa_9000))); } [Theory] @@ -689,7 +689,7 @@ public void TryGetStubKind_RangeListStubs(string version, MockTarget.Architectur _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - StubKind kind = em.TryGetStubKind(new TargetCodePointer(codeRangeStart + 0x100)); + StubKind kind = em.GetStubKind(new TargetCodePointer(codeRangeStart + 0x100)); Assert.Equal(StubKind.CodeBlockPrecode, kind); } @@ -720,7 +720,7 @@ public void TryGetStubKind_CodeHeapStubs(string version, MockTarget.Architecture _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - StubKind kind = em.TryGetStubKind(new TargetCodePointer(stubCodeAddress)); + StubKind kind = em.GetStubKind(new TargetCodePointer(stubCodeAddress)); Assert.Equal(StubKind.CodeBlockJumpStub, kind); } diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs index 772477d988b8e1..8ae48812d16e1f 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs @@ -596,11 +596,11 @@ internal MockExecutionManagerBuilder(string version, MockMemorySpace.Builder bui }; globals.Add((nameof(Constants.Globals.HashMapSlotsPerBucket), MockHashMapBucket.SlotsPerBucket)); globals.Add((nameof(Constants.Globals.HashMapValueMask), Builder.TargetTestHelpers.MaxSignedTargetAddress)); - globals.Add((nameof(Constants.Globals.ThePreStub), 0x00aa_1000)); - globals.Add((nameof(Constants.Globals.GenericPInvokeCalliHelper), 0x00aa_2000)); - globals.Add((nameof(Constants.Globals.VarargPInvokeStub), 0x00aa_3000)); - globals.Add((nameof(Constants.Globals.VarargPInvokeStub_RetBuffArg), 0x00aa_4000)); - globals.Add((nameof(Constants.Globals.TailCallJitHelper), 0x00aa_5000)); + globals.Add((nameof(Constants.Globals.ThePreStub), AddPointerGlobal(0x00aa_1000, "ThePreStub"))); + globals.Add((nameof(Constants.Globals.GenericPInvokeCalliHelper), AddPointerGlobal(0x00aa_2000, "GenericPInvokeCalliHelper"))); + globals.Add((nameof(Constants.Globals.VarargPInvokeStub), AddPointerGlobal(0x00aa_3000, "VarargPInvokeStub"))); + globals.Add((nameof(Constants.Globals.VarargPInvokeStub_RetBuffArg), AddPointerGlobal(0x00aa_4000, "VarargPInvokeStub_RetBuffArg"))); + globals.Add((nameof(Constants.Globals.TailCallJitHelper), AddPointerGlobal(0x00aa_5000, "TailCallJitHelper"))); Globals = [.. globals]; } From d999fafbaaed1ae4c6e4b4080dcbfe3bcff65ed7 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 22 Apr 2026 16:04:04 -0700 Subject: [PATCH 5/8] code review --- docs/design/datacontracts/ExecutionManager.md | 30 +-- docs/design/datacontracts/PrecodeStubs.md | 18 -- src/coreclr/debug/daccess/daccess.cpp | 182 +----------------- src/coreclr/inc/gfunc_list.h | 8 - src/coreclr/vm/cgensys.h | 7 - src/coreclr/vm/class.h | 3 - .../vm/datadescriptor/datadescriptor.inc | 11 -- src/coreclr/vm/jitinterface.h | 4 - .../Contracts/IExecutionManager.cs | 25 +-- .../Contracts/IPrecodeStubs.cs | 2 - .../Constants.cs | 6 +- .../ExecutionManagerCore.EEJitManager.cs | 50 ++--- ...ecutionManagerCore.ReadyToRunJitManager.cs | 6 +- .../ExecutionManager/ExecutionManagerCore.cs | 59 +----- .../ExecutionManager/ExecutionManager_1.cs | 2 +- .../ExecutionManager/ExecutionManager_2.cs | 2 +- .../Contracts/PrecodeStubs_Common.cs | 21 -- .../SOSDacImpl.IXCLRDataProcess.cs | 121 +----------- .../ExecutionManager/ExecutionManagerTests.cs | 27 ++- .../MockDescriptors.ExecutionManager.cs | 5 - 20 files changed, 73 insertions(+), 516 deletions(-) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index cf430fac49d155..f0429580fd2a5c 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -52,9 +52,9 @@ struct CodeBlockHandle // Get the exception clause info for the code block List GetExceptionClauses(CodeBlockHandle codeInfoHandle); - // Classify a code address as a known stub kind (precode, jump stub, VSD stub, etc.) - // or as managed code. Returns CodeBlockUnknown if the address is not recognized. - StubKind GetStubKind(TargetCodePointer jittedCodeAddress); + // If the code refers to a dynamically generated runtime stub, return a non-null name + // describing what kind of stub it is. Returns null for managed code or unrecognized addresses. + string? GetStubSymbol(TargetCodePointer jittedCodeAddress); // Extension Methods (implemented in terms of other APIs) // Returns true if the code block is a funclet (exception handler, filter, or finally) @@ -225,11 +225,6 @@ Global variables used: | `GCInfoVersion` | uint32 | JITted code GCInfo version | | `FeatureOnStackReplacement` | uint8 | 1 if FEATURE_ON_STACK_REPLACEMENT is enabled, 0 otherwise | | `FeaturePortableEntrypoints` | uint8 | 1 if FEATURE_PORTABLE_ENTRYPOINTS is enabled, 0 otherwise | -| `ThePreStub` | TargetPointer | Address of the pre-stub entry point (only present when `FeaturePortableEntrypoints` is disabled) | -| `GenericPInvokeCalliHelper` | TargetPointer | Address of the generic PInvoke CALLI helper stub | -| `VarargPInvokeStub` | TargetPointer | Address of the vararg PInvoke stub | -| `VarargPInvokeStub_RetBuffArg` | TargetPointer | Address of the vararg PInvoke stub with return buffer argument (not present on x86, ARM64, LoongArch64, RISC-V) | -| `TailCallJitHelper` | TargetPointer | Address of the JIT tail call helper (only present on x86 Windows) | | `ObjectMethodTable` | TargetPointer | Pointer to the `System.Object` MethodTable, used for catch-all handler detection | Contract constants used: @@ -512,33 +507,26 @@ 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. -### Stub Kind Classification +### Stub Symbol Classification -`GetStubKind` classifies a code address as a known stub type or managed code. It first checks the address against well-known global stub pointers (`ThePreStub`, `VarargPInvokeStub`, `VarargPInvokeStub_RetBuffArg`, `GenericPInvokeCalliHelper`, `TailCallJitHelper`). If the address matches one of these, it returns the corresponding `StubKind` immediately. +`GetStubSymbol` classifies a code address as a known stub type. It returns a descriptive string for stub addresses, or `null` for managed code or unrecognized addresses. The exact kinds of stubs and their names might shift across different runtime versions. -If no global match is found, the method looks up the address in the `RangeSectionMap`. If a `RangeSection` is found, the JIT manager for that section classifies the code: +The method looks up the address in the `RangeSectionMap`. If a `RangeSection` is found, the JIT manager for that section classifies the code: - **EEJitManager**: If the range section is a range list, reads the `CodeRangeMapRangeList.RangeListType` to determine the stub code block kind. Otherwise, it uses the nibble map to find the method code start, reads the code header indirect pointer, and checks whether it is a stub code block (value ≤ `StubCodeBlockLast`). If so, the value identifies the specific stub kind. - **ReadyToRunJitManager**: Checks whether the address falls within a delay-load method call thunk region. ```csharp -StubKind GetStubKind(TargetCodePointer jittedCodeAddress) +string? GetStubSymbol(TargetCodePointer jittedCodeAddress) { TargetPointer address = CodePointerUtils.AddressFromCodePointer(jittedCodeAddress); - // Check well-known global stubs - if (address == ThePreStub) return StubKind.PreStub; - if (address == VarargPInvokeStub || address == VarargPInvokeStub_RetBuffArg - || address == GenericPInvokeCalliHelper) - return StubKind.InteropDispatchStub; - if (address == TailCallJitHelper) return StubKind.TailCallStub; - // Look up in range section map RangeSection range = FindRangeSection(jittedCodeAddress); - if (range == null) return StubKind.CodeBlockUnknown; + if (range == null) return null; JitManager jitManager = GetJitManager(range); - return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); + return jitManager.GetStubSymbol(range, jittedCodeAddress); } ``` diff --git a/docs/design/datacontracts/PrecodeStubs.md b/docs/design/datacontracts/PrecodeStubs.md index a664e3b759a2ea..b336b433ac2e13 100644 --- a/docs/design/datacontracts/PrecodeStubs.md +++ b/docs/design/datacontracts/PrecodeStubs.md @@ -7,11 +7,6 @@ This contract provides support for examining [precode](../coreclr/botr/method-de ```csharp // Gets a pointer to the MethodDesc for a given stub entrypoint TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint); - - // Enumerates candidate precode entry points near a given code address. - // This is used to resolve a code address that falls within a - // precode stub back to its entry point. - IEnumerable GetCandidateEntryPoints(TargetCodePointer address); ``` ## Version 1, 2, and 3 @@ -300,17 +295,4 @@ After the initial precode type is determined, for stub precodes a refined precod return precode.GetMethodDesc(_target, MachineDescriptor); } - - IEnumerable IPrecodeStubs.GetCandidateEntryPoints(TargetCodePointer address) - { - TargetPointer instrPointer = CodePointerReadableInstrPointer(address); - ulong aligned = instrPointer.Value & ~(ulong)(PointerSize - 1); - uint count = StubPrecodeSize / PointerSize; - - for (uint i = 0; i < count; i++) - { - TargetPointer candidateAddr = new TargetPointer(aligned - (i * PointerSize)); - yield return CodePointerFromAddress(candidateAddr); - } - } ``` diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 12e0ff453b1f02..32387101898ddd 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -5309,86 +5309,6 @@ ClrDataAccess::GetJitHelperName(IN TADDR address) return NULL; } -// This function expects more memory than maybe needed. -static int FormatCLRStubName( - _In_opt_z_ LPCWSTR stubNameMaybe, - _In_ TADDR stubAddr, - _In_ ULONG32 bufLen, - _Out_ ULONG32 *symbolLen, - _Out_writes_bytes_opt_(bufLen) WCHAR* symbolBuf) -{ - // Parts needed to construct a name: - // With stub manager name: "CLRStub[%s]@%p" - // No stub manager name: "CLRStub@%p" - const WCHAR formatName_Prefix[] = W("CLRStub"); - const WCHAR formatName_OpenBracket[] = W("["); - const WCHAR formatName_CloseBracket[] = W("]"); - const WCHAR formatName_PrefixEnd[] = W("@"); - - // Compute the address as a string safely. - WCHAR addrString[Max64BitHexString + 1]; - FormatInteger(addrString, ARRAY_SIZE(addrString), sizeof(void*) == 8 ? "%016llX" : "%08X", stubAddr); - size_t addStringLen = u16_strlen(addrString); - - // Compute maximum length, include the null terminator. - size_t formatName_MaxLen = ARRAY_SIZE(formatName_Prefix) // Include trailing null - + ARRAY_SIZE(formatName_PrefixEnd) - 1 - + addStringLen; - - // Consider stub manager name - size_t stubManagedNameLen = 0; - if (stubNameMaybe != NULL) - { - stubManagedNameLen = u16_strlen(stubNameMaybe); - formatName_MaxLen += ARRAY_SIZE(formatName_OpenBracket) - 1; - formatName_MaxLen += ARRAY_SIZE(formatName_CloseBracket) - 1; - } - - HRESULT hr = S_FALSE; - - // Compute the exact length needed. - const size_t lenNeeded = formatName_MaxLen + stubManagedNameLen; - if (lenNeeded <= bufLen) - { - size_t written = 0; - - // Set the prefix - wcscpy_s(symbolBuf, bufLen - written, formatName_Prefix); - written += ARRAY_SIZE(formatName_Prefix) - 1; - - // Add the name - if (stubManagedNameLen > 0) - { - wcscat_s(symbolBuf, bufLen - written, formatName_OpenBracket); - written += ARRAY_SIZE(formatName_OpenBracket) - 1; - wcscat_s(symbolBuf, bufLen - written, stubNameMaybe); - written += stubManagedNameLen; - wcscat_s(symbolBuf, bufLen - written, formatName_CloseBracket); - written += ARRAY_SIZE(formatName_CloseBracket) - 1; - } - - // Append the prefix end - wcscat_s(symbolBuf, bufLen - written, formatName_PrefixEnd); - written += ARRAY_SIZE(formatName_PrefixEnd) - 1; - - // Append the address - wcscat_s(symbolBuf, bufLen - written, addrString); - written += addStringLen; - - hr = S_OK; - } - - if (symbolLen) - { - if (!FitsIn(lenNeeded)) - return COR_E_OVERFLOW; - - *symbolLen = (ULONG32)lenNeeded; - } - - return hr; -} - HRESULT ClrDataAccess::RawGetMethodName( /* [in] */ CLRDATA_ADDRESS address, @@ -5421,87 +5341,24 @@ ClrDataAccess::RawGetMethodName( return status; } - PTR_StubManager pStubManager; - MethodDesc* methodDesc = NULL; - + if (displacement) { - EECodeInfo codeInfo(GetInterpreterCodeFromInterpreterPrecodeIfPresent(TO_TADDR(address))); - if (codeInfo.IsValid()) - { - if (displacement) - { - *displacement = codeInfo.GetRelOffset(); - } - - methodDesc = codeInfo.GetMethodDesc(); - goto NameFromMethodDesc; - } + *displacement = 0; } + PTR_StubManager pStubManager; + pStubManager = StubManager::FindStubManager(TO_TADDR(address)); if (pStubManager != NULL) { - if (displacement) - { - *displacement = 0; - } - - // - // Special-cased stub managers - // - if (pStubManager == PrecodeStubManager::g_pManager) - { - PCODE alignedAddress = AlignDown(TO_TADDR(address), PRECODE_ALIGNMENT); - -#ifdef TARGET_ARM - alignedAddress += THUMB_CODE; -#endif - - SIZE_T maxPrecodeSize = sizeof(StubPrecode); - -#ifdef HAS_THISPTR_RETBUF_PRECODE - maxPrecodeSize = max((size_t)maxPrecodeSize, sizeof(ThisPtrRetBufPrecode)); -#endif - - for (SIZE_T i = 0; i < maxPrecodeSize / PRECODE_ALIGNMENT; i++) - { - EX_TRY - { - // Try to find matching precode entrypoint - Precode* pPrecode = Precode::GetPrecodeFromEntryPoint(alignedAddress, TRUE); - if (pPrecode != NULL && pPrecode->GetType() != PRECODE_UMENTRY_THUNK) - { - methodDesc = pPrecode->GetMethodDesc(); - if (methodDesc != NULL) - { - if (DacValidateMD(methodDesc)) - { - if (displacement) - { - *displacement = TO_TADDR(address) - PCODEToPINSTR(alignedAddress); - } - goto NameFromMethodDesc; - } - } - } - alignedAddress -= PRECODE_ALIGNMENT; - } - EX_CATCH - { - } - EX_END_CATCH - } - } - LPCWSTR wszStubManagerName = pStubManager->GetStubManagerName(TO_TADDR(address)); _ASSERTE(wszStubManagerName != NULL); - - return FormatCLRStubName( - wszStubManagerName, - TO_TADDR(address), - bufLen, - symbolLen, - symbolBuf); + if (wcscmp(wszStubManagerName, W("ThePreStub")) != 0 && wcscmp(wszStubManagerName, W("InteropDispatchStub")) != 0 && wcscmp(wszStubManagerName, W("TailCallStub")) != 0) + { + // Skip the stubs that are just assembly helpers. + wcscpy_s(symbolBuf, bufLen, wszStubManagerName); + return S_OK; + } } // Do not waste time looking up name for static helper. Debugger can get the actual name from .pdb. @@ -5509,11 +5366,6 @@ ClrDataAccess::RawGetMethodName( pHelperName = GetJitHelperName(TO_TADDR(address)); if (pHelperName != NULL) { - if (displacement) - { - *displacement = 0; - } - HRESULT hr = ConvertUtf8(pHelperName, bufLen, symbolLen, symbolBuf); if (FAILED(hr)) return S_FALSE; @@ -5522,20 +5374,6 @@ ClrDataAccess::RawGetMethodName( } return E_NOINTERFACE; - -NameFromMethodDesc: - if (methodDesc->GetClassification() == mcDynamic - && methodDesc->GetSigParser().IsNull()) - { - return FormatCLRStubName( - NULL, - TO_TADDR(address), - bufLen, - symbolLen, - symbolBuf); - } - - return GetFullMethodName(methodDesc, bufLen, symbolLen, symbolBuf); } HRESULT diff --git a/src/coreclr/inc/gfunc_list.h b/src/coreclr/inc/gfunc_list.h index 44031c75a12332..9631099ff92f46 100644 --- a/src/coreclr/inc/gfunc_list.h +++ b/src/coreclr/inc/gfunc_list.h @@ -12,14 +12,6 @@ DEFINE_DACGFN(DACNotifyCompilationFinished) DEFINE_DACGFN(ThePreStub) -DEFINE_DACGFN(GenericPInvokeCalliHelper) -DEFINE_DACGFN(VarargPInvokeStub) -#if !defined(TARGET_X86) && !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64) -DEFINE_DACGFN(VarargPInvokeStub_RetBuffArg) -#endif -#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) -DEFINE_DACGFN(JIT_TailCall) -#endif DEFINE_DACGFN(ThePreStubPatchLabel) #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/vm/cgensys.h b/src/coreclr/vm/cgensys.h index 38e82565cead5c..59c451b0a90ba7 100644 --- a/src/coreclr/vm/cgensys.h +++ b/src/coreclr/vm/cgensys.h @@ -56,13 +56,6 @@ extern "C" void STDCALL GenericPInvokeCalliHelper(void); extern "C" PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBlock, TADDR pIndirection, DWORD sectionIndex, Module * pModule); -// cDAC-visible TADDR wrappers for function entrypoints. -inline const TADDR g_cdacGenericPInvokeCalliHelper = (TADDR)(void*)GenericPInvokeCalliHelper; -inline const TADDR g_cdacVarargPInvokeStub = (TADDR)(void*)VarargPInvokeStub; -#if !defined(TARGET_X86) && !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64) -inline const TADDR g_cdacVarargPInvokeStub_RetBuffArg = (TADDR)(void*)VarargPInvokeStub_RetBuffArg; -#endif - extern "C" void STDCALL VirtualMethodFixupStub(void); extern "C" void STDCALL VirtualMethodFixupPatchLabel(void); diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 917394985901ed..13d1ee37a8d3cd 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -1955,9 +1955,6 @@ inline BOOL EEClass::IsInt128OrHasInt128Fields() VOID InitPreStubManager(); EXTERN_C void STDCALL ThePreStub(); -#ifndef FEATURE_PORTABLE_ENTRYPOINTS -inline const TADDR g_cdacThePreStub = (TADDR)(void*)ThePreStub; -#endif // !FEATURE_PORTABLE_ENTRYPOINTS inline PCODE GetPreStubEntryPoint() { diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index dd0ab088a5f58b..baa439d0c0b49f 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1418,17 +1418,6 @@ CDAC_GLOBAL(ArrayBaseSize, T_UINT32, ARRAYBASE_BASESIZE) CDAC_GLOBAL(SyncBlockValueToObjectOffset, T_UINT16, OBJHEADER_SIZE - cdac_data::SyncBlockValue) CDAC_GLOBAL(StubCodeBlockLast, T_UINT8, STUB_CODE_BLOCK_LAST) CDAC_GLOBAL(DefaultADID, T_UINT32, DefaultADID) -#ifndef FEATURE_PORTABLE_ENTRYPOINTS -CDAC_GLOBAL_POINTER(ThePreStub, &g_cdacThePreStub) -#endif // !FEATURE_PORTABLE_ENTRYPOINTS -CDAC_GLOBAL_POINTER(GenericPInvokeCalliHelper, &g_cdacGenericPInvokeCalliHelper) -CDAC_GLOBAL_POINTER(VarargPInvokeStub, &g_cdacVarargPInvokeStub) -#if !defined(TARGET_X86) && !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64) -CDAC_GLOBAL_POINTER(VarargPInvokeStub_RetBuffArg, &g_cdacVarargPInvokeStub_RetBuffArg) -#endif -#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) -CDAC_GLOBAL_POINTER(TailCallJitHelper, &g_cdacTailCallJitHelper) -#endif // TARGET_X86 && !UNIX_X86_ABI #ifndef TARGET_UNIX CDAC_GLOBAL(SizeOfGenericModeBlock, T_UINT32, sizeof(GenericModeBlock)) #endif diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 2b8f15a684a027..839df4ca92455b 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -273,10 +273,6 @@ extern "C" #endif // !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64) }; -#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) -inline const TADDR g_cdacTailCallJitHelper = (TADDR)(void*)JIT_TailCall; -#endif // TARGET_X86 && !UNIX_X86_ABI - /*********************************************************************/ /*********************************************************************/ 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 16678ce332e712..9593f5ad5de97a 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 @@ -46,26 +46,6 @@ public interface ICodeHeapInfo { } -public enum StubKind : uint -{ - CodeBlockUnknown = 0, - CodeBlockJumpStub = 1, - CodeBlockDynamicHelper = 3, - CodeBlockPrecode = 4, - CodeBlockVSDDispatchStub = 5, - CodeBlockVSDResolveStub = 6, - CodeBlockVSDLookupStub = 7, - CodeBlockVSDVTableStub = 8, - CodeBlockCallCounting = 9, - CodeBlockStubLinkStub = 10, - CodeBlockMethodCallThunk = 11, - CodeBlockNoCode = 12, - CodeBlockManaged = 13, - PreStub = 14, - InteropDispatchStub = 15, - TailCallStub = 16, -} - public sealed class LoaderCodeHeapInfo : ICodeHeapInfo { public TargetPointer HeapAddress { get; } @@ -121,7 +101,10 @@ public interface IExecutionManager : IContract List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException(); JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException(); IEnumerable GetCodeHeapInfos() => throw new NotImplementedException(); - StubKind GetStubKind(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); + // If the code refers to a dynamically generated runtime stub, return a non-null name + // describing what kind of stub it is. The exact kinds of stubs and their functionality + // might shift across different runtime versions. + string? GetStubSymbol(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); } public readonly struct ExecutionManager : IExecutionManager diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs index fce6ee7d12a874..aced1d2316dd08 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IPrecodeStubs.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -10,7 +9,6 @@ public interface IPrecodeStubs : IContract { static string IContract.Name { get; } = nameof(PrecodeStubs); TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint) => throw new NotImplementedException(); - IEnumerable GetCandidateEntryPoints(TargetCodePointer address) => throw new NotImplementedException(); } public readonly struct PrecodeStubs : IPrecodeStubs 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 56985d783e3173..07dd7b7972a4c6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -82,11 +82,7 @@ public static class Globals public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); public const string EEJitManagerAddress = nameof(EEJitManagerAddress); public const string StubCodeBlockLast = nameof(StubCodeBlockLast); - public const string ThePreStub = nameof(ThePreStub); - public const string VarargPInvokeStub = nameof(VarargPInvokeStub); - public const string VarargPInvokeStub_RetBuffArg = nameof(VarargPInvokeStub_RetBuffArg); - public const string GenericPInvokeCalliHelper = nameof(GenericPInvokeCalliHelper); - public const string TailCallJitHelper = nameof(TailCallJitHelper); + public const string DefaultADID = nameof(DefaultADID); public const string StaticsPointerMask = nameof(StaticsPointerMask); public const string PtrArrayOffsetToDataArray = nameof(PtrArrayOffsetToDataArray); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs index d0f5abf60856ad..aa0b8ac7746e5c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs @@ -131,17 +131,17 @@ public override TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCode return realCodeHeader.DebugInfo; } - public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) + public override string? GetStubSymbol(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) { if (rangeSection.IsRangeList) { Data.CodeRangeMapRangeList rangeList = Target.ProcessedData.GetOrAdd(rangeSection.Data!.RangeList); - return GetStubKind((StubCodeBlockKind)rangeList.RangeListType); + return GetStubSymbolForCodeBlockKind((StubCodeBlockKind)rangeList.RangeListType); } TargetPointer startAddr = FindMethodCode(rangeSection, jittedCodeAddress); // validate that the code address is within the method's code range if (startAddr == TargetPointer.Null) - return StubKind.CodeBlockNoCode; - return GetCodeHeaderStubKind(rangeSection, startAddr); + return null; + return GetCodeHeaderStubSymbol(rangeSection, startAddr); } public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion) @@ -216,43 +216,33 @@ private bool GetRealCodeHeader(RangeSection rangeSection, TargetPointer codeStar return true; } - private static StubKind GetStubKind(StubCodeBlockKind stubCodeBlockKind) + private static string? GetStubSymbolForCodeBlockKind(StubCodeBlockKind stubCodeBlockKind) { - switch (stubCodeBlockKind) + return stubCodeBlockKind switch { - case StubCodeBlockKind.JumpStub: - return StubKind.CodeBlockJumpStub; - case StubCodeBlockKind.DynamicHelper: - return StubKind.CodeBlockDynamicHelper; - case StubCodeBlockKind.StubPrecode: - case StubCodeBlockKind.FixupPrecode: - return StubKind.CodeBlockPrecode; - case StubCodeBlockKind.VSDDispatchStub: - return StubKind.CodeBlockVSDDispatchStub; - case StubCodeBlockKind.VSDResolveStub: - return StubKind.CodeBlockVSDResolveStub; - case StubCodeBlockKind.VSDLookupStub: - return StubKind.CodeBlockVSDLookupStub; - case StubCodeBlockKind.VSDVTableStub: - return StubKind.CodeBlockVSDVTableStub; - case StubCodeBlockKind.CallCountingStub: - return StubKind.CodeBlockCallCounting; - default: - return StubKind.CodeBlockUnknown; - } + StubCodeBlockKind.JumpStub => "JumpStub", + StubCodeBlockKind.DynamicHelper => "DynamicHelper", + StubCodeBlockKind.StubPrecode or StubCodeBlockKind.FixupPrecode => "MethodDescPrestub", + StubCodeBlockKind.VSDDispatchStub => "VSD_DispatchStub", + StubCodeBlockKind.VSDResolveStub => "VSD_ResolveStub", + StubCodeBlockKind.VSDLookupStub => "VSD_LookupStub", + StubCodeBlockKind.VSDVTableStub => "VSD_VTableStub", + StubCodeBlockKind.CallCountingStub => "CallCountingStub", + _ => null, + }; } - private StubKind GetCodeHeaderStubKind(RangeSection rangeSection, TargetPointer codeStart) + private string? GetCodeHeaderStubSymbol(RangeSection rangeSection, TargetPointer codeStart) { if (GetCodeHeaderAddress(rangeSection, codeStart, out TargetPointer codeHeaderAddress)) { if (RangeSection.IsStubCodeBlock(Target, codeHeaderAddress)) { - return GetStubKind((StubCodeBlockKind)codeHeaderAddress.Value); + return GetStubSymbolForCodeBlockKind((StubCodeBlockKind)codeHeaderAddress.Value); } - return StubKind.CodeBlockManaged; + return null; // managed code, not a stub } - return StubKind.CodeBlockUnknown; + return null; } public override void GetExceptionClauses(RangeSection rangeSection, CodeBlockHandle codeInfoHandle, out TargetPointer startAddr, out TargetPointer endAddr) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs index af13dd60d354c4..004ea0092ab474 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs @@ -142,11 +142,11 @@ public override TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCode return imageBase + debugInfoOffset; } - public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) + public override string? GetStubSymbol(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) { if (rangeSection.Data == null) - return StubKind.CodeBlockUnknown; - return IsStubCodeBlockThunk(rangeSection.Data, GetReadyToRunInfo(rangeSection), jittedCodeAddress) ? StubKind.CodeBlockMethodCallThunk : StubKind.CodeBlockUnknown; + return null; + return IsStubCodeBlockThunk(rangeSection.Data, GetReadyToRunInfo(rangeSection), jittedCodeAddress) ? "MethodCallThunk" : null; } public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion) 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 f95e67535329bc..0c66df69048eda 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 @@ -21,11 +21,6 @@ internal sealed partial class ExecutionManagerCore : IExecutionManager private readonly ExecutionManagerHelpers.RangeSectionMap _rangeSectionMapLookup; private readonly EEJitManager _eeJitManager; private readonly ReadyToRunJitManager _r2rJitManager; - private readonly TargetPointer _thePreStub; - private readonly TargetPointer _varargPInvokeStub; - private readonly TargetPointer _varargPInvokeStub_RetBuffArg; - private readonly TargetPointer _genericPInvokeCalliHelper; - private readonly TargetPointer _tailCallJitHelper; public ExecutionManagerCore(Target target, Data.RangeSectionMap topRangeSectionMap) { @@ -35,19 +30,6 @@ public ExecutionManagerCore(Target target, Data.RangeSectionMap topRangeSectionM INibbleMap nibbleMap = T.Create(_target); _eeJitManager = new EEJitManager(_target, nibbleMap); _r2rJitManager = new ReadyToRunJitManager(_target); - _thePreStub = ReadOptionalGlobalPointer(_target, Constants.Globals.ThePreStub); - _varargPInvokeStub = ReadOptionalGlobalPointer(_target, Constants.Globals.VarargPInvokeStub); - _varargPInvokeStub_RetBuffArg = ReadOptionalGlobalPointer(_target, Constants.Globals.VarargPInvokeStub_RetBuffArg); - _genericPInvokeCalliHelper = ReadOptionalGlobalPointer(_target, Constants.Globals.GenericPInvokeCalliHelper); - _tailCallJitHelper = ReadOptionalGlobalPointer(_target, Constants.Globals.TailCallJitHelper); - } - - private static TargetPointer ReadOptionalGlobalPointer(Target target, string name) - { - if (!target.TryReadGlobalPointer(name, out TargetPointer? ptr)) - return TargetPointer.Null; - - return target.ReadPointer(ptr.Value); } public void Flush() @@ -117,7 +99,7 @@ public abstract void GetMethodRegionInfo( public abstract TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out bool hasFlagByte); public abstract void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion); public abstract void GetExceptionClauses(RangeSection rangeSection, CodeBlockHandle codeInfoHandle, out TargetPointer startAddr, out TargetPointer endAddr); - public abstract StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress); + public abstract string? GetStubSymbol(RangeSection rangeSection, TargetCodePointer jittedCodeAddress); } private sealed class RangeSection @@ -559,46 +541,13 @@ List IExecutionManager.GetExceptionClauses(CodeBlockHandle return exceptionClauses; } - private bool TryGetStubKindFromConstants(TargetPointer jittedCodeAddress, out StubKind stubKind) - { - stubKind = StubKind.CodeBlockUnknown; - if (jittedCodeAddress == TargetPointer.Null) - { - return false; - } - if (jittedCodeAddress == _thePreStub) - { - stubKind = StubKind.PreStub; - return true; - } - else if (jittedCodeAddress == _varargPInvokeStub - || jittedCodeAddress == _varargPInvokeStub_RetBuffArg - || jittedCodeAddress == _genericPInvokeCalliHelper) - { - stubKind = StubKind.InteropDispatchStub; - return true; - } - else if (jittedCodeAddress == _tailCallJitHelper) - { - stubKind = StubKind.TailCallStub; - return true; - } - return false; - } - - public StubKind GetStubKind(TargetCodePointer jittedCodeAddress) + public string? GetStubSymbol(TargetCodePointer jittedCodeAddress) { - TargetPointer jittedPtr = CodePointerUtils.AddressFromCodePointer(jittedCodeAddress, _target); - if (TryGetStubKindFromConstants(jittedPtr, out StubKind stubKind)) - { - return stubKind; - } - RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, jittedCodeAddress); if (range.Data == null) - return StubKind.CodeBlockUnknown; + return null; JitManager jitManager = GetJitManager(range.Data); - return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); + return jitManager.GetStubSymbol(range, jittedCodeAddress); } } 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 c23094f8c88c93..b16cb06f8d3d1d 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 @@ -34,6 +34,6 @@ internal ExecutionManager_1(Target target) public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); public IEnumerable GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos(); - public StubKind GetStubKind(TargetCodePointer entryPoint) => _executionManagerCore.GetStubKind(entryPoint); + public string? GetStubSymbol(TargetCodePointer entryPoint) => _executionManagerCore.GetStubSymbol(entryPoint); public void Flush() => _executionManagerCore.Flush(); } 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 ee17e586860b31..60501591ecb902 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 @@ -34,6 +34,6 @@ internal ExecutionManager_2(Target target) public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); public IEnumerable GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos(); - public StubKind GetStubKind(TargetCodePointer entryPoint) => _executionManagerCore.GetStubKind(entryPoint); + public string? GetStubSymbol(TargetCodePointer entryPoint) => _executionManagerCore.GetStubSymbol(entryPoint); public void Flush() => _executionManagerCore.Flush(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs index 03e723ee85350c..c8b76481107e5c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/PrecodeStubs_Common.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics; -using System.Collections.Generic; using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -147,24 +146,4 @@ TargetPointer IPrecodeStubs.GetMethodDescFromStubAddress(TargetCodePointer entry return precode.GetMethodDesc(_target, MachineDescriptor); } - - IEnumerable IPrecodeStubs.GetCandidateEntryPoints(TargetCodePointer address) - { - uint pointerSize = (uint)_target.PointerSize; - TargetPointer instrPointer = CodePointerReadableInstrPointer(address); - ulong aligned = instrPointer.Value & ~(ulong)(pointerSize - 1); - - if (MachineDescriptor.StubPrecodeSize is not byte maxPrecodeSize) - throw new InvalidOperationException("StubPrecodeSize is required to enumerate candidate entry points"); - uint count = maxPrecodeSize / pointerSize; - - for (uint i = 0; i < count; i++) - { - ulong offset = i * pointerSize; - if (aligned < offset) - yield break; - TargetPointer candidateAddr = new TargetPointer(aligned - offset); - yield return CodePointerUtils.CodePointerFromAddress(candidateAddr, _target); - } - } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index 1f0e7c9652f455..dacfcec209667d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -120,58 +120,18 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( IExecutionManager eman = _target.Contracts.ExecutionManager; string? resultName = null; - // First, try to find it as managed code (equivalent of EECodeInfo path in legacy DAC) - CodeBlockHandle? cbh = eman.GetCodeBlockHandle(codeAddr); - if (cbh is CodeBlockHandle codeBlock) - { - TargetPointer methodDescPtr = eman.GetMethodDesc(codeBlock); - if (displacement is not null) - { - TargetNUInt relOffset = eman.GetRelativeOffset(codeBlock); - *displacement = relOffset.Value; - } + // Try stub classification + resultName = eman.GetStubSymbol(codeAddr); - resultName = GetNameFromMethodDesc(methodDescPtr, address); - } - else + // try aux symbols + if (resultName is null && _target.Contracts.AuxiliarySymbols.TryGetAuxiliarySymbolName(address.ToTargetPointer(_target), out string? auxSymbolName)) { - // Try stub classification - StubKind stubKind = eman.GetStubKind(codeAddr); - - if (stubKind == StubKind.CodeBlockPrecode) - { - // For precode stubs, resolve the MethodDesc from the precode entry point - IPrecodeStubs precodeStubs = _target.Contracts.PrecodeStubs; - foreach (TargetCodePointer potentialEntryPoint in precodeStubs.GetCandidateEntryPoints(codeAddr)) - { - TargetPointer methodDescPtr = eman.NonVirtualEntry2MethodDesc(potentialEntryPoint); - if (methodDescPtr != TargetPointer.Null) - { - if (displacement is not null) - *displacement = codeAddr.Value - potentialEntryPoint.Value; - - resultName = GetNameFromMethodDesc(methodDescPtr, address); - break; - } - } - resultName ??= FormatCLRStubName(GetStubName(stubKind)!, address); - } - else - { - // Known stub type - format as CLRStub[]@ - string? stubName = GetStubName(stubKind); + resultName = auxSymbolName; + } - if (stubName is not null) - resultName = FormatCLRStubName(stubName, address); - else if (_target.Contracts.AuxiliarySymbols.TryGetAuxiliarySymbolName(address.ToTargetPointer(_target), out string? auxSymbolName)) - { - resultName = auxSymbolName; - } - } - if (resultName is null) - { - throw new InvalidCastException(); - } + if (resultName is null) + { + throw new InvalidCastException(); } OutputBufferHelpers.CopyStringToBuffer(nameBuf, bufLen, nameLen, resultName); @@ -220,69 +180,6 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( return hr; } - private static string? GetStubName(Contracts.StubKind stubKind) - { - return stubKind switch - { - Contracts.StubKind.CodeBlockJumpStub => "JumpStub", - Contracts.StubKind.CodeBlockPrecode => "MethodDescPrestub", - Contracts.StubKind.CodeBlockVSDDispatchStub => "VSD_DispatchStub", - Contracts.StubKind.CodeBlockVSDResolveStub => "VSD_ResolveStub", - Contracts.StubKind.CodeBlockVSDLookupStub => "VSD_LookupStub", - Contracts.StubKind.CodeBlockVSDVTableStub => "VSD_VTableStub", - Contracts.StubKind.CodeBlockCallCounting => "CallCountingStub", - Contracts.StubKind.CodeBlockStubLinkStub => "StubLinkStub", - Contracts.StubKind.CodeBlockMethodCallThunk => "MethodCallThunk", - Contracts.StubKind.PreStub => "ThePreStub", - Contracts.StubKind.InteropDispatchStub => "InteropDispatchStub", - Contracts.StubKind.TailCallStub => "TailCallStub", - _ => null, - }; - } - - private string GetNameFromMethodDesc(TargetPointer methodDescPtr, ClrDataAddress address) - { - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - MethodDescHandle mdHandle = rts.GetMethodDescHandle(methodDescPtr); - - // Dynamic methods with no stored signature get formatted as CLRStub@ - if (rts.IsNoMetadataMethod(mdHandle, out _) - && rts.IsStoredSigMethodDesc(mdHandle, out ReadOnlySpan signature) - && signature.IsEmpty) - { - return FormatCLRStubName(null, address); - } - - // Get the full method name - StringBuilder sb = new(); - TypeNameBuilder.AppendMethodInternal( - _target, - sb, - mdHandle, - TypeNameFormat.FormatSignature | - TypeNameFormat.FormatNamespace | - TypeNameFormat.FormatFullInst); - - return sb.ToString(); - } - - private string FormatCLRStubName(string? stubName, ClrDataAddress address) - { - // Format: "CLRStub[]@" or "CLRStub@" - StringBuilder sb = new(); - sb.Append("CLRStub"); - if (!string.IsNullOrEmpty(stubName)) - { - sb.Append('['); - sb.Append(stubName); - sb.Append(']'); - } - sb.Append('@'); - sb.Append(address.Value.ToString($"X{_target.PointerSize * 2}")); - - return sb.ToString(); - } - int IXCLRDataProcess.StartEnumAppDomains(ulong* handle) => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index 3effcbbe31190f..21f28b72a8c0b7 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -658,21 +658,16 @@ public void GetCodeHeapList_LinkedList_TwoNodes(string version, MockTarget.Archi [Theory] [MemberData(nameof(StdArchAllVersions))] - public void TryGetStubKind_GlobalConstants(string version, MockTarget.Architecture arch) + public void GetStubSymbol_NoRangeSection(string version, MockTarget.Architecture arch) { IExecutionManager em = CreateExecutionManagerContract(version, arch); - Assert.Equal(StubKind.PreStub, em.GetStubKind(new TargetCodePointer(0x00aa_1000))); - Assert.Equal(StubKind.InteropDispatchStub, em.GetStubKind(new TargetCodePointer(0x00aa_2000))); - Assert.Equal(StubKind.InteropDispatchStub, em.GetStubKind(new TargetCodePointer(0x00aa_3000))); - Assert.Equal(StubKind.InteropDispatchStub, em.GetStubKind(new TargetCodePointer(0x00aa_4000))); - Assert.Equal(StubKind.TailCallStub, em.GetStubKind(new TargetCodePointer(0x00aa_5000))); - Assert.Equal(StubKind.CodeBlockUnknown, em.GetStubKind(new TargetCodePointer(0x00aa_9000))); + Assert.Null(em.GetStubSymbol(new TargetCodePointer(0x00aa_9000))); } [Theory] [MemberData(nameof(StdArchAllVersions))] - public void TryGetStubKind_RangeListStubs(string version, MockTarget.Architecture arch) + public void GetStubSymbol_RangeListStubs(string version, MockTarget.Architecture arch) { const ulong codeRangeStart = 0x0a0a_0000u; const uint codeRangeSize = 0x4000u; @@ -689,13 +684,13 @@ public void TryGetStubKind_RangeListStubs(string version, MockTarget.Architectur _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - StubKind kind = em.GetStubKind(new TargetCodePointer(codeRangeStart + 0x100)); - Assert.Equal(StubKind.CodeBlockPrecode, kind); + string? symbol = em.GetStubSymbol(new TargetCodePointer(codeRangeStart + 0x100)); + Assert.Equal("MethodDescPrestub", symbol); } [Theory] [MemberData(nameof(StdArchAllVersions))] - public void TryGetStubKind_CodeHeapStubs(string version, MockTarget.Architecture arch) + public void GetStubSymbol_CodeHeapStubs(string version, MockTarget.Architecture arch) { const ulong codeRangeStart = 0x0a0a_0000u; const uint codeRangeSize = 0xc000u; @@ -720,13 +715,13 @@ public void TryGetStubKind_CodeHeapStubs(string version, MockTarget.Architecture _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - StubKind kind = em.GetStubKind(new TargetCodePointer(stubCodeAddress)); - Assert.Equal(StubKind.CodeBlockJumpStub, kind); + string? symbol = em.GetStubSymbol(new TargetCodePointer(stubCodeAddress)); + Assert.Equal("JumpStub", symbol); } [Theory] [MemberData(nameof(StdArchAllVersions))] - public void TryGetStubKind_ManagedCode(string version, MockTarget.Architecture arch) + public void GetStubSymbol_ManagedCode(string version, MockTarget.Architecture arch) { const ulong codeRangeStart = 0x0a0a_0000u; const uint codeRangeSize = 0xc000u; @@ -751,8 +746,8 @@ public void TryGetStubKind_ManagedCode(string version, MockTarget.Architecture a _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - StubKind kind = em.GetStubKind(new TargetCodePointer(methodStart)); - Assert.Equal(StubKind.CodeBlockManaged, kind); + string? symbol = em.GetStubSymbol(new TargetCodePointer(methodStart)); + Assert.Null(symbol); } public static IEnumerable StdArchAllVersions() diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs index 8ae48812d16e1f..a15509a9c7fe01 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs @@ -596,11 +596,6 @@ internal MockExecutionManagerBuilder(string version, MockMemorySpace.Builder bui }; globals.Add((nameof(Constants.Globals.HashMapSlotsPerBucket), MockHashMapBucket.SlotsPerBucket)); globals.Add((nameof(Constants.Globals.HashMapValueMask), Builder.TargetTestHelpers.MaxSignedTargetAddress)); - globals.Add((nameof(Constants.Globals.ThePreStub), AddPointerGlobal(0x00aa_1000, "ThePreStub"))); - globals.Add((nameof(Constants.Globals.GenericPInvokeCalliHelper), AddPointerGlobal(0x00aa_2000, "GenericPInvokeCalliHelper"))); - globals.Add((nameof(Constants.Globals.VarargPInvokeStub), AddPointerGlobal(0x00aa_3000, "VarargPInvokeStub"))); - globals.Add((nameof(Constants.Globals.VarargPInvokeStub_RetBuffArg), AddPointerGlobal(0x00aa_4000, "VarargPInvokeStub_RetBuffArg"))); - globals.Add((nameof(Constants.Globals.TailCallJitHelper), AddPointerGlobal(0x00aa_5000, "TailCallJitHelper"))); Globals = [.. globals]; } From 06b4f8387e18e73fdea69d6ead0d4b30ab34a7ef Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Wed, 22 Apr 2026 16:21:36 -0700 Subject: [PATCH 6/8] Update PrecodeMachineDescriptor.cs --- .../Data/PrecodeMachineDescriptor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs index 4413f639c3f02c..840059e1511c95 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PrecodeMachineDescriptor.cs @@ -43,7 +43,7 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) if (type.Fields.ContainsKey(nameof(StubPrecodeSize))) { - StubPrecodeSize = target.ReadField(address, type, nameof(StubPrecodeSize)); + StubPrecodeSize = target.ReadField(address, type, nameof(FixupStubPrecodeSize)); StubBytes = new byte[StubPrecodeSize.Value]; target.ReadBuffer(address + (ulong)type.Fields[nameof(StubBytes)].Offset, StubBytes); StubIgnoredBytes = new byte[StubPrecodeSize.Value]; @@ -52,8 +52,8 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) else { StubPrecodeSize = null; - StubBytes = null; - StubIgnoredBytes = null; + FixupBytes = null; + FixupIgnoredBytes = null; } PInvokeImportPrecodeType = MaybeGetPrecodeType(target, address, nameof(PInvokeImportPrecodeType)); From fa282226fc18133c199e2efc64a6407a4ebfb756 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 23 Apr 2026 13:00:27 -0700 Subject: [PATCH 7/8] code review --- docs/design/datacontracts/ExecutionManager.md | 16 ++-- src/coreclr/debug/daccess/daccess.cpp | 15 ++-- src/coreclr/vm/stubmgr.h | 2 +- .../Contracts/IExecutionManager.cs | 24 +++++- .../ExecutionManagerCore.EEJitManager.cs | 36 ++++---- ...ecutionManagerCore.ReadyToRunJitManager.cs | 6 +- .../ExecutionManager/ExecutionManagerCore.cs | 8 +- .../ExecutionManager/ExecutionManager_1.cs | 2 +- .../ExecutionManager/ExecutionManager_2.cs | 2 +- .../SOSDacImpl.IXCLRDataProcess.cs | 16 +++- .../ExecutionManager/ExecutionManagerTests.cs | 83 ++++++++++++++++--- .../MockDescriptors.ExecutionManager.cs | 40 +++++++++ 12 files changed, 190 insertions(+), 60 deletions(-) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index f0429580fd2a5c..3b6a51cb4c2dae 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -52,9 +52,9 @@ struct CodeBlockHandle // Get the exception clause info for the code block List GetExceptionClauses(CodeBlockHandle codeInfoHandle); - // If the code refers to a dynamically generated runtime stub, return a non-null name - // describing what kind of stub it is. Returns null for managed code or unrecognized addresses. - string? GetStubSymbol(TargetCodePointer jittedCodeAddress); + // Classify a code address as a known stub kind (precode, jump stub, VSD stub, etc.) + // or as managed code. Returns CodeBlockUnknown if the address is not recognized. + StubKind GetStubKind(TargetCodePointer jittedCodeAddress); // Extension Methods (implemented in terms of other APIs) // Returns true if the code block is a funclet (exception handler, filter, or finally) @@ -507,9 +507,9 @@ 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. -### Stub Symbol Classification +### Stub Kind Classification -`GetStubSymbol` classifies a code address as a known stub type. It returns a descriptive string for stub addresses, or `null` for managed code or unrecognized addresses. The exact kinds of stubs and their names might shift across different runtime versions. +`GetStubKind` classifies a code address as a known stub type or managed code. It returns `UnknownStub` if the address is not recognized. The method looks up the address in the `RangeSectionMap`. If a `RangeSection` is found, the JIT manager for that section classifies the code: @@ -517,16 +517,16 @@ The method looks up the address in the `RangeSectionMap`. If a `RangeSection` is - **ReadyToRunJitManager**: Checks whether the address falls within a delay-load method call thunk region. ```csharp -string? GetStubSymbol(TargetCodePointer jittedCodeAddress) +StubKind GetStubKind(TargetCodePointer jittedCodeAddress) { TargetPointer address = CodePointerUtils.AddressFromCodePointer(jittedCodeAddress); // Look up in range section map RangeSection range = FindRangeSection(jittedCodeAddress); - if (range == null) return null; + if (range == null) return StubKind.UnknownStub; JitManager jitManager = GetJitManager(range); - return jitManager.GetStubSymbol(range, jittedCodeAddress); + return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); } ``` diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 32387101898ddd..1a2dc72a430021 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -5341,11 +5341,6 @@ ClrDataAccess::RawGetMethodName( return status; } - if (displacement) - { - *displacement = 0; - } - PTR_StubManager pStubManager; pStubManager = StubManager::FindStubManager(TO_TADDR(address)); @@ -5353,10 +5348,14 @@ ClrDataAccess::RawGetMethodName( { LPCWSTR wszStubManagerName = pStubManager->GetStubManagerName(TO_TADDR(address)); _ASSERTE(wszStubManagerName != NULL); - if (wcscmp(wszStubManagerName, W("ThePreStub")) != 0 && wcscmp(wszStubManagerName, W("InteropDispatchStub")) != 0 && wcscmp(wszStubManagerName, W("TailCallStub")) != 0) + if (u16_strcmp(wszStubManagerName, W("ThePreStub")) != 0 && u16_strcmp(wszStubManagerName, W("InteropDispatchStub")) != 0 && u16_strcmp(wszStubManagerName, W("TailCallStub")) != 0) { // Skip the stubs that are just assembly helpers. wcscpy_s(symbolBuf, bufLen, wszStubManagerName); + if (displacement) + { + *displacement = 0; + } return S_OK; } } @@ -5370,6 +5369,10 @@ ClrDataAccess::RawGetMethodName( if (FAILED(hr)) return S_FALSE; + if (displacement) + { + *displacement = 0; + } return S_OK; } diff --git a/src/coreclr/vm/stubmgr.h b/src/coreclr/vm/stubmgr.h index bbce9d33591dd2..da04e1f11dbe63 100644 --- a/src/coreclr/vm/stubmgr.h +++ b/src/coreclr/vm/stubmgr.h @@ -432,7 +432,7 @@ class PrecodeStubManager : public StubManager protected: virtual LPCWSTR GetStubManagerName(PCODE addr) - { LIMITED_METHOD_CONTRACT; return W("MethodDescPrestub"); } + { LIMITED_METHOD_CONTRACT; return W("Prestub"); } #endif }; #endif // !FEATURE_PORTABLE_ENTRYPOINTS 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 9593f5ad5de97a..6f19e079ea7472 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 @@ -42,6 +42,23 @@ public struct JitManagerInfo public TargetPointer HeapListAddress; } +public enum StubKind : uint +{ + UnknownStub = 0, + JumpStub = 1, + DynamicHelper = 3, + Prestub = 4, + VSD_DispatchStub = 5, + VSD_ResolveStub = 6, + VSD_LookupStub = 7, + VSD_VTableStub = 8, + CallCountingStub = 9, + StubLinkStub = 10, + MethodCallThunk = 11, + NoCodeStub = 12, + Managed = 13, +} + public interface ICodeHeapInfo { } @@ -101,10 +118,9 @@ public interface IExecutionManager : IContract List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException(); JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException(); IEnumerable GetCodeHeapInfos() => throw new NotImplementedException(); - // If the code refers to a dynamically generated runtime stub, return a non-null name - // describing what kind of stub it is. The exact kinds of stubs and their functionality - // might shift across different runtime versions. - string? GetStubSymbol(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); + // Classify a code address as a known stub kind (precode, jump stub, VSD stub, etc.) + // or as managed code. Returns UnknownStub if the address is not recognized. + StubKind GetStubKind(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); } public readonly struct ExecutionManager : IExecutionManager diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs index aa0b8ac7746e5c..c71759812c2267 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs @@ -131,17 +131,17 @@ public override TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCode return realCodeHeader.DebugInfo; } - public override string? GetStubSymbol(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) + public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) { if (rangeSection.IsRangeList) { Data.CodeRangeMapRangeList rangeList = Target.ProcessedData.GetOrAdd(rangeSection.Data!.RangeList); - return GetStubSymbolForCodeBlockKind((StubCodeBlockKind)rangeList.RangeListType); + return GetStubKind((StubCodeBlockKind)rangeList.RangeListType); } TargetPointer startAddr = FindMethodCode(rangeSection, jittedCodeAddress); // validate that the code address is within the method's code range if (startAddr == TargetPointer.Null) - return null; - return GetCodeHeaderStubSymbol(rangeSection, startAddr); + return StubKind.NoCodeStub; + return GetCodeHeaderStubKind(rangeSection, startAddr); } public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion) @@ -216,33 +216,33 @@ private bool GetRealCodeHeader(RangeSection rangeSection, TargetPointer codeStar return true; } - private static string? GetStubSymbolForCodeBlockKind(StubCodeBlockKind stubCodeBlockKind) + private static StubKind GetStubKind(StubCodeBlockKind stubCodeBlockKind) { return stubCodeBlockKind switch { - StubCodeBlockKind.JumpStub => "JumpStub", - StubCodeBlockKind.DynamicHelper => "DynamicHelper", - StubCodeBlockKind.StubPrecode or StubCodeBlockKind.FixupPrecode => "MethodDescPrestub", - StubCodeBlockKind.VSDDispatchStub => "VSD_DispatchStub", - StubCodeBlockKind.VSDResolveStub => "VSD_ResolveStub", - StubCodeBlockKind.VSDLookupStub => "VSD_LookupStub", - StubCodeBlockKind.VSDVTableStub => "VSD_VTableStub", - StubCodeBlockKind.CallCountingStub => "CallCountingStub", - _ => null, + StubCodeBlockKind.JumpStub => StubKind.JumpStub, + StubCodeBlockKind.DynamicHelper => StubKind.DynamicHelper, + StubCodeBlockKind.StubPrecode or StubCodeBlockKind.FixupPrecode => StubKind.Prestub, + StubCodeBlockKind.VSDDispatchStub => StubKind.VSD_DispatchStub, + StubCodeBlockKind.VSDResolveStub => StubKind.VSD_ResolveStub, + StubCodeBlockKind.VSDLookupStub => StubKind.VSD_LookupStub, + StubCodeBlockKind.VSDVTableStub => StubKind.VSD_VTableStub, + StubCodeBlockKind.CallCountingStub => StubKind.CallCountingStub, + _ => StubKind.UnknownStub, }; } - private string? GetCodeHeaderStubSymbol(RangeSection rangeSection, TargetPointer codeStart) + private StubKind GetCodeHeaderStubKind(RangeSection rangeSection, TargetPointer codeStart) { if (GetCodeHeaderAddress(rangeSection, codeStart, out TargetPointer codeHeaderAddress)) { if (RangeSection.IsStubCodeBlock(Target, codeHeaderAddress)) { - return GetStubSymbolForCodeBlockKind((StubCodeBlockKind)codeHeaderAddress.Value); + return GetStubKind((StubCodeBlockKind)codeHeaderAddress.Value); } - return null; // managed code, not a stub + return StubKind.Managed; } - return null; + return StubKind.UnknownStub; } public override void GetExceptionClauses(RangeSection rangeSection, CodeBlockHandle codeInfoHandle, out TargetPointer startAddr, out TargetPointer endAddr) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs index 004ea0092ab474..0a21b135b6aa13 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs @@ -142,11 +142,11 @@ public override TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCode return imageBase + debugInfoOffset; } - public override string? GetStubSymbol(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) + public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) { if (rangeSection.Data == null) - return null; - return IsStubCodeBlockThunk(rangeSection.Data, GetReadyToRunInfo(rangeSection), jittedCodeAddress) ? "MethodCallThunk" : null; + return StubKind.UnknownStub; + return IsStubCodeBlockThunk(rangeSection.Data, GetReadyToRunInfo(rangeSection), jittedCodeAddress) ? StubKind.MethodCallThunk : StubKind.UnknownStub; } public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion) 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 0c66df69048eda..4d494ad819d9e5 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 @@ -99,7 +99,7 @@ public abstract void GetMethodRegionInfo( public abstract TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out bool hasFlagByte); public abstract void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion); public abstract void GetExceptionClauses(RangeSection rangeSection, CodeBlockHandle codeInfoHandle, out TargetPointer startAddr, out TargetPointer endAddr); - public abstract string? GetStubSymbol(RangeSection rangeSection, TargetCodePointer jittedCodeAddress); + public abstract StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress); } private sealed class RangeSection @@ -541,13 +541,13 @@ List IExecutionManager.GetExceptionClauses(CodeBlockHandle return exceptionClauses; } - public string? GetStubSymbol(TargetCodePointer jittedCodeAddress) + public StubKind GetStubKind(TargetCodePointer jittedCodeAddress) { RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, jittedCodeAddress); if (range.Data == null) - return null; + return StubKind.UnknownStub; JitManager jitManager = GetJitManager(range.Data); - return jitManager.GetStubSymbol(range, jittedCodeAddress); + return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); } } 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 b16cb06f8d3d1d..c23094f8c88c93 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 @@ -34,6 +34,6 @@ internal ExecutionManager_1(Target target) public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); public IEnumerable GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos(); - public string? GetStubSymbol(TargetCodePointer entryPoint) => _executionManagerCore.GetStubSymbol(entryPoint); + public StubKind GetStubKind(TargetCodePointer entryPoint) => _executionManagerCore.GetStubKind(entryPoint); public void Flush() => _executionManagerCore.Flush(); } 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 60501591ecb902..ee17e586860b31 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 @@ -34,6 +34,6 @@ internal ExecutionManager_2(Target target) public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); public IEnumerable GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos(); - public string? GetStubSymbol(TargetCodePointer entryPoint) => _executionManagerCore.GetStubSymbol(entryPoint); + public StubKind GetStubKind(TargetCodePointer entryPoint) => _executionManagerCore.GetStubKind(entryPoint); public void Flush() => _executionManagerCore.Flush(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index dacfcec209667d..f9a94329bc6a6e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -103,8 +103,6 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( char* nameBuf, ClrDataAddress* displacement) { - if (displacement is not null) - *displacement = default; int hr = HResults.S_OK; try { @@ -121,7 +119,8 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( string? resultName = null; // Try stub classification - resultName = eman.GetStubSymbol(codeAddr); + StubKind stubKind = eman.GetStubKind(codeAddr); + resultName = GetStubName(stubKind); // try aux symbols if (resultName is null && _target.Contracts.AuxiliarySymbols.TryGetAuxiliarySymbolName(address.ToTargetPointer(_target), out string? auxSymbolName)) @@ -133,6 +132,10 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( { throw new InvalidCastException(); } + else if (displacement is not null) + { + *displacement = 0; + } OutputBufferHelpers.CopyStringToBuffer(nameBuf, bufLen, nameLen, resultName); @@ -180,6 +183,13 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( return hr; } + private static string? GetStubName(Contracts.StubKind stubKind) + { + if (stubKind == Contracts.StubKind.UnknownStub || stubKind == Contracts.StubKind.Managed || stubKind == Contracts.StubKind.NoCodeStub) + return null; + return stubKind.ToString(); + } + int IXCLRDataProcess.StartEnumAppDomains(ulong* handle) => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index 21f28b72a8c0b7..beb31972846e79 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -30,6 +30,7 @@ public class ExecutionManagerTests [DataType.EEJitManager] = TargetTestHelpers.CreateTypeInfo(emBuilder.EEJitManagerLayout), [DataType.Module] = TargetTestHelpers.CreateTypeInfo(emBuilder.ModuleLayout), [DataType.CodeRangeMapRangeList] = TargetTestHelpers.CreateTypeInfo(emBuilder.CodeRangeMapRangeListLayout), + [DataType.ImageDataDirectory] = TargetTestHelpers.CreateTypeInfo(emBuilder.ImageDataDirectoryLayout), [DataType.HashMap] = TargetTestHelpers.CreateTypeInfo(MockHashMap.CreateLayout(helpers.Arch)), [DataType.Bucket] = TargetTestHelpers.CreateTypeInfo(MockHashMapBucket.CreateLayout(helpers.Arch)), }; @@ -658,16 +659,16 @@ public void GetCodeHeapList_LinkedList_TwoNodes(string version, MockTarget.Archi [Theory] [MemberData(nameof(StdArchAllVersions))] - public void GetStubSymbol_NoRangeSection(string version, MockTarget.Architecture arch) + public void GetStubKind_NoRangeSection(string version, MockTarget.Architecture arch) { IExecutionManager em = CreateExecutionManagerContract(version, arch); - Assert.Null(em.GetStubSymbol(new TargetCodePointer(0x00aa_9000))); + Assert.Equal(StubKind.UnknownStub, em.GetStubKind(new TargetCodePointer(0x00aa_9000))); } [Theory] [MemberData(nameof(StdArchAllVersions))] - public void GetStubSymbol_RangeListStubs(string version, MockTarget.Architecture arch) + public void GetStubKind_RangeListStubs(string version, MockTarget.Architecture arch) { const ulong codeRangeStart = 0x0a0a_0000u; const uint codeRangeSize = 0x4000u; @@ -684,13 +685,13 @@ public void GetStubSymbol_RangeListStubs(string version, MockTarget.Architecture _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - string? symbol = em.GetStubSymbol(new TargetCodePointer(codeRangeStart + 0x100)); - Assert.Equal("MethodDescPrestub", symbol); + StubKind kind = em.GetStubKind(new TargetCodePointer(codeRangeStart + 0x100)); + Assert.Equal(StubKind.Prestub, kind); } [Theory] [MemberData(nameof(StdArchAllVersions))] - public void GetStubSymbol_CodeHeapStubs(string version, MockTarget.Architecture arch) + public void GetStubKind_CodeHeapStubs(string version, MockTarget.Architecture arch) { const ulong codeRangeStart = 0x0a0a_0000u; const uint codeRangeSize = 0xc000u; @@ -715,13 +716,13 @@ public void GetStubSymbol_CodeHeapStubs(string version, MockTarget.Architecture _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - string? symbol = em.GetStubSymbol(new TargetCodePointer(stubCodeAddress)); - Assert.Equal("JumpStub", symbol); + StubKind kind = em.GetStubKind(new TargetCodePointer(stubCodeAddress)); + Assert.Equal(StubKind.JumpStub, kind); } [Theory] [MemberData(nameof(StdArchAllVersions))] - public void GetStubSymbol_ManagedCode(string version, MockTarget.Architecture arch) + public void GetStubKind_ManagedCode(string version, MockTarget.Architecture arch) { const ulong codeRangeStart = 0x0a0a_0000u; const uint codeRangeSize = 0xc000u; @@ -746,8 +747,68 @@ public void GetStubSymbol_ManagedCode(string version, MockTarget.Architecture ar _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - string? symbol = em.GetStubSymbol(new TargetCodePointer(methodStart)); - Assert.Null(symbol); + StubKind kind = em.GetStubKind(new TargetCodePointer(methodStart)); + Assert.Equal(StubKind.Managed, kind); + } + + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void GetStubKind_R2R_MethodCallThunk(string version, MockTarget.Architecture arch) + { + const ulong codeRangeStart = 0x0a0a_0000u; + const uint codeRangeSize = 0xc000u; + const ulong jitManagerAddress = 0x000b_ff00; + const uint thunkRva = 0x2000; + const uint thunkSize = 0x100; + + IExecutionManager em = CreateExecutionManagerContract( + version, + arch, + emBuilder => + { + var jittedCode = emBuilder.AllocateJittedCodeRange(codeRangeStart, codeRangeSize); + MockReadyToRunInfo r2rInfo = emBuilder.AddReadyToRunInfo([], []); + emBuilder.SetDelayLoadMethodCallThunks(r2rInfo, thunkRva, thunkSize); + MockHashMapBuilder hashMapBuilder = new(emBuilder.Builder); + hashMapBuilder.PopulatePtrMap(r2rInfo.EntryPointToMethodDescMapAddress, []); + + MockLoaderModule r2rModule = emBuilder.AddReadyToRunModule(r2rInfo.Address); + MockRangeSection rangeSection = emBuilder.AddReadyToRunRangeSection(jittedCode, jitManagerAddress, r2rModule.Address); + _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); + }); + + StubKind kind = em.GetStubKind(new TargetCodePointer(codeRangeStart + thunkRva + 0x10)); + Assert.Equal(StubKind.MethodCallThunk, kind); + } + + [Theory] + [MemberData(nameof(StdArchAllVersions))] + public void GetStubKind_R2R_OutsideThunkRange(string version, MockTarget.Architecture arch) + { + const ulong codeRangeStart = 0x0a0a_0000u; + const uint codeRangeSize = 0xc000u; + const ulong jitManagerAddress = 0x000b_ff00; + const uint thunkRva = 0x2000; + const uint thunkSize = 0x100; + + IExecutionManager em = CreateExecutionManagerContract( + version, + arch, + emBuilder => + { + var jittedCode = emBuilder.AllocateJittedCodeRange(codeRangeStart, codeRangeSize); + MockReadyToRunInfo r2rInfo = emBuilder.AddReadyToRunInfo([], []); + emBuilder.SetDelayLoadMethodCallThunks(r2rInfo, thunkRva, thunkSize); + MockHashMapBuilder hashMapBuilder = new(emBuilder.Builder); + hashMapBuilder.PopulatePtrMap(r2rInfo.EntryPointToMethodDescMapAddress, []); + + MockLoaderModule r2rModule = emBuilder.AddReadyToRunModule(r2rInfo.Address); + MockRangeSection rangeSection = emBuilder.AddReadyToRunRangeSection(jittedCode, jitManagerAddress, r2rModule.Address); + _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); + }); + + StubKind kind = em.GetStubKind(new TargetCodePointer(codeRangeStart + thunkRva + thunkSize + 0x10)); + Assert.Equal(StubKind.UnknownStub, kind); } public static IEnumerable StdArchAllVersions() diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs index a15509a9c7fe01..cfe1d4fcb77753 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.ExecutionManager.cs @@ -407,9 +407,39 @@ public ulong ExceptionInfoSection set => WritePointerField(ExceptionInfoSectionFieldName, value); } + public ulong DelayLoadMethodCallThunks + { + get => ReadPointerField(DelayLoadMethodCallThunksFieldName); + set => WritePointerField(DelayLoadMethodCallThunksFieldName, value); + } + public ulong EntryPointToMethodDescMapAddress => GetFieldAddress(EntryPointToMethodDescMapFieldName); } +internal sealed class MockImageDataDirectory : TypedView +{ + private const string VirtualAddressFieldName = "VirtualAddress"; + private const string SizeFieldName = "Size"; + + public static Layout CreateLayout(MockTarget.Architecture architecture) + => new SequentialLayoutBuilder("ImageDataDirectory", architecture) + .AddUInt32Field(VirtualAddressFieldName) + .AddUInt32Field(SizeFieldName) + .Build(); + + public uint VirtualAddress + { + get => ReadUInt32Field(VirtualAddressFieldName); + set => WriteUInt32Field(VirtualAddressFieldName, value); + } + + public uint Size + { + get => ReadUInt32Field(SizeFieldName); + set => WriteUInt32Field(SizeFieldName, value); + } +} + internal sealed class MockEEJitManager : TypedView { private const string StoreRichDebugInfoFieldName = "StoreRichDebugInfo"; @@ -527,6 +557,7 @@ internal readonly struct JittedCodeRange internal Layout EEJitManagerLayout { get; } internal Layout ModuleLayout { get; } internal Layout CodeRangeMapRangeListLayout { get; } + internal Layout ImageDataDirectoryLayout { get; } internal Layout RuntimeFunctionLayout => _runtimeFunctions.RuntimeFunctionLayout; internal Layout UnwindInfoLayout => _runtimeFunctions.UnwindInfoLayout; internal (string Name, ulong Value)[] Globals { get; } @@ -582,6 +613,7 @@ internal MockExecutionManagerBuilder(string version, MockMemorySpace.Builder bui EEJitManagerLayout = MockEEJitManager.CreateLayout(architecture); ModuleLayout = MockLoaderModule.CreateLayout(architecture); CodeRangeMapRangeListLayout = MockCodeRangeMapRangeList.CreateLayout(architecture); + ImageDataDirectoryLayout = MockImageDataDirectory.CreateLayout(architecture); _eeJitManager = AllocateAndCreate(EEJitManagerLayout, "EEJitManager"); _eeJitManager.AllCodeHeaps = allCodeHeaps; @@ -758,6 +790,14 @@ public MockReadyToRunInfo AddReadyToRunInfo(uint[] runtimeFunctions, uint[] hotC return readyToRunInfo; } + public void SetDelayLoadMethodCallThunks(MockReadyToRunInfo readyToRunInfo, uint thunkRva, uint thunkSize) + { + MockImageDataDirectory imageDataDir = AllocateAndCreate(ImageDataDirectoryLayout, "DelayLoadMethodCallThunks"); + imageDataDir.VirtualAddress = thunkRva; + imageDataDir.Size = thunkSize; + readyToRunInfo.DelayLoadMethodCallThunks = imageDataDir.Address; + } + public MockLoaderModule AddReadyToRunModule(ulong readyToRunInfoAddress) { MockLoaderModule module = AllocateAndCreate(ModuleLayout, "R2R Module"); From 634d396d63cdfe8bd8be6ef3f4474873ee1566ba Mon Sep 17 00:00:00 2001 From: rcj1 Date: Mon, 27 Apr 2026 10:45:51 -0700 Subject: [PATCH 8/8] code review, consolidating stubs --- docs/design/datacontracts/ExecutionManager.md | 23 +++++++++++++++---- src/coreclr/vm/codeman.cpp | 6 ++--- src/coreclr/vm/codeman.h | 4 ---- .../Contracts/IExecutionManager.cs | 6 ++--- .../ExecutionManagerCore.EEJitManager.cs | 7 +++--- ...ecutionManagerCore.ReadyToRunJitManager.cs | 4 ++-- .../ExecutionManager/ExecutionManagerCore.cs | 2 +- .../SOSDacImpl.IXCLRDataProcess.cs | 3 +-- .../ExecutionManager/ExecutionManagerTests.cs | 6 ++--- 9 files changed, 34 insertions(+), 27 deletions(-) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index 3b6a51cb4c2dae..61e7b2a8b93bfc 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -52,8 +52,8 @@ struct CodeBlockHandle // Get the exception clause info for the code block List GetExceptionClauses(CodeBlockHandle codeInfoHandle); - // Classify a code address as a known stub kind (precode, jump stub, VSD stub, etc.) - // or as managed code. Returns CodeBlockUnknown if the address is not recognized. + // Classify a code address as a known stub kind (precode, jump stub, VSD stub, etc.). + // Returns Unknown if the address is not a recognized stub. StubKind GetStubKind(TargetCodePointer jittedCodeAddress); // Extension Methods (implemented in terms of other APIs) @@ -123,6 +123,21 @@ public struct ExceptionClauseInfo public TargetNUInt? TypeHandle; public TargetPointer? ModuleAddr; } + +public enum StubKind : uint +{ + Unknown = 0, + JumpStub = 1, + DynamicHelper = 3, + Prestub = 4, + VSD_DispatchStub = 5, + VSD_ResolveStub = 6, + VSD_LookupStub = 7, + VSD_VTableStub = 8, + CallCountingStub = 9, + StubLinkStub = 10, + MethodCallThunk = 11, +} ``` ## Version 1 @@ -509,7 +524,7 @@ After obtaining the clause array bounds, the common iteration logic classifies e ### Stub Kind Classification -`GetStubKind` classifies a code address as a known stub type or managed code. It returns `UnknownStub` if the address is not recognized. +`GetStubKind` classifies a code address as a known stub type or managed code. It returns `Unknown` if the address is not recognized. The method looks up the address in the `RangeSectionMap`. If a `RangeSection` is found, the JIT manager for that section classifies the code: @@ -523,7 +538,7 @@ StubKind GetStubKind(TargetCodePointer jittedCodeAddress) // Look up in range section map RangeSection range = FindRangeSection(jittedCodeAddress); - if (range == null) return StubKind.UnknownStub; + if (range == null) return StubKind.Unknown; JitManager jitManager = GetJitManager(range); return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 5ba8d32028e0ef..033a2d62645e3e 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -4728,9 +4728,9 @@ StubCodeBlockKind EEJitManager::GetStubCodeBlockKind(RangeSection * pRangeSectio TADDR start = dac_cast(pRangeSection->_pjit)->FindMethodCode(pRangeSection, currentPC); if (start == (TADDR)0) - return STUB_CODE_BLOCK_NOCODE; + return STUB_CODE_BLOCK_UNKNOWN; CodeHeader * pCHdr = PTR_CodeHeader(start - sizeof(CodeHeader)); - return pCHdr->IsStubCodeBlock() ? pCHdr->GetStubCodeBlockKind() : STUB_CODE_BLOCK_MANAGED; + return pCHdr->IsStubCodeBlock() ? pCHdr->GetStubCodeBlockKind() : STUB_CODE_BLOCK_UNKNOWN; } @@ -4744,7 +4744,7 @@ TADDR EECodeGenManager::FindMethodCode(PCODE currentPC) RangeSection * pRS = ExecutionManager::FindCodeRange(currentPC, ExecutionManager::GetScanFlags()); if (pRS == NULL || (pRS->_flags & RangeSection::RANGE_SECTION_CODEHEAP) == 0) - return STUB_CODE_BLOCK_NOCODE; + return STUB_CODE_BLOCK_UNKNOWN; return dac_cast(pRS->_pjit)->FindMethodCode(pRS, currentPC); } diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 6afa441a9d3839..c6636548a6d9e1 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -113,8 +113,6 @@ enum StubCodeBlockKind : int // Last valid value. Note that the definition is duplicated in debug\daccess\fntableaccess.cpp STUB_CODE_BLOCK_LAST = 0xF, // Placeholders returned by code:GetStubCodeBlockKind - STUB_CODE_BLOCK_NOCODE = 0x10, - STUB_CODE_BLOCK_MANAGED = 0x11, STUB_CODE_BLOCK_STUBLINK = 0x12, // Placeholder used by ReadyToRun images STUB_CODE_BLOCK_METHOD_CALL_THUNK = 0x13, @@ -128,8 +126,6 @@ inline const char *GetStubCodeBlockKindString(StubCodeBlockKind kind) return "JumpStub"; case STUB_CODE_BLOCK_STUBLINK: return "StubLinkStub"; - case STUB_CODE_BLOCK_MANAGED: - return "Managed"; case STUB_CODE_BLOCK_METHOD_CALL_THUNK: return "MethodCallThunk"; #ifdef FEATURE_TIERED_COMPILATION 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 6f19e079ea7472..3c1630b3442f35 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 @@ -44,7 +44,7 @@ public struct JitManagerInfo public enum StubKind : uint { - UnknownStub = 0, + Unknown = 0, JumpStub = 1, DynamicHelper = 3, Prestub = 4, @@ -55,8 +55,6 @@ public enum StubKind : uint CallCountingStub = 9, StubLinkStub = 10, MethodCallThunk = 11, - NoCodeStub = 12, - Managed = 13, } public interface ICodeHeapInfo @@ -119,7 +117,7 @@ public interface IExecutionManager : IContract JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException(); IEnumerable GetCodeHeapInfos() => throw new NotImplementedException(); // Classify a code address as a known stub kind (precode, jump stub, VSD stub, etc.) - // or as managed code. Returns UnknownStub if the address is not recognized. + // or as managed code. Returns Unknown if the address is not recognized. StubKind GetStubKind(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs index c71759812c2267..06f6476ea68f5e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.EEJitManager.cs @@ -140,7 +140,7 @@ public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetC } TargetPointer startAddr = FindMethodCode(rangeSection, jittedCodeAddress); // validate that the code address is within the method's code range if (startAddr == TargetPointer.Null) - return StubKind.NoCodeStub; + return StubKind.Unknown; return GetCodeHeaderStubKind(rangeSection, startAddr); } @@ -228,7 +228,7 @@ private static StubKind GetStubKind(StubCodeBlockKind stubCodeBlockKind) StubCodeBlockKind.VSDLookupStub => StubKind.VSD_LookupStub, StubCodeBlockKind.VSDVTableStub => StubKind.VSD_VTableStub, StubCodeBlockKind.CallCountingStub => StubKind.CallCountingStub, - _ => StubKind.UnknownStub, + _ => StubKind.Unknown, }; } @@ -240,9 +240,8 @@ private StubKind GetCodeHeaderStubKind(RangeSection rangeSection, TargetPointer { return GetStubKind((StubCodeBlockKind)codeHeaderAddress.Value); } - return StubKind.Managed; } - return StubKind.UnknownStub; + return StubKind.Unknown; } public override void GetExceptionClauses(RangeSection rangeSection, CodeBlockHandle codeInfoHandle, out TargetPointer startAddr, out TargetPointer endAddr) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs index 0a21b135b6aa13..c60ea39819678b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.ReadyToRunJitManager.cs @@ -145,8 +145,8 @@ public override TargetPointer GetDebugInfo(RangeSection rangeSection, TargetCode public override StubKind GetStubCodeBlockKind(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) { if (rangeSection.Data == null) - return StubKind.UnknownStub; - return IsStubCodeBlockThunk(rangeSection.Data, GetReadyToRunInfo(rangeSection), jittedCodeAddress) ? StubKind.MethodCallThunk : StubKind.UnknownStub; + return StubKind.Unknown; + return IsStubCodeBlockThunk(rangeSection.Data, GetReadyToRunInfo(rangeSection), jittedCodeAddress) ? StubKind.MethodCallThunk : StubKind.Unknown; } public override void GetGCInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, out TargetPointer gcInfo, out uint gcVersion) 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 4d494ad819d9e5..5db7e99481a447 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 @@ -545,7 +545,7 @@ public StubKind GetStubKind(TargetCodePointer jittedCodeAddress) { RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, jittedCodeAddress); if (range.Data == null) - return StubKind.UnknownStub; + return StubKind.Unknown; JitManager jitManager = GetJitManager(range.Data); return jitManager.GetStubCodeBlockKind(range, jittedCodeAddress); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index f9a94329bc6a6e..6b3f70dfe0ed74 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; -using System.Text; using Microsoft.Diagnostics.DataContractReader.Contracts; using Microsoft.Diagnostics.DataContractReader.Contracts.Extensions; @@ -185,7 +184,7 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( private static string? GetStubName(Contracts.StubKind stubKind) { - if (stubKind == Contracts.StubKind.UnknownStub || stubKind == Contracts.StubKind.Managed || stubKind == Contracts.StubKind.NoCodeStub) + if (stubKind == Contracts.StubKind.Unknown) return null; return stubKind.ToString(); } diff --git a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs index beb31972846e79..cc3ab112551453 100644 --- a/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/ExecutionManager/ExecutionManagerTests.cs @@ -663,7 +663,7 @@ public void GetStubKind_NoRangeSection(string version, MockTarget.Architecture a { IExecutionManager em = CreateExecutionManagerContract(version, arch); - Assert.Equal(StubKind.UnknownStub, em.GetStubKind(new TargetCodePointer(0x00aa_9000))); + Assert.Equal(StubKind.Unknown, em.GetStubKind(new TargetCodePointer(0x00aa_9000))); } [Theory] @@ -748,7 +748,7 @@ public void GetStubKind_ManagedCode(string version, MockTarget.Architecture arch }); StubKind kind = em.GetStubKind(new TargetCodePointer(methodStart)); - Assert.Equal(StubKind.Managed, kind); + Assert.Equal(StubKind.Unknown, kind); } [Theory] @@ -808,7 +808,7 @@ public void GetStubKind_R2R_OutsideThunkRange(string version, MockTarget.Archite }); StubKind kind = em.GetStubKind(new TargetCodePointer(codeRangeStart + thunkRva + thunkSize + 0x10)); - Assert.Equal(StubKind.UnknownStub, kind); + Assert.Equal(StubKind.Unknown, kind); } public static IEnumerable StdArchAllVersions()