From 601938db892fc126789df4eea032aa274e2ca914 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 19 Jul 2024 16:37:49 -0400 Subject: [PATCH 01/66] wip: NativeCodePointers and MethodDesc CodeData --- .../debug/runtimeinfo/datadescriptor.h | 11 ++++++ src/coreclr/vm/method.hpp | 2 + .../src/Contracts/NativeCodePointers.cs | 25 +++++++++++++ .../src/Contracts/NativeCodePointers_1.cs | 16 ++++++++ .../cdacreader/src/Contracts/Registry.cs | 1 + .../RuntimeTypeSystem_1.NonValidated.cs | 12 ++++++ .../src/Contracts/RuntimeTypeSystem_1.cs | 6 +++ .../managed/cdacreader/src/Data/MethodDesc.cs | 2 + src/native/managed/cdacreader/src/DataType.cs | 2 + src/native/managed/cdacreader/src/Target.cs | 37 +++++++++++++++++++ 10 files changed, 114 insertions(+) create mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs create mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 967df850abcc9..1550d4ae554af 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -304,6 +304,8 @@ CDAC_TYPE_FIELD(MethodDesc, /*uint8*/, ChunkIndex, cdac_data::ChunkI CDAC_TYPE_FIELD(MethodDesc, /*uint16*/, Slot, cdac_data::Slot) CDAC_TYPE_FIELD(MethodDesc, /*uint16*/, Flags, cdac_data::Flags) CDAC_TYPE_FIELD(MethodDesc, /*uint16*/, Flags3AndTokenRemainder, cdac_data::Flags3AndTokenRemainder) +CDAC_TYPE_FIELD(MethodDesc, /*uint8*/, EntryPointFlags, cdac_data::EntryPointFlags) +CDAC_TYPE_FIELD(MethodDesc, /*pointer*/, CodeData, cdac_data::CodeData) CDAC_TYPE_END(MethodDesc) CDAC_TYPE_BEGIN(MethodDescChunk) @@ -334,6 +336,15 @@ CDAC_TYPE_INDETERMINATE(DynamicMethodDesc) CDAC_TYPE_FIELD(DynamicMethodDesc, /*pointer*/, MethodName, cdac_data::MethodName) CDAC_TYPE_END(DynamicMethodDesc) +CDAC_TYPE_BEGIN(CodePointer) +CDAC_TYPE_SIZE(sizeof(PCODE)) +CDAC_TYPE_END(CodePointer) + +CDAC_TYPE_BEGIN(MethodDescCodeData) +CDAC_TYPE_INDETERMINATE(MethodDescCodeData) +CDAC_TYPE_FIELD(MethodDescCodeData, /*CodePointer*/, TemporaryEntryPoint, offsetof(MethodDescCodeData,TemporaryEntryPoint)) +CDAC_TYPE_END(MethodDescCodeData) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 35882fdde5ddf..2f1bdcacfe593 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1916,6 +1916,8 @@ template<> struct cdac_data static constexpr size_t Slot = offsetof(MethodDesc, m_wSlotNumber); static constexpr size_t Flags = offsetof(MethodDesc, m_wFlags); static constexpr size_t Flags3AndTokenRemainder = offsetof(MethodDesc, m_wFlags3AndTokenRemainder); + static constexpr size_t EntryPointFlags = offsetof(MethodDesc, m_bFlags4); + static constexpr size_t CodeData = offsetof(MethodDesc, m_codeData); }; #ifndef DACCESS_COMPILE diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs new file mode 100644 index 0000000000000..f2babc41decd4 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal interface INativeCodePointers : IContract +{ + static string IContract.Name { get; } = nameof(NativeCodePointers); + static IContract IContract.Create(Target target, int version) + { + return version switch + { + 1 => new NativeCodePointers_1(target), + _ => default(NativeCodePointers), + }; + } + +} + +internal readonly struct NativeCodePointers : INativeCodePointers +{ + // throws NotImplementedException for all methods +} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs new file mode 100644 index 0000000000000..b1cbcf4830a7e --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly struct NativeCodePointers_1 : INativeCodePointers +{ + private readonly Target _target; + + public NativeCodePointers_1(Target target) + { + _target = target; + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/Registry.cs b/src/native/managed/cdacreader/src/Contracts/Registry.cs index a5d3721f06f88..23088c95c556c 100644 --- a/src/native/managed/cdacreader/src/Contracts/Registry.cs +++ b/src/native/managed/cdacreader/src/Contracts/Registry.cs @@ -25,6 +25,7 @@ public Registry(Target target) public IThread Thread => GetContract(); public IRuntimeTypeSystem RuntimeTypeSystem => GetContract(); public IDacStreams DacStreams => GetContract(); + public INativeCodePointers NativeCodePointers => GetContract(); private T GetContract() where T : IContract { diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index b319f728eaf91..1b88f10ae469a 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -99,11 +99,14 @@ internal MethodDesc(Target target, Data.MethodDesc desc, Data.MethodDescChunk ch } private bool HasFlag(MethodDescFlags flag) => (_desc.Flags & (ushort)flag) != 0; + private bool HasFlag(MethodDescEntryPointFlags flag) => (_desc.EntryPointFlags & (byte)flag) != 0; internal byte ChunkIndex => _desc.ChunkIndex; internal TargetPointer MethodTable => _chunk.MethodTable; internal ushort Slot => _desc.Slot; internal bool HasNonVtableSlot => HasFlag(MethodDescFlags.HasNonVtableSlot); + + internal bool TemporaryEntryPointAssigned => HasFlag(MethodDescEntryPointFlags.TemporaryEntryPointAssigned); } internal static MethodTable GetMethodTableData(Target target, TargetPointer methodTablePointer) @@ -244,6 +247,15 @@ private NonValidated.MethodDesc GetMethodDescThrowing(TargetPointer methodDescPo return new NonValidated.MethodDesc(_target, desc, chunk); } + private TargetCodePointer GetTemporaryEntryPointIfExists(NonValidated.MethodDesc umd) + { + if (!umd.TemporaryEntryPointAssigned) + { + return TargetCodePointer.Null; + } + throw new NotImplementedException(); // TODO[cdac]: read MethodDescCodeData::TemporaryEntryPoint + } + private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNullWhen(true)] out TargetPointer methodDescChunkPointer) { methodDescChunkPointer = TargetPointer.Null; diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index cc15327ae16a7..eae54207e723a 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -109,6 +109,12 @@ internal enum DynamicMethodDescExtendedFlags : uint IsILStub = 0x00008000, } + [Flags] + internal enum MethodDescEntryPointFlags : byte + { + TemporaryEntryPointAssigned = 0x04, + } + internal struct MethodDesc { private readonly Data.MethodDesc _desc; diff --git a/src/native/managed/cdacreader/src/Data/MethodDesc.cs b/src/native/managed/cdacreader/src/Data/MethodDesc.cs index d51153ab53e59..fe38484822a26 100644 --- a/src/native/managed/cdacreader/src/Data/MethodDesc.cs +++ b/src/native/managed/cdacreader/src/Data/MethodDesc.cs @@ -16,12 +16,14 @@ public MethodDesc(Target target, TargetPointer address) Slot = target.Read(address + (ulong)type.Fields[nameof(Slot)].Offset); Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); Flags3AndTokenRemainder = target.Read(address + (ulong)type.Fields[nameof(Flags3AndTokenRemainder)].Offset); + EntryPointFlags = target.Read(address + (ulong)type.Fields[nameof(EntryPointFlags)].Offset); } public byte ChunkIndex { get; init; } public ushort Slot { get; init; } public ushort Flags { get; init; } public ushort Flags3AndTokenRemainder { get; init; } + public byte EntryPointFlags { get; init; } } internal sealed class InstantiatedMethodDesc : IData diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 3d9926eb4f505..1b19ebe1ab21f 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -20,6 +20,7 @@ public enum DataType pointer, GCHandle, + CodePointer, Thread, ThreadStore, GCAllocContext, @@ -42,6 +43,7 @@ public enum DataType String, MethodDesc, MethodDescChunk, + MethodDescCodeData, Array, SyncBlock, SyncTableEntry, diff --git a/src/native/managed/cdacreader/src/Target.cs b/src/native/managed/cdacreader/src/Target.cs index 03e0d7ad8a409..4ca70ebdcf98b 100644 --- a/src/native/managed/cdacreader/src/Target.cs +++ b/src/native/managed/cdacreader/src/Target.cs @@ -33,6 +33,29 @@ namespace Microsoft.Diagnostics.DataContractReader; public override int GetHashCode() => Value.GetHashCode(); } +public readonly struct TargetCodePointer : IEquatable +{ + public static TargetCodePointer Null = new(0); + public readonly ulong Value; + public TargetCodePointer(ulong value) => Value = value; + + public static implicit operator ulong(TargetCodePointer p) => p.Value; + public static implicit operator TargetCodePointer(ulong v) => new TargetCodePointer(v); + + public static bool operator ==(TargetCodePointer left, TargetCodePointer right) => left.Value == right.Value; + public static bool operator !=(TargetCodePointer left, TargetCodePointer right) => left.Value != right.Value; + + public override bool Equals(object? obj) => obj is TargetCodePointer pointer && Equals(pointer); + public bool Equals(TargetCodePointer other) => Value == other.Value; + + public override int GetHashCode() => Value.GetHashCode(); + + public bool Equals(TargetCodePointer x, TargetCodePointer y) => x.Value == y.Value; + public int GetHashCode(TargetCodePointer obj) => obj.Value.GetHashCode(); + + public TargetPointer AsTargetPointer => new(Value); +} + public readonly struct TargetNUInt { public readonly ulong Value; @@ -339,6 +362,20 @@ public TargetPointer ReadPointerFromSpan(ReadOnlySpan bytes) } } + public TargetCodePointer ReadCodePointer(ulong address) + { + TypeInfo codePointerTypeInfo = GetTypeInfo(DataType.CodePointer); + if (codePointerTypeInfo.Size is sizeof(uint)) + { + return new TargetCodePointer(Read(address)); + } + else if (codePointerTypeInfo.Size is sizeof(ulong)) + { + return new TargetCodePointer(Read(address)); + } + throw new InvalidOperationException($"Failed to read code pointer at 0x{address:x8} because CodePointer size is not 4 or 8"); + } + public void ReadPointers(ulong address, Span buffer) { // TODO(cdac) - This could do a single read, and then swizzle in place if it is useful for performance From 5f3599ce564b9970d6181fc9f698d54e1bbd1dd5 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 23 Jul 2024 16:40:48 -0400 Subject: [PATCH 02/66] checkpoint: PrecodeMachineDescriptor and KnownPrecodeType --- .../debug/runtimeinfo/datadescriptor.h | 12 ++ src/coreclr/vm/precode.cpp | 3 + src/coreclr/vm/precode.h | 61 ++++++- .../managed/cdacreader/src/Constants.cs | 2 + .../src/Contracts/NativeCodePointers.cs | 5 +- .../src/Contracts/NativeCodePointers_1.cs | 149 +++++++++++++++++- .../RuntimeTypeSystem_1.NonValidated.cs | 19 ++- .../src/Data/PrecodeMachineDescriptor.cs | 40 +++++ src/native/managed/cdacreader/src/DataType.cs | 1 + 9 files changed, 276 insertions(+), 16 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 1550d4ae554af..1a96440cdf8c1 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -345,6 +345,17 @@ CDAC_TYPE_INDETERMINATE(MethodDescCodeData) CDAC_TYPE_FIELD(MethodDescCodeData, /*CodePointer*/, TemporaryEntryPoint, offsetof(MethodDescCodeData,TemporaryEntryPoint)) CDAC_TYPE_END(MethodDescCodeData) +CDAC_TYPE_BEGIN(PrecodeMachineDescriptor) +CDAC_TYPE_INDETERMINATE(PrecodeMachineDescriptor) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uintptr*/, CodePointerToInstrPointerMask, offsetof(PrecodeMachineDescriptor, CodePointerToInstrPointerMask)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, OffsetOfPrecodeType, offsetof(PrecodeMachineDescriptor, OffsetOfPrecodeType)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, InvalidPrecodeType, offsetof(PrecodeMachineDescriptor, InvalidPrecodeType)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, StubPrecodeType, offsetof(PrecodeMachineDescriptor, StubPrecodeType)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, HasNDirectImportPrecode, offsetof(PrecodeMachineDescriptor, HasNDirectImportPrecode)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, NDirectImportPrecodeType, offsetof(PrecodeMachineDescriptor, NDirectImportPrecodeType)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, HasFixupPrecode, offsetof(PrecodeMachineDescriptor, HasFixupPrecode)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, FixupPrecodeType, offsetof(PrecodeMachineDescriptor, FixupPrecodeType)) +CDAC_TYPE_END(PrecodeMachineDescriptor) CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -383,6 +394,7 @@ CDAC_GLOBAL_POINTER(StringMethodTable, &::g_pStringClass) CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable) CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize) +CDAC_GLOBAL_POINTER(PrecodeMachineDescriptor, &::g_PrecodeMachDesc) CDAC_GLOBALS_END() #undef CDAC_BASELINE diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index 4dbc3e4394834..cfca67eb7582c 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -662,4 +662,7 @@ BOOL DoesSlotCallPrestub(PCODE pCode) return FALSE; } +PrecodeMachineDescriptor g_PrecodeMachDesc; + #endif // !DACCESS_COMPILE + diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 22ae9b1adaf18..0e8cd36b9d94b 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -14,8 +14,8 @@ #if defined(TARGET_AMD64) #define OFFSETOF_PRECODE_TYPE 0 -#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 -#define OFFSETOF_PRECODE_TYPE_MOV_R10 10 +#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 // FIXME: unused +#define OFFSETOF_PRECODE_TYPE_MOV_R10 10 // FIXME: unused #define SIZEOF_PRECODE_BASE 16 @@ -24,8 +24,8 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk(); #define OFFSETOF_PRECODE_TYPE 0 -#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 -#define OFFSETOF_PRECODE_TYPE_MOV_RM_R 6 +#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 // FIXME: unuxed +#define OFFSETOF_PRECODE_TYPE_MOV_RM_R 6 // FIXME: unused #define SIZEOF_PRECODE_BASE 8 @@ -596,4 +596,57 @@ static_assert_no_msg(NDirectImportPrecode::Type != ThisPtrRetBufPrecode::Type); static_assert_no_msg(sizeof(Precode) <= sizeof(NDirectImportPrecode)); static_assert_no_msg(sizeof(Precode) <= sizeof(FixupPrecode)); static_assert_no_msg(sizeof(Precode) <= sizeof(ThisPtrRetBufPrecode)); + +#ifndef DACCESS_COMPILE +// A summary of the precode layout for diagnostic purposes +struct PrecodeMachineDescriptor +{ +#ifndef TARGET_ARM + uintptr_t CodePointerToInstrPointerMask = ~0; +#else + // mask off the thumb bit + uintptr_t CodePointerToInstrPointerMask = ~1; +#endif + uint8_t OffsetOfPrecodeType = OFFSETOF_PRECODE_TYPE; // FIXME(cdac): sometimes OFFSETOF_PRECODE_TYPE is undefined? + // cDAC will do (where N = 8*ReadWidthOfPrecodeType): + // uintN_t PrecodeType = *(uintN_t*)(pPrecode + OffsetOfPrecodeType); + // PrecodeType >>= ShiftOfPrecodeType; + // return (byte)PrecodeType; +#ifdef TARGET_LOONGARCH64 + uint8_t ReadWidthOfPrecodeType = 2; + uint8_t ShiftOfPrecodeType = 5; +#else + uint8_t ReadWidthOfPrecodeType = 1; + uint8_t ShiftOfPrecodeType = 0; +#endif + // uint8_t SizeOfPrecodeBase = SIZEOF_PRECODE_BASE; + + uint8_t InvalidPrecodeType = InvalidPrecode::Type; + uint8_t StubPrecodeType = StubPrecode::Type; +#ifdef HAS_NDIRECT_IMPORT_PRECODE + uint8_t HasNDirectImportPrecode = 1; + uint8_t NDirectImportPrecodeType = NDirectImportPrecode::Type; +#else + uint8_t HasNDirectImportPrecode = 0; + uint8_t NDirectImportPrecodeType = 0; +#endif // HAS_NDIRECT_IMPORT_PRECODE +#ifdef HAS_FIXUP_PRECODE + uint8_t HasFixupPrecode = 1; + uint8_t FixupPrecodeType = FixupPrecode::Type; +#else + uint8_t HasFixupPrecode = 0; + uint8_t FixupPrecodeType = 0; +#endif // HAS_FIXUP_PRECODE +#ifdef HAS_THISPTR_RETBUF_PRECODE + uint8_t HasThisPtrRetBufPrecode = 1; + uint8_t HasThisPointerRetBufPrecodeType = ThisPtrRetBufPrecode::Type, +#else + uint8_t HasThisPtrRetBufPrecode = 0; + uint8_t HasThisPointerRetBufPrecodeType = 0; +#endif // HAS_THISPTR_RETBUF_PRECODE +}; + +extern PrecodeMachineDescriptor g_PrecodeMachDesc; +#endif DACCESS_COMPILE + #endif // __PRECODE_H__ diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs index 5353fed750344..8003156a6c99c 100644 --- a/src/native/managed/cdacreader/src/Constants.cs +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -38,5 +38,7 @@ internal static class Globals internal const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); internal const string DirectorySeparator = nameof(DirectorySeparator); + + internal const string PrecodeMachineDescriptor = nameof(PrecodeMachineDescriptor); } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index f2babc41decd4..ba1bc76a130a3 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -10,13 +10,16 @@ internal interface INativeCodePointers : IContract static string IContract.Name { get; } = nameof(NativeCodePointers); static IContract IContract.Create(Target target, int version) { + TargetPointer precodeMachineDescriptorAddress = target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor); + Data.PrecodeMachineDescriptor precodeMachineDescriptor = target.ProcessedData.GetOrAdd(precodeMachineDescriptorAddress); return version switch { - 1 => new NativeCodePointers_1(target), + 1 => new NativeCodePointers_1(target, precodeMachineDescriptor), _ => default(NativeCodePointers), }; } + public virtual TargetPointer MethodDescFromStubAddress(TargetCodePointer codeAddress) => throw new NotImplementedException(); } internal readonly struct NativeCodePointers : INativeCodePointers diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index b1cbcf4830a7e..5196563420152 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -2,15 +2,162 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly struct NativeCodePointers_1 : INativeCodePointers { private readonly Target _target; + private readonly Data.PrecodeMachineDescriptor _precodeMachineDescriptor; - public NativeCodePointers_1(Target target) + private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); + + internal enum KnownPrecodeType + { + Stub = 1, + NDirectImport, + Fixup, + ThisPtrRetBuf, + } + + internal abstract class ValidPrecode + { + public TargetPointer InstrPointer { get; } + public KnownPrecodeType PrecodeType { get; } + + protected ValidPrecode(TargetPointer instrPointer, KnownPrecodeType precodeType) + { + InstrPointer = instrPointer; + PrecodeType = precodeType; + } + + internal abstract TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); + + } + + internal class StubPrecode : ValidPrecode + { + internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } + + internal override TargetPointer GetMethodDesc(Target targret, PrecodeMachineDescriptor precodeMachineDescriptor) + { + TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + Data.StubPrecodeData stubPrecodeData = target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); + return stubPrecodeData.MethodDesc; + } + } + + internal sealed class NDirectImportPrecode : StubPrecode + { + internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.NDirectImport) { } + } + + internal sealed class FixupPrecode : StubPrecode + { + internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } + } + + internal sealed class ThisPtrRetBufPrecode : ValidPrecode // FIXME: is this a StubPrecode? + { + internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } + + internal override TargetPointer GetMethodDesc(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) + { + throw new NotImplementedException(); // TODO(cdac) + } + } + + private byte ReadPrecodeType(TargetPointer instrPointer) + { + if (_precodeMachineDescriptor.ReadWidthOfPrecodeType == 1) + { + byte precodeType = _target.Read(instrPointer + _precodeMachineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> _precodeMachineDescriptor.ShiftOfPrecodeType); + } + else if (_precodeMachineDescriptor.ReadWidthOfPrecodeType == 2) + { + ushort precodeType = _target.Read(instrPointer + _precodeMachineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> _precodeMachineDescriptor.ShiftOfPrecodeType); + } + else + { + throw new InvalidOperationException($"Invalid precode type width {_precodeMachineDescriptor.ReadWidthOfPrecodeType}"); + } + } + + private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) + { + // precode.h Precode::GetType() + byte precodeType = ReadPrecodeType(instrAddress); + if (precodeType == _precodeMachineDescriptor.StubPrecodeType) + { + // get the actual type from the StubPrecodeData + TargetPointer stubPrecodeDataAddress = instrAddress + _precodeMachineDescriptor.StubCodePageSize; + Data.StubPrecodeData stubPrecodeData = _target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); + precodeType = stubPrecodeData.PrecodeType; + } + + if (precodeType == _precodeMachineDescriptor.StubPrecodeType) + { + return KnownPrecodeType.Stub; + } + else if (_precodeMachineDescriptor.NDirectImportPrecodeType is byte ndType && precodeType == ndType) + { + return KnownPrecodeType.NDirectImport; + } + else if (_precodeMachineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) + { + return KnownPrecodeType.Fixup; + } + // TODO: ThisPtrRetBuf + else + { + return null; + } + } + + public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) { _target = target; + _precodeMachineDescriptor = precodeMachineDescriptor; + } + + internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) + { + // Mask off the thumb bit, if we're on arm32, to get the actual instruction pointer + ulong instrPointer = (ulong)codePointer.AsTargetPointer & _precodeMachineDescriptor.CodePointerToInstrPointerMask.Value; + return new TargetPointer(instrPointer); + } + + + internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint) + { + TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint); + if (IsAlignedInstrPointer(instrPointer) && TryGetKnownPrecodeType(instrPointer) is KnownPrecodeType precodeType) + { + switch (precodeType) + { + case KnownPrecodeType.Stub: + return new StubPrecode(instrPointer); + case KnownPrecodeType.Fixup: + return new FixupPrecode(instrPointer); + case KnownPrecodeType.NDirectImport: + return new NDirectImportPrecode(instrPointer); + case KnownPrecodeType.ThisPtrRetBuf: + return new ThisPtrRetBufPrecode(instrPointer); + default: + break; + } + } + throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}"); + } + + + TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer entryPoint) + { + ValidPrecode precode = GetPrecodeFromEntryPoint(entryPoint); + + return precode.GetMethodDesc(_target, _precodeMachineDescriptor); } } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 1b88f10ae469a..18e6e9c6ba3cf 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -247,7 +247,7 @@ private NonValidated.MethodDesc GetMethodDescThrowing(TargetPointer methodDescPo return new NonValidated.MethodDesc(_target, desc, chunk); } - private TargetCodePointer GetTemporaryEntryPointIfExists(NonValidated.MethodDesc umd) + private static TargetCodePointer GetTemporaryEntryPointIfExists(NonValidated.MethodDesc umd) { if (!umd.TemporaryEntryPointAssigned) { @@ -275,18 +275,17 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull { return false; } - // TODO: request.cpp - // TODO[cdac]: this needs a Precode lookup - // see MethodDescChunk::GetTemporaryEntryPoint -#if false - MethodDesc *pMDCheck = MethodDesc::GetMethodDescFromStubAddr(pMD->GetTemporaryEntryPoint(), TRUE); - if (PTR_HOST_TO_TADDR(pMD) != PTR_HOST_TO_TADDR(pMDCheck)) + TargetCodePointer temporaryEntryPoint = GetTemporaryEntryPointIfExists(umd); + if (temporaryEntryPoint != TargetCodePointer.Null) { - retval = FALSE; + Contracts.INativeCodePointers codePointers = _target.Contracts.NativeCodePointers; + TargetPointer methodDesc = codePointers.MethodDescFromStubAddress(temporaryEntryPoint, speculative: true); + if (methodDesc != methodDescPointer) + { + return false; + } } -#endif - // TODO: request.cpp // TODO[cdac]: needs MethodDesc::GetNativeCode and MethodDesc::GetMethodEntryPoint() #if false diff --git a/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs new file mode 100644 index 0000000000000..dbf3046362972 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs @@ -0,0 +1,40 @@ +// 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 PrecodeMachineDescriptor : IData +{ + static PrecodeMachineDescriptor IData.Create(Target target, TargetPointer address) + => new PrecodeMachineDescriptor(target, address); + + public PrecodeMachineDescriptor(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.PrecodeMachineDescriptor); + CodePointerToInstrPointerMask = target.ReadNUInt(address + (ulong)type.Fields[nameof(CodePointerToInstrPointerMask)].Offset); + OffsetOfPrecodeType = target.Read(address + (ulong)type.Fields[nameof(OffsetOfPrecodeType)].Offset); + ReadWidthOfPrecodeType = target.Read(address + (ulong)type.Fields[nameof(ReadWidthOfPrecodeType)].Offset); + ShiftOfPrecodeType = target.Read(address + (ulong)type.Fields[nameof(ShiftOfPrecodeType)].Offset); + InvalidPrecodeType = target.Read(address + (ulong)type.Fields[nameof(InvalidPrecodeType)].Offset); + StubPrecodeType = target.Read(address + (ulong)type.Fields[nameof(StubPrecodeType)].Offset); + if (target.ReadGlobal(HasNDirectImportPrecode) == 1) + { + NDirectImportPrecodeType = target.Read(address + (ulong)type.Fields[nameof(NDirectImportPrecodeType)].Offset); + } + if (target.ReadGlobal(HasFixupPrecode) == 1) + { + FixupPrecodeType = target.Read(address + (ulong)type.Fields[nameof(FixupPrecodeType)].Offset); + } + } + + public TargetNUInt CodePointerToInstrPointerMask { get; init; } + public byte OffsetOfPrecodeType { get; init; } + public byte ReadWidthOfPrecodeType { get; init; } + public byte ShiftOfPrecodeType { get; init; } + public byte InvalidPrecodeType { get; init; } + public byte StubPrecodeType { get; init; } + public byte? NDirectImportPrecodeType { get; init; } + public byte? FixupPrecodeType { get; init; } + private const string HasNDirectImportPrecode = nameof(HasNDirectImportPrecode); + private const string HasFixupPrecode = nameof(HasFixupPrecode); +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 1b19ebe1ab21f..308cc8c3448e1 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -44,6 +44,7 @@ public enum DataType MethodDesc, MethodDescChunk, MethodDescCodeData, + PrecodeMachineDescriptor, Array, SyncBlock, SyncTableEntry, From 2cf8fd437bbc6603123be39f965c26203bdc2fa1 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 24 Jul 2024 15:21:38 -0400 Subject: [PATCH 03/66] checkpoint: StubPrecodeData, StubCodePageSize --- .../debug/runtimeinfo/datadescriptor.h | 10 +++- src/coreclr/vm/ceemain.cpp | 1 + src/coreclr/vm/precode.cpp | 50 ++++++++++++++++++- src/coreclr/vm/precode.h | 12 +++-- .../src/Contracts/NativeCodePointers_1.cs | 13 +++-- .../RuntimeTypeSystem_1.NonValidated.cs | 2 +- .../src/Data/PrecodeMachineDescriptor.cs | 3 ++ .../cdacreader/src/Data/StubPrecodeData.cs | 20 ++++++++ src/native/managed/cdacreader/src/DataType.cs | 1 + 9 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/StubPrecodeData.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 1a96440cdf8c1..fab7ea8acb561 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -355,7 +355,15 @@ CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, HasNDirectImportPrecode, of CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, NDirectImportPrecodeType, offsetof(PrecodeMachineDescriptor, NDirectImportPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, HasFixupPrecode, offsetof(PrecodeMachineDescriptor, HasFixupPrecode)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, FixupPrecodeType, offsetof(PrecodeMachineDescriptor, FixupPrecodeType)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint32*/, StubCodePageSize, offsetof(PrecodeMachineDescriptor, StubCodePageSize)) CDAC_TYPE_END(PrecodeMachineDescriptor) + +CDAC_TYPE_BEGIN(StubPrecodeData) +CDAC_TYPE_INDETERMINATE(StubPrecodeData) +CDAC_TYPE_FIELD(StubPrecodeData, /*pointer*/, MethodDesc, offsetof(StubPrecodeData, MethodDesc)) +CDAC_TYPE_FIELD(StubPrecodeData, /*uint8*/, Type, offsetof(StubPrecodeData, Type)) +CDAC_TYPE_END(StubPrecodeData) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -394,7 +402,7 @@ CDAC_GLOBAL_POINTER(StringMethodTable, &::g_pStringClass) CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable) CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize) -CDAC_GLOBAL_POINTER(PrecodeMachineDescriptor, &::g_PrecodeMachDesc) +CDAC_GLOBAL_POINTER(PrecodeMachineDescriptor, &::g_PrecodeMachineDescriptor) CDAC_GLOBALS_END() #undef CDAC_BASELINE diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 1b309fef76eab..b2978f23ebaff 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -624,6 +624,7 @@ void EEStartupHelper() // We cache the SystemInfo for anyone to use throughout the life of the EE. GetSystemInfo(&g_SystemInfo); + PrecodeMachineDescriptor::Init(); // Set callbacks so that LoadStringRC knows which language our // threads are in so that it can return the proper localized string. diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index cfca67eb7582c..cb708b428ef79 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -662,7 +662,55 @@ BOOL DoesSlotCallPrestub(PCODE pCode) return FALSE; } -PrecodeMachineDescriptor g_PrecodeMachDesc; +PrecodeMachineDescriptor g_PrecodeMachineDescriptor; + +void PrecodeMachineDescriptor::Init() +{ +#ifndef TARGET_ARM + g_PrecodeMachineDescriptor.CodePointerToInstrPointerMask = ~0; +#else + // mask off the thumb bit + g_PrecodeMachineDescriptor.CodePointerToInstrPointerMask = ~1; +#endif + g_PrecodeMachineDescriptor.OffsetOfPrecodeType = OFFSETOF_PRECODE_TYPE; // FIXME(cdac): sometimes OFFSETOF_PRECODE_TYPE is undefined? + // cDAC will do (where N = 8*ReadWidthOfPrecodeType): + // uintN_t PrecodeType = *(uintN_t*)(pPrecode + OffsetOfPrecodeType); + // PrecodeType >>= ShiftOfPrecodeType; + // return (byte)PrecodeType; +#ifdef TARGET_LOONGARCH64 + g_PrecodeMachineDescriptor.ReadWidthOfPrecodeType = 2; + g_PrecodeMachineDescriptor.ShiftOfPrecodeType = 5; +#else + g_PrecodeMachineDescriptor.ReadWidthOfPrecodeType = 1; + g_PrecodeMachineDescriptor.ShiftOfPrecodeType = 0; +#endif + // uint8_t SizeOfPrecodeBase = SIZEOF_PRECODE_BASE; + + g_PrecodeMachineDescriptor.InvalidPrecodeType = InvalidPrecode::Type; + g_PrecodeMachineDescriptor.StubPrecodeType = StubPrecode::Type; +#ifdef HAS_NDIRECT_IMPORT_PRECODE + g_PrecodeMachineDescriptor.HasNDirectImportPrecode = 1; + g_PrecodeMachineDescriptor.NDirectImportPrecodeType = NDirectImportPrecode::Type; +#else + g_PrecodeMachineDescriptor.HasNDirectImportPrecode = 0; + g_PrecodeMachineDescriptor.NDirectImportPrecodeType = 0; +#endif // HAS_NDIRECT_IMPORT_PRECODE +#ifdef HAS_FIXUP_PRECODE + g_PrecodeMachineDescriptor.HasFixupPrecode = 1; + g_PrecodeMachineDescriptor.FixupPrecodeType = FixupPrecode::Type; +#else + g_PrecodeMachineDescriptor.HasFixupPrecode = 0; + g_PrecodeMachineDescriptor.FixupPrecodeType = 0; +#endif // HAS_FIXUP_PRECODE +#ifdef HAS_THISPTR_RETBUF_PRECODE + g_PrecodeMachineDescriptor.HasThisPtrRetBufPrecode = 1; + g_PrecodeMachineDescriptor.HasThisPointerRetBufPrecodeType = ThisPtrRetBufPrecode::Type; +#else + g_PrecodeMachineDescriptor.HasThisPtrRetBufPrecode = 0; + g_PrecodeMachineDescriptor.HasThisPointerRetBufPrecodeType = 0; +#endif // HAS_THISPTR_RETBUF_PRECODE + g_PrecodeMachineDescriptor.StubCodePageSize = GetStubCodePageSize(); +} #endif // !DACCESS_COMPILE diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 0e8cd36b9d94b..a35596d1b47f3 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -639,14 +639,20 @@ struct PrecodeMachineDescriptor #endif // HAS_FIXUP_PRECODE #ifdef HAS_THISPTR_RETBUF_PRECODE uint8_t HasThisPtrRetBufPrecode = 1; - uint8_t HasThisPointerRetBufPrecodeType = ThisPtrRetBufPrecode::Type, + uint8_t HasThisPointerRetBufPrecodeType = ThisPtrRetBufPrecode::Type; #else uint8_t HasThisPtrRetBufPrecode = 0; uint8_t HasThisPointerRetBufPrecodeType = 0; #endif // HAS_THISPTR_RETBUF_PRECODE + uint32_t StubCodePageSize = GetStubCodePageSize(); +public: + PrecodeMachineDescriptor() = default; + PrecodeMachineDescriptor(const PrecodeMachineDescriptor&) = delete; + PrecodeMachineDescriptor& operator=(const PrecodeMachineDescriptor&) = delete; + static void Init(); }; -extern PrecodeMachineDescriptor g_PrecodeMachDesc; -#endif DACCESS_COMPILE +extern PrecodeMachineDescriptor g_PrecodeMachineDescriptor; +#endif //DACCESS_COMPILE #endif // __PRECODE_H__ diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 5196563420152..a492cd2fb73a0 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -40,7 +40,7 @@ internal class StubPrecode : ValidPrecode { internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } - internal override TargetPointer GetMethodDesc(Target targret, PrecodeMachineDescriptor precodeMachineDescriptor) + internal override TargetPointer GetMethodDesc(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) { TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; Data.StubPrecodeData stubPrecodeData = target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); @@ -86,6 +86,12 @@ private byte ReadPrecodeType(TargetPointer instrPointer) } } + private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) + { + TargetPointer stubPrecodeDataAddress = stubInstrPointer + _precodeMachineDescriptor.StubCodePageSize; + return _target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); + } + private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) { // precode.h Precode::GetType() @@ -93,9 +99,8 @@ private byte ReadPrecodeType(TargetPointer instrPointer) if (precodeType == _precodeMachineDescriptor.StubPrecodeType) { // get the actual type from the StubPrecodeData - TargetPointer stubPrecodeDataAddress = instrAddress + _precodeMachineDescriptor.StubCodePageSize; - Data.StubPrecodeData stubPrecodeData = _target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); - precodeType = stubPrecodeData.PrecodeType; + Data.StubPrecodeData stubPrecodeData = GetStubPrecodeData(instrAddress); + precodeType = stubPrecodeData.Type; } if (precodeType == _precodeMachineDescriptor.StubPrecodeType) diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 18e6e9c6ba3cf..c7b0e0673edfa 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -280,7 +280,7 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull if (temporaryEntryPoint != TargetCodePointer.Null) { Contracts.INativeCodePointers codePointers = _target.Contracts.NativeCodePointers; - TargetPointer methodDesc = codePointers.MethodDescFromStubAddress(temporaryEntryPoint, speculative: true); + TargetPointer methodDesc = codePointers.MethodDescFromStubAddress(temporaryEntryPoint); if (methodDesc != methodDescPointer) { return false; diff --git a/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs index dbf3046362972..c4f2f8f2c926b 100644 --- a/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs +++ b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs @@ -25,6 +25,7 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) { FixupPrecodeType = target.Read(address + (ulong)type.Fields[nameof(FixupPrecodeType)].Offset); } + StubCodePageSize = target.Read(address + (ulong)type.Fields[nameof(StubCodePageSize)].Offset); } public TargetNUInt CodePointerToInstrPointerMask { get; init; } @@ -35,6 +36,8 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) public byte StubPrecodeType { get; init; } public byte? NDirectImportPrecodeType { get; init; } public byte? FixupPrecodeType { get; init; } + + public uint StubCodePageSize { get; init; } private const string HasNDirectImportPrecode = nameof(HasNDirectImportPrecode); private const string HasFixupPrecode = nameof(HasFixupPrecode); } diff --git a/src/native/managed/cdacreader/src/Data/StubPrecodeData.cs b/src/native/managed/cdacreader/src/Data/StubPrecodeData.cs new file mode 100644 index 0000000000000..320795b41d542 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/StubPrecodeData.cs @@ -0,0 +1,20 @@ +// 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 StubPrecodeData : IData +{ + static StubPrecodeData IData.Create(Target target, TargetPointer address) + => new StubPrecodeData(target, address); + + public StubPrecodeData(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.StubPrecodeData); + MethodDesc = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodDesc)].Offset); + Type = target.Read(address + (ulong)type.Fields[nameof(Type)].Offset); + } + + public TargetPointer MethodDesc { get; init; } + public byte Type { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 308cc8c3448e1..ffb3df4f868e3 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -45,6 +45,7 @@ public enum DataType MethodDescChunk, MethodDescCodeData, PrecodeMachineDescriptor, + StubPrecodeData, Array, SyncBlock, SyncTableEntry, From 7ef901629e8e8c452c587fc23df4191406792188 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 24 Jul 2024 16:33:24 -0400 Subject: [PATCH 04/66] GetTemporaryEntryPointIfExists --- .../src/Contracts/NativeCodePointers_1.cs | 6 +++++- .../RuntimeTypeSystem_1.NonValidated.cs | 9 ++++++--- .../managed/cdacreader/src/Data/MethodDesc.cs | 3 +++ .../cdacreader/src/Data/MethodDescCodeData.cs | 18 ++++++++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/MethodDescCodeData.cs diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index a492cd2fb73a0..44be858ca4cb1 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -53,9 +53,13 @@ internal sealed class NDirectImportPrecode : StubPrecode internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.NDirectImport) { } } - internal sealed class FixupPrecode : StubPrecode + internal sealed class FixupPrecode : ValidPrecode { internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } + internal override TargetPointer GetMethodDesc(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) + { + throw new NotImplementedException(); // TODO(cdac) + } } internal sealed class ThisPtrRetBufPrecode : ValidPrecode // FIXME: is this a StubPrecode? diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index c7b0e0673edfa..e21094e6410dd 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -107,6 +107,8 @@ internal MethodDesc(Target target, Data.MethodDesc desc, Data.MethodDescChunk ch internal bool HasNonVtableSlot => HasFlag(MethodDescFlags.HasNonVtableSlot); internal bool TemporaryEntryPointAssigned => HasFlag(MethodDescEntryPointFlags.TemporaryEntryPointAssigned); + + internal TargetPointer CodeData => _desc.CodeData; } internal static MethodTable GetMethodTableData(Target target, TargetPointer methodTablePointer) @@ -247,13 +249,14 @@ private NonValidated.MethodDesc GetMethodDescThrowing(TargetPointer methodDescPo return new NonValidated.MethodDesc(_target, desc, chunk); } - private static TargetCodePointer GetTemporaryEntryPointIfExists(NonValidated.MethodDesc umd) + private TargetCodePointer GetTemporaryEntryPointIfExists(NonValidated.MethodDesc umd) { - if (!umd.TemporaryEntryPointAssigned) + if (!umd.TemporaryEntryPointAssigned || umd.CodeData == TargetPointer.Null) { return TargetCodePointer.Null; } - throw new NotImplementedException(); // TODO[cdac]: read MethodDescCodeData::TemporaryEntryPoint + Data.MethodDescCodeData codeData = _target.ProcessedData.GetOrAdd(umd.CodeData); + return codeData.TemporaryEntryPoint; } private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNullWhen(true)] out TargetPointer methodDescChunkPointer) diff --git a/src/native/managed/cdacreader/src/Data/MethodDesc.cs b/src/native/managed/cdacreader/src/Data/MethodDesc.cs index fe38484822a26..eea2a61619421 100644 --- a/src/native/managed/cdacreader/src/Data/MethodDesc.cs +++ b/src/native/managed/cdacreader/src/Data/MethodDesc.cs @@ -17,6 +17,7 @@ public MethodDesc(Target target, TargetPointer address) Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); Flags3AndTokenRemainder = target.Read(address + (ulong)type.Fields[nameof(Flags3AndTokenRemainder)].Offset); EntryPointFlags = target.Read(address + (ulong)type.Fields[nameof(EntryPointFlags)].Offset); + CodeData = target.ReadPointer(address + (ulong)type.Fields[nameof(CodeData)].Offset); } public byte ChunkIndex { get; init; } @@ -24,6 +25,8 @@ public MethodDesc(Target target, TargetPointer address) public ushort Flags { get; init; } public ushort Flags3AndTokenRemainder { get; init; } public byte EntryPointFlags { get; init; } + + public TargetPointer CodeData { get; set; } } internal sealed class InstantiatedMethodDesc : IData diff --git a/src/native/managed/cdacreader/src/Data/MethodDescCodeData.cs b/src/native/managed/cdacreader/src/Data/MethodDescCodeData.cs new file mode 100644 index 0000000000000..9b80d3b891729 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/MethodDescCodeData.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 MethodDescCodeData : IData +{ + static MethodDescCodeData IData.Create(Target target, TargetPointer address) => new MethodDescCodeData(target, address); + public MethodDescCodeData(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.MethodDescCodeData); + + TemporaryEntryPoint = target.ReadCodePointer(address + (ulong)type.Fields[nameof(TemporaryEntryPoint)].Offset); + } + + public TargetCodePointer TemporaryEntryPoint { get; set; } +} From 9cf7a7a3198a05be9a3c166ab4e95cd2aca6562d Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 26 Jul 2024 16:01:38 -0400 Subject: [PATCH 05/66] wip GetMethodEntryPointIfExists --- .../RuntimeTypeSystem_1.NonValidated.cs | 166 ++++++++++++++++-- .../src/Contracts/RuntimeTypeSystem_1.cs | 59 +++++++ 2 files changed, 207 insertions(+), 18 deletions(-) diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index e21094e6410dd..5e6255b15d0aa 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -101,16 +101,61 @@ internal MethodDesc(Target target, Data.MethodDesc desc, Data.MethodDescChunk ch private bool HasFlag(MethodDescFlags flag) => (_desc.Flags & (ushort)flag) != 0; private bool HasFlag(MethodDescEntryPointFlags flag) => (_desc.EntryPointFlags & (byte)flag) != 0; + private bool HasFlag(MethodDescFlags3 flag) => (_desc.Flags3AndTokenRemainder & (ushort)flag) != 0; + internal byte ChunkIndex => _desc.ChunkIndex; internal TargetPointer MethodTable => _chunk.MethodTable; internal ushort Slot => _desc.Slot; internal bool HasNonVtableSlot => HasFlag(MethodDescFlags.HasNonVtableSlot); + internal bool HasMethodImpl => HasFlag(MethodDescFlags.HasMethodImpl); + internal bool HasNativeCodeSlot => HasFlag(MethodDescFlags.HasNativeCodeSlot); internal bool TemporaryEntryPointAssigned => HasFlag(MethodDescEntryPointFlags.TemporaryEntryPointAssigned); internal TargetPointer CodeData => _desc.CodeData; + + internal MethodClassification Classification => (MethodClassification)(_desc.Flags & (ushort)MethodDescFlags.ClassificationMask); + internal bool IsFCall => Classification == MethodClassification.FCall; + + #region Additional Pointers + private int AdditionalPointersHelper(MethodDescFlags extraFlags) + => int.PopCount(_desc.Flags & (ushort)extraFlags); + + // non-vtable slot, native code slot and MethodImpl slots are stored after the MethodDesc itself, packed tightly + // in the order: [non-vtable; native code; method-impl]. + internal int NonVtableSlotIndex => HasNonVtableSlot ? 0 : throw new InvalidOperationException("no non-vtable slot"); + internal int MethodImplIndex + { + get + { + if (!HasMethodImpl) + { + throw new InvalidOperationException("no method impl slot"); + } + return 1 + AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot); + } + } + internal int NativeCodeSlotIndex + { + get + { + if (!HasNativeCodeSlot) + { + throw new InvalidOperationException("no native code slot"); + } + return 1 + AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot | MethodDescFlags.HasNativeCodeSlot); + } + } + + internal int AdditionalPointersCount => AdditionalPointersHelper(MethodDescFlags.MethodDescAdditionalPointersMask); + #endregion Additional Pointers + + internal bool HasStableEntryPoint => HasFlag(MethodDescFlags3.HasStableEntryPoint); + internal bool HasPrecode => HasFlag(MethodDescFlags3.HasPrecode); + } + internal static MethodTable GetMethodTableData(Target target, TargetPointer methodTablePointer) { return new MethodTable(target, methodTablePointer); @@ -259,6 +304,103 @@ private TargetCodePointer GetTemporaryEntryPointIfExists(NonValidated.MethodDesc return codeData.TemporaryEntryPoint; } + private TargetPointer GetAddrOfNativeCodeSlot(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) + { + uint offset = MethodDescAdditioinalPointersOffset(umd); + offset += (uint)(_target.PointerSize * umd.NativeCodeSlotIndex); + return methodDescPointer.Value + offset; + } + + private TargetPointer GetAddresOfNonVtableSlot(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) + { + uint offset = MethodDescAdditioinalPointersOffset(umd); + offset += (uint)(_target.PointerSize * umd.NonVtableSlotIndex); + return methodDescPointer.Value + offset; + } + + private TargetCodePointer GetCodePointer(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) + { + // TODO(cdac): _ASSERTE(!IsDefaultInterfaceMethod() || HasNativeCodeSlot()); + if (umd.HasNativeCodeSlot) + { + // When profiler is enabled, profiler may ask to rejit a code even though we + // we have ngen code for this MethodDesc. (See MethodDesc::DoPrestub). + // This means that *ppCode is not stable. It can turn from non-zero to zero. + TargetPointer ppCode = GetAddrOfNativeCodeSlot(methodDescPointer, umd); + TargetCodePointer pCode = _target.ReadCodePointer(ppCode); + + // if arm32, set the thumb bit + Data.PrecodeMachineDescriptor precodeMachineDescriptor = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor)); + pCode = (TargetCodePointer)(pCode.Value | precodeMachineDescriptor.CodePointerToInstrPointerMask.Value); + + return pCode; + } + + if (!umd.HasStableEntryPoint || umd.HasPrecode) + return TargetCodePointer.Null; + + return GetStableEntryPoint(methodDescPointer, umd); + } + + private TargetCodePointer GetStableEntryPoint(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) + { + // TODO(cdac): _ASSERTE(HasStableEntryPoint()); + // TODO(cdac): _ASSERTE(!IsVersionableWithVtableSlotBackpatch()); + + return GetMethodEntryPointIfExists(methodDescPointer, umd); + } + + private TargetCodePointer GetMethodEntryPointIfExists(TargetPointer methodDescAddress, NonValidated.MethodDesc umd) + { + if (umd.HasNonVtableSlot) + { + TargetPointer pSlot = GetAddresOfNonVtableSlot(methodDescAddress, umd); + + return _target.ReadCodePointer(pSlot); + } + + TargetPointer methodTablePointer = umd.MethodTable; + TypeHandle typeHandle = GetTypeHandle(methodTablePointer); + // TODO: cdac: _ASSERTE(GetMethodTable()->IsCanonicalMethodTable()); + TargetPointer addrOfSlot = GetAddressOfSlot(typeHandle, umd.Slot); + return _target.ReadCodePointer(addrOfSlot); + } + + private uint MethodDescAdditioinalPointersOffset(NonValidated.MethodDesc umd) + { + MethodClassification cls = umd.Classification; + switch (cls) + { + case MethodClassification.IL: + return _target.GetTypeInfo(DataType.MethodDesc).Size ?? throw new InvalidOperationException("size of MethodDesc not known"); + case MethodClassification.FCall: + throw new NotImplementedException(); + case MethodClassification.NDirect: + throw new NotImplementedException(); + case MethodClassification.EEImpl: + throw new NotImplementedException(); + case MethodClassification.Array: + throw new NotImplementedException(); + case MethodClassification.Instantiated: + throw new NotImplementedException(); + case MethodClassification.ComInterop: + throw new NotImplementedException(); + case MethodClassification.Dynamic: + throw new NotImplementedException(); + default: + throw new InvalidOperationException($"Unexpected method classification 0x{cls:x2} for MethodDesc"); + } + } + + internal uint GetMethodDescBaseSize(NonValidated.MethodDesc umd) + { + uint baseSize = MethodDescAdditioinalPointersOffset(umd); + baseSize += (uint)(_target.PointerSize * umd.AdditionalPointersCount); + return baseSize; + } + + private bool HasNativeCode(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) => GetCodePointer(methodDescPointer, umd) != TargetCodePointer.Null; + private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNullWhen(true)] out TargetPointer methodDescChunkPointer) { methodDescChunkPointer = TargetPointer.Null; @@ -291,28 +433,15 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull } // TODO: request.cpp // TODO[cdac]: needs MethodDesc::GetNativeCode and MethodDesc::GetMethodEntryPoint() -#if false - if (retval && pMD->HasNativeCode() && !pMD->IsFCall()) - { - PCODE jitCodeAddr = pMD->GetNativeCode(); - - MethodDesc *pMDCheck = ExecutionManager::GetCodeMethodDesc(jitCodeAddr); - if (pMDCheck) + if (HasNativeCode(methodDescPointer, umd) && !umd.IsFCall) { - // Check that the given MethodDesc matches the MethodDesc from - // the CodeHeader - if (PTR_HOST_TO_TADDR(pMD) != PTR_HOST_TO_TADDR(pMDCheck)) + TargetCodePointer jitCodeAddr = GetCodePointer(methodDescPointer, umd); + TargetPointer methodDescCheckAddress = _target.Contracts.NativeCodePointers.MethodDescFromStubAddress(jitCodeAddr); + if (methodDescCheckAddress == TargetPointer.Null || methodDescCheckAddress != methodDescPointer) { - retval = FALSE; + return false; } } - else - { - retval = FALSE; - } - } -#endif - } catch (System.Exception) { @@ -324,4 +453,5 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull } return true; } + } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index eae54207e723a..b46debb9b1b31 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -90,7 +90,36 @@ internal enum MethodClassification internal enum MethodDescFlags : ushort { ClassificationMask = 0x7, + #region Additional pointers + // The below flags each imply that there's an extra pointer-sized piece of data after the MethodDesc in the MethodDescChunk HasNonVtableSlot = 0x0008, + HasMethodImpl = 0x0010, + HasNativeCodeSlot = 0x0020, + // Mask for the above flags + MethodDescAdditionalPointersMask = 0x0038, + #endregion Additional pointers + } + + [Flags] + internal enum MethodDescFlags3 : ushort + { + // HasPrecode implies that HasStableEntryPoint is set. + HasStableEntryPoint = 0x1000, // The method entrypoint is stable (either precode or actual code) + HasPrecode = 0x2000, // Precode has been allocated for this method + } + + internal enum MethodClassification + { + IL = 0, // IL + FCall = 1, // FCall (also includes tlbimped ctor, Delegate ctor) + NDirect = 2, // N/Direct + EEImpl = 3, // special method; implementation provided by EE (like Delegate Invoke) + Array = 4, // Array ECall + Instantiated = 5, // Instantiated generic methods, including descriptors + // for both shared and unshared code (see InstantiatedMethodDesc) + + ComInterop = 6, // if FEATURE_COMINTEROP + Dynamic = 7, // for method desc with no metadata behind } internal enum InstantiatedMethodDescFlags2 : ushort @@ -775,4 +804,34 @@ public bool IsILStub(MethodDescHandle methodDescHandle) return AsDynamicMethodDesc(methodDesc).IsILStub; } + + // FIXME: move to RuntimeT + private TargetPointer GetAddressOfSlot(TypeHandle typeHandle, uint slotNum) + { + if (!typeHandle.IsMethodTable()) + throw new InvalidOperationException("typeHandle is not a MethodTable"); + MethodTable mt = _methodTables[typeHandle.Address]; + // MethodTable::GetSlotPtrRaw + // TODO(cdac): CONSISTENCY_CHECK(slotNum < GetNumVtableSlots()); + + if (slotNum < mt.NumVirtuals) + { + // Virtual slots live in chunks pointed to by vtable indirections +#if false + return GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum); +#endif + throw new NotImplementedException(); // TODO(cdac): + } + else + { + // Non-virtual slots < GetNumVtableSlots live before the MethodTableAuxiliaryData. The array grows backwards + // TODO(cdac): _ASSERTE(HasNonVirtualSlots()); +#if false + return MethodTableAuxiliaryData::GetNonVirtualSlotsArray(GetAuxiliaryDataForWrite()) - (1 + (slotNum - GetNumVirtuals())); +#endif + throw new NotImplementedException(); // TODO(cdac): + } + + } + } From 2d1e34e9262117d09613c9d41619c656d020600b Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 29 Jul 2024 13:40:39 -0400 Subject: [PATCH 06/66] add contract --- src/coreclr/debug/runtimeinfo/contracts.jsonc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/debug/runtimeinfo/contracts.jsonc index 499a284cbcd70..235ce32ea0b11 100644 --- a/src/coreclr/debug/runtimeinfo/contracts.jsonc +++ b/src/coreclr/debug/runtimeinfo/contracts.jsonc @@ -13,6 +13,7 @@ "EcmaMetadata" : 1, "Exception": 1, "Loader": 1, + "NativeCodePointers": 1, "Object": 1, "RuntimeTypeSystem": 1, "Thread": 1 From 2d4252a0dc6b0935b083c89edb1df8df3baaf055 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 29 Jul 2024 13:56:24 -0400 Subject: [PATCH 07/66] add missing descriptor fields --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index fab7ea8acb561..6ae432fcd554e 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -348,6 +348,8 @@ CDAC_TYPE_END(MethodDescCodeData) CDAC_TYPE_BEGIN(PrecodeMachineDescriptor) CDAC_TYPE_INDETERMINATE(PrecodeMachineDescriptor) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uintptr*/, CodePointerToInstrPointerMask, offsetof(PrecodeMachineDescriptor, CodePointerToInstrPointerMask)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, ReadWidthOfPrecodeType, offsetof(PrecodeMachineDescriptor, ReadWidthOfPrecodeType)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, ShiftOfPrecodeType, offsetof(PrecodeMachineDescriptor, ShiftOfPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, OffsetOfPrecodeType, offsetof(PrecodeMachineDescriptor, OffsetOfPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, InvalidPrecodeType, offsetof(PrecodeMachineDescriptor, InvalidPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, StubPrecodeType, offsetof(PrecodeMachineDescriptor, StubPrecodeType)) From c83ad250d22ad8b1f1adb0b07df134c8ed4a837f Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 29 Jul 2024 14:19:15 -0400 Subject: [PATCH 08/66] fix data descriptor reads --- .../managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs index c4f2f8f2c926b..e61080d5f3fbf 100644 --- a/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs +++ b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs @@ -17,11 +17,11 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) ShiftOfPrecodeType = target.Read(address + (ulong)type.Fields[nameof(ShiftOfPrecodeType)].Offset); InvalidPrecodeType = target.Read(address + (ulong)type.Fields[nameof(InvalidPrecodeType)].Offset); StubPrecodeType = target.Read(address + (ulong)type.Fields[nameof(StubPrecodeType)].Offset); - if (target.ReadGlobal(HasNDirectImportPrecode) == 1) + if (target.Read(address + (ulong)type.Fields[nameof(HasNDirectImportPrecode)].Offset) == 1) { NDirectImportPrecodeType = target.Read(address + (ulong)type.Fields[nameof(NDirectImportPrecodeType)].Offset); } - if (target.ReadGlobal(HasFixupPrecode) == 1) + if (target.Read(address + (ulong)type.Fields[nameof(HasFixupPrecode)].Offset) == 1) { FixupPrecodeType = target.Read(address + (ulong)type.Fields[nameof(FixupPrecodeType)].Offset); } From c6dae6f6667c1a274c99dbf09eb4655920656203 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 29 Jul 2024 14:24:12 -0400 Subject: [PATCH 09/66] add FixupPrecodeData --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 5 +++++ .../src/Contracts/NativeCodePointers_1.cs | 5 ++++- .../cdacreader/src/Data/FixupPrecodeData.cs | 18 ++++++++++++++++++ src/native/managed/cdacreader/src/DataType.cs | 1 + 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/native/managed/cdacreader/src/Data/FixupPrecodeData.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 6ae432fcd554e..ac9117694c94b 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -366,6 +366,11 @@ CDAC_TYPE_FIELD(StubPrecodeData, /*pointer*/, MethodDesc, offsetof(StubPrecodeDa CDAC_TYPE_FIELD(StubPrecodeData, /*uint8*/, Type, offsetof(StubPrecodeData, Type)) CDAC_TYPE_END(StubPrecodeData) +CDAC_TYPE_BEGIN(FixupPrecodeData) +CDAC_TYPE_INDETERMINATE(FixupPrecodeData) +CDAC_TYPE_FIELD(FixupPrecodeData, /*pointer*/, MethodDesc, offsetof(FixupPrecodeData, MethodDesc)) +CDAC_TYPE_END(FixupPrecodeData) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 44be858ca4cb1..a1df509f99ce9 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -58,7 +58,10 @@ internal sealed class FixupPrecode : ValidPrecode internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } internal override TargetPointer GetMethodDesc(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) { - throw new NotImplementedException(); // TODO(cdac) + TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + Data.FixupPrecodeData fixupPrecodeData = target.ProcessedData.GetOrAdd(fixupPrecodeDataAddress); + return fixupPrecodeData.MethodDesc; + } } diff --git a/src/native/managed/cdacreader/src/Data/FixupPrecodeData.cs b/src/native/managed/cdacreader/src/Data/FixupPrecodeData.cs new file mode 100644 index 0000000000000..811508cc4354a --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/FixupPrecodeData.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 FixupPrecodeData : IData +{ + static FixupPrecodeData IData.Create(Target target, TargetPointer address) + => new FixupPrecodeData(target, address); + + public FixupPrecodeData(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.FixupPrecodeData); + MethodDesc = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodDesc)].Offset); + } + + public TargetPointer MethodDesc { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index ffb3df4f868e3..294c598c5fbc3 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -46,6 +46,7 @@ public enum DataType MethodDescCodeData, PrecodeMachineDescriptor, StubPrecodeData, + FixupPrecodeData, Array, SyncBlock, SyncTableEntry, From 43e174843e08e0ce2c7f77eeb2382eaad241a33a Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 29 Jul 2024 15:27:54 -0400 Subject: [PATCH 10/66] add size of MethodDesc --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index ac9117694c94b..6f9d898c69999 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -299,7 +299,7 @@ CDAC_TYPE_FIELD(DynamicMetadata, /*inline byte array*/, Data, cdac_data::ChunkIndex) CDAC_TYPE_FIELD(MethodDesc, /*uint16*/, Slot, cdac_data::Slot) CDAC_TYPE_FIELD(MethodDesc, /*uint16*/, Flags, cdac_data::Flags) From 72369e38ab1cbc2b66d7c0389b1eef55963f0c26 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 29 Jul 2024 15:28:06 -0400 Subject: [PATCH 11/66] fix thumb flag logic --- .../src/Contracts/RuntimeTypeSystem_1.NonValidated.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 5e6255b15d0aa..ed17142ca0b52 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -331,7 +331,7 @@ private TargetCodePointer GetCodePointer(TargetPointer methodDescPointer, NonVal // if arm32, set the thumb bit Data.PrecodeMachineDescriptor precodeMachineDescriptor = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor)); - pCode = (TargetCodePointer)(pCode.Value | precodeMachineDescriptor.CodePointerToInstrPointerMask.Value); + pCode = (TargetCodePointer)(pCode.Value | ~precodeMachineDescriptor.CodePointerToInstrPointerMask.Value); return pCode; } From 93f0a3d2cadbe84404f8aa8cfda45ac7b452f7ce Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 29 Jul 2024 15:46:02 -0400 Subject: [PATCH 12/66] WIP - broken - ExecutionManagerGetCodeMethodDesc --- .../debug/runtimeinfo/datadescriptor.h | 1 + src/coreclr/vm/codeman.h | 20 ++++++--- .../src/Contracts/NativeCodePointers.cs | 1 + .../src/Contracts/NativeCodePointers_1.cs | 43 +++++++++++++++++++ .../RuntimeTypeSystem_1.NonValidated.cs | 13 ++++-- 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 6f9d898c69999..51b4bef028e9f 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -410,6 +410,7 @@ CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable) CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize) CDAC_GLOBAL_POINTER(PrecodeMachineDescriptor, &::g_PrecodeMachineDescriptor) +CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_offsets::CodeRangeMapAddress) CDAC_GLOBALS_END() #undef CDAC_BASELINE diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 0ff86927b6a58..25e3cf8c7dd33 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -835,7 +835,7 @@ class RangeSectionMap { // Upgrade to non-collectible #ifdef _DEBUG - TADDR initialValue = + TADDR initialValue = #endif InterlockedCompareExchangeT(&_ptr, ptr - 1, ptr); assert(initialValue == ptr || initialValue == (ptr - 1)); @@ -951,7 +951,7 @@ class RangeSectionMap auto levelNew = static_castVolatileLoad(NULL))[0])>(AllocateLevel()); if (levelNew == NULL) return NULL; - + if (!outerLevel->Install(levelNew, collectible)) { // Handle race where another thread grew the table @@ -1017,7 +1017,7 @@ class RangeSectionMap auto rangeSectionL3 = rangeSectionL3Ptr->VolatileLoadWithoutBarrier(pLockState); if (rangeSectionL3 == NULL) return NULL; - + auto rangeSectionL2Ptr = &((*rangeSectionL3)[EffectiveBitsForLevel(address, 3)]); if (level == 2) return rangeSectionL2Ptr; @@ -1071,7 +1071,7 @@ class RangeSectionMap // Account for the range not starting at the beginning of a last level fragment rangeSize += pRangeSection->_range.RangeStart() & (bytesAtLastLevel - 1); - + uintptr_t fragmentCount = ((rangeSize - 1) / bytesAtLastLevel) + 1; return fragmentCount; } @@ -1314,7 +1314,7 @@ class RangeSectionMap else { // Since the fragment linked lists are sorted such that the collectible ones are always after the non-collectible ones, this should never happen. - assert(!seenCollectibleRangeList); + assert(!seenCollectibleRangeList); } #endif entryInMapToUpdate = &(entryInMapToUpdate->VolatileLoadWithoutBarrier(pLockState))->pRangeSectionFragmentNext; @@ -1355,7 +1355,7 @@ class RangeSectionMap if (foundMeaningfulValue) break; - + // This level is completely empty. Free it, and then null out the pointer to it. pointerToLevelData->Uninstall(); #if defined(__GNUC__) @@ -2246,6 +2246,14 @@ class ExecutionManager JumpStubBlockHeader * m_pBlocks; JumpStubTable m_Table; }; + + template friend struct ::cdac_offsets; +}; + +template<> +struct cdac_offsets +{ + static constexpr void* CodeRangeMapAddress = &ExecutionManager::g_codeRangeMap; }; inline CodeHeader * EEJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index ba1bc76a130a3..5064fceb5c6c3 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -20,6 +20,7 @@ static IContract IContract.Create(Target target, int version) } public virtual TargetPointer MethodDescFromStubAddress(TargetCodePointer codeAddress) => throw new NotImplementedException(); + public virtual TargetPointer ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); } internal readonly struct NativeCodePointers : INativeCodePointers diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index a1df509f99ce9..065174d431b8d 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -172,4 +172,47 @@ TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer en return precode.GetMethodDesc(_target, _precodeMachineDescriptor); } + + + private class EECodeInfo + { + public TargetCodePointer CodeAddress { get; } + public TargetPointer MethodDescAddress { get; } + public EECodeInfo(TargetCodePointer jittedCodeAdderss, TargetPointer methodDescAddress) + { + CodeAddress = jittedCodeAdderss; + MethodDescAddress = methodDescAddress; + } + + bool Valid => CodeAddress != default && MethodDescAddress != default; + } + + private sealed class RangeSection + { + + } + + private EECodeInfo GetEECodeInfo(TargetCodePointer jittedCodeAddress) + { + RangeSection range = ExecutionManagerFindCodeRange(jittedCodeAddress); + if (!range.JitCodeToMethodInfo(jittedCodeAddress, out TargetPointer methodDescAddress)) + { + return default(EECodeInfo); + } + return new EECodeInfo(jittedCodeAddress, methodDescAddress); + } + + private RangeSection ExecutionManagerFindCodeRange(TargetCodePointer jittedCodeAddress) + { + // GetCodeRangeMap()->LookupRangeSection(addr, pLockState); + + throw new NotImplementedException(); // TODO(cdac) + } + + TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) + { + EECodeInfo info = GetEECodeInfo(jittedCodeAddress); + return info.MethodDescAddress; + } + } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index ed17142ca0b52..58fb7ae476bdb 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -431,13 +431,18 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull return false; } } - // TODO: request.cpp - // TODO[cdac]: needs MethodDesc::GetNativeCode and MethodDesc::GetMethodEntryPoint() + if (HasNativeCode(methodDescPointer, umd) && !umd.IsFCall) { TargetCodePointer jitCodeAddr = GetCodePointer(methodDescPointer, umd); - TargetPointer methodDescCheckAddress = _target.Contracts.NativeCodePointers.MethodDescFromStubAddress(jitCodeAddr); - if (methodDescCheckAddress == TargetPointer.Null || methodDescCheckAddress != methodDescPointer) + //FIXME: this is the wrong code. + + TargetPointer methodDesc = _target.Contracts.NativeCodePointers.ExecutionManagerGetCodeMethodDesc(jitCodeAddr); + if (methodDesc == TargetPointer.Null) + { + return false; + } + if (methodDesc != methodDescPointer) { return false; } From 58aa6147d72ef521c664478f3b0f94d60a0bd9bb Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 30 Jul 2024 10:57:06 -0400 Subject: [PATCH 13/66] fix build --- src/coreclr/vm/codeman.h | 12 +++- .../managed/cdacreader/src/Constants.cs | 2 + .../src/Contracts/NativeCodePointers.cs | 3 +- .../src/Contracts/NativeCodePointers_1.cs | 70 +++++++++++++++++-- 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 25e3cf8c7dd33..bf0b6bb279b5f 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -1432,8 +1432,16 @@ class RangeSectionMap } #endif// DACCESS_COMPILE + template friend struct ::cdac_offsets; }; +template<> +struct cdac_offsets +{ + +}; + + struct RangeSectionMapData { BYTE Data[sizeof(RangeSectionMap)]; @@ -2250,11 +2258,13 @@ class ExecutionManager template friend struct ::cdac_offsets; }; +#ifndef DACCESS_COMPILE template<> struct cdac_offsets { - static constexpr void* CodeRangeMapAddress = &ExecutionManager::g_codeRangeMap; + static constexpr void* const CodeRangeMapAddress = (void*)&ExecutionManager::g_codeRangeMap.Data[0]; }; +#endif inline CodeHeader * EEJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) { diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs index 8003156a6c99c..cb63cb6098b18 100644 --- a/src/native/managed/cdacreader/src/Constants.cs +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -40,5 +40,7 @@ internal static class Globals internal const string DirectorySeparator = nameof(DirectorySeparator); internal const string PrecodeMachineDescriptor = nameof(PrecodeMachineDescriptor); + + internal const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index 5064fceb5c6c3..9d4d99614630b 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -12,9 +12,10 @@ static IContract IContract.Create(Target target, int version) { TargetPointer precodeMachineDescriptorAddress = target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor); Data.PrecodeMachineDescriptor precodeMachineDescriptor = target.ProcessedData.GetOrAdd(precodeMachineDescriptorAddress); + TargetPointer executionManagerCodeRangeMapAddress = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress); return version switch { - 1 => new NativeCodePointers_1(target, precodeMachineDescriptor), + 1 => new NativeCodePointers_1(target, precodeMachineDescriptor, executionManagerCodeRangeMapAddress), _ => default(NativeCodePointers), }; } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 065174d431b8d..aa4b841ba7917 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -10,6 +10,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; { private readonly Target _target; private readonly Data.PrecodeMachineDescriptor _precodeMachineDescriptor; + private readonly TargetPointer _executionManagerCodeRangeMapAddress; private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); @@ -129,10 +130,11 @@ private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) } } - public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor, TargetPointer executionManagerCodeRangeMapAddress) { _target = target; _precodeMachineDescriptor = precodeMachineDescriptor; + _executionManagerCodeRangeMapAddress = executionManagerCodeRangeMapAddress; } internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) @@ -184,20 +186,23 @@ public EECodeInfo(TargetCodePointer jittedCodeAdderss, TargetPointer methodDescA MethodDescAddress = methodDescAddress; } - bool Valid => CodeAddress != default && MethodDescAddress != default; + public bool Valid => CodeAddress != default && MethodDescAddress != default; } private sealed class RangeSection { - + public bool JitCodeToMethodInfo(TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + { + throw new NotImplementedException(); + } } - private EECodeInfo GetEECodeInfo(TargetCodePointer jittedCodeAddress) + private EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) { RangeSection range = ExecutionManagerFindCodeRange(jittedCodeAddress); if (!range.JitCodeToMethodInfo(jittedCodeAddress, out TargetPointer methodDescAddress)) { - return default(EECodeInfo); + return null; } return new EECodeInfo(jittedCodeAddress, methodDescAddress); } @@ -209,9 +214,62 @@ private RangeSection ExecutionManagerFindCodeRange(TargetCodePointer jittedCodeA throw new NotImplementedException(); // TODO(cdac) } + private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) + { +#if false + PTR_RangeSectionFragment fragment = GetRangeSectionForAddress(address, pLockState); + if (fragment == NULL) + return NULL; + + while ((fragment != NULL) && !fragment->InRange(address)) + { + fragment = fragment->pRangeSectionFragmentNext.VolatileLoadWithoutBarrier(pLockState); + } + + if (fragment != NULL) + { + if (fragment->pRangeSection->_pRangeSectionNextForDelete != NULL) + return NULL; + return fragment->pRangeSection; + } +#endif + throw new NotImplementedException(); + } + +#if false + PTR_RangeSectionFragment GetRangeSectionForAddress(TADDR address, RangeSectionLockState* pLockState) + { + uintptr_t topLevelIndex = EffectiveBitsForLevel(address, mapLevels); + auto nextLevelAddress = &(GetTopLevel()[topLevelIndex]); + ifdef TARGET_64BIT + auto rangeSectionL4 = nextLevelAddress->VolatileLoad(pLockState); + if (rangeSectionL4 == NULL) + return NULL; + auto rangeSectionL3 = (*rangeSectionL4)[EffectiveBitsForLevel(address, 4)].VolatileLoadWithoutBarrier(pLockState); + if (rangeSectionL3 == NULL) + return NULL; + auto rangeSectionL2 = (*rangeSectionL3)[EffectiveBitsForLevel(address, 3)].VolatileLoadWithoutBarrier(pLockState); + if (rangeSectionL2 == NULL) + return NULL; + auto rangeSectionL1 = (*rangeSectionL2)[EffectiveBitsForLevel(address, 2)].VolatileLoadWithoutBarrier(pLockState); + else + auto rangeSectionL1 = nextLevelAddress->VolatileLoad(pLockState); + endif + if (rangeSectionL1 == NULL) + return NULL; + + return ((*rangeSectionL1)[EffectiveBitsForLevel(address, 1)]).VolatileLoadWithoutBarrier(pLockState); + throw new NotImplementedException(); + } +#endif + TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) { - EECodeInfo info = GetEECodeInfo(jittedCodeAddress); + EECodeInfo? info = GetEECodeInfo(jittedCodeAddress); + if (info == null || !info.Valid) + { + throw new InvalidOperationException($"Failed to get EECodeInfo for {jittedCodeAddress}"); + } return info.MethodDescAddress; } From 4c211d4d61f2c6eb595291d0d5cb84438c97f435 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 30 Jul 2024 11:06:33 -0400 Subject: [PATCH 14/66] fixup cdac_offsets<> -> cdac_data<> --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 2 +- src/coreclr/vm/codeman.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 51b4bef028e9f..ae3834599066f 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -410,7 +410,7 @@ CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable) CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize) CDAC_GLOBAL_POINTER(PrecodeMachineDescriptor, &::g_PrecodeMachineDescriptor) -CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_offsets::CodeRangeMapAddress) +CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_data::CodeRangeMapAddress) CDAC_GLOBALS_END() #undef CDAC_BASELINE diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index bf0b6bb279b5f..fc743fab583be 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -1432,11 +1432,11 @@ class RangeSectionMap } #endif// DACCESS_COMPILE - template friend struct ::cdac_offsets; + template friend struct ::cdac_data; }; template<> -struct cdac_offsets +struct cdac_data { }; @@ -2255,12 +2255,12 @@ class ExecutionManager JumpStubTable m_Table; }; - template friend struct ::cdac_offsets; + template friend struct ::cdac_data; }; #ifndef DACCESS_COMPILE template<> -struct cdac_offsets +struct cdac_data { static constexpr void* const CodeRangeMapAddress = (void*)&ExecutionManager::g_codeRangeMap.Data[0]; }; From ce772d96b73dc457bed45fcd4653fed473f59c81 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 31 Jul 2024 10:38:49 -0400 Subject: [PATCH 15/66] WIP RangeSectionMap --- .../debug/runtimeinfo/datadescriptor.h | 20 +++ src/coreclr/vm/codeman.h | 20 +++ .../src/Contracts/NativeCodePointers.cs | 3 +- .../src/Contracts/NativeCodePointers_1.cs | 159 ++++++++++++++---- .../cdacreader/src/Data/RangeSection.cs | 22 +++ .../src/Data/RangeSectionFragment.cs | 24 +++ .../cdacreader/src/Data/RangeSectionMap.cs | 19 +++ src/native/managed/cdacreader/src/DataType.cs | 3 + 8 files changed, 234 insertions(+), 36 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/RangeSection.cs create mode 100644 src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs create mode 100644 src/native/managed/cdacreader/src/Data/RangeSectionMap.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index ae3834599066f..f9eb8c30c41b4 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -371,6 +371,26 @@ CDAC_TYPE_INDETERMINATE(FixupPrecodeData) CDAC_TYPE_FIELD(FixupPrecodeData, /*pointer*/, MethodDesc, offsetof(FixupPrecodeData, MethodDesc)) CDAC_TYPE_END(FixupPrecodeData) +CDAC_TYPE_BEGIN(RangeSectionMap) +CDAC_TYPE_INDETERMINATE(RangeSectionMap) +CDAC_TYPE_FIELD(RangeSectionMap, /*pointer*/, TopLevelData, cdac_data::TopLevelData) +CDAC_TYPE_END(RangeSectionMap) + +CDAC_TYPE_BEGIN(RangeSectionFragment) +CDAC_TYPE_INDETERMINATE(RangeSectionFragment) +CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeBegin, cdac_data::RangeSectionFragment::RangeBegin) +CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeEndOpen, cdac_data::RangeSectionFragment::RangeEndOpen) +CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeSection, cdac_data::RangeSectionFragment::RangeSection) +CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, Next, cdac_data::RangeSectionFragment::Next) +CDAC_TYPE_END(RangeSectionFragment) + +CDAC_TYPE_BEGIN(RangeSection) +CDAC_TYPE_INDETERMINATE(RangeSection) +CDAC_TYPE_FIELD(RangeSection, /*pointer*/, RangeBegin, cdac_data::RangeBegin) +CDAC_TYPE_FIELD(RangeSection, /*pointer*/, RangeEndOpen, cdac_data::RangeEndOpen) +CDAC_TYPE_FIELD(RangeSection, /*pointer*/, NextForDelete, cdac_data::NextForDelete) +CDAC_TYPE_END(RangeSection) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index fc743fab583be..379af550bf121 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -555,6 +555,8 @@ class Range { return end; } + + template friend struct ::cdac_data; }; struct RangeSection @@ -626,6 +628,15 @@ struct RangeSection RangeSection* _pRangeSectionNextForDelete = NULL; // Used for adding to the cleanup list + + template friend struct ::cdac_data; +}; + +template<> struct cdac_data +{ + static constexpr size_t RangeBegin = offsetof(RangeSection, _range.begin); + static constexpr size_t RangeEndOpen = offsetof(RangeSection, _range.end); + static constexpr size_t NextForDelete = offsetof(RangeSection, _pRangeSectionNextForDelete); }; enum class RangeSectionLockState @@ -1438,10 +1449,19 @@ class RangeSectionMap template<> struct cdac_data { + static constexpr size_t TopLevelData = offsetof(RangeSectionMap, _topLevelData); + struct RangeSectionFragment + { + static constexpr size_t RangeBegin = offsetof(RangeSectionMap::RangeSectionFragment, _range.begin); + static constexpr size_t RangeEndOpen = offsetof(RangeSectionMap::RangeSectionFragment, _range.end); + static constexpr size_t RangeSection = offsetof(RangeSectionMap::RangeSectionFragment, pRangeSection); + static constexpr size_t Next = offsetof(RangeSectionMap::RangeSectionFragment, pRangeSectionFragmentNext); + }; }; + struct RangeSectionMapData { BYTE Data[sizeof(RangeSectionMap)]; diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index 9d4d99614630b..666e0fa153fa5 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -13,9 +13,10 @@ static IContract IContract.Create(Target target, int version) TargetPointer precodeMachineDescriptorAddress = target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor); Data.PrecodeMachineDescriptor precodeMachineDescriptor = target.ProcessedData.GetOrAdd(precodeMachineDescriptorAddress); TargetPointer executionManagerCodeRangeMapAddress = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress); + Data.RangeSectionMap rangeSectionMap = target.ProcessedData.GetOrAdd(executionManagerCodeRangeMapAddress); return version switch { - 1 => new NativeCodePointers_1(target, precodeMachineDescriptor, executionManagerCodeRangeMapAddress), + 1 => new NativeCodePointers_1(target, precodeMachineDescriptor, rangeSectionMap), _ => default(NativeCodePointers), }; } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index aa4b841ba7917..4b76ff8eefdc5 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -10,7 +9,8 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; { private readonly Target _target; private readonly Data.PrecodeMachineDescriptor _precodeMachineDescriptor; - private readonly TargetPointer _executionManagerCodeRangeMapAddress; + private readonly Data.RangeSectionMap _topRangeSectionMap; + private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); @@ -41,7 +41,7 @@ internal class StubPrecode : ValidPrecode { internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } - internal override TargetPointer GetMethodDesc(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) { TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; Data.StubPrecodeData stubPrecodeData = target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); @@ -57,7 +57,7 @@ internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, K internal sealed class FixupPrecode : ValidPrecode { internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } - internal override TargetPointer GetMethodDesc(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) { TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; Data.FixupPrecodeData fixupPrecodeData = target.ProcessedData.GetOrAdd(fixupPrecodeDataAddress); @@ -70,7 +70,7 @@ internal sealed class ThisPtrRetBufPrecode : ValidPrecode // FIXME: is this a St { internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } - internal override TargetPointer GetMethodDesc(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) { throw new NotImplementedException(); // TODO(cdac) } @@ -130,11 +130,12 @@ private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) } } - public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor, TargetPointer executionManagerCodeRangeMapAddress) + public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor, Data.RangeSectionMap topRangeSectionMap) { _target = target; _precodeMachineDescriptor = precodeMachineDescriptor; - _executionManagerCodeRangeMapAddress = executionManagerCodeRangeMapAddress; + _topRangeSectionMap = topRangeSectionMap; ; + _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); } internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) @@ -189,17 +190,66 @@ public EECodeInfo(TargetCodePointer jittedCodeAdderss, TargetPointer methodDescA public bool Valid => CodeAddress != default && MethodDescAddress != default; } + private readonly struct TargetCodeManagerDescriptor + { + public int MapLevels { get; } + public int BitsPerLevel { get; } = 8; + public int MaxSetBit { get; } + public int EntriesPerMapLevel { get; } = 256; + + private TargetCodeManagerDescriptor(int mapLevels, int maxSetBit) + { + MapLevels = mapLevels; + MaxSetBit = maxSetBit; + } + public static TargetCodeManagerDescriptor Create(Target target) + { + if (target.PointerSize == 4) + { + return new(mapLevels: 2, maxSetBit: 31); // 0 indexed + } + else if (target.PointerSize == 8) + { + return new(mapLevels: 5, maxSetBit: 56); // 0 indexed + } + else + { + throw new InvalidOperationException("Invalid pointer size"); + } + } + } + private sealed class RangeSection { + private readonly Data.RangeSection? _rangeSection; + + public RangeSection() + { + _rangeSection = default; + } + public RangeSection(Data.RangeSection rangeSection) + { + _rangeSection = rangeSection; + } public bool JitCodeToMethodInfo(TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) { throw new NotImplementedException(); } + + // note: level is 1-indexed + public static uint EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, TargetCodePointer address, int level) + { + ulong addressAsInt = address.Value; + ulong addressBitsUsedInMap = addressAsInt >> (descriptor.MaxSetBit + 1 - (descriptor.MapLevels * descriptor.BitsPerLevel)); + ulong addressBitsShifted = addressBitsUsedInMap >> ((level - 1) * descriptor.BitsPerLevel); + ulong addressBitsUsedInLevel = (ulong)(descriptor.EntriesPerMapLevel - 1) & addressBitsShifted; + return checked((uint)addressBitsUsedInLevel); + } } private EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) { - RangeSection range = ExecutionManagerFindCodeRange(jittedCodeAddress); + RangeSection range = LookupRangeSection(jittedCodeAddress); if (!range.JitCodeToMethodInfo(jittedCodeAddress, out TargetPointer methodDescAddress)) { return null; @@ -207,15 +257,38 @@ public bool JitCodeToMethodInfo(TargetCodePointer jittedCodeAddress, out TargetP return new EECodeInfo(jittedCodeAddress, methodDescAddress); } - private RangeSection ExecutionManagerFindCodeRange(TargetCodePointer jittedCodeAddress) + private static bool InRange(Data.RangeSectionFragment fragment, TargetCodePointer address) { - // GetCodeRangeMap()->LookupRangeSection(addr, pLockState); - - throw new NotImplementedException(); // TODO(cdac) + return fragment.RangeBegin <= address && address < fragment.RangeEndOpen; } private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) { + TargetPointer rangeSectionFragmentPtr = GetRangeSectionForAddress(jittedCodeAddress); + if (rangeSectionFragmentPtr == TargetPointer.Null) + { + return new RangeSection(); + } + while (rangeSectionFragmentPtr != TargetPointer.Null) + { + Data.RangeSectionFragment fragment = _target.ProcessedData.GetOrAdd(rangeSectionFragmentPtr); + if (InRange(fragment, jittedCodeAddress)) + { + break; + } + rangeSectionFragmentPtr = fragment.Next; // TODO: load? + } + if (rangeSectionFragmentPtr != TargetPointer.Null) + { + Data.RangeSectionFragment fragment = _target.ProcessedData.GetOrAdd(rangeSectionFragmentPtr); + Data.RangeSection rangeSection = _target.ProcessedData.GetOrAdd(fragment.RangeSection); + if (rangeSection.NextForDelete != TargetPointer.Null) + { + return new RangeSection(); + } + return new RangeSection(rangeSection); + } + return new RangeSection(); #if false PTR_RangeSectionFragment fragment = GetRangeSectionForAddress(address, pLockState); if (fragment == NULL) @@ -236,32 +309,48 @@ private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) throw new NotImplementedException(); } -#if false - PTR_RangeSectionFragment GetRangeSectionForAddress(TADDR address, RangeSectionLockState* pLockState) + private TargetPointer RangeSectionPointerLoad(TargetPointer ptr) { - uintptr_t topLevelIndex = EffectiveBitsForLevel(address, mapLevels); - auto nextLevelAddress = &(GetTopLevel()[topLevelIndex]); - ifdef TARGET_64BIT - auto rangeSectionL4 = nextLevelAddress->VolatileLoad(pLockState); - if (rangeSectionL4 == NULL) - return NULL; - auto rangeSectionL3 = (*rangeSectionL4)[EffectiveBitsForLevel(address, 4)].VolatileLoadWithoutBarrier(pLockState); - if (rangeSectionL3 == NULL) - return NULL; - auto rangeSectionL2 = (*rangeSectionL3)[EffectiveBitsForLevel(address, 3)].VolatileLoadWithoutBarrier(pLockState); - if (rangeSectionL2 == NULL) - return NULL; - auto rangeSectionL1 = (*rangeSectionL2)[EffectiveBitsForLevel(address, 2)].VolatileLoadWithoutBarrier(pLockState); - else - auto rangeSectionL1 = nextLevelAddress->VolatileLoad(pLockState); - endif - if (rangeSectionL1 == NULL) - return NULL; + // clear the lowest bit, which is used as a tag for collectible levels, and read the pointer + return _target.ReadPointer(ptr.Value & (ulong)~1u); + } - return ((*rangeSectionL1)[EffectiveBitsForLevel(address, 1)]).VolatileLoadWithoutBarrier(pLockState); - throw new NotImplementedException(); + private TargetPointer /*PTR_RangeSectionFragment*/ GetRangeSectionForAddress(TargetCodePointer jittedCodeAddress) + { + uint topLevelIndex = RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, _targetCodeManagerDescriptor.MapLevels); + + TargetPointer nextLevelAddress = _topRangeSectionMap.TopLevelData + (ulong)_target.PointerSize * topLevelIndex; + TargetPointer rangeSectionL1; + if (_target.PointerSize == 8) + { + TargetPointer rangeSectionL4 = RangeSectionPointerLoad(nextLevelAddress); + if (rangeSectionL4 == TargetPointer.Null) + return TargetPointer.Null; + nextLevelAddress = rangeSectionL4 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 4); + TargetPointer rangeSectionL3 = RangeSectionPointerLoad(nextLevelAddress); + if (rangeSectionL3 == TargetPointer.Null) + return TargetPointer.Null; + nextLevelAddress = rangeSectionL3 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 3); + TargetPointer rangeSectionL2 = RangeSectionPointerLoad(nextLevelAddress); + if (rangeSectionL2 == TargetPointer.Null) + return TargetPointer.Null; + nextLevelAddress = rangeSectionL2 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 2); + rangeSectionL1 = RangeSectionPointerLoad(nextLevelAddress); + + } + else if (_target.PointerSize == 4) + { + rangeSectionL1 = RangeSectionPointerLoad(nextLevelAddress); + } + else + { + throw new InvalidOperationException("Invalid pointer size"); + } + if (rangeSectionL1 == TargetPointer.Null) + return TargetPointer.Null; + nextLevelAddress = rangeSectionL1 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 1); + return RangeSectionPointerLoad(nextLevelAddress); } -#endif TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) { diff --git a/src/native/managed/cdacreader/src/Data/RangeSection.cs b/src/native/managed/cdacreader/src/Data/RangeSection.cs new file mode 100644 index 0000000000000..32795db52f65e --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/RangeSection.cs @@ -0,0 +1,22 @@ +// 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 RangeSection : IData +{ + static RangeSection IData.Create(Target target, TargetPointer address) + => new RangeSection(target, address); + + public RangeSection(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.RangeSection); + RangeBegin = target.ReadPointer(address + (ulong)type.Fields[nameof(RangeBegin)].Offset); + RangeEndOpen = target.ReadPointer(address + (ulong)type.Fields[nameof(RangeEndOpen)].Offset); + NextForDelete = target.ReadPointer(address + (ulong)type.Fields[nameof(NextForDelete)].Offset); + } + + public TargetPointer RangeBegin { get; init; } + public TargetPointer RangeEndOpen { get; init; } + public TargetPointer NextForDelete { get; init; } +} diff --git a/src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs b/src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs new file mode 100644 index 0000000000000..5ae05ec16910f --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs @@ -0,0 +1,24 @@ +// 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 RangeSectionFragment : IData +{ + static RangeSectionFragment IData.Create(Target target, TargetPointer address) + => new RangeSectionFragment(target, address); + + public RangeSectionFragment(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.RangeSectionFragment); + RangeBegin = target.ReadPointer(address + (ulong)type.Fields[nameof(RangeBegin)].Offset); + RangeEndOpen = target.ReadPointer(address + (ulong)type.Fields[nameof(RangeEndOpen)].Offset); + RangeSection = target.ReadPointer(address + (ulong)type.Fields[nameof(RangeSection)].Offset); + Next = target.ReadPointer(address + (ulong)type.Fields[nameof(Next)].Offset); + } + + public TargetPointer RangeBegin { get; init; } + public TargetPointer RangeEndOpen { get; init; } + public TargetPointer RangeSection { get; init; } + public TargetPointer Next { get; init; } +} diff --git a/src/native/managed/cdacreader/src/Data/RangeSectionMap.cs b/src/native/managed/cdacreader/src/Data/RangeSectionMap.cs new file mode 100644 index 0000000000000..aa0539cedddcb --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/RangeSectionMap.cs @@ -0,0 +1,19 @@ +// 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 RangeSectionMap : IData +{ + static RangeSectionMap IData.Create(Target target, TargetPointer address) + => new RangeSectionMap(target, address); + + public RangeSectionMap(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.RangeSectionMap); + TopLevelData = new TargetPointer(address + (ulong)type.Fields[nameof(TopLevelData)].Offset); + } + + // pointer to first element + public TargetPointer TopLevelData { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 294c598c5fbc3..48976f97dba0f 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -54,4 +54,7 @@ public enum DataType InstantiatedMethodDesc, DynamicMethodDesc, StoredSigMethodDesc, + RangeSectionMap, + RangeSectionFragment, + RangeSection, } From 891f07f41218a8740ddccb59c4b8fd483747dca1 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 31 Jul 2024 13:31:45 -0400 Subject: [PATCH 16/66] tag ExecutionManager pointers --- .../debug/runtimeinfo/datadescriptor.h | 2 +- src/coreclr/vm/codeman.h | 2 + .../NativeCodePointers_1.ExecutionManager.cs | 190 ++++++++++ .../Contracts/NativeCodePointers_1.Precode.cs | 172 +++++++++ .../src/Contracts/NativeCodePointers_1.cs | 342 +----------------- 5 files changed, 373 insertions(+), 335 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs create mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index f9eb8c30c41b4..d6144dc6c760d 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -377,7 +377,7 @@ CDAC_TYPE_FIELD(RangeSectionMap, /*pointer*/, TopLevelData, cdac_data::RangeSectionFragmentSize) CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeBegin, cdac_data::RangeSectionFragment::RangeBegin) CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeEndOpen, cdac_data::RangeSectionFragment::RangeEndOpen) CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeSection, cdac_data::RangeSectionFragment::RangeSection) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 379af550bf121..246845aa365f0 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -1458,6 +1458,8 @@ struct cdac_data static constexpr size_t RangeSection = offsetof(RangeSectionMap::RangeSectionFragment, pRangeSection); static constexpr size_t Next = offsetof(RangeSectionMap::RangeSectionFragment, pRangeSectionFragmentNext); }; + + static constexpr size_t RangeSectionFragmentSize = sizeof(RangeSectionMap::RangeSectionFragment); }; diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs new file mode 100644 index 0000000000000..98590fb7809e1 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -0,0 +1,190 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly partial struct NativeCodePointers_1 : INativeCodePointers +{ + internal class EECodeInfo + { + public TargetCodePointer CodeAddress { get; } + public TargetPointer MethodDescAddress { get; } + public EECodeInfo(TargetCodePointer jittedCodeAdderss, TargetPointer methodDescAddress) + { + CodeAddress = jittedCodeAdderss; + MethodDescAddress = methodDescAddress; + } + + public bool Valid => CodeAddress != default && MethodDescAddress != default; + } + + // RangeFragment and RangeSection pointers have a collectible flag on the lowest bit + private struct ExMgrPtr + { + public readonly TargetPointer RawValue; + + public TargetPointer Address => RawValue & (ulong)~1u; + + public bool IsNull => Address == TargetPointer.Null; + + public static ExMgrPtr Null => new ExMgrPtr(TargetPointer.Null); + + public ExMgrPtr(TargetPointer value) + { + RawValue = value; + } + + public ExMgrPtr Offset(int stride, int idx) + { + return new ExMgrPtr(RawValue.Value + (ulong)(stride * idx)); + } + + public T Load(Target target) where T : Data.IData + { + return target.ProcessedData.GetOrAdd(Address); + } + + public ExMgrPtr LoadPointer(Target target) + { + return new ExMgrPtr(target.ReadPointer(Address)); + } + } + + private readonly struct TargetCodeManagerDescriptor + { + public int MapLevels { get; } + public int BitsPerLevel { get; } = 8; + public int MaxSetBit { get; } + public int EntriesPerMapLevel { get; } = 256; + + private TargetCodeManagerDescriptor(int mapLevels, int maxSetBit) + { + MapLevels = mapLevels; + MaxSetBit = maxSetBit; + } + public static TargetCodeManagerDescriptor Create(Target target) + { + if (target.PointerSize == 4) + { + return new(mapLevels: 2, maxSetBit: 31); // 0 indexed + } + else if (target.PointerSize == 8) + { + return new(mapLevels: 5, maxSetBit: 56); // 0 indexed + } + else + { + throw new InvalidOperationException("Invalid pointer size"); + } + } + } + + + internal struct ExecutionManagerContract + { + internal readonly Target _target; + private readonly Data.RangeSectionMap _topRangeSectionMap; + private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; + + public ExecutionManagerContract(Target target, Data.RangeSectionMap topRangeSectionMap) + { + _target = target; + _topRangeSectionMap = topRangeSectionMap; + _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); + } + + private sealed class RangeSection + { + private readonly Data.RangeSection? _rangeSection; + + public RangeSection() + { + _rangeSection = default; + } + public RangeSection(Data.RangeSection rangeSection) + { + _rangeSection = rangeSection; + } + public bool JitCodeToMethodInfo(TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + { + throw new NotImplementedException(); + } + + } + + // note: level is 1-indexed + private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, TargetCodePointer address, int level) + { + ulong addressAsInt = address.Value; + ulong addressBitsUsedInMap = addressAsInt >> (descriptor.MaxSetBit + 1 - (descriptor.MapLevels * descriptor.BitsPerLevel)); + ulong addressBitsShifted = addressBitsUsedInMap >> ((level - 1) * descriptor.BitsPerLevel); + ulong addressBitsUsedInLevel = (ulong)(descriptor.EntriesPerMapLevel - 1) & addressBitsShifted; + return checked((int)addressBitsUsedInLevel); + } + + internal EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) + { + RangeSection range = LookupRangeSection(jittedCodeAddress); + if (!range.JitCodeToMethodInfo(jittedCodeAddress, out TargetPointer methodDescAddress)) + { + return null; + } + return new EECodeInfo(jittedCodeAddress, methodDescAddress); + } + + private static bool InRange(Data.RangeSectionFragment fragment, TargetCodePointer address) + { + return fragment.RangeBegin <= address && address < fragment.RangeEndOpen; + } + + private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) + { + ExMgrPtr rangeSectionFragmentPtr = GetRangeSectionForAddress(jittedCodeAddress); + if (rangeSectionFragmentPtr.IsNull) + { + return new RangeSection(); + } + while (!rangeSectionFragmentPtr.IsNull) + { + Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); + if (InRange(fragment, jittedCodeAddress)) + { + break; + } + rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); // TODO: load? + } + if (rangeSectionFragmentPtr.IsNull) + { + Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); + Data.RangeSection rangeSection = _target.ProcessedData.GetOrAdd(fragment.RangeSection); + if (rangeSection.NextForDelete != TargetPointer.Null) + { + return new RangeSection(); + } + return new RangeSection(rangeSection); + } + return new RangeSection(); + } + + private ExMgrPtr /*PTR_RangeSectionFragment*/ GetRangeSectionForAddress(TargetCodePointer jittedCodeAddress) + { + /* The outer levels are all pointer arrays to the next level down. Level 1 is an array of pointers to a RangeSectionFragment */ + int topLevelIndex = EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, _targetCodeManagerDescriptor.MapLevels); + + ExMgrPtr top = new ExMgrPtr(_topRangeSectionMap.TopLevelData); + + ExMgrPtr nextLevelAddress = top.Offset(_target.PointerSize, topLevelIndex); + for (int level = _targetCodeManagerDescriptor.MapLevels - 1; level >= 1; level--) + { + ExMgrPtr rangeSectionL = nextLevelAddress.LoadPointer(_target); + if (rangeSectionL.IsNull) + return ExMgrPtr.Null; + nextLevelAddress = rangeSectionL.Offset(_target.PointerSize, EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, level)); + } + return nextLevelAddress; + } + + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs new file mode 100644 index 0000000000000..2374b4e2a5afe --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Microsoft.Diagnostics.DataContractReader.Data; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly partial struct NativeCodePointers_1 : INativeCodePointers +{ + internal enum KnownPrecodeType + { + Stub = 1, + NDirectImport, + Fixup, + ThisPtrRetBuf, + } + + internal abstract class ValidPrecode + { + public TargetPointer InstrPointer { get; } + public KnownPrecodeType PrecodeType { get; } + + protected ValidPrecode(TargetPointer instrPointer, KnownPrecodeType precodeType) + { + InstrPointer = instrPointer; + PrecodeType = precodeType; + } + + internal abstract TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); + + } + + internal class StubPrecode : ValidPrecode + { + internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } + + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + Data.StubPrecodeData stubPrecodeData = target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); + return stubPrecodeData.MethodDesc; + } + } + + internal sealed class NDirectImportPrecode : StubPrecode + { + internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.NDirectImport) { } + } + + internal sealed class FixupPrecode : ValidPrecode + { + internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + Data.FixupPrecodeData fixupPrecodeData = target.ProcessedData.GetOrAdd(fixupPrecodeDataAddress); + return fixupPrecodeData.MethodDesc; + + } + } + + internal sealed class ThisPtrRetBufPrecode : ValidPrecode // FIXME: is this a StubPrecode? + { + internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } + + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + throw new NotImplementedException(); // TODO(cdac) + } + } + + internal struct PrecodeContract + { + public readonly Target _target; + public readonly PrecodeMachineDescriptor _machineDescriptor; + + public PrecodeContract(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) + { + _target = target; + _machineDescriptor = precodeMachineDescriptor; + } + + internal PrecodeMachineDescriptor MachineDescriptor => _machineDescriptor; + private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); + + private byte ReadPrecodeType(TargetPointer instrPointer) + { + if (_machineDescriptor.ReadWidthOfPrecodeType == 1) + { + byte precodeType = _target.Read(instrPointer + _machineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> _machineDescriptor.ShiftOfPrecodeType); + } + else if (_machineDescriptor.ReadWidthOfPrecodeType == 2) + { + ushort precodeType = _target.Read(instrPointer + _machineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> _machineDescriptor.ShiftOfPrecodeType); + } + else + { + throw new InvalidOperationException($"Invalid precode type width {_machineDescriptor.ReadWidthOfPrecodeType}"); + } + } + + private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) + { + TargetPointer stubPrecodeDataAddress = stubInstrPointer + _machineDescriptor.StubCodePageSize; + return _target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); + } + + private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) + { + // precode.h Precode::GetType() + byte precodeType = ReadPrecodeType(instrAddress); + if (precodeType == _machineDescriptor.StubPrecodeType) + { + // get the actual type from the StubPrecodeData + Data.StubPrecodeData stubPrecodeData = GetStubPrecodeData(instrAddress); + precodeType = stubPrecodeData.Type; + } + + if (precodeType == _machineDescriptor.StubPrecodeType) + { + return KnownPrecodeType.Stub; + } + else if (_machineDescriptor.NDirectImportPrecodeType is byte ndType && precodeType == ndType) + { + return KnownPrecodeType.NDirectImport; + } + else if (_machineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) + { + return KnownPrecodeType.Fixup; + } + // TODO: ThisPtrRetBuf + else + { + return null; + } + } + + internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) + { + // Mask off the thumb bit, if we're on arm32, to get the actual instruction pointer + ulong instrPointer = (ulong)codePointer.AsTargetPointer & _machineDescriptor.CodePointerToInstrPointerMask.Value; + return new TargetPointer(instrPointer); + } + + + internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint) + { + TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint); + if (IsAlignedInstrPointer(instrPointer) && TryGetKnownPrecodeType(instrPointer) is KnownPrecodeType precodeType) + { + switch (precodeType) + { + case KnownPrecodeType.Stub: + return new StubPrecode(instrPointer); + case KnownPrecodeType.Fixup: + return new FixupPrecode(instrPointer); + case KnownPrecodeType.NDirectImport: + return new NDirectImportPrecode(instrPointer); + case KnownPrecodeType.ThisPtrRetBuf: + return new ThisPtrRetBufPrecode(instrPointer); + default: + break; + } + } + throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}"); + } + + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 4b76ff8eefdc5..e8acd7c785de8 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -5,356 +5,30 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; -internal readonly struct NativeCodePointers_1 : INativeCodePointers +internal readonly partial struct NativeCodePointers_1 : INativeCodePointers { private readonly Target _target; - private readonly Data.PrecodeMachineDescriptor _precodeMachineDescriptor; - private readonly Data.RangeSectionMap _topRangeSectionMap; - private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; + private readonly PrecodeContract _precodeContract; + private readonly ExecutionManagerContract _executionManagerContract; - private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); - - internal enum KnownPrecodeType - { - Stub = 1, - NDirectImport, - Fixup, - ThisPtrRetBuf, - } - - internal abstract class ValidPrecode - { - public TargetPointer InstrPointer { get; } - public KnownPrecodeType PrecodeType { get; } - - protected ValidPrecode(TargetPointer instrPointer, KnownPrecodeType precodeType) - { - InstrPointer = instrPointer; - PrecodeType = precodeType; - } - - internal abstract TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); - - } - - internal class StubPrecode : ValidPrecode - { - internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } - - internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) - { - TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; - Data.StubPrecodeData stubPrecodeData = target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); - return stubPrecodeData.MethodDesc; - } - } - - internal sealed class NDirectImportPrecode : StubPrecode - { - internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.NDirectImport) { } - } - - internal sealed class FixupPrecode : ValidPrecode - { - internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } - internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) - { - TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; - Data.FixupPrecodeData fixupPrecodeData = target.ProcessedData.GetOrAdd(fixupPrecodeDataAddress); - return fixupPrecodeData.MethodDesc; - - } - } - - internal sealed class ThisPtrRetBufPrecode : ValidPrecode // FIXME: is this a StubPrecode? - { - internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } - - internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) - { - throw new NotImplementedException(); // TODO(cdac) - } - } - - private byte ReadPrecodeType(TargetPointer instrPointer) - { - if (_precodeMachineDescriptor.ReadWidthOfPrecodeType == 1) - { - byte precodeType = _target.Read(instrPointer + _precodeMachineDescriptor.OffsetOfPrecodeType); - return (byte)(precodeType >> _precodeMachineDescriptor.ShiftOfPrecodeType); - } - else if (_precodeMachineDescriptor.ReadWidthOfPrecodeType == 2) - { - ushort precodeType = _target.Read(instrPointer + _precodeMachineDescriptor.OffsetOfPrecodeType); - return (byte)(precodeType >> _precodeMachineDescriptor.ShiftOfPrecodeType); - } - else - { - throw new InvalidOperationException($"Invalid precode type width {_precodeMachineDescriptor.ReadWidthOfPrecodeType}"); - } - } - - private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) - { - TargetPointer stubPrecodeDataAddress = stubInstrPointer + _precodeMachineDescriptor.StubCodePageSize; - return _target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); - } - - private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) - { - // precode.h Precode::GetType() - byte precodeType = ReadPrecodeType(instrAddress); - if (precodeType == _precodeMachineDescriptor.StubPrecodeType) - { - // get the actual type from the StubPrecodeData - Data.StubPrecodeData stubPrecodeData = GetStubPrecodeData(instrAddress); - precodeType = stubPrecodeData.Type; - } - - if (precodeType == _precodeMachineDescriptor.StubPrecodeType) - { - return KnownPrecodeType.Stub; - } - else if (_precodeMachineDescriptor.NDirectImportPrecodeType is byte ndType && precodeType == ndType) - { - return KnownPrecodeType.NDirectImport; - } - else if (_precodeMachineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) - { - return KnownPrecodeType.Fixup; - } - // TODO: ThisPtrRetBuf - else - { - return null; - } - } public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor, Data.RangeSectionMap topRangeSectionMap) { _target = target; - _precodeMachineDescriptor = precodeMachineDescriptor; - _topRangeSectionMap = topRangeSectionMap; ; - _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); - } - - internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) - { - // Mask off the thumb bit, if we're on arm32, to get the actual instruction pointer - ulong instrPointer = (ulong)codePointer.AsTargetPointer & _precodeMachineDescriptor.CodePointerToInstrPointerMask.Value; - return new TargetPointer(instrPointer); - } - - - internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint) - { - TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint); - if (IsAlignedInstrPointer(instrPointer) && TryGetKnownPrecodeType(instrPointer) is KnownPrecodeType precodeType) - { - switch (precodeType) - { - case KnownPrecodeType.Stub: - return new StubPrecode(instrPointer); - case KnownPrecodeType.Fixup: - return new FixupPrecode(instrPointer); - case KnownPrecodeType.NDirectImport: - return new NDirectImportPrecode(instrPointer); - case KnownPrecodeType.ThisPtrRetBuf: - return new ThisPtrRetBufPrecode(instrPointer); - default: - break; - } - } - throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}"); + _precodeContract = new PrecodeContract(target, precodeMachineDescriptor); + _executionManagerContract = new ExecutionManagerContract(target, topRangeSectionMap); } - TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer entryPoint) { - ValidPrecode precode = GetPrecodeFromEntryPoint(entryPoint); - - return precode.GetMethodDesc(_target, _precodeMachineDescriptor); - } - - - private class EECodeInfo - { - public TargetCodePointer CodeAddress { get; } - public TargetPointer MethodDescAddress { get; } - public EECodeInfo(TargetCodePointer jittedCodeAdderss, TargetPointer methodDescAddress) - { - CodeAddress = jittedCodeAdderss; - MethodDescAddress = methodDescAddress; - } - - public bool Valid => CodeAddress != default && MethodDescAddress != default; - } - - private readonly struct TargetCodeManagerDescriptor - { - public int MapLevels { get; } - public int BitsPerLevel { get; } = 8; - public int MaxSetBit { get; } - public int EntriesPerMapLevel { get; } = 256; - - private TargetCodeManagerDescriptor(int mapLevels, int maxSetBit) - { - MapLevels = mapLevels; - MaxSetBit = maxSetBit; - } - public static TargetCodeManagerDescriptor Create(Target target) - { - if (target.PointerSize == 4) - { - return new(mapLevels: 2, maxSetBit: 31); // 0 indexed - } - else if (target.PointerSize == 8) - { - return new(mapLevels: 5, maxSetBit: 56); // 0 indexed - } - else - { - throw new InvalidOperationException("Invalid pointer size"); - } - } - } - - private sealed class RangeSection - { - private readonly Data.RangeSection? _rangeSection; - - public RangeSection() - { - _rangeSection = default; - } - public RangeSection(Data.RangeSection rangeSection) - { - _rangeSection = rangeSection; - } - public bool JitCodeToMethodInfo(TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) - { - throw new NotImplementedException(); - } - - // note: level is 1-indexed - public static uint EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, TargetCodePointer address, int level) - { - ulong addressAsInt = address.Value; - ulong addressBitsUsedInMap = addressAsInt >> (descriptor.MaxSetBit + 1 - (descriptor.MapLevels * descriptor.BitsPerLevel)); - ulong addressBitsShifted = addressBitsUsedInMap >> ((level - 1) * descriptor.BitsPerLevel); - ulong addressBitsUsedInLevel = (ulong)(descriptor.EntriesPerMapLevel - 1) & addressBitsShifted; - return checked((uint)addressBitsUsedInLevel); - } - } - - private EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) - { - RangeSection range = LookupRangeSection(jittedCodeAddress); - if (!range.JitCodeToMethodInfo(jittedCodeAddress, out TargetPointer methodDescAddress)) - { - return null; - } - return new EECodeInfo(jittedCodeAddress, methodDescAddress); - } - - private static bool InRange(Data.RangeSectionFragment fragment, TargetCodePointer address) - { - return fragment.RangeBegin <= address && address < fragment.RangeEndOpen; - } - - private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) - { - TargetPointer rangeSectionFragmentPtr = GetRangeSectionForAddress(jittedCodeAddress); - if (rangeSectionFragmentPtr == TargetPointer.Null) - { - return new RangeSection(); - } - while (rangeSectionFragmentPtr != TargetPointer.Null) - { - Data.RangeSectionFragment fragment = _target.ProcessedData.GetOrAdd(rangeSectionFragmentPtr); - if (InRange(fragment, jittedCodeAddress)) - { - break; - } - rangeSectionFragmentPtr = fragment.Next; // TODO: load? - } - if (rangeSectionFragmentPtr != TargetPointer.Null) - { - Data.RangeSectionFragment fragment = _target.ProcessedData.GetOrAdd(rangeSectionFragmentPtr); - Data.RangeSection rangeSection = _target.ProcessedData.GetOrAdd(fragment.RangeSection); - if (rangeSection.NextForDelete != TargetPointer.Null) - { - return new RangeSection(); - } - return new RangeSection(rangeSection); - } - return new RangeSection(); -#if false - PTR_RangeSectionFragment fragment = GetRangeSectionForAddress(address, pLockState); - if (fragment == NULL) - return NULL; - - while ((fragment != NULL) && !fragment->InRange(address)) - { - fragment = fragment->pRangeSectionFragmentNext.VolatileLoadWithoutBarrier(pLockState); - } + ValidPrecode precode = _precodeContract.GetPrecodeFromEntryPoint(entryPoint); - if (fragment != NULL) - { - if (fragment->pRangeSection->_pRangeSectionNextForDelete != NULL) - return NULL; - return fragment->pRangeSection; - } -#endif - throw new NotImplementedException(); - } - - private TargetPointer RangeSectionPointerLoad(TargetPointer ptr) - { - // clear the lowest bit, which is used as a tag for collectible levels, and read the pointer - return _target.ReadPointer(ptr.Value & (ulong)~1u); - } - - private TargetPointer /*PTR_RangeSectionFragment*/ GetRangeSectionForAddress(TargetCodePointer jittedCodeAddress) - { - uint topLevelIndex = RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, _targetCodeManagerDescriptor.MapLevels); - - TargetPointer nextLevelAddress = _topRangeSectionMap.TopLevelData + (ulong)_target.PointerSize * topLevelIndex; - TargetPointer rangeSectionL1; - if (_target.PointerSize == 8) - { - TargetPointer rangeSectionL4 = RangeSectionPointerLoad(nextLevelAddress); - if (rangeSectionL4 == TargetPointer.Null) - return TargetPointer.Null; - nextLevelAddress = rangeSectionL4 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 4); - TargetPointer rangeSectionL3 = RangeSectionPointerLoad(nextLevelAddress); - if (rangeSectionL3 == TargetPointer.Null) - return TargetPointer.Null; - nextLevelAddress = rangeSectionL3 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 3); - TargetPointer rangeSectionL2 = RangeSectionPointerLoad(nextLevelAddress); - if (rangeSectionL2 == TargetPointer.Null) - return TargetPointer.Null; - nextLevelAddress = rangeSectionL2 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 2); - rangeSectionL1 = RangeSectionPointerLoad(nextLevelAddress); - - } - else if (_target.PointerSize == 4) - { - rangeSectionL1 = RangeSectionPointerLoad(nextLevelAddress); - } - else - { - throw new InvalidOperationException("Invalid pointer size"); - } - if (rangeSectionL1 == TargetPointer.Null) - return TargetPointer.Null; - nextLevelAddress = rangeSectionL1 + (ulong)_target.PointerSize * RangeSection.EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, 1); - return RangeSectionPointerLoad(nextLevelAddress); + return precode.GetMethodDesc(_target, _precodeContract.MachineDescriptor); } TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) { - EECodeInfo? info = GetEECodeInfo(jittedCodeAddress); + EECodeInfo? info = _executionManagerContract.GetEECodeInfo(jittedCodeAddress); if (info == null || !info.Valid) { throw new InvalidOperationException($"Failed to get EECodeInfo for {jittedCodeAddress}"); From 5717664507bbc2d2d6f8c36943ddaf45446d3634 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 31 Jul 2024 14:37:46 -0400 Subject: [PATCH 17/66] Add IJitManager::JitManagerKind --- src/coreclr/debug/daccess/fntableaccess.h | 1 + src/coreclr/debug/runtimeinfo/datadescriptor.h | 3 ++- src/coreclr/vm/codeman.cpp | 5 ++++- src/coreclr/vm/codeman.h | 16 +++++++++++++--- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/coreclr/debug/daccess/fntableaccess.h b/src/coreclr/debug/daccess/fntableaccess.h index c4a72a6d93ded..0cf1ca5fb477a 100644 --- a/src/coreclr/debug/daccess/fntableaccess.h +++ b/src/coreclr/debug/daccess/fntableaccess.h @@ -22,6 +22,7 @@ struct FakeEEJitManager { LPVOID __VFN_table; LPVOID m_runtimeSupport; + uint32_t m_jitManagerKind; LPVOID m_pCodeHeap; // Nothing after this point matters: we only need the correct offset of m_pCodeHeap. }; diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index d6144dc6c760d..787612599bdfd 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -377,7 +377,7 @@ CDAC_TYPE_FIELD(RangeSectionMap, /*pointer*/, TopLevelData, cdac_data::RangeSectionFragmentSize) +CDAC_TYPE_INDETERMINATE(RangeSectionFragment) CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeBegin, cdac_data::RangeSectionFragment::RangeBegin) CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeEndOpen, cdac_data::RangeSectionFragment::RangeEndOpen) CDAC_TYPE_FIELD(RangeSectionFragment, /*pointer*/, RangeSection, cdac_data::RangeSectionFragment::RangeSection) @@ -389,6 +389,7 @@ CDAC_TYPE_INDETERMINATE(RangeSection) CDAC_TYPE_FIELD(RangeSection, /*pointer*/, RangeBegin, cdac_data::RangeBegin) CDAC_TYPE_FIELD(RangeSection, /*pointer*/, RangeEndOpen, cdac_data::RangeEndOpen) CDAC_TYPE_FIELD(RangeSection, /*pointer*/, NextForDelete, cdac_data::NextForDelete) +CDAC_TYPE_FIELD(RangeSection, /*pointer*/, JitManager, cdac_data::JitManager) CDAC_TYPE_END(RangeSection) CDAC_TYPES_END() diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index d019affc33b33..5db4c2ac418ab 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -918,11 +918,12 @@ BOOL IsFunctionFragment(TADDR baseAddress, PTR_RUNTIME_FUNCTION pFunctionEntry) //********************************************************************************** // IJitManager //********************************************************************************** -IJitManager::IJitManager() +IJitManager::IJitManager(IJitManager::JitManagerKind kind) { LIMITED_METHOD_CONTRACT; m_runtimeSupport = ExecutionManager::GetDefaultCodeManager(); + m_jitManagerKind = kind; } #endif // #ifndef DACCESS_COMPILE @@ -1207,6 +1208,7 @@ PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFuncti EEJitManager::EEJitManager() : + IJitManager (IJitManager::JitManagerKind::EE), // CRST_DEBUGGER_THREAD - We take this lock on debugger thread during EnC add method, among other things // CRST_TAKEN_DURING_SHUTDOWN - We take this lock during shutdown if ETW is on (to do rundown) m_CodeHeapCritSec( CrstSingleUseLock, @@ -5484,6 +5486,7 @@ int HotColdMappingLookupTable::LookupMappingForMethod(ReadyToRunInfo* pInfo, ULO #ifndef DACCESS_COMPILE ReadyToRunJitManager::ReadyToRunJitManager() + : IJitManager(IJitManager::JitManagerKind::ReadyToRun) { WRAPPER_NO_CONTRACT; } diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 246845aa365f0..8cad72205dd62 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -637,6 +637,7 @@ template<> struct cdac_data static constexpr size_t RangeBegin = offsetof(RangeSection, _range.begin); static constexpr size_t RangeEndOpen = offsetof(RangeSection, _range.end); static constexpr size_t NextForDelete = offsetof(RangeSection, _pRangeSectionNextForDelete); + static constexpr size_t JitManager = offsetof(RangeSection, _pjit); }; enum class RangeSectionLockState @@ -1458,8 +1459,6 @@ struct cdac_data static constexpr size_t RangeSection = offsetof(RangeSectionMap::RangeSectionFragment, pRangeSection); static constexpr size_t Next = offsetof(RangeSectionMap::RangeSectionFragment, pRangeSectionFragmentNext); }; - - static constexpr size_t RangeSectionFragmentSize = sizeof(RangeSectionMap::RangeSectionFragment); }; @@ -1553,7 +1552,11 @@ class IJitManager }; #ifndef DACCESS_COMPILE - IJitManager(); +protected: + enum class JitManagerKind : uint32_t; + IJitManager(JitManagerKind); + +public: #endif // !DACCESS_COMPILE virtual DWORD GetCodeType() = 0; @@ -1651,6 +1654,11 @@ class IJitManager protected: PTR_ICodeManager m_runtimeSupport; + enum class JitManagerKind : uint32_t { + EE = 0, + ReadyToRun = 1, + }; + JitManagerKind m_jitManagerKind; }; //----------------------------------------------------------------------------- @@ -2592,6 +2600,8 @@ class EECodeInfo // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info. UNWIND_INFO * GetUnwindInfoHelper(ULONG unwindInfoOffset); #endif // TARGET_AMD64 + + template friend struct ::cdac_data; }; #include "codeman.inl" From 1eeb513d66af37cf5ef1a2cae76f911891508166 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 31 Jul 2024 16:31:12 -0400 Subject: [PATCH 18/66] WIP JitCodeToMethodInfo --- .../debug/runtimeinfo/datadescriptor.h | 20 +++ src/coreclr/vm/codeman.h | 11 ++ .../managed/cdacreader/src/Constants.cs | 1 + .../NativeCodePointers_1.ExecutionManager.cs | 167 +++++++++++++++++- .../cdacreader/src/Data/IJitManager.cs | 18 ++ .../cdacreader/src/Data/RangeSection.cs | 6 + .../cdacreader/src/Data/RealCodeHeader.cs | 18 ++ src/native/managed/cdacreader/src/DataType.cs | 2 + 8 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/IJitManager.cs create mode 100644 src/native/managed/cdacreader/src/Data/RealCodeHeader.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 787612599bdfd..31a1f5a118762 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -390,8 +390,27 @@ CDAC_TYPE_FIELD(RangeSection, /*pointer*/, RangeBegin, cdac_data:: CDAC_TYPE_FIELD(RangeSection, /*pointer*/, RangeEndOpen, cdac_data::RangeEndOpen) CDAC_TYPE_FIELD(RangeSection, /*pointer*/, NextForDelete, cdac_data::NextForDelete) CDAC_TYPE_FIELD(RangeSection, /*pointer*/, JitManager, cdac_data::JitManager) +CDAC_TYPE_FIELD(RangeSection, /*int32_t*/, Flags, cdac_data::Flags) +CDAC_TYPE_FIELD(RangeSection, /*pointer*/, HeapList, cdac_data::HeapList) CDAC_TYPE_END(RangeSection) +CDAC_TYPE_BEGIN(IJitManager) +CDAC_TYPE_INDETERMINATE(IJitManager) +CDAC_TYPE_FIELD(IJitManager, /*uint32*/, JitManagerKind, cdac_data::JitManagerKind) +CDAC_TYPE_END(IJitManager) + +CDAC_TYPE_BEGIN(RealCodeHeader) +CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, MethodDesc, offsetof(RealCodeHeader, m_pMethodDesc)) +CDAC_TYPE_END(RealCodeHeader) + +CDAC_TYPE_BEGIN(HeapList) +CDAC_TYPE_FIELD(HeapList, /*pointer*/, Next, offsetof(HeapList, hpNext)) +CDAC_TYPE_FIELD(HeapList, /*pointer*/, StartAddress, offsetof(HeapList, startAddress)) +CDAC_TYPE_FIELD(HeapList, /*pointer*/, EndAddress, offsetof(HeapList, endAddress)) +CDAC_TYPE_FIELD(HeapList, /*pointer*/, MapBase, offsetof(HeapList, mapBase)) +CDAC_TYPE_FIELD(HeapList, /*pointer*/, HeaderMap, offsetof(HeapList, pHdrMap)) +CDAC_TYPE_END(HeapList) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -421,6 +440,7 @@ CDAC_GLOBAL(DirectorySeparator, uint8, (uint8_t)DIRECTORY_SEPARATOR_CHAR_A) CDAC_GLOBAL(MethodDescAlignment, uint64, MethodDesc::ALIGNMENT) CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE) CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data::SyncBlockValue) +CDAC_GLOBAL(StubCodeBlockLast, uint8, STUB_CODE_BLOCK_LAST) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 8cad72205dd62..4f499ff9d2795 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -147,6 +147,7 @@ typedef struct _hpRealCodeHdr public: // if we're using the indirect codeheaders then all enumeration is done by the code header + } RealCodeHeader; typedef struct _hpCodeHdr @@ -638,6 +639,8 @@ template<> struct cdac_data static constexpr size_t RangeEndOpen = offsetof(RangeSection, _range.end); static constexpr size_t NextForDelete = offsetof(RangeSection, _pRangeSectionNextForDelete); static constexpr size_t JitManager = offsetof(RangeSection, _pjit); + static constexpr size_t Flags = offsetof(RangeSection, _flags); + static constexpr size_t HeapList = offsetof(RangeSection, _pHeapList); }; enum class RangeSectionLockState @@ -1659,6 +1662,14 @@ class IJitManager ReadyToRun = 1, }; JitManagerKind m_jitManagerKind; + + template friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + static constexpr size_t JitManagerKind = offsetof(IJitManager, m_jitManagerKind); }; //----------------------------------------------------------------------------- diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs index cb63cb6098b18..41df7d732aebb 100644 --- a/src/native/managed/cdacreader/src/Constants.cs +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -42,5 +42,6 @@ internal static class Globals internal const string PrecodeMachineDescriptor = nameof(PrecodeMachineDescriptor); internal const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); + internal const string StubCodeBlockLast = nameof(StubCodeBlockLast); } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index 98590fb7809e1..d4d16efe2ad82 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -88,6 +88,13 @@ internal struct ExecutionManagerContract private readonly Data.RangeSectionMap _topRangeSectionMap; private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; + + internal enum JitManagerKind + { + EEJitManager = 0, + ReadyToRunJitManager = 1, + } + public ExecutionManagerContract(Target target, Data.RangeSectionMap topRangeSectionMap) { _target = target; @@ -95,6 +102,13 @@ public ExecutionManagerContract(Target target, Data.RangeSectionMap topRangeSect _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); } + [Flags] + enum RangeSectionFlags : int + { + CodeHeap = 0x02, + RangeList = 0x04, + } + private sealed class RangeSection { private readonly Data.RangeSection? _rangeSection; @@ -107,11 +121,160 @@ public RangeSection(Data.RangeSection rangeSection) { _rangeSection = rangeSection; } - public bool JitCodeToMethodInfo(TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + + private bool HasFlags(RangeSectionFlags mask) => (_rangeSection!.Flags & (int)mask) != 0; + private bool IsRangeList => HasFlags(RangeSectionFlags.RangeList); + private bool IsCodeHeap => HasFlags(RangeSectionFlags.CodeHeap); + + public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) { - throw new NotImplementedException(); + if (_rangeSection == null) + { + methodDescAddress = TargetPointer.Null; + return false; + } + Data.IJitManager jitManager = target.ProcessedData.GetOrAdd(_rangeSection.JitManager); + switch ((JitManagerKind)jitManager.JitManagerKind) + { + case JitManagerKind.EEJitManager: + return EEJitCodeToMethodInfo(target, jitManager, jittedCodeAddress, out methodDescAddress); + case JitManagerKind.ReadyToRunJitManager: + methodDescAddress = TargetPointer.Null; + throw new NotImplementedException(); // TODO[cdac]: + default: + throw new InvalidOperationException($"Invalid JitManagerKind {jitManager.JitManagerKind}"); + } } + private bool EEJitCodeToMethodInfo(Target target, Data.IJitManager jitManager, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + { + // EEJitManager::JitCodeToMethodInfo + if (IsRangeList) + { + methodDescAddress = TargetPointer.Null; + return false; + } + TargetPointer start = EEFindMethodCode(jitManager, jittedCodeAddress); + if (start == TargetPointer.Null) + { + methodDescAddress = TargetPointer.Null; + return false; + } + TargetPointer codeHeaderIndirect = new TargetPointer(start - (ulong)target.PointerSize); + if (IsStubCodeBlock(target, codeHeaderIndirect)) + { + methodDescAddress = TargetPointer.Null; + return false; + } + TargetPointer codeHeaderAddress = target.ReadPointer(codeHeaderIndirect); + Data.RealCodeHeader realCodeHeader = target.ProcessedData.GetOrAdd(codeHeaderAddress); + methodDescAddress = realCodeHeader.MethodDesc; + return true; + } + + private static bool IsStubCodeBlock(Target target, TargetPointer codeHeaderIndirect) + { + uint stubCodeBlockLast = target.ReadGlobal(Constants.Globals.StubCodeBlockLast); + return codeHeaderIndirect.Value <= stubCodeBlockLast; + } + + private TargetPointer EEFindMethodCode(Data.IJitManager jitManager, TargetCodePointer jittedCodeAddress) + { + // EEJitManager::FindMethodCode + if (_rangeSection == null) + { + throw new InvalidOperationException(); + } + if (!IsCodeHeap) + { + throw new InvalidOperationException("RangeSection is not a code heap"); + } + TargetPointer heapListAddress = _rangeSection.HeapList; +#if false + HeapList *pHp = pRangeSection->_pHeapList; + + if ((currentPC < pHp->startAddress) || + (currentPC > pHp->endAddress)) + { + return 0; + } + + TADDR base = pHp->mapBase; + TADDR delta = currentPC - base; + PTR_DWORD pMap = pHp->pHdrMap; + PTR_DWORD pMapStart = pMap; + + DWORD tmp; + + size_t startPos = ADDR2POS(delta); // align to 32byte buckets + // ( == index into the array of nibbles) + DWORD offset = ADDR2OFFS(delta); // this is the offset inside the bucket + 1 + + _ASSERTE(offset == (offset & NIBBLE_MASK)); + + pMap += (startPos >> LOG2_NIBBLES_PER_DWORD); // points to the proper DWORD of the map + + // get DWORD and shift down our nibble + + PREFIX_ASSUME(pMap != NULL); + tmp = VolatileLoadWithoutBarrier(pMap) >> POS2SHIFTCOUNT(startPos); + + if ((tmp & NIBBLE_MASK) && ((tmp & NIBBLE_MASK) <= offset) ) + { + return base + POSOFF2ADDR(startPos, tmp & NIBBLE_MASK); + } + + // Is there a header in the remainder of the DWORD ? + tmp = tmp >> NIBBLE_SIZE; + + if (tmp) + { + startPos--; + while (!(tmp & NIBBLE_MASK)) + { + tmp = tmp >> NIBBLE_SIZE; + startPos--; + } + return base + POSOFF2ADDR(startPos, tmp & NIBBLE_MASK); + } + + // We skipped the remainder of the DWORD, + // so we must set startPos to the highest position of + // previous DWORD, unless we are already on the first DWORD + + if (startPos < NIBBLES_PER_DWORD) + return 0; + + startPos = ((startPos >> LOG2_NIBBLES_PER_DWORD) << LOG2_NIBBLES_PER_DWORD) - 1; + + // Skip "headerless" DWORDS + + while (pMapStart < pMap && 0 == (tmp = VolatileLoadWithoutBarrier(--pMap))) + { + startPos -= NIBBLES_PER_DWORD; + } + + // This helps to catch degenerate error cases. This relies on the fact that + // startPos cannot ever be bigger than MAX_UINT + if (((INT_PTR)startPos) < 0) + return 0; + + // Find the nibble with the header in the DWORD + + while (startPos && !(tmp & NIBBLE_MASK)) + { + tmp = tmp >> NIBBLE_SIZE; + startPos--; + } + + if (startPos == 0 && tmp == 0) + return 0; + + return base + POSOFF2ADDR(startPos, tmp & NIBBLE_MASK); + +#endif + + } } // note: level is 1-indexed diff --git a/src/native/managed/cdacreader/src/Data/IJitManager.cs b/src/native/managed/cdacreader/src/Data/IJitManager.cs new file mode 100644 index 0000000000000..cb0e5a9768781 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/IJitManager.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 IJitManager : IData +{ + static IJitManager IData.Create(Target target, TargetPointer address) + => new IJitManager(target, address); + + public IJitManager(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.IJitManager); + JitManagerKind = target.Read(address + (ulong)type.Fields[nameof(JitManagerKind)].Offset); + } + + public uint JitManagerKind { get; init; } +} diff --git a/src/native/managed/cdacreader/src/Data/RangeSection.cs b/src/native/managed/cdacreader/src/Data/RangeSection.cs index 32795db52f65e..050bfcbd48c10 100644 --- a/src/native/managed/cdacreader/src/Data/RangeSection.cs +++ b/src/native/managed/cdacreader/src/Data/RangeSection.cs @@ -14,9 +14,15 @@ public RangeSection(Target target, TargetPointer address) RangeBegin = target.ReadPointer(address + (ulong)type.Fields[nameof(RangeBegin)].Offset); RangeEndOpen = target.ReadPointer(address + (ulong)type.Fields[nameof(RangeEndOpen)].Offset); NextForDelete = target.ReadPointer(address + (ulong)type.Fields[nameof(NextForDelete)].Offset); + JitManager = target.ReadPointer(address + (ulong)type.Fields[nameof(JitManager)].Offset); + Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); + HeapList = target.ReadPointer(address + (ulong)type.Fields[nameof(HeapList)].Offset); } public TargetPointer RangeBegin { get; init; } public TargetPointer RangeEndOpen { get; init; } public TargetPointer NextForDelete { get; init; } + public TargetPointer JitManager { get; init; } + public TargetPointer HeapList { get; init; } + public int Flags { get; init; } } diff --git a/src/native/managed/cdacreader/src/Data/RealCodeHeader.cs b/src/native/managed/cdacreader/src/Data/RealCodeHeader.cs new file mode 100644 index 0000000000000..22a33b4820e32 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/RealCodeHeader.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 RealCodeHeader : IData +{ + static RealCodeHeader IData.Create(Target target, TargetPointer address) + => new RealCodeHeader(target, address); + + public RealCodeHeader(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.RealCodeHeader); + MethodDesc = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodDesc)].Offset); + } + + public TargetPointer MethodDesc { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 48976f97dba0f..e76491bbe04c2 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -57,4 +57,6 @@ public enum DataType RangeSectionMap, RangeSectionFragment, RangeSection, + IJitManager, + RealCodeHeader, } From 2a95bda24b4a1b3f5cbd29cb3ec2d69c323f01e9 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 2 Aug 2024 15:33:19 -0400 Subject: [PATCH 19/66] WIP NibbleMap --- .../NativeCodePointers_1.ExecutionManager.cs | 83 +-------- .../NativeCodePointers_1.NibbleMap.cs | 172 ++++++++++++++++++ 2 files changed, 181 insertions(+), 74 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index d4d16efe2ad82..89caaf297a6e4 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -103,7 +103,7 @@ public ExecutionManagerContract(Target target, Data.RangeSectionMap topRangeSect } [Flags] - enum RangeSectionFlags : int + private enum RangeSectionFlags : int { CodeHeap = 0x02, RangeList = 0x04, @@ -133,6 +133,8 @@ public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddre methodDescAddress = TargetPointer.Null; return false; } + // FIXME(cdac): prototype uses R2RModule to determine if the RangeSection belongs to the JIT or to R2R, + // we don't need an extra JitManagerKind field. Data.IJitManager jitManager = target.ProcessedData.GetOrAdd(_rangeSection.JitManager); switch ((JitManagerKind)jitManager.JitManagerKind) { @@ -154,7 +156,7 @@ private bool EEJitCodeToMethodInfo(Target target, Data.IJitManager jitManager, T methodDescAddress = TargetPointer.Null; return false; } - TargetPointer start = EEFindMethodCode(jitManager, jittedCodeAddress); + TargetPointer start = EEFindMethodCode(target, jitManager, jittedCodeAddress); if (start == TargetPointer.Null) { methodDescAddress = TargetPointer.Null; @@ -178,7 +180,7 @@ private static bool IsStubCodeBlock(Target target, TargetPointer codeHeaderIndir return codeHeaderIndirect.Value <= stubCodeBlockLast; } - private TargetPointer EEFindMethodCode(Data.IJitManager jitManager, TargetCodePointer jittedCodeAddress) + private TargetPointer EEFindMethodCode(Target target, Data.IJitManager jitManager, TargetCodePointer jittedCodeAddress) { // EEJitManager::FindMethodCode if (_rangeSection == null) @@ -190,6 +192,7 @@ private TargetPointer EEFindMethodCode(Data.IJitManager jitManager, TargetCodePo throw new InvalidOperationException("RangeSection is not a code heap"); } TargetPointer heapListAddress = _rangeSection.HeapList; + Data.HeapList heapList = _target.ProcessedData.GetOrAdd(heapListAddress); #if false HeapList *pHp = pRangeSection->_pHeapList; @@ -200,79 +203,11 @@ private TargetPointer EEFindMethodCode(Data.IJitManager jitManager, TargetCodePo } TADDR base = pHp->mapBase; - TADDR delta = currentPC - base; PTR_DWORD pMap = pHp->pHdrMap; PTR_DWORD pMapStart = pMap; - - DWORD tmp; - - size_t startPos = ADDR2POS(delta); // align to 32byte buckets - // ( == index into the array of nibbles) - DWORD offset = ADDR2OFFS(delta); // this is the offset inside the bucket + 1 - - _ASSERTE(offset == (offset & NIBBLE_MASK)); - - pMap += (startPos >> LOG2_NIBBLES_PER_DWORD); // points to the proper DWORD of the map - - // get DWORD and shift down our nibble - - PREFIX_ASSUME(pMap != NULL); - tmp = VolatileLoadWithoutBarrier(pMap) >> POS2SHIFTCOUNT(startPos); - - if ((tmp & NIBBLE_MASK) && ((tmp & NIBBLE_MASK) <= offset) ) - { - return base + POSOFF2ADDR(startPos, tmp & NIBBLE_MASK); - } - - // Is there a header in the remainder of the DWORD ? - tmp = tmp >> NIBBLE_SIZE; - - if (tmp) - { - startPos--; - while (!(tmp & NIBBLE_MASK)) - { - tmp = tmp >> NIBBLE_SIZE; - startPos--; - } - return base + POSOFF2ADDR(startPos, tmp & NIBBLE_MASK); - } - - // We skipped the remainder of the DWORD, - // so we must set startPos to the highest position of - // previous DWORD, unless we are already on the first DWORD - - if (startPos < NIBBLES_PER_DWORD) - return 0; - - startPos = ((startPos >> LOG2_NIBBLES_PER_DWORD) << LOG2_NIBBLES_PER_DWORD) - 1; - - // Skip "headerless" DWORDS - - while (pMapStart < pMap && 0 == (tmp = VolatileLoadWithoutBarrier(--pMap))) - { - startPos -= NIBBLES_PER_DWORD; - } - - // This helps to catch degenerate error cases. This relies on the fact that - // startPos cannot ever be bigger than MAX_UINT - if (((INT_PTR)startPos) < 0) - return 0; - - // Find the nibble with the header in the DWORD - - while (startPos && !(tmp & NIBBLE_MASK)) - { - tmp = tmp >> NIBBLE_SIZE; - startPos--; - } - - if (startPos == 0 && tmp == 0) - return 0; - - return base + POSOFF2ADDR(startPos, tmp & NIBBLE_MASK); - #endif + NibbleMap nibbleMap = NibbleMap.Create(target); + return nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); } } @@ -290,7 +225,7 @@ private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, internal EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) { RangeSection range = LookupRangeSection(jittedCodeAddress); - if (!range.JitCodeToMethodInfo(jittedCodeAddress, out TargetPointer methodDescAddress)) + if (!range.JitCodeToMethodInfo(_target, jittedCodeAddress, out TargetPointer methodDescAddress)) { return null; } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs new file mode 100644 index 0000000000000..4e73491cef007 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Numerics; + +using MapUnit = uint; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + + +#pragma warning disable SA1121 // Use built in alias +internal readonly partial struct NativeCodePointers_1 : INativeCodePointers +{ + // Given a contiguous region of memory in which we lay out a collection of non-overlapping code blocks that are + // not too small (so that two adjacent ones aren't too close together) and where the start of each code block is preceeded by a code header aligned on some power of 2, + // we can break up the whole memory space into buckets of a fixed size (32-bytes in the current implementation), where + // each bucket either has a code block header or not. + // Thinking of each code block header address as a hex number, we can view it as: [index, offset, zeros] + // where each index gives us a bucket and the offset gives us the position of the header within the bucket. + // We encode each offset into a 4-bit nibble, reserving the special value 0 to mark the places in the map where a method doesn't start. + // + // To find the start of a method given an address we first convert it into a bucket index (giving the map unit) + // and an offset which we can then turn into the index of the nibble that covers that address. + // If the nibble is non-zero, we have the start of a method and it is near the given address. + // If the nibble is zero, we have to search backward first through the current map unit, and then through previous map + // units until we find a non-zero nibble. + internal sealed class NibbleMap + { + + public static NibbleMap Create(Target target, uint codeHeaderSize) + { + return new NibbleMap(target, codeHeaderSize); + } + + private readonly Target _target; + private readonly uint _codeHeaderSize; + private NibbleMap(Target target, uint codeHeaderSize) + { + _target = target; + _codeHeaderSize = codeHeaderSize; + } + + // Shift the next nibble into the least significant position. + private static T NextNibble(T n) where T : IBinaryInteger + { + return n >>> 4; + } + + + private const uint MapUnitBytes = sizeof(MapUnit); // our units are going to be 32-bit integers + private const MapUnit NibbleMask = 0x0F; + private const ulong NibblesPerMapUnit = 2 * MapUnitBytes; // 2 nibbles per byte * N bytes per map unit + + // we will partition the address space into buckets of this many bytes. + // There is at most one code block header per bucket. + // normally we would then need Log2(BytesPerBucket) bits to find the exact start address, + // but because code headers are aligned, we can store the offset in a 4-bit nibble instead and shift appropriately to compute + // the effective address + private const ulong BytesPerBucket = 8 * sizeof(MapUnit); + + + // given the index of a nibble in the map, compute how much we have to shift a MapUnit to put that + // nible in the least significant position. + private static int ComputeNibbleShift(ulong mapIdx) + { + // the low bits of the nibble index give us how many nibbles we have to shift by. + int nibbleOffsetInMapUnit = (int)(mapIdx & (NibblesPerMapUnit - 1)); + return 28 - (nibbleOffsetInMapUnit * 4); // bit shift - 4 bits per nibble + } + + private static ulong ComputeByteOffset(ulong mapIdx, uint nibble) + { + return mapIdx * BytesPerBucket + (nibble - 1) * MapUnitBytes; + } + private TargetPointer GetAbsoluteAddress(TargetPointer baseAddress, ulong mapIdx, uint nibble) + { + return baseAddress + ComputeByteOffset(mapIdx, nibble) - _codeHeaderSize; + } + + // Given a relative address, decompose it into + // the bucket index and an offset within the bucket. + private static void DecomposeAddress(TargetNUInt relative, out ulong mapIdx, out uint bucketByteIndex) + { + mapIdx = relative.Value / BytesPerBucket; + bucketByteIndex = ((uint)(relative.Value & (BytesPerBucket - 1)) / MapUnitBytes) + 1; + System.Diagnostics.Debug.Assert(bucketByteIndex == (bucketByteIndex & NibbleMask)); + } + + private static TargetPointer GetMapUnitAddress(TargetPointer mapStart, ulong mapIdx) + { + return mapStart + (mapIdx / NibblesPerMapUnit) * MapUnitBytes; + } + + public TargetPointer FindMethodCode(TargetPointer mapBase, TargetPointer mapStart, TargetPointer currentPC) + { + TargetNUInt relativeAddress = new TargetNUInt(currentPC.Value - mapBase.Value); + DecomposeAddress(relativeAddress, out ulong mapIdx, out uint bucketByteIndex); + + MapUnit t = _target.Read(GetMapUnitAddress(mapStart, mapIdx)); + + // shift the nibble we want to the least significant position + t = t >>> ComputeNibbleShift(mapIdx); + uint nibble = t & NibbleMask; + if (nibble != 0 && nibble <= bucketByteIndex) + { + return GetAbsoluteAddress(mapBase, mapIdx, nibble); + } + + // search backwards through the current map unit + // we processed the lsb nibble, move to the next one + t = NextNibble(t); + + // if there's any nibble set in the current unit, find it + if (t != 0) + { + mapIdx--; + nibble = t & NibbleMask; + while (nibble == 0) + { + t = NextNibble(t); + mapIdx--; + nibble = t & NibbleMask; + } + return GetAbsoluteAddress(mapBase, mapIdx, nibble); + } + + // if we were near the beginning of the address space, there is not enough space for the code header, + // so we can stop + if (mapIdx < NibblesPerMapUnit) + { + return TargetPointer.Null; + } + + // We're now done with the current map index. + // Align the map index and move to the previous map unit, then move back one nibble. + mapIdx = mapIdx & (~(NibblesPerMapUnit - 1)) - 1; + + // read the map unit containing mapIdx and skip over it if it is all zeros + while (mapIdx >= NibblesPerMapUnit) + { + t = _target.Read(GetMapUnitAddress(mapStart, mapIdx)); + if (t != 0) + break; + mapIdx -= NibblesPerMapUnit; + } + + // if we went all the way to the front, we didn't find a code header + if (mapIdx < NibblesPerMapUnit) + { + return TargetPointer.Null; + } + + // move to the correct nibble in the map unit + while (mapIdx != 0 && (t & NibbleMask) == 0) + { + t = NextNibble(t); + mapIdx--; + } + + if (mapIdx == 0 && t == 0) + { + return TargetPointer.Null; + } + + nibble = t & NibbleMask; + return GetAbsoluteAddress(mapBase, mapIdx, nibble); + } + + } +} +#pragma warning restore SA1121 // Use built in alias From ebf76a3964662c54a19ee18e0c53e0812648e323 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 2 Aug 2024 16:01:53 -0400 Subject: [PATCH 20/66] add HeapList --- .../debug/runtimeinfo/datadescriptor.h | 1 + .../NativeCodePointers_1.ExecutionManager.cs | 31 +++++++------------ .../NativeCodePointers_1.NibbleMap.cs | 4 ++- .../managed/cdacreader/src/Data/HeapList.cs | 28 +++++++++++++++++ src/native/managed/cdacreader/src/DataType.cs | 1 + 5 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/HeapList.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 31a1f5a118762..3b064107fd9a3 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -400,6 +400,7 @@ CDAC_TYPE_FIELD(IJitManager, /*uint32*/, JitManagerKind, cdac_data: CDAC_TYPE_END(IJitManager) CDAC_TYPE_BEGIN(RealCodeHeader) +CDAC_TYPE_INDETERMINATE(RealCodeHeader) CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, MethodDesc, offsetof(RealCodeHeader, m_pMethodDesc)) CDAC_TYPE_END(RealCodeHeader) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index 89caaf297a6e4..5c86953eb47c4 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -139,7 +139,7 @@ public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddre switch ((JitManagerKind)jitManager.JitManagerKind) { case JitManagerKind.EEJitManager: - return EEJitCodeToMethodInfo(target, jitManager, jittedCodeAddress, out methodDescAddress); + return EEJitCodeToMethodInfo(target, jittedCodeAddress, out methodDescAddress); case JitManagerKind.ReadyToRunJitManager: methodDescAddress = TargetPointer.Null; throw new NotImplementedException(); // TODO[cdac]: @@ -148,7 +148,7 @@ public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddre } } - private bool EEJitCodeToMethodInfo(Target target, Data.IJitManager jitManager, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + private bool EEJitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) { // EEJitManager::JitCodeToMethodInfo if (IsRangeList) @@ -156,7 +156,7 @@ private bool EEJitCodeToMethodInfo(Target target, Data.IJitManager jitManager, T methodDescAddress = TargetPointer.Null; return false; } - TargetPointer start = EEFindMethodCode(target, jitManager, jittedCodeAddress); + TargetPointer start = EEFindMethodCode(target, jittedCodeAddress); if (start == TargetPointer.Null) { methodDescAddress = TargetPointer.Null; @@ -180,7 +180,7 @@ private static bool IsStubCodeBlock(Target target, TargetPointer codeHeaderIndir return codeHeaderIndirect.Value <= stubCodeBlockLast; } - private TargetPointer EEFindMethodCode(Target target, Data.IJitManager jitManager, TargetCodePointer jittedCodeAddress) + private TargetPointer EEFindMethodCode(Target target, TargetCodePointer jittedCodeAddress) { // EEJitManager::FindMethodCode if (_rangeSection == null) @@ -192,21 +192,14 @@ private TargetPointer EEFindMethodCode(Target target, Data.IJitManager jitManage throw new InvalidOperationException("RangeSection is not a code heap"); } TargetPointer heapListAddress = _rangeSection.HeapList; - Data.HeapList heapList = _target.ProcessedData.GetOrAdd(heapListAddress); -#if false - HeapList *pHp = pRangeSection->_pHeapList; - - if ((currentPC < pHp->startAddress) || - (currentPC > pHp->endAddress)) - { - return 0; - } - - TADDR base = pHp->mapBase; - PTR_DWORD pMap = pHp->pHdrMap; - PTR_DWORD pMapStart = pMap; -#endif - NibbleMap nibbleMap = NibbleMap.Create(target); + Data.HeapList heapList = target.ProcessedData.GetOrAdd(heapListAddress); + if (jittedCodeAddress < heapList.StartAddress || jittedCodeAddress > heapList.EndAddress) + { + return TargetPointer.Null; + } + TargetPointer mapBase = heapList.MapBase; + TargetPointer mapStart = heapList.HeaderMap; + NibbleMap nibbleMap = NibbleMap.Create(target, (uint)target.PointerSize); return nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs index 4e73491cef007..9fa6076e2070d 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs @@ -92,7 +92,7 @@ private static TargetPointer GetMapUnitAddress(TargetPointer mapStart, ulong map return mapStart + (mapIdx / NibblesPerMapUnit) * MapUnitBytes; } - public TargetPointer FindMethodCode(TargetPointer mapBase, TargetPointer mapStart, TargetPointer currentPC) + public TargetPointer FindMethodCode(TargetPointer mapBase, TargetPointer mapStart, TargetCodePointer currentPC) { TargetNUInt relativeAddress = new TargetNUInt(currentPC.Value - mapBase.Value); DecomposeAddress(relativeAddress, out ulong mapIdx, out uint bucketByteIndex); @@ -134,7 +134,9 @@ public TargetPointer FindMethodCode(TargetPointer mapBase, TargetPointer mapStar // We're now done with the current map index. // Align the map index and move to the previous map unit, then move back one nibble. +#pragma warning disable IDE0054 // use compound assignment mapIdx = mapIdx & (~(NibblesPerMapUnit - 1)) - 1; +#pragma warning restore IDE0054 // use compound assignment // read the map unit containing mapIdx and skip over it if it is all zeros while (mapIdx >= NibblesPerMapUnit) diff --git a/src/native/managed/cdacreader/src/Data/HeapList.cs b/src/native/managed/cdacreader/src/Data/HeapList.cs new file mode 100644 index 0000000000000..b87dfdaad89fa --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/HeapList.cs @@ -0,0 +1,28 @@ +// 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 HeapList : IData +{ + static HeapList IData.Create(Target target, TargetPointer address) + => new HeapList(target, address); + + public HeapList(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.HeapList); + Next = target.ReadPointer(address + (ulong)type.Fields[nameof(Next)].Offset); + StartAddress = target.ReadPointer(address + (ulong)type.Fields[nameof(StartAddress)].Offset); + EndAddress = target.ReadPointer(address + (ulong)type.Fields[nameof(EndAddress)].Offset); + MapBase = target.ReadPointer(address + (ulong)type.Fields[nameof(MapBase)].Offset); + HeaderMap = target.ReadPointer(address + (ulong)type.Fields[nameof(HeaderMap)].Offset); + } + + public TargetPointer Next { get; init; } + public TargetPointer StartAddress { get; init; } + public TargetPointer EndAddress { get; init; } + + public TargetPointer MapBase { get; init; } + + public TargetPointer HeaderMap { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index e76491bbe04c2..324deb5ad1a58 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -59,4 +59,5 @@ public enum DataType RangeSection, IJitManager, RealCodeHeader, + HeapList, } From 7defaefa5b9a6b18488ace7927c30ec2ce67a796 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 2 Aug 2024 16:18:45 -0400 Subject: [PATCH 21/66] fix datadescriptor.h typo --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 3b064107fd9a3..d67a5699a9a34 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -401,7 +401,7 @@ CDAC_TYPE_END(IJitManager) CDAC_TYPE_BEGIN(RealCodeHeader) CDAC_TYPE_INDETERMINATE(RealCodeHeader) -CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, MethodDesc, offsetof(RealCodeHeader, m_pMethodDesc)) +CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, MethodDesc, offsetof(RealCodeHeader, phdrMDesc)) CDAC_TYPE_END(RealCodeHeader) CDAC_TYPE_BEGIN(HeapList) From 9181f3fa711e92ebfbbe4b533108a123e124dc95 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 5 Aug 2024 13:01:47 -0400 Subject: [PATCH 22/66] Add StoredSigMethodDesc --- src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index 37e513995767b..c311393f14797 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -105,6 +105,8 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; Contracts.MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(methodDesc); + data->requestedIP = ip; + data->bIsDynamic = rtsContract.IsDynamicMethod(methodDescHandle) ? 1 : 0; data->MethodTablePtr = rtsContract.GetMethodTable(methodDescHandle); return HResults.E_NOTIMPL; From 86954df4c72e0a092dd2fd2a81d722871e2aeec6 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 5 Aug 2024 13:35:46 -0400 Subject: [PATCH 23/66] fix bit twiddling --- .../src/Contracts/NativeCodePointers_1.ExecutionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index 5c86953eb47c4..9560a508d5a6c 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -25,7 +25,7 @@ private struct ExMgrPtr { public readonly TargetPointer RawValue; - public TargetPointer Address => RawValue & (ulong)~1u; + public TargetPointer Address => RawValue & ~1ul; public bool IsNull => Address == TargetPointer.Null; From 0d0b592446a657ae7a9c3484beba96b22d56d3be Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 5 Aug 2024 15:43:40 -0400 Subject: [PATCH 24/66] fixup NonValidated.MethodDesc.NativeCodeSlotIndex --- .../src/Contracts/RuntimeTypeSystem_1.NonValidated.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 58fb7ae476bdb..1ffa5b4578233 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -143,7 +143,7 @@ internal int NativeCodeSlotIndex { throw new InvalidOperationException("no native code slot"); } - return 1 + AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot | MethodDescFlags.HasNativeCodeSlot); + return 1 + AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot | MethodDescFlags.HasMethodImpl); } } From 63e0334755936e24222efd1c7e8c6540e685371f Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 5 Aug 2024 15:59:37 -0400 Subject: [PATCH 25/66] fixup additional pointers packing index --- .../src/Contracts/RuntimeTypeSystem_1.NonValidated.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 1ffa5b4578233..83b3847e788f6 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -122,7 +122,7 @@ private int AdditionalPointersHelper(MethodDescFlags extraFlags) => int.PopCount(_desc.Flags & (ushort)extraFlags); // non-vtable slot, native code slot and MethodImpl slots are stored after the MethodDesc itself, packed tightly - // in the order: [non-vtable; native code; method-impl]. + // in the order: [non-vtable; methhod impl; native code]. internal int NonVtableSlotIndex => HasNonVtableSlot ? 0 : throw new InvalidOperationException("no non-vtable slot"); internal int MethodImplIndex { @@ -132,7 +132,7 @@ internal int MethodImplIndex { throw new InvalidOperationException("no method impl slot"); } - return 1 + AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot); + return AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot); } } internal int NativeCodeSlotIndex @@ -143,7 +143,7 @@ internal int NativeCodeSlotIndex { throw new InvalidOperationException("no native code slot"); } - return 1 + AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot | MethodDescFlags.HasMethodImpl); + return AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot | MethodDescFlags.HasMethodImpl); } } From c177e4d39322207f49538fc9b4df577c78b8bfb5 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 5 Aug 2024 16:23:22 -0400 Subject: [PATCH 26/66] fix logic typo --- .../src/Contracts/NativeCodePointers_1.ExecutionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index 9560a508d5a6c..72ce143398d5b 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -246,7 +246,7 @@ private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) } rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); // TODO: load? } - if (rangeSectionFragmentPtr.IsNull) + if (!rangeSectionFragmentPtr.IsNull) { Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); Data.RangeSection rangeSection = _target.ProcessedData.GetOrAdd(fragment.RangeSection); From 3956b0689a886867c9323e417ce36e3100e8781b Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 7 Aug 2024 16:06:57 -0400 Subject: [PATCH 27/66] checkpoint: jitted methods validate --- .../Contracts/NativeCodePointers_1.ExecutionManager.cs | 8 ++++++-- .../src/Contracts/NativeCodePointers_1.NibbleMap.cs | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index 72ce143398d5b..cc774c5a0ed97 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -141,8 +141,7 @@ public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddre case JitManagerKind.EEJitManager: return EEJitCodeToMethodInfo(target, jittedCodeAddress, out methodDescAddress); case JitManagerKind.ReadyToRunJitManager: - methodDescAddress = TargetPointer.Null; - throw new NotImplementedException(); // TODO[cdac]: + return ReadyToRunJitCodeToMethodInfo(target, jittedCodeAddress, out methodDescAddress); default: throw new InvalidOperationException($"Invalid JitManagerKind {jitManager.JitManagerKind}"); } @@ -203,8 +202,13 @@ private TargetPointer EEFindMethodCode(Target target, TargetCodePointer jittedCo return nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); } + private bool ReadyToRunJitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + { + throw new NotImplementedException(); // TODO(cdac): ReadyToRunJitManager::JitCodeToMethodInfo + } } + // note: level is 1-indexed private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, TargetCodePointer address, int level) { diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs index 9fa6076e2070d..c69e1ae3a0840 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs @@ -73,9 +73,9 @@ private static ulong ComputeByteOffset(ulong mapIdx, uint nibble) { return mapIdx * BytesPerBucket + (nibble - 1) * MapUnitBytes; } - private TargetPointer GetAbsoluteAddress(TargetPointer baseAddress, ulong mapIdx, uint nibble) + private static TargetPointer GetAbsoluteAddress(TargetPointer baseAddress, ulong mapIdx, uint nibble) { - return baseAddress + ComputeByteOffset(mapIdx, nibble) - _codeHeaderSize; + return baseAddress + ComputeByteOffset(mapIdx, nibble); } // Given a relative address, decompose it into From 0b91b85f4fc35404a51e8604762008879f612f24 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 7 Aug 2024 16:33:09 -0400 Subject: [PATCH 28/66] more asserts in legacy GetMethodDescData --- src/coreclr/debug/daccess/request.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 5fd4428ad092e..7947988d0a48e 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1089,7 +1089,15 @@ HRESULT ClrDataAccess::GetMethodDescData( _ASSERTE(methodDescData->wSlotNumber == mdDataLocal.wSlotNumber); _ASSERTE(methodDescData->NativeCodeAddr == mdDataLocal.NativeCodeAddr); _ASSERTE(methodDescData->AddressOfNativeCodeSlot == mdDataLocal.AddressOfNativeCodeSlot); - //TODO[cdac]: assert the rest of mdDataLocal contains the same info as methodDescData + _ASSERTE(methodDescData->MethodDescPtr == mdDataLocal.MethodDescPtr); + _ASSERTE(methodDescData->MethodTablePtr == mdDataLocal.MethodTablePtr); + _ASSERTE(methodDescData->ModulePtr == mdDataLocal.ModulePtr); + _ASSERTE(methodDescData->MDToken == mdDataLocal.MDToken); + _ASSERTE(methodDescData->GCInfo == mdDataLocal.GCInfo); + _ASSERTE(methodDescData->GCStressCodeCopy == mdDataLocal.GCStressCodeCopy); + _ASSERTE(methodDescData->managedDynamicMethodObject == mdDataLocal.managedDynamicMethodObject); + _ASSERTE(methodDescData->requestedIP == mdDataLocal.requestedIP); + _ASSERTE(methodDescData->cJittedRejitVersions == mdDataLocal.cJittedRejitVersions); if (rgRevertedRejitData != NULL) { _ASSERTE (cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData); From d3a8bb039554aca878c3984df35810c6642a3ce0 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 7 Aug 2024 16:33:23 -0400 Subject: [PATCH 29/66] WIP: native code version --- .../cdacreader/src/Legacy/SOSDacImpl.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index c311393f14797..fe95a31d0be25 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.DataContractReader.Contracts; using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; @@ -105,6 +106,26 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; Contracts.MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(methodDesc); + if (rgRevertedRejitData != null) + { + NativeMemory.Clear(rgRevertedRejitData, (nuint)(sizeof(DacpReJitData) * cRevertedRejitVersions)); + } + if (pcNeededRevertedRejitData != null) + { + *pcNeededRevertedRejitData = 0; + } + + NativeCodeVersionHandle requestedCodeVersion, activeCodeVersion; ; + if (ip != null) + { + throw new NotImplementedException(); // TODO[cdac]: ExecutionManager::GetNativeCodeVersion + } + else + { + activeCodeVersion = rtsContract.GetActiveNativeCodeVersion(methodDescHandle); // TODO[cdac]: pMD->GetCodeVersionManager()->GetActiveILCodeVersion(pMD).GetActiveNativeCodeVersion(pMD) + requestedCodeVersion = activeCodeVersion; + } + data->requestedIP = ip; data->bIsDynamic = rtsContract.IsDynamicMethod(methodDescHandle) ? 1 : 0; data->MethodTablePtr = rtsContract.GetMethodTable(methodDescHandle); From 5fcdc608b3d7ff1baf79fdc4628a39b41e71baf1 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 8 Aug 2024 11:57:11 -0400 Subject: [PATCH 30/66] WIP: native code version --- .../src/Contracts/NativeCodePointers.cs | 15 ++++++++++++ .../NativeCodePointers_1.NativeCodeVersion.cs | 24 +++++++++++++++++++ .../cdacreader/src/Legacy/SOSDacImpl.cs | 16 +++++++++---- 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index 666e0fa153fa5..fc3362a86c8a8 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -23,6 +23,21 @@ static IContract IContract.Create(Target target, int version) public virtual TargetPointer MethodDescFromStubAddress(TargetCodePointer codeAddress) => throw new NotImplementedException(); public virtual TargetPointer ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); + + public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException(); + public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); +} + +internal struct NativeCodeVersionHandle +{ + // no public constructors + internal readonly TargetPointer _methodDescAddress; + internal readonly TargetPointer _codeVersionNodeAddress; + internal NativeCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer codeVersionNodeAddress) + { + _methodDescAddress = methodDescAddress; + _codeVersionNodeAddress = codeVersionNodeAddress; + } } internal readonly struct NativeCodePointers : INativeCodePointers diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs new file mode 100644 index 0000000000000..457434e322bfa --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Numerics; + +using MapUnit = uint; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + + +#pragma warning disable SA1121 // Use built in alias +internal readonly partial struct NativeCodePointers_1 : INativeCodePointers +{ + internal struct NativeCodeVersionContract + { + private readonly Target _target; + + public NativeCodeVersionContract(Target target) + { + _target = target; + } + } +} diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index fe95a31d0be25..6c4d6b46b2df2 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -101,10 +101,15 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa // elements we return return HResults.E_INVALIDARG; } + if (cRevertedRejitVersions != 0) + { + return HResults.E_NOTIMPL; // TODO[cdac]: rejit + } try { Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; Contracts.MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(methodDesc); + Contracts.INativeCodePointers nativeCodeContract = _target.Contracts.NativeCodePointers; if (rgRevertedRejitData != null) { @@ -115,15 +120,16 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa *pcNeededRevertedRejitData = 0; } - NativeCodeVersionHandle requestedCodeVersion, activeCodeVersion; ; - if (ip != null) + NativeCodeVersionHandle requestedCodeVersion; + NativeCodeVersionHandle? activeCodeVersion = null; + if (ip != 0) { - throw new NotImplementedException(); // TODO[cdac]: ExecutionManager::GetNativeCodeVersion + requestedCodeVersion = nativeCodeContract.GetSpecificNativeCodeVersion(new TargetCodePointer(ip)); } else { - activeCodeVersion = rtsContract.GetActiveNativeCodeVersion(methodDescHandle); // TODO[cdac]: pMD->GetCodeVersionManager()->GetActiveILCodeVersion(pMD).GetActiveNativeCodeVersion(pMD) - requestedCodeVersion = activeCodeVersion; + requestedCodeVersion = nativeCodeContract.GetActiveNativeCodeVersion(new TargetPointer(methodDesc)); // TODO[cdac]: pMD->GetCodeVersionManager()->GetActiveILCodeVersion(pMD).GetActiveNativeCodeVersion(pMD) + activeCodeVersion = requestedCodeVersion; } data->requestedIP = ip; From efad4eaccf85bcc6c124551f75648dfac5f0faea Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 9 Aug 2024 11:48:52 -0400 Subject: [PATCH 31/66] checkpoint start adding NativeCodeVersion operations --- .../debug/runtimeinfo/datadescriptor.h | 10 +++ src/coreclr/vm/ceeload.h | 1 - src/coreclr/vm/loaderallocator.cpp | 4 +- src/coreclr/vm/loaderallocator.hpp | 24 ++++-- .../managed/cdacreader/src/Constants.cs | 1 + .../cdacreader/src/Contracts/Loader.cs | 2 + .../cdacreader/src/Contracts/Loader_1.cs | 8 ++ .../src/Contracts/NativeCodePointers.cs | 14 +++- .../NativeCodePointers_1.ExecutionManager.cs | 14 +++- .../NativeCodePointers_1.NativeCodeVersion.cs | 10 ++- .../src/Contracts/NativeCodePointers_1.cs | 45 ++++++++++- .../src/Contracts/RuntimeTypeSystem.cs | 4 + .../src/Contracts/RuntimeTypeSystem_1.cs | 78 +++++++++++++++++++ .../cdacreader/src/Data/LoaderAllocator.cs | 19 +++++ .../cdacreader/src/Data/ProfControlBlock.cs | 18 +++++ src/native/managed/cdacreader/src/DataType.cs | 2 + .../cdacreader/src/Legacy/ICorProfiler.cs | 13 ++++ 17 files changed, 248 insertions(+), 19 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/LoaderAllocator.cs create mode 100644 src/native/managed/cdacreader/src/Data/ProfControlBlock.cs create mode 100644 src/native/managed/cdacreader/src/Legacy/ICorProfiler.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index d67a5699a9a34..6786d10e093e3 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -235,6 +235,11 @@ CDAC_TYPE_BEGIN(ModuleLookupMap) CDAC_TYPE_FIELD(ModuleLookupMap, /*pointer*/, TableData, offsetof(LookupMapBase, pTable)) CDAC_TYPE_END(ModuleLookupMap) +CDAC_TYPE_BEGIN(LoaderAllocator) +CDAC_TYPE_INDETERMINATE(LoaderAllocator) +CDAC_TYPE_FIELD(LoaderAllocator, /*uint8*/, IsCollectible, cdac_data::IsCollectible) +CDAC_TYPE_END(LoaderAllocator) + // RuntimeTypeSystem CDAC_TYPE_BEGIN(MethodTable) @@ -412,6 +417,10 @@ CDAC_TYPE_FIELD(HeapList, /*pointer*/, MapBase, offsetof(HeapList, mapBase)) CDAC_TYPE_FIELD(HeapList, /*pointer*/, HeaderMap, offsetof(HeapList, pHdrMap)) CDAC_TYPE_END(HeapList) +CDAC_TYPE_BEGIN(ProfControlBlock) +CDAC_TYPE_FIELD(ProfControlBlock, /*uint64*/, GlobalEventMask, offsetof(ProfControlBlock, globalEventMask)) +CDAC_TYPE_END(ProfControlBlock) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -453,6 +462,7 @@ CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize) CDAC_GLOBAL_POINTER(PrecodeMachineDescriptor, &::g_PrecodeMachineDescriptor) CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_data::CodeRangeMapAddress) +CDAC_GLOBAL_POINTER(ProfilerControlBlock, &::g_profControlBlock) CDAC_GLOBALS_END() #undef CDAC_BASELINE diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 5fee2e09f4bf7..bc3a232459d60 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -585,7 +585,6 @@ class ModuleBase // string helper void InitializeStringData(DWORD token, EEStringData *pstrData, CQuickBytes *pqb); #endif - }; // A code:Module represents a DLL or EXE file loaded from the disk. A module live in a code:Assembly diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 6cc8b62480a00..c76746ca3e9de 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -17,7 +17,7 @@ UINT64 LoaderAllocator::cLoaderAllocatorsCreated = 1; -LoaderAllocator::LoaderAllocator(bool collectible) : +LoaderAllocator::LoaderAllocator(bool collectible) : m_stubPrecodeRangeList(STUB_CODE_BLOCK_STUBPRECODE, collectible), m_fixupPrecodeRangeList(STUB_CODE_BLOCK_FIXUPPRECODE, collectible) { @@ -68,7 +68,7 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_pLastUsedCodeHeap = NULL; m_pLastUsedDynamicCodeHeap = NULL; m_pJumpStubCache = NULL; - m_IsCollectible = collectible; + m_IsCollectible = collectible ? 1 : 0; m_pMarshalingData = NULL; diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 0bf475e33d5fa..6271692294550 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -47,7 +47,7 @@ class CodeRangeMapRangeList : public RangeList VPTR_VTABLE_CLASS(CodeRangeMapRangeList, RangeList) #if defined(DACCESS_COMPILE) || !defined(TARGET_WINDOWS) - CodeRangeMapRangeList() : + CodeRangeMapRangeList() : _RangeListRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT), _rangeListType(STUB_CODE_BLOCK_UNKNOWN), _id(NULL), @@ -55,7 +55,7 @@ class CodeRangeMapRangeList : public RangeList {} #endif - CodeRangeMapRangeList(StubCodeBlockKind rangeListType, bool collectible) : + CodeRangeMapRangeList(StubCodeBlockKind rangeListType, bool collectible) : _RangeListRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT), _rangeListType(rangeListType), _id(NULL), @@ -84,7 +84,7 @@ class CodeRangeMapRangeList : public RangeList _ASSERTE(id == _id || _id == NULL); _id = id; - // Grow the array first, so that a failure cannot break the + // Grow the array first, so that a failure cannot break the RangeSection::RangeSectionFlags flags = RangeSection::RANGE_SECTION_RANGELIST; if (_collectible) @@ -92,7 +92,7 @@ class CodeRangeMapRangeList : public RangeList _starts.Preallocate(_starts.GetCount() + 1); flags = (RangeSection::RangeSectionFlags)(flags | RangeSection::RANGE_SECTION_COLLECTIBLE); } - + ExecutionManager::AddCodeRange(start, end, ExecutionManager::GetEEJitManager(), flags, this); if (_collectible) @@ -145,7 +145,7 @@ class CodeRangeMapRangeList : public RangeList // This implementation only works for the case where the RangeList is used in a single LoaderHeap _ASSERTE(start == NULL); _ASSERTE(end == NULL); - + SimpleWriteLockHolder lh(&_RangeListRWLock); _ASSERTE(id == _id || (_id == NULL && _starts.IsEmpty())); @@ -171,7 +171,7 @@ class CodeRangeMapRangeList : public RangeList return FALSE; if ((pRS->_flags & RangeSection::RANGE_SECTION_RANGELIST) == 0) return FALSE; - + return (pRS->_pRangeList == this); } @@ -332,7 +332,7 @@ class LoaderAllocator bool m_fTerminated; bool m_fMarked; int m_nGCCount; - bool m_IsCollectible; + BYTE m_IsCollectible; // Pre-allocated blocks of heap for collectible assemblies. Will be set to NULL as soon as it is // used. See code in GetVSDHeapInitialBlock and GetCodeHeapInitialBlock @@ -570,7 +570,7 @@ class LoaderAllocator DispatchToken GetDispatchToken(UINT32 typeId, UINT32 slotNumber); virtual LoaderAllocatorID* Id() =0; - BOOL IsCollectible() { WRAPPER_NO_CONTRACT; return m_IsCollectible; } + BOOL IsCollectible() { WRAPPER_NO_CONTRACT; return m_IsCollectible != 0; } // This function may only be called while the runtime is suspended // As it does not lock around access to a RangeList @@ -865,8 +865,16 @@ class LoaderAllocator virtual void UnregisterDependentHandleToNativeObjectFromCleanup(LADependentHandleToNativeObject *dependentHandle) {}; virtual void CleanupDependentHandlesToNativeObjects() {}; #endif + + template friend struct ::cdac_data; }; // class LoaderAllocator +template<> +struct cdac_data +{ + static constexpr size_t IsCollectible = offsetof(LoaderAllocator, m_IsCollectible); +}; + typedef VPTR(LoaderAllocator) PTR_LoaderAllocator; extern "C" BOOL QCALLTYPE LoaderAllocator_Destroy(QCall::LoaderAllocatorHandle pLoaderAllocator); diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs index 41df7d732aebb..4b9a218d0276e 100644 --- a/src/native/managed/cdacreader/src/Constants.cs +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -43,5 +43,6 @@ internal static class Globals internal const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); internal const string StubCodeBlockLast = nameof(StubCodeBlockLast); + internal const string ProfilerControlBlock = nameof(ProfilerControlBlock); } } diff --git a/src/native/managed/cdacreader/src/Contracts/Loader.cs b/src/native/managed/cdacreader/src/Contracts/Loader.cs index a71bdd4d12951..39ced78bd67f9 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader.cs @@ -54,6 +54,8 @@ static IContract IContract.Create(Target target, int version) public virtual TargetPointer GetThunkHeap(ModuleHandle handle) => throw new NotImplementedException(); public virtual TargetPointer GetILBase(ModuleHandle handle) => throw new NotImplementedException(); public virtual ModuleLookupTables GetLookupTables(ModuleHandle handle) => throw new NotImplementedException(); + + public virtual bool IsCollectibleLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException(); } internal readonly struct Loader : ILoader diff --git a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs index 215eaed4a39a3..c77cd21c77c4b 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs @@ -91,4 +91,12 @@ ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle) module.TypeRefToMethodTableMap, module.MethodDefToILCodeVersioningStateMap); } + + bool ILoader.IsCollectibleLoaderAllocator(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + TargetPointer loaderAllocator = module.LoaderAllocator; + Data.LoaderAllocator la = _target.ProcessedData.GetOrAdd(loaderAllocator); + return la.IsCollectible != 0; + } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index fc3362a86c8a8..2a4a14925a421 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -14,9 +14,11 @@ static IContract IContract.Create(Target target, int version) Data.PrecodeMachineDescriptor precodeMachineDescriptor = target.ProcessedData.GetOrAdd(precodeMachineDescriptorAddress); TargetPointer executionManagerCodeRangeMapAddress = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress); Data.RangeSectionMap rangeSectionMap = target.ProcessedData.GetOrAdd(executionManagerCodeRangeMapAddress); + TargetPointer profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock); + Data.ProfControlBlock profControlBlock = target.ProcessedData.GetOrAdd(profControlBlockAddress); return version switch { - 1 => new NativeCodePointers_1(target, precodeMachineDescriptor, rangeSectionMap), + 1 => new NativeCodePointers_1(target, precodeMachineDescriptor, rangeSectionMap, profControlBlock), _ => default(NativeCodePointers), }; } @@ -26,6 +28,9 @@ static IContract IContract.Create(Target target, int version) public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException(); public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); + + public virtual bool IsReJITEnabled() => throw new NotImplementedException(); + public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); } internal struct NativeCodeVersionHandle @@ -35,9 +40,16 @@ internal struct NativeCodeVersionHandle internal readonly TargetPointer _codeVersionNodeAddress; internal NativeCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer codeVersionNodeAddress) { + if (methodDescAddress != TargetPointer.Null && codeVersionNodeAddress != TargetPointer.Null) + { + throw new ArgumentException("Only one of methodDescAddress and codeVersionNodeAddress can be non-null"); + } _methodDescAddress = methodDescAddress; _codeVersionNodeAddress = codeVersionNodeAddress; } + + internal static NativeCodeVersionHandle Invalid => new(TargetPointer.Null, TargetPointer.Null); + public bool Valid => _methodDescAddress != TargetPointer.Null || _codeVersionNodeAddress != TargetPointer.Null; } internal readonly struct NativeCodePointers : INativeCodePointers diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index cc774c5a0ed97..1fb6eb8056c19 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -85,6 +85,7 @@ public static TargetCodeManagerDescriptor Create(Target target) internal struct ExecutionManagerContract { internal readonly Target _target; + private readonly Data.ProfControlBlock _profControlBlock; private readonly Data.RangeSectionMap _topRangeSectionMap; private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; @@ -95,11 +96,12 @@ internal enum JitManagerKind ReadyToRunJitManager = 1, } - public ExecutionManagerContract(Target target, Data.RangeSectionMap topRangeSectionMap) + public ExecutionManagerContract(Target target, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) { _target = target; _topRangeSectionMap = topRangeSectionMap; _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); + _profControlBlock = profControlBlock; } [Flags] @@ -281,5 +283,15 @@ private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) return nextLevelAddress; } + internal bool IsReJITEnabled() + { + bool profEnabledReJIT = (_profControlBlock.GlobalEventMask & (ulong)Legacy.COR_PRF_MONITOR.COR_PRF_ENABLE_REJIT) != 0; + // FIXME: it is very likely this is always true in the DAC + // Most people don't set DOTNET_ProfAPI_RejitOnAttach = 0 + // See https://github.com/dotnet/runtime/issues/106148 + bool clrConfigEnabledReJIT = true; + return profEnabledReJIT || clrConfigEnabledReJIT; + } + } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index 457434e322bfa..1bf0cbeb034b4 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -2,14 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Numerics; - -using MapUnit = uint; namespace Microsoft.Diagnostics.DataContractReader.Contracts; -#pragma warning disable SA1121 // Use built in alias internal readonly partial struct NativeCodePointers_1 : INativeCodePointers { internal struct NativeCodeVersionContract @@ -20,5 +16,11 @@ public NativeCodeVersionContract(Target target) { _target = target; } + + public NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) + { + throw new NotImplementedException(); + } + } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index e8acd7c785de8..a0850e884deed 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -10,13 +10,15 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; private readonly Target _target; private readonly PrecodeContract _precodeContract; private readonly ExecutionManagerContract _executionManagerContract; + private readonly NativeCodeVersionContract _nativeCodeVersionContract; - public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor, Data.RangeSectionMap topRangeSectionMap) + public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) { _target = target; _precodeContract = new PrecodeContract(target, precodeMachineDescriptor); - _executionManagerContract = new ExecutionManagerContract(target, topRangeSectionMap); + _executionManagerContract = new ExecutionManagerContract(target, topRangeSectionMap, profControlBlock); + _nativeCodeVersionContract = new NativeCodeVersionContract(target); } TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer entryPoint) @@ -36,4 +38,43 @@ TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePo return info.MethodDescAddress; } + NativeCodeVersionHandle INativeCodePointers.GetSpecificNativeCodeVersion(TargetCodePointer ip) + { + EECodeInfo? info = _executionManagerContract.GetEECodeInfo(ip); + if (info == null || !info.Valid) + { + return NativeCodeVersionHandle.Invalid; + } + TargetPointer methodDescAddress = info.MethodDescAddress; + if (methodDescAddress == TargetPointer.Null) + { + return NativeCodeVersionHandle.Invalid; + } + + return _nativeCodeVersionContract.GetSpecificNativeCodeVersion(ip); + } + + bool INativeCodePointers.IsReJITEnabled() + { + return _executionManagerContract.IsReJITEnabled(); + } + + bool INativeCodePointers.CodeVersionManagerSupportsMethod(TargetPointer methodDescAddress) + { + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); + if (rts.IsDynamicMethod(md)) + return false; + if (rts.IsCollectibleMethod(md)) + return false; + TargetPointer mtAddr = rts.GetMethodTable(md); + TypeHandle mt = rts.GetTypeHandle(mtAddr); + TargetPointer modAddr = rts.GetModule(mt); + ILoader loader = _target.Contracts.Loader; + ModuleHandle mod = loader.GetModuleHandle(modAddr); + ModuleFlags modFlags = loader.GetFlags(mod); + if (modFlags.HasFlag(ModuleFlags.EditAndContinue)) + return false; + return true; + } } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index 5a87fe72f1535..2e0468071419f 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -164,6 +164,10 @@ static IContract IContract.Create(Target target, int version) // A IL Stub method is also a StoredSigMethodDesc, and a NoMetadataMethod public virtual bool IsILStub(MethodDescHandle methodDesc) => throw new NotImplementedException(); +======= + public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc) => throw new NotImplementedException(); + public virtual bool InEnCEnabledModule(MethodDescHandle methodDesc) => throw new NotImplementedException(); + public virtual bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index b46debb9b1b31..474c63b6d05c4 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -106,6 +106,8 @@ internal enum MethodDescFlags3 : ushort // HasPrecode implies that HasStableEntryPoint is set. HasStableEntryPoint = 0x1000, // The method entrypoint is stable (either precode or actual code) HasPrecode = 0x2000, // Precode has been allocated for this method + IsUnboxingStub = 0x4000, + IsEligibleForTieredCompilation = 0x8000, } internal enum MethodClassification @@ -180,6 +182,14 @@ private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.Metho } public MethodClassification Classification => (MethodClassification)((int)_desc.Flags & (int)MethodDescFlags.ClassificationMask); + + internal bool HasFlags(MethodDescFlags3 flags) => (_desc.Flags3AndTokenRemainder & (ushort)flags) != 0; + + public bool IsEligibleForTieredCompilation => HasFlags(MethodDescFlags3.IsEligibleForTieredCompilation); + + + public bool IsUnboxingStub => HasFlags(MethodDescFlags3.IsUnboxingStub); + } private class InstantiatedMethodDesc : IData @@ -834,4 +844,72 @@ private TargetPointer GetAddressOfSlot(TypeHandle typeHandle, uint slotNum) } + private bool IsWrapperStub(MethodDesc md) + { + return md.IsUnboxingStub || IsInstantiatingStub(md); + } + + private bool IsInstantiatingStub(MethodDesc md) + { + return md.Classification == MethodClassification.Instantiated && !md.IsUnboxingStub && AsInstantiatedMethodDesc(md).IsWrapperStubWithInstantiations; + } + + private bool HasMethodInstantiation(MethodDesc md) + { + return md.Classification == MethodClassification.Instantiated && AsInstantiatedMethodDesc(md).HasMethodInstantiation; + } + + private TargetPointer GetLoaderModule(TypeHandle typeHandle) + { + throw new NotImplementedException(); + } + + private bool IsGenericMethodDefinition(MethodDesc md) + { + return md.Classification == MethodClassification.Instantiated && AsInstantiatedMethodDesc(md).IsGenericMethodDefinition; + } + + private TargetPointer GetLoaderModule(MethodDesc md) + { + + if (HasMethodInstantiation(md) && !IsGenericMethodDefinition(md)) + { + // TODO[cdac]: don't reimplement ComputeLoaderModuleWorker, + // but try caching the LoaderModule (or just the LoaderAllocator?) on the + // MethodDescChunk (and maybe MethodTable?). + throw new NotImplementedException(); + } + else + { + TargetPointer mtAddr = GetMethodTable(new MethodDescHandle(md.Address)); + TypeHandle mt = GetTypeHandle(mtAddr); + return GetLoaderModule(mt); + } + } + + bool IRuntimeTypeSystem.IsCollectibleMethod(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + TargetPointer loaderModuleAddr = GetLoaderModule(md); + ModuleHandle mod = _target.Contracts.Loader.GetModuleHandle(loaderModuleAddr); + return _target.Contracts.Loader.IsCollectibleLoaderAllocator(mod); // TODO[cdac]: return pMethodDesc->GetLoaderAllocator()->IsCollectible() + } + + bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + if (md.IsEligibleForTieredCompilation) + return true; + // MethodDesc::IsEligibleForReJIT + if (_target.Contracts.NativeCodePointers.IsReJITEnabled()) + { + if (!md.IsIL) + return false; + if (IsWrapperStub(md)) + return false; + return _target.Contracts.NativeCodePointers.CodeVersionManagerSupportsMethod(methodDesc.Address); + } + return false; + } + } diff --git a/src/native/managed/cdacreader/src/Data/LoaderAllocator.cs b/src/native/managed/cdacreader/src/Data/LoaderAllocator.cs new file mode 100644 index 0000000000000..7d5a2ebc5f04a --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/LoaderAllocator.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class LoaderAllocator : IData +{ + static LoaderAllocator IData.Create(Target target, TargetPointer address) => new LoaderAllocator(target, address); + public LoaderAllocator(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.LoaderAllocator); + + IsCollectible = target.Read(address + (ulong)type.Fields[nameof(IsCollectible)].Offset); + } + + public byte IsCollectible { get; init; } +} diff --git a/src/native/managed/cdacreader/src/Data/ProfControlBlock.cs b/src/native/managed/cdacreader/src/Data/ProfControlBlock.cs new file mode 100644 index 0000000000000..e598647b7dee6 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/ProfControlBlock.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 ProfControlBlock : IData +{ + static ProfControlBlock IData.Create(Target target, TargetPointer address) + => new ProfControlBlock(target, address); + + public ProfControlBlock(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ProfControlBlock); + GlobalEventMask = target.Read(address + (ulong)type.Fields[nameof(GlobalEventMask)].Offset); + } + + public ulong GlobalEventMask { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 324deb5ad1a58..0ccfe9375319c 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -29,6 +29,7 @@ public enum DataType RuntimeThreadLocals, Module, ModuleLookupMap, + LoaderAllocator, MethodTable, EEClass, ArrayClass, @@ -60,4 +61,5 @@ public enum DataType IJitManager, RealCodeHeader, HeapList, + ProfControlBlock, } diff --git a/src/native/managed/cdacreader/src/Legacy/ICorProfiler.cs b/src/native/managed/cdacreader/src/Legacy/ICorProfiler.cs new file mode 100644 index 0000000000000..f9173590eefbf --- /dev/null +++ b/src/native/managed/cdacreader/src/Legacy/ICorProfiler.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Microsoft.Diagnostics.DataContractReader.Legacy; + +internal enum COR_PRF_MONITOR +{ + COR_PRF_ENABLE_REJIT = 0x00040000, +} From 6febf724eae2464ea32fee70facdb471ca570320 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 9 Aug 2024 17:35:50 -0400 Subject: [PATCH 32/66] checkpoint: NativeCodeVersionContract.GetSpecificNativeCodeVersion --- .../debug/runtimeinfo/datadescriptor.h | 20 +++++++ src/coreclr/vm/appdomain.hpp | 12 ++++ src/coreclr/vm/codeversion.h | 18 ++++++ .../NativeCodePointers_1.ExecutionManager.cs | 56 +++++++++++-------- .../NativeCodePointers_1.NativeCodeVersion.cs | 34 ++++++++++- .../src/Contracts/NativeCodePointers_1.cs | 21 ++++++- .../src/Contracts/RuntimeTypeSystem.cs | 2 + .../src/Contracts/RuntimeTypeSystem_1.cs | 9 +++ .../managed/cdacreader/src/Data/AppDomain.cs | 19 +++++++ .../cdacreader/src/Data/MethodDescCodeData.cs | 2 + .../src/Data/MethodDescVersioningState.cs | 19 +++++++ .../src/Data/NativeCodeVersionNode.cs | 24 ++++++++ src/native/managed/cdacreader/src/DataType.cs | 4 ++ 13 files changed, 211 insertions(+), 29 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/AppDomain.cs create mode 100644 src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs create mode 100644 src/native/managed/cdacreader/src/Data/NativeCodeVersionNode.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 6786d10e093e3..4d2d5cbe3ac09 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -212,6 +212,13 @@ CDAC_TYPE_END(SyncTableEntry) // Loader +CDAC_TYPE_BEGIN(AppDomain) +CDAC_TYPE_INDETERMINATE(AppDomain) +#ifdef FEATURE_CODE_VERSIONING +CDAC_TYPE_FIELD(AppDomain, /*pointer*/, CodeVersionManager, cdac_data::CodeVersionManager) +#endif +CDAC_TYPE_END(AppDomain) + CDAC_TYPE_BEGIN(Module) CDAC_TYPE_INDETERMINATE(Module) CDAC_TYPE_FIELD(Module, /*pointer*/, Assembly, cdac_data::Assembly) @@ -348,8 +355,14 @@ CDAC_TYPE_END(CodePointer) CDAC_TYPE_BEGIN(MethodDescCodeData) CDAC_TYPE_INDETERMINATE(MethodDescCodeData) CDAC_TYPE_FIELD(MethodDescCodeData, /*CodePointer*/, TemporaryEntryPoint, offsetof(MethodDescCodeData,TemporaryEntryPoint)) +CDAC_TYPE_FIELD(MethodDescCodeData, /*pointer*/, VersioningState, offsetof(MethodDescCodeData,VersioningState)) CDAC_TYPE_END(MethodDescCodeData) +CDAC_TYPE_BEGIN(MethodDescVersioningState) +CDAC_TYPE_INDETERMINATE(MethodDescVersioningState) +CDAC_TYPE_FIELD(MethodDescVersioningState, /*pointer*/, NativeCodeVersionNode, cdac_data::NativeCodeVersionNode) +CDAC_TYPE_END(MethodDescVersioningState) + CDAC_TYPE_BEGIN(PrecodeMachineDescriptor) CDAC_TYPE_INDETERMINATE(PrecodeMachineDescriptor) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uintptr*/, CodePointerToInstrPointerMask, offsetof(PrecodeMachineDescriptor, CodePointerToInstrPointerMask)) @@ -417,6 +430,13 @@ CDAC_TYPE_FIELD(HeapList, /*pointer*/, MapBase, offsetof(HeapList, mapBase)) CDAC_TYPE_FIELD(HeapList, /*pointer*/, HeaderMap, offsetof(HeapList, pHdrMap)) CDAC_TYPE_END(HeapList) +CDAC_TYPE_BEGIN(NativeCodeVersionNode) +CDAC_TYPE_INDETERMINATE(NativeCodeVersionNode) +CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, Next, cdac_data::Next) +CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, MethodDesc, cdac_data::MethodDesc) +CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, NativeCode, cdac_data::NativeCode) +CDAC_TYPE_END(NativeCodeVersionNode) + CDAC_TYPE_BEGIN(ProfControlBlock) CDAC_TYPE_FIELD(ProfControlBlock, /*uint64*/, GlobalEventMask, offsetof(ProfControlBlock, globalEventMask)) CDAC_TYPE_END(ProfControlBlock) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index a81f1a6a054a3..8fa8dd78de77d 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -35,6 +35,8 @@ #include "codeversion.h" +#include "cdacdata.h" + class BaseDomain; class SystemDomain; class AppDomain; @@ -1817,8 +1819,18 @@ class AppDomain : public BaseDomain TieredCompilationManager m_tieredCompilationManager; #endif + + template friend struct ::cdac_data; }; // class AppDomain +template<> +struct cdac_data +{ +#ifdef FEATURE_CODE_VERSIONING + static constexpr size_t CodeVersionManager = offsetof(AppDomain, m_CodeVersionManager); +#endif +}; + // Just a ref holder typedef ReleaseHolder AppDomainRefHolder; diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index bd778bd47d7bf..16c969ca75f89 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -316,6 +316,16 @@ class NativeCodeVersionNode IsActiveChildFlag = 1 }; DWORD m_flags; + + template friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + static constexpr size_t Next = offsetof(NativeCodeVersionNode, m_pNextMethodDescSibling); + static constexpr size_t MethodDesc = offsetof(NativeCodeVersionNode, m_pMethodDesc); + static constexpr size_t NativeCode = offsetof(NativeCodeVersionNode, m_pNativeCode); }; class NativeCodeVersionCollection @@ -473,6 +483,14 @@ class MethodDescVersioningState BYTE m_flags; NativeCodeVersionId m_nextId; PTR_NativeCodeVersionNode m_pFirstVersionNode; + + template friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + static constexpr size_t NativeCodeVersionNode = offsetof(MethodDescVersioningState, m_pFirstVersionNode); }; class ILCodeVersioningState diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index 1fb6eb8056c19..858ecd31541ee 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -9,15 +11,25 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; { internal class EECodeInfo { - public TargetCodePointer CodeAddress { get; } - public TargetPointer MethodDescAddress { get; } - public EECodeInfo(TargetCodePointer jittedCodeAdderss, TargetPointer methodDescAddress) + private readonly int _codeHeaderOffset; + public TargetCodePointer StartAddress { get; } + // note: this is the address of the pointer to the "real code header", you need to + // dereference it to get the address of _codeHeaderData + public TargetPointer CodeHeaderAddress => StartAddress.Value - (ulong)_codeHeaderOffset; + private Data.RealCodeHeader _codeHeaderData; + public TargetPointer JitManagerAddress { get; } + public TargetNUInt RelativeOffset { get; } + public EECodeInfo(TargetCodePointer startAddress, int codeHeaderOffset, TargetNUInt relativeOffset, Data.RealCodeHeader codeHeaderData, TargetPointer jitManagerAddress) { - CodeAddress = jittedCodeAdderss; - MethodDescAddress = methodDescAddress; + _codeHeaderOffset = codeHeaderOffset; + StartAddress = startAddress; + _codeHeaderData = codeHeaderData; + RelativeOffset = relativeOffset; + JitManagerAddress = jitManagerAddress; } - public bool Valid => CodeAddress != default && MethodDescAddress != default; + public TargetPointer MethodDescAddress => _codeHeaderData.MethodDesc; + public bool Valid => JitManagerAddress != TargetPointer.Null; } // RangeFragment and RangeSection pointers have a collectible flag on the lowest bit @@ -128,50 +140,52 @@ public RangeSection(Data.RangeSection rangeSection) private bool IsRangeList => HasFlags(RangeSectionFlags.RangeList); private bool IsCodeHeap => HasFlags(RangeSectionFlags.CodeHeap); - public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) { + info = null; if (_rangeSection == null) { - methodDescAddress = TargetPointer.Null; return false; } + TargetPointer jitManagerAddress = _rangeSection.JitManager; // FIXME(cdac): prototype uses R2RModule to determine if the RangeSection belongs to the JIT or to R2R, // we don't need an extra JitManagerKind field. Data.IJitManager jitManager = target.ProcessedData.GetOrAdd(_rangeSection.JitManager); switch ((JitManagerKind)jitManager.JitManagerKind) { case JitManagerKind.EEJitManager: - return EEJitCodeToMethodInfo(target, jittedCodeAddress, out methodDescAddress); + return EEJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); case JitManagerKind.ReadyToRunJitManager: - return ReadyToRunJitCodeToMethodInfo(target, jittedCodeAddress, out methodDescAddress); + return ReadyToRunJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); default: throw new InvalidOperationException($"Invalid JitManagerKind {jitManager.JitManagerKind}"); } } - private bool EEJitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + private bool EEJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) { + info = null; // EEJitManager::JitCodeToMethodInfo if (IsRangeList) { - methodDescAddress = TargetPointer.Null; return false; } TargetPointer start = EEFindMethodCode(target, jittedCodeAddress); if (start == TargetPointer.Null) { - methodDescAddress = TargetPointer.Null; return false; } - TargetPointer codeHeaderIndirect = new TargetPointer(start - (ulong)target.PointerSize); + Debug.Assert(start.Value <= jittedCodeAddress.Value); + TargetNUInt relativeOffset = new TargetNUInt(jittedCodeAddress.Value - start.Value); + int codeHeaderOffset = target.PointerSize; + TargetPointer codeHeaderIndirect = new TargetPointer(start - (ulong)codeHeaderOffset); if (IsStubCodeBlock(target, codeHeaderIndirect)) { - methodDescAddress = TargetPointer.Null; return false; } TargetPointer codeHeaderAddress = target.ReadPointer(codeHeaderIndirect); Data.RealCodeHeader realCodeHeader = target.ProcessedData.GetOrAdd(codeHeaderAddress); - methodDescAddress = realCodeHeader.MethodDesc; + info = new EECodeInfo(jittedCodeAddress, codeHeaderOffset, relativeOffset, realCodeHeader, jitManagerAddress); return true; } @@ -204,7 +218,7 @@ private TargetPointer EEFindMethodCode(Target target, TargetCodePointer jittedCo return nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); } - private bool ReadyToRunJitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, out TargetPointer methodDescAddress) + private bool ReadyToRunJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) { throw new NotImplementedException(); // TODO(cdac): ReadyToRunJitManager::JitCodeToMethodInfo } @@ -224,11 +238,8 @@ private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, internal EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) { RangeSection range = LookupRangeSection(jittedCodeAddress); - if (!range.JitCodeToMethodInfo(_target, jittedCodeAddress, out TargetPointer methodDescAddress)) - { - return null; - } - return new EECodeInfo(jittedCodeAddress, methodDescAddress); + range.JitCodeToMethodInfo(_target, jittedCodeAddress, out EECodeInfo? info); + return info; } private static bool InRange(Data.RangeSectionFragment fragment, TargetCodePointer address) @@ -292,6 +303,5 @@ internal bool IsReJITEnabled() bool clrConfigEnabledReJIT = true; return profEnabledReJIT || clrConfigEnabledReJIT; } - } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index 1bf0cbeb034b4..fae99920a2349 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -11,15 +11,43 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal struct NativeCodeVersionContract { private readonly Target _target; + private readonly TargetPointer _codeVersionManagerAddress; - public NativeCodeVersionContract(Target target) + public NativeCodeVersionContract(Target target, TargetPointer codeVersionManagerAddress) { _target = target; + _codeVersionManagerAddress = codeVersionManagerAddress; } - public NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) + public NativeCodeVersionHandle GetSpecificNativeCodeVersion(IRuntimeTypeSystem rts, MethodDescHandle md, TargetCodePointer startAddress) { - throw new NotImplementedException(); + TargetPointer methodDescVersioningStateAddress = rts.GetMethodDescVersioningState(md); + if (methodDescVersioningStateAddress == TargetPointer.Null) + { + return NativeCodeVersionHandle.Invalid; + } + Data.MethodDescVersioningState methodDescVersioningStateData = _target.ProcessedData.GetOrAdd(methodDescVersioningStateAddress); + // CodeVersionManager::GetNativeCodeVersion(PTR_MethodDesc, PCODE startAddress) + return FindFirstCodeVersion(methodDescVersioningStateData, (codeVersion) => + { + return codeVersion.MethodDesc == md.Address && codeVersion.NativeCode == startAddress; + }); + } + + private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningState versioningState, Func predicate) + { + // NativeCodeVersion::Next, heavily inlined + TargetPointer currentAddress = versioningState.NativeCodeVersionNode; + while (currentAddress != TargetPointer.Null) + { + Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd(currentAddress); + if (predicate(current)) + { + return new NativeCodeVersionHandle(methodDescAddress: TargetPointer.Null, currentAddress); + } + currentAddress = current.Next; + } + return NativeCodeVersionHandle.Invalid; } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index a0850e884deed..4dc9e4be574db 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -18,7 +18,11 @@ public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precode _target = target; _precodeContract = new PrecodeContract(target, precodeMachineDescriptor); _executionManagerContract = new ExecutionManagerContract(target, topRangeSectionMap, profControlBlock); - _nativeCodeVersionContract = new NativeCodeVersionContract(target); + TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain); + TargetPointer appDomainAddress = _target.ReadPointer(appDomainPointer); + Data.AppDomain appDomain = _target.ProcessedData.GetOrAdd(appDomainAddress); + TargetPointer codeVersionManagerAddress = appDomain.CodeVersionManager; + _nativeCodeVersionContract = new NativeCodeVersionContract(target, codeVersionManagerAddress); } TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer entryPoint) @@ -28,6 +32,7 @@ TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer en return precode.GetMethodDesc(_target, _precodeContract.MachineDescriptor); } + TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) { EECodeInfo? info = _executionManagerContract.GetEECodeInfo(jittedCodeAddress); @@ -40,6 +45,8 @@ TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePo NativeCodeVersionHandle INativeCodePointers.GetSpecificNativeCodeVersion(TargetCodePointer ip) { + // ExecutionManager::GetNativeCodeVersion(PCODE ip)) + // and EECodeInfo::GetNativeCodeVersion EECodeInfo? info = _executionManagerContract.GetEECodeInfo(ip); if (info == null || !info.Valid) { @@ -50,8 +57,16 @@ NativeCodeVersionHandle INativeCodePointers.GetSpecificNativeCodeVersion(TargetC { return NativeCodeVersionHandle.Invalid; } - - return _nativeCodeVersionContract.GetSpecificNativeCodeVersion(ip); + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); + if (!rts.IsVersionable(md)) + { + return new NativeCodeVersionHandle(methodDescAddress, codeVersionNodeAddress: TargetPointer.Null); + } + else + { + return _nativeCodeVersionContract.GetSpecificNativeCodeVersion(rts, md, info.StartAddress); + } } bool INativeCodePointers.IsReJITEnabled() diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index 2e0468071419f..1f61a346e2b24 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -168,6 +168,8 @@ static IContract IContract.Create(Target target, int version) public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual bool InEnCEnabledModule(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index 474c63b6d05c4..845bc254c1ff7 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -190,6 +190,7 @@ private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.Metho public bool IsUnboxingStub => HasFlags(MethodDescFlags3.IsUnboxingStub); + public TargetPointer CodeData => _desc.CodeData; } private class InstantiatedMethodDesc : IData @@ -912,4 +913,12 @@ bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) return false; } + TargetPointer IRuntimeTypeSystem.GetMethodDescVersioningState(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + TargetPointer codeDataAddress = md.CodeData; + Data.MethodDescCodeData codeData = _target.ProcessedData.GetOrAdd(codeDataAddress); + return codeData.VersioningState; + } + } diff --git a/src/native/managed/cdacreader/src/Data/AppDomain.cs b/src/native/managed/cdacreader/src/Data/AppDomain.cs new file mode 100644 index 0000000000000..c3f56ca49e359 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/AppDomain.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class AppDomain : IData +{ + static AppDomain IData.Create(Target target, TargetPointer address) => new AppDomain(target, address); + public AppDomain(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.AppDomain); + + CodeVersionManager = target.ReadPointer(address + (ulong)type.Fields[nameof(CodeVersionManager)].Offset); + } + + public TargetPointer CodeVersionManager { get; init; } +} diff --git a/src/native/managed/cdacreader/src/Data/MethodDescCodeData.cs b/src/native/managed/cdacreader/src/Data/MethodDescCodeData.cs index 9b80d3b891729..dc76b8981b610 100644 --- a/src/native/managed/cdacreader/src/Data/MethodDescCodeData.cs +++ b/src/native/managed/cdacreader/src/Data/MethodDescCodeData.cs @@ -12,7 +12,9 @@ public MethodDescCodeData(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.MethodDescCodeData); TemporaryEntryPoint = target.ReadCodePointer(address + (ulong)type.Fields[nameof(TemporaryEntryPoint)].Offset); + VersioningState = target.ReadPointer(address + (ulong)type.Fields[nameof(VersioningState)].Offset); } public TargetCodePointer TemporaryEntryPoint { get; set; } + public TargetPointer VersioningState { get; set; } } diff --git a/src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs b/src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs new file mode 100644 index 0000000000000..a8c9c0427a6ff --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class MethodDescVersioningState : IData +{ + static MethodDescVersioningState IData.Create(Target target, TargetPointer address) => new MethodDescVersioningState(target, address); + public MethodDescVersioningState(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.MethodDescVersioningState); + + NativeCodeVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(NativeCodeVersionNode)].Offset); + } + + public TargetPointer NativeCodeVersionNode { get; init; } +} diff --git a/src/native/managed/cdacreader/src/Data/NativeCodeVersionNode.cs b/src/native/managed/cdacreader/src/Data/NativeCodeVersionNode.cs new file mode 100644 index 0000000000000..87b89201a97fc --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/NativeCodeVersionNode.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class NativeCodeVersionNode : IData +{ + static NativeCodeVersionNode IData.Create(Target target, TargetPointer address) => new NativeCodeVersionNode(target, address); + public NativeCodeVersionNode(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.NativeCodeVersionNode); + + Next = target.ReadPointer(address + (ulong)type.Fields[nameof(Next)].Offset); + MethodDesc = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodDesc)].Offset); + NativeCode = target.ReadCodePointer(address + (ulong)type.Fields[nameof(NativeCode)].Offset); + } + + public TargetPointer Next { get; init; } + public TargetPointer MethodDesc { get; init; } + + public TargetCodePointer NativeCode { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 0ccfe9375319c..f84d300043e3c 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -27,6 +27,7 @@ public enum DataType Exception, ExceptionInfo, RuntimeThreadLocals, + AppDomain, Module, ModuleLookupMap, LoaderAllocator, @@ -61,5 +62,8 @@ public enum DataType IJitManager, RealCodeHeader, HeapList, + MethodDescVersioningState, + NativeCodeVersionNode, ProfControlBlock, + } From dd860951ea6d13da3bbd323b4c0a0e8a7c174b03 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 9 Aug 2024 17:45:58 -0400 Subject: [PATCH 33/66] remove AppDomain.CodeVersionManager from cdac CodeVersionManager is basically a static class in the C++ side --- .../debug/runtimeinfo/datadescriptor.h | 7 ------- src/coreclr/vm/appdomain.hpp | 9 --------- .../NativeCodePointers_1.NativeCodeVersion.cs | 4 +--- .../src/Contracts/NativeCodePointers_1.cs | 6 +----- .../managed/cdacreader/src/Data/AppDomain.cs | 19 ------------------- src/native/managed/cdacreader/src/DataType.cs | 1 - 6 files changed, 2 insertions(+), 44 deletions(-) delete mode 100644 src/native/managed/cdacreader/src/Data/AppDomain.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 4d2d5cbe3ac09..9b79f0c8b213d 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -212,13 +212,6 @@ CDAC_TYPE_END(SyncTableEntry) // Loader -CDAC_TYPE_BEGIN(AppDomain) -CDAC_TYPE_INDETERMINATE(AppDomain) -#ifdef FEATURE_CODE_VERSIONING -CDAC_TYPE_FIELD(AppDomain, /*pointer*/, CodeVersionManager, cdac_data::CodeVersionManager) -#endif -CDAC_TYPE_END(AppDomain) - CDAC_TYPE_BEGIN(Module) CDAC_TYPE_INDETERMINATE(Module) CDAC_TYPE_FIELD(Module, /*pointer*/, Assembly, cdac_data::Assembly) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 8fa8dd78de77d..10bd274022a9a 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1820,17 +1820,8 @@ class AppDomain : public BaseDomain #endif - template friend struct ::cdac_data; }; // class AppDomain -template<> -struct cdac_data -{ -#ifdef FEATURE_CODE_VERSIONING - static constexpr size_t CodeVersionManager = offsetof(AppDomain, m_CodeVersionManager); -#endif -}; - // Just a ref holder typedef ReleaseHolder AppDomainRefHolder; diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index fae99920a2349..98e54e3778539 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -11,12 +11,10 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal struct NativeCodeVersionContract { private readonly Target _target; - private readonly TargetPointer _codeVersionManagerAddress; - public NativeCodeVersionContract(Target target, TargetPointer codeVersionManagerAddress) + public NativeCodeVersionContract(Target target) { _target = target; - _codeVersionManagerAddress = codeVersionManagerAddress; } public NativeCodeVersionHandle GetSpecificNativeCodeVersion(IRuntimeTypeSystem rts, MethodDescHandle md, TargetCodePointer startAddress) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 4dc9e4be574db..d4493ac914c6b 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -18,11 +18,7 @@ public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precode _target = target; _precodeContract = new PrecodeContract(target, precodeMachineDescriptor); _executionManagerContract = new ExecutionManagerContract(target, topRangeSectionMap, profControlBlock); - TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain); - TargetPointer appDomainAddress = _target.ReadPointer(appDomainPointer); - Data.AppDomain appDomain = _target.ProcessedData.GetOrAdd(appDomainAddress); - TargetPointer codeVersionManagerAddress = appDomain.CodeVersionManager; - _nativeCodeVersionContract = new NativeCodeVersionContract(target, codeVersionManagerAddress); + _nativeCodeVersionContract = new NativeCodeVersionContract(target); } TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer entryPoint) diff --git a/src/native/managed/cdacreader/src/Data/AppDomain.cs b/src/native/managed/cdacreader/src/Data/AppDomain.cs deleted file mode 100644 index c3f56ca49e359..0000000000000 --- a/src/native/managed/cdacreader/src/Data/AppDomain.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace Microsoft.Diagnostics.DataContractReader.Data; - -internal sealed class AppDomain : IData -{ - static AppDomain IData.Create(Target target, TargetPointer address) => new AppDomain(target, address); - public AppDomain(Target target, TargetPointer address) - { - Target.TypeInfo type = target.GetTypeInfo(DataType.AppDomain); - - CodeVersionManager = target.ReadPointer(address + (ulong)type.Fields[nameof(CodeVersionManager)].Offset); - } - - public TargetPointer CodeVersionManager { get; init; } -} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index f84d300043e3c..58fcd2d874cd1 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -27,7 +27,6 @@ public enum DataType Exception, ExceptionInfo, RuntimeThreadLocals, - AppDomain, Module, ModuleLookupMap, LoaderAllocator, From 5b33737e432663836a1e3ad66c350967464074ee Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 12 Aug 2024 14:25:06 -0400 Subject: [PATCH 34/66] WIP: il code version lookup table --- .../debug/runtimeinfo/datadescriptor.h | 1 + .../managed/cdacreader/src/Constants.cs | 2 + .../NativeCodePointers_1.NativeCodeVersion.cs | 39 +++++++++++++++++++ .../src/Contracts/NativeCodePointers_1.cs | 18 +++++++++ .../src/Contracts/RuntimeTypeSystem.cs | 1 + .../src/Contracts/RuntimeTypeSystem_1.cs | 22 +++++++++++ 6 files changed, 83 insertions(+) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 9b79f0c8b213d..09104a7db84f4 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -464,6 +464,7 @@ CDAC_GLOBAL(MethodDescAlignment, uint64, MethodDesc::ALIGNMENT) CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE) CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data::SyncBlockValue) CDAC_GLOBAL(StubCodeBlockLast, uint8, STUB_CODE_BLOCK_LAST) +CDAC_GLOBAL(MethodDescTokenRemainderBitCount, uint16, METHOD_TOKEN_REMAINDER_BIT_COUNT) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable) diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs index 4b9a218d0276e..c6918ad903347 100644 --- a/src/native/managed/cdacreader/src/Constants.cs +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -34,6 +34,8 @@ internal static class Globals internal const string SyncTableEntries = nameof(SyncTableEntries); + internal const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); + internal const string ArrayBoundsZero = nameof(ArrayBoundsZero); internal const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index 98e54e3778539..1580c173f8552 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -8,6 +8,26 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly partial struct NativeCodePointers_1 : INativeCodePointers { + + internal struct ILCodeVersionHandle + { + internal readonly TargetPointer MethodDesc; + internal readonly TargetPointer ILCodeVersionNode; + + internal ILCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer ilCodeVersionNodeAddress) + { + MethodDesc = methodDescAddress; + ILCodeVersionNode = ilCodeVersionNodeAddress; + if (MethodDesc != TargetPointer.Null && ILCodeVersionNode != TargetPointer.Null) + { + throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null"); + + } + + public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, TargetPointer.Null); + public bool IsValid => MethodDesc != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; + } + internal struct NativeCodeVersionContract { private readonly Target _target; @@ -48,5 +68,24 @@ private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningSt return NativeCodeVersionHandle.Invalid; } + public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint methodDefinition) + { + ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); + TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).ILCodeVersionTable; + TargetPointer ilNode = _target.Contracts.GetModuleLookupTableElement(module, methodDefinition, out var _); + if (ilNode == TargetPointer.Null) + { + return ILCodeVersionHandle.Invalid; + } + + + throw new NotImplementedException(); + } + + public NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion) + { + throw new NotImplementedException(); + } + } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index d4493ac914c6b..6acefa6fda730 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -65,6 +65,24 @@ NativeCodeVersionHandle INativeCodePointers.GetSpecificNativeCodeVersion(TargetC } } + NativeCodeVersionHandle INativeCodePointers.GetActiveNativeCodeVersion(TargetPointer methodDesc) + { + // CodeVersionManager::GetActiveILCodeVersion + // then ILCodeVersion::GetActiveNativeCodeVersion + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); + TargetPointer mtAddr = rts.GetMethodTable(md); + TypeHandle typeHandle = rts.GetTypeHandle(mtAddr); + TargetPointer module = rts.GetModule(typeHandle); + uint methodDefToken = rts.GetMethodToken(md); + ILCodeVersionHandle methodDefActiveVersion = _nativeCodeVersionContract.FindActiveILCodeVersion(module, methodDefToken); + if (!methodDefActiveVersion.IsValid) + { + return NativeCodeVersionHandle.Invalid; + } + return _nativeCodeVersionContract.FindActiveNativeCodeVersion(methodDefActiveVersion); + } + bool INativeCodePointers.IsReJITEnabled() { return _executionManagerContract.IsReJITEnabled(); diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index 1f61a346e2b24..013456d5c15cb 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -170,6 +170,7 @@ static IContract IContract.Create(Target target, int version) public virtual bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); + public virtual uint GetMethodToken(MethodDescHandle methodDesc) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index 845bc254c1ff7..4401ca66ffea3 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -191,6 +191,22 @@ private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.Metho public bool IsUnboxingStub => HasFlags(MethodDescFlags3.IsUnboxingStub); public TargetPointer CodeData => _desc.CodeData; + + public uint Token { get; } + + private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.MethodDescChunk chunk) + { + int tokenRemainderBitCount = target.ReadGlobal(Constants.Globals.MethodDescTokenRemainderBitCount); + int tokenRangeBitCount = 24 - tokenRemainderBitCount; + uint allRidBitsSet = 0xFFFFFF; + uint tokenRemainderMask = allRidBitsSet >> tokenRangeBitCount; + uint tokenRangeMask = allRidBitsSet >> tokenRemainderBitCount; + + uint tokenRemainder = (uint)(desc.Flags3AndTokenRemainder & tokenRemainderMask); + uint tokenRange = ((uint)(chunk.FlagsAndTokenRange & tokenRangeMask)) << tokenRemainderBitCount; + + return 0x06000000 | tokenRange | tokenRemainder; + } } private class InstantiatedMethodDesc : IData @@ -921,4 +937,10 @@ TargetPointer IRuntimeTypeSystem.GetMethodDescVersioningState(MethodDescHandle m return codeData.VersioningState; } + uint IRuntimeTypeSystem.GetMethodToken(MethodDescHandle methodDescHandle) + { + MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + return methodDesc.Token; + } + } From de58ab53147e1cca8f36904acdc67e611eef33b7 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 12 Aug 2024 16:03:27 -0400 Subject: [PATCH 35/66] fixup build --- .../NativeCodePointers_1.NativeCodeVersion.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index 1580c173f8552..898bcc406f7f2 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -23,8 +23,8 @@ internal ILCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer ilCo throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null"); } - - public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, TargetPointer.Null); + } + public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, TargetPointer.Null); public bool IsValid => MethodDesc != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; } @@ -70,14 +70,16 @@ private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningSt public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint methodDefinition) { + //TODO[cdac]: implement FindActiveILCodeVersion +#if false ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); - TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).ILCodeVersionTable; + TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; TargetPointer ilNode = _target.Contracts.GetModuleLookupTableElement(module, methodDefinition, out var _); if (ilNode == TargetPointer.Null) { return ILCodeVersionHandle.Invalid; } - +#endif throw new NotImplementedException(); } From 0b6f6e4d39c43452ab0b541ab4cc7d153ea4e79c Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 12 Aug 2024 16:24:27 -0400 Subject: [PATCH 36/66] wip: FindActiveILCodeVersion/FindActiveNativeCodeVersion TODO: Loader GetModuleLookupTableElement --- .../debug/runtimeinfo/datadescriptor.h | 5 +++ src/coreclr/vm/codeversion.h | 8 +++++ .../cdacreader/src/Contracts/Loader.cs | 1 + .../cdacreader/src/Contracts/Loader_1.cs | 5 +++ .../NativeCodePointers_1.NativeCodeVersion.cs | 33 +++++++++++-------- .../src/Data/ILCodeVersioningState.cs | 19 +++++++++++ src/native/managed/cdacreader/src/DataType.cs | 1 + 7 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 09104a7db84f4..a2ce20edf4cc5 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -423,6 +423,11 @@ CDAC_TYPE_FIELD(HeapList, /*pointer*/, MapBase, offsetof(HeapList, mapBase)) CDAC_TYPE_FIELD(HeapList, /*pointer*/, HeaderMap, offsetof(HeapList, pHdrMap)) CDAC_TYPE_END(HeapList) +CDAC_TYPE_BEGIN(ILCodeVersioningState) +CDAC_TYPE_INDETERMINATE(ILCodeVersioningState) +CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, Node, cdac_data::Node) +CDAC_TYPE_END(ILCodeVersioningState) + CDAC_TYPE_BEGIN(NativeCodeVersionNode) CDAC_TYPE_INDETERMINATE(NativeCodeVersionNode) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, Next, cdac_data::Next) diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 16c969ca75f89..648a525f16e1d 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -523,6 +523,14 @@ class ILCodeVersioningState PTR_ILCodeVersionNode m_pFirstVersionNode; PTR_Module m_pModule; mdMethodDef m_methodDef; + + template friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + static constexpr size_t Node = offsetof(ILCodeVersioningState, m_pFirstVersionNode); }; class CodeVersionManager diff --git a/src/native/managed/cdacreader/src/Contracts/Loader.cs b/src/native/managed/cdacreader/src/Contracts/Loader.cs index 39ced78bd67f9..e80cedac34485 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader.cs @@ -55,6 +55,7 @@ static IContract IContract.Create(Target target, int version) public virtual TargetPointer GetILBase(ModuleHandle handle) => throw new NotImplementedException(); public virtual ModuleLookupTables GetLookupTables(ModuleHandle handle) => throw new NotImplementedException(); + public virtual TargetPointer GetModuleLookupTableElement(TargetPointer table, uint rid, out TargetNUInt flags) => throw new NotImplementedException(); public virtual bool IsCollectibleLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException(); } diff --git a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs index c77cd21c77c4b..fad81557b1bed 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs @@ -92,6 +92,11 @@ ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle) module.MethodDefToILCodeVersioningStateMap); } + TargetPointer ILoader.GetModuleLookupTableElement(TargetPointer table, uint rid, out TargetNUInt flags) + { + throw new NotImplementedException(); // TODO[cdac]: GetModuleLookupTableElement + } + bool ILoader.IsCollectibleLoaderAllocator(ModuleHandle handle) { Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index 898bcc406f7f2..05e91bd7af809 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -11,21 +12,27 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal struct ILCodeVersionHandle { - internal readonly TargetPointer MethodDesc; + internal readonly TargetPointer Module; + internal uint MethodDefinition; internal readonly TargetPointer ILCodeVersionNode; - internal ILCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer ilCodeVersionNodeAddress) + internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress) { - MethodDesc = methodDescAddress; + Module = module; + MethodDefinition = methodDef; ILCodeVersionNode = ilCodeVersionNodeAddress; - if (MethodDesc != TargetPointer.Null && ILCodeVersionNode != TargetPointer.Null) + if (Module != TargetPointer.Null && ILCodeVersionNode != TargetPointer.Null) { throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null"); } + if (Module != TargetPointer.Null && MethodDefinition == 0) + { + throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null"); + } } - public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, TargetPointer.Null); - public bool IsValid => MethodDesc != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; + public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null); + public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; } internal struct NativeCodeVersionContract @@ -70,18 +77,16 @@ private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningSt public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint methodDefinition) { - //TODO[cdac]: implement FindActiveILCodeVersion -#if false ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; - TargetPointer ilNode = _target.Contracts.GetModuleLookupTableElement(module, methodDefinition, out var _); - if (ilNode == TargetPointer.Null) + TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupTableElement(ilCodeVersionTable, methodDefinition, out var _); + if (ilVersionStateAddress == TargetPointer.Null) { - return ILCodeVersionHandle.Invalid; + return new ILCodeVersionHandle(module, methodDefinition, TargetPointer.Null); } -#endif - - throw new NotImplementedException(); + Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd(ilVersionStateAddress); + TargetPointer ilVersionNode = ilState.Node; + return new ILCodeVersionHandle(TargetPointer.Null, 0, ilVersionNode); } public NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion) diff --git a/src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs b/src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs new file mode 100644 index 0000000000000..a8286327bd5f3 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs @@ -0,0 +1,19 @@ +// 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 ILCodeVersioningState : IData +{ + static ILCodeVersioningState IData.Create(Target target, TargetPointer address) + => new ILCodeVersioningState(target, address); + + public ILCodeVersioningState(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersioningState); + + Node = target.ReadPointer(address + (ulong)type.Fields[nameof(Node)].Offset); + } + + public TargetPointer Node { get; init; } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 58fcd2d874cd1..99ce454727553 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -62,6 +62,7 @@ public enum DataType RealCodeHeader, HeapList, MethodDescVersioningState, + ILCodeVersioningState, NativeCodeVersionNode, ProfControlBlock, From 502cd31e1994b86e83f4f3b0c3708e85fca79acf Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 13 Aug 2024 11:27:37 -0400 Subject: [PATCH 37/66] implement GetModuleLookupMapElement --- .../debug/runtimeinfo/datadescriptor.h | 3 ++ .../cdacreader/src/Contracts/Loader.cs | 2 +- .../cdacreader/src/Contracts/Loader_1.cs | 30 +++++++++++++++++-- .../NativeCodePointers_1.NativeCodeVersion.cs | 2 +- .../cdacreader/src/Data/ModuleLookupMap.cs | 6 ++++ 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index a2ce20edf4cc5..f49eca92c39a3 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -233,6 +233,9 @@ CDAC_TYPE_END(Module) CDAC_TYPE_BEGIN(ModuleLookupMap) CDAC_TYPE_FIELD(ModuleLookupMap, /*pointer*/, TableData, offsetof(LookupMapBase, pTable)) +CDAC_TYPE_FIELD(ModuleLookupMap, /*pointer*/, Next, offsetof(LookupMapBase, pNext)) +CDAC_TYPE_FIELD(ModuleLookupMap, /*uint32*/, Count, offsetof(LookupMapBase, dwCount)) +CDAC_TYPE_FIELD(ModuleLookupMap, /*nuint*/, SupportedFlagsMask, offsetof(LookupMapBase, supportedFlags)) CDAC_TYPE_END(ModuleLookupMap) CDAC_TYPE_BEGIN(LoaderAllocator) diff --git a/src/native/managed/cdacreader/src/Contracts/Loader.cs b/src/native/managed/cdacreader/src/Contracts/Loader.cs index e80cedac34485..e62b45967d5d9 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader.cs @@ -55,7 +55,7 @@ static IContract IContract.Create(Target target, int version) public virtual TargetPointer GetILBase(ModuleHandle handle) => throw new NotImplementedException(); public virtual ModuleLookupTables GetLookupTables(ModuleHandle handle) => throw new NotImplementedException(); - public virtual TargetPointer GetModuleLookupTableElement(TargetPointer table, uint rid, out TargetNUInt flags) => throw new NotImplementedException(); + public virtual TargetPointer GetModuleLookupMapElement(TargetPointer table, uint rid, out TargetNUInt flags) => throw new NotImplementedException(); public virtual bool IsCollectibleLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException(); } diff --git a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs index fad81557b1bed..96f62a83cb181 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs @@ -92,9 +92,35 @@ ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle) module.MethodDefToILCodeVersioningStateMap); } - TargetPointer ILoader.GetModuleLookupTableElement(TargetPointer table, uint rid, out TargetNUInt flags) + TargetPointer ILoader.GetModuleLookupMapElement(TargetPointer table, uint rid, out TargetNUInt flags) { - throw new NotImplementedException(); // TODO[cdac]: GetModuleLookupTableElement + rid &= 0x00FFFFFF; // FIXME: do we have a util that does this? + ArgumentOutOfRangeException.ThrowIfZero(rid); + flags = new TargetNUInt(0); + if (table == TargetPointer.Null) + return TargetPointer.Null; + uint index = rid; + Data.ModuleLookupMap lookupMap = _target.ProcessedData.GetOrAdd(table); + // have to read lookupMap an extra time upfront because only the first map + // has valid supportedFlagsMask + TargetNUInt supportedFlagsMask = lookupMap.SupportedFlagsMask; + do + { + lookupMap = _target.ProcessedData.GetOrAdd(table); + if (index < lookupMap.Count) + { + TargetPointer entryAddress = lookupMap.TableData + (ulong)(index * _target.PointerSize); + TargetPointer rawValue = _target.ReadPointer(entryAddress); + flags = new TargetNUInt(rawValue & supportedFlagsMask.Value); + return rawValue & ~(supportedFlagsMask.Value); + } + else + { + table = lookupMap.Next; + index -= lookupMap.Count; + } + } while (table != TargetPointer.Null); + return TargetPointer.Null; } bool ILoader.IsCollectibleLoaderAllocator(ModuleHandle handle) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index 05e91bd7af809..fe56a5d6ac711 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -79,7 +79,7 @@ public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint me { ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; - TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupTableElement(ilCodeVersionTable, methodDefinition, out var _); + TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefinition, out var _); if (ilVersionStateAddress == TargetPointer.Null) { return new ILCodeVersionHandle(module, methodDefinition, TargetPointer.Null); diff --git a/src/native/managed/cdacreader/src/Data/ModuleLookupMap.cs b/src/native/managed/cdacreader/src/Data/ModuleLookupMap.cs index db69c68fe2c13..449dfb0cb0452 100644 --- a/src/native/managed/cdacreader/src/Data/ModuleLookupMap.cs +++ b/src/native/managed/cdacreader/src/Data/ModuleLookupMap.cs @@ -12,7 +12,13 @@ private ModuleLookupMap(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.ModuleLookupMap); TableData = target.ReadPointer(address + (ulong)type.Fields[nameof(TableData)].Offset); + Next = target.ReadPointer(address + (ulong)type.Fields[nameof(Next)].Offset); + Count = target.Read(address + (ulong)type.Fields[nameof(Count)].Offset); + SupportedFlagsMask = target.ReadNUInt(address + (ulong)type.Fields[nameof(SupportedFlagsMask)].Offset); } public TargetPointer TableData { get; init; } + public TargetPointer Next { get; init; } + public uint Count { get; init; } + public TargetNUInt SupportedFlagsMask { get; init; } } From 312f2ce07c199b817ac3c067f7a30c86668c2bd8 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 13 Aug 2024 14:53:35 -0400 Subject: [PATCH 38/66] FindActiveILCodeVersion --- .../debug/runtimeinfo/datadescriptor.h | 4 +++ src/coreclr/vm/codeversion.h | 12 +++++++++ .../NativeCodePointers_1.NativeCodeVersion.cs | 25 +++++++++++++++++-- .../src/Data/ILCodeVersioningState.cs | 8 ++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index f49eca92c39a3..486bb75b3f2fe 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -429,6 +429,10 @@ CDAC_TYPE_END(HeapList) CDAC_TYPE_BEGIN(ILCodeVersioningState) CDAC_TYPE_INDETERMINATE(ILCodeVersioningState) CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, Node, cdac_data::Node) +CDAC_TYPE_FIELD(ILCodeVersioningState, /*uint32*/, ActiveVersionKind, cdac_data::ActiveVersionKind) +CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionNode, cdac_data::ActiveVersionNode) +CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionModule, cdac_data::ActiveVersionModule) +CDAC_TYPE_FIELD(ILCodeVersioningState, /*uint32*/, ActiveVersionMethodDef, cdac_data::ActiveVersionMethodDef) CDAC_TYPE_END(ILCodeVersioningState) CDAC_TYPE_BEGIN(NativeCodeVersionNode) diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 648a525f16e1d..484aa50480fab 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -248,6 +248,14 @@ class ILCodeVersion mdMethodDef m_methodDef; } m_synthetic; }; + + template friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + // All fields are accessed via ILCodeVersioningState.m_activeVersion }; @@ -531,6 +539,10 @@ template<> struct cdac_data { static constexpr size_t Node = offsetof(ILCodeVersioningState, m_pFirstVersionNode); + static constexpr size_t ActiveVersionKind = offsetof(ILCodeVersioningState, m_activeVersion.m_storageKind); + static constexpr size_t ActiveVersionNode = offsetof(ILCodeVersioningState, m_activeVersion.m_pVersionNode); + static constexpr size_t ActiveVersionModule = offsetof(ILCodeVersioningState, m_activeVersion.m_synthetic.m_pModule); + static constexpr size_t ActiveVersionMethodDef = offsetof(ILCodeVersioningState, m_activeVersion.m_synthetic.m_methodDef); }; class CodeVersionManager diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index fe56a5d6ac711..f58db59543ac3 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -15,6 +15,7 @@ internal struct ILCodeVersionHandle internal readonly TargetPointer Module; internal uint MethodDefinition; internal readonly TargetPointer ILCodeVersionNode; + internal readonly uint RejitId; internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress) { @@ -75,6 +76,27 @@ private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningSt return NativeCodeVersionHandle.Invalid; } + + private enum ILCodeVersionKind + { + Unknown = 0, + Explicit = 1, + Synthetic = 2, + } + private static ILCodeVersionHandle ILCodeVersionHandleFromState(Data.ILCodeVersioningState ilState) + { + switch ((ILCodeVersionKind)ilState.ActiveVersionKind) + { + case ILCodeVersionKind.Explicit: + return new ILCodeVersionHandle(module: TargetPointer.Null, methodDef: 0, ilState.ActiveVersionNode); + case ILCodeVersionKind.Synthetic: + case ILCodeVersionKind.Unknown: + return new ILCodeVersionHandle(ilState.ActiveVersionModule, ilState.ActiveVersionMethodDef, TargetPointer.Null); + default: + throw new InvalidOperationException($"Unknown ILCodeVersionKind {ilState.ActiveVersionKind}"); + } + } + public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint methodDefinition) { ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); @@ -85,8 +107,7 @@ public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint me return new ILCodeVersionHandle(module, methodDefinition, TargetPointer.Null); } Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd(ilVersionStateAddress); - TargetPointer ilVersionNode = ilState.Node; - return new ILCodeVersionHandle(TargetPointer.Null, 0, ilVersionNode); + return ILCodeVersionHandleFromState(ilState); } public NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion) diff --git a/src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs b/src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs index a8286327bd5f3..34256abe54569 100644 --- a/src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs +++ b/src/native/managed/cdacreader/src/Data/ILCodeVersioningState.cs @@ -13,7 +13,15 @@ public ILCodeVersioningState(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersioningState); Node = target.ReadPointer(address + (ulong)type.Fields[nameof(Node)].Offset); + ActiveVersionKind = target.Read(address + (ulong)type.Fields[nameof(ActiveVersionKind)].Offset); + ActiveVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionNode)].Offset); + ActiveVersionModule = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionModule)].Offset); + ActiveVersionMethodDef = target.Read(address + (ulong)type.Fields[nameof(ActiveVersionMethodDef)].Offset); } public TargetPointer Node { get; init; } + public uint ActiveVersionKind { get; set; } + public TargetPointer ActiveVersionNode { get; set; } + public TargetPointer ActiveVersionModule { get; set; } + public uint ActiveVersionMethodDef { get; set; } } From c813a7809ca444a32041e9d13d14fb905b4e3b3d Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Aug 2024 10:49:01 -0400 Subject: [PATCH 39/66] checkpoint sketch out one working path through GetMethodDescData lots of TODOs leftover --- .../src/Contracts/NativeCodePointers.cs | 4 ++ .../NativeCodePointers_1.NativeCodeVersion.cs | 4 +- .../src/Contracts/NativeCodePointers_1.cs | 5 ++ .../src/Contracts/RuntimeTypeSystem.cs | 8 +++ .../src/Contracts/RuntimeTypeSystem_1.cs | 8 +++ .../cdacreader/src/Legacy/SOSDacImpl.cs | 64 +++++++++++++++++-- 6 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index 2a4a14925a421..1fa08564819f8 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -31,6 +31,10 @@ static IContract IContract.Create(Target target, int version) public virtual bool IsReJITEnabled() => throw new NotImplementedException(); public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); + + public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + + public virtual TargetPointer GetGCCoverageInfo(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); } internal struct NativeCodeVersionHandle diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index f58db59543ac3..dcdf8b70ed220 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -80,8 +80,8 @@ private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningSt private enum ILCodeVersionKind { Unknown = 0, - Explicit = 1, - Synthetic = 2, + Explicit = 1, // means Node is set + Synthetic = 2, // means Module and Token are set } private static ILCodeVersionHandle ILCodeVersionHandleFromState(Data.ILCodeVersioningState ilState) { diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 6acefa6fda730..14fad635d4ada 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -106,4 +106,9 @@ bool INativeCodePointers.CodeVersionManagerSupportsMethod(TargetPointer methodDe return false; return true; } + + TargetCodePointer INativeCodePointers.GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + + TargetPointer INativeCodePointers.GetGCCoverageInfo(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index 013456d5c15cb..ce3f66e6e5228 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -171,6 +171,14 @@ static IContract IContract.Create(Target target, int version) public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual uint GetMethodToken(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + public virtual ushort GetSlotNumber(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + public virtual bool HasNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + public virtual TargetPointer GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + public virtual uint GetMemberDef(MethodDescHandle methodDesc) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index 4401ca66ffea3..7566e93588c81 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -943,4 +943,12 @@ uint IRuntimeTypeSystem.GetMethodToken(MethodDescHandle methodDescHandle) return methodDesc.Token; } + ushort IRuntimeTypeSystem.GetSlotNumber(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + bool IRuntimeTypeSystem.HasNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + TargetPointer IRuntimeTypeSystem.GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + uint IRuntimeTypeSystem.GetMemberDef(MethodDescHandle methodDesc) => throw new NotImplementedException(); + } diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index 6c4d6b46b2df2..5892ffbad70f2 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -120,23 +120,73 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa *pcNeededRevertedRejitData = 0; } - NativeCodeVersionHandle requestedCodeVersion; - NativeCodeVersionHandle? activeCodeVersion = null; + NativeCodeVersionHandle requestedNativeCodeVersion; + NativeCodeVersionHandle? activeNativeCodeVersion = null; if (ip != 0) { - requestedCodeVersion = nativeCodeContract.GetSpecificNativeCodeVersion(new TargetCodePointer(ip)); + requestedNativeCodeVersion = nativeCodeContract.GetSpecificNativeCodeVersion(new TargetCodePointer(ip)); } else { - requestedCodeVersion = nativeCodeContract.GetActiveNativeCodeVersion(new TargetPointer(methodDesc)); // TODO[cdac]: pMD->GetCodeVersionManager()->GetActiveILCodeVersion(pMD).GetActiveNativeCodeVersion(pMD) - activeCodeVersion = requestedCodeVersion; + requestedNativeCodeVersion = nativeCodeContract.GetActiveNativeCodeVersion(new TargetPointer(methodDesc)); + activeNativeCodeVersion = requestedNativeCodeVersion; } data->requestedIP = ip; data->bIsDynamic = rtsContract.IsDynamicMethod(methodDescHandle) ? 1 : 0; - data->MethodTablePtr = rtsContract.GetMethodTable(methodDescHandle); + data->wSlotNumber = rtsContract.GetSlotNumber(methodDescHandle); + TargetCodePointer nativeCodeAddr = TargetCodePointer.Null; + if (requestedNativeCodeVersion.Valid) + { + nativeCodeAddr = nativeCodeContract.GetNativeCode(requestedNativeCodeVersion); + } + if (nativeCodeAddr != TargetCodePointer.Null) + { + data->bHasNativeCode = 1; + data->NativeCodeAddr = 0xffffffff_fffffffful; + } + else + { + data->bHasNativeCode = 0; + } + if (rtsContract.HasNativeCodeSlot(methodDescHandle)) + { + data->AddressOfNativeCodeSlot = rtsContract.GetAddressOfNativeCodeSlot(methodDescHandle); + } + else + { + data->AddressOfNativeCodeSlot = 0; + } + data->MDToken = rtsContract.GetMemberDef(methodDescHandle); + data->MethodDescPtr = methodDesc; + TargetPointer methodTableAddr = rtsContract.GetMethodTable(methodDescHandle); + data->MethodTablePtr = methodTableAddr; + TypeHandle typeHandle = rtsContract.GetTypeHandle(methodTableAddr); + data->ModulePtr = rtsContract.GetModule(typeHandle); + if (!nativeCodeContract.IsReJITEnabled()) + { + *pcNeededRevertedRejitData = 0; // TODO[cdac]: copy active code version data + } + else + { + return HResults.E_NOTIMPL; // TODO[cdac]: copy rejit data + } - return HResults.E_NOTIMPL; + if (requestedNativeCodeVersion.Valid) + { + TargetPointer gcCoverAddr = nativeCodeContract.GetGCCoverageInfo(requestedNativeCodeVersion); + if (gcCoverAddr != TargetPointer.Null) + { + return HResults.E_NOTIMPL; // TODO[cdac]: copy gc cover data + } + } + + if (data->bIsDynamic != 0) + { + return HResults.E_NOTIMPL; // TODO[cdac]: get the dynamic method managed object + } + + return HResults.S_OK; } catch (global::System.Exception ex) { From f225adbe557877ba3be79377ffb5fca04f97b8e3 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Aug 2024 11:52:27 -0400 Subject: [PATCH 40/66] fixup after rebase --- .../managed/cdacreader/src/Constants.cs | 2 -- .../src/Contracts/RuntimeTypeSystem.cs | 2 -- .../RuntimeTypeSystem_1.NonValidated.cs | 2 +- .../src/Contracts/RuntimeTypeSystem_1.cs | 30 +------------------ 4 files changed, 2 insertions(+), 34 deletions(-) diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs index c6918ad903347..4b9a218d0276e 100644 --- a/src/native/managed/cdacreader/src/Constants.cs +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -34,8 +34,6 @@ internal static class Globals internal const string SyncTableEntries = nameof(SyncTableEntries); - internal const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); - internal const string ArrayBoundsZero = nameof(ArrayBoundsZero); internal const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index ce3f66e6e5228..d58d49017b3e3 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -164,13 +164,11 @@ static IContract IContract.Create(Target target, int version) // A IL Stub method is also a StoredSigMethodDesc, and a NoMetadataMethod public virtual bool IsILStub(MethodDescHandle methodDesc) => throw new NotImplementedException(); -======= public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual bool InEnCEnabledModule(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); - public virtual uint GetMethodToken(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual ushort GetSlotNumber(MethodDescHandle methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 83b3847e788f6..0cea0a67c7c35 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -375,7 +375,7 @@ private uint MethodDescAdditioinalPointersOffset(NonValidated.MethodDesc umd) return _target.GetTypeInfo(DataType.MethodDesc).Size ?? throw new InvalidOperationException("size of MethodDesc not known"); case MethodClassification.FCall: throw new NotImplementedException(); - case MethodClassification.NDirect: + case MethodClassification.PInvoke: throw new NotImplementedException(); case MethodClassification.EEImpl: throw new NotImplementedException(); diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index 7566e93588c81..5ecbe9e965f3c 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -110,20 +110,6 @@ internal enum MethodDescFlags3 : ushort IsEligibleForTieredCompilation = 0x8000, } - internal enum MethodClassification - { - IL = 0, // IL - FCall = 1, // FCall (also includes tlbimped ctor, Delegate ctor) - NDirect = 2, // N/Direct - EEImpl = 3, // special method; implementation provided by EE (like Delegate Invoke) - Array = 4, // Array ECall - Instantiated = 5, // Instantiated generic methods, including descriptors - // for both shared and unshared code (see InstantiatedMethodDesc) - - ComInterop = 6, // if FEATURE_COMINTEROP - Dynamic = 7, // for method desc with no metadata behind - } - internal enum InstantiatedMethodDescFlags2 : ushort { KindMask = 0x07, @@ -191,22 +177,8 @@ private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.Metho public bool IsUnboxingStub => HasFlags(MethodDescFlags3.IsUnboxingStub); public TargetPointer CodeData => _desc.CodeData; + public bool IsIL => Classification == MethodClassification.IL || Classification == MethodClassification.Instantiated; - public uint Token { get; } - - private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.MethodDescChunk chunk) - { - int tokenRemainderBitCount = target.ReadGlobal(Constants.Globals.MethodDescTokenRemainderBitCount); - int tokenRangeBitCount = 24 - tokenRemainderBitCount; - uint allRidBitsSet = 0xFFFFFF; - uint tokenRemainderMask = allRidBitsSet >> tokenRangeBitCount; - uint tokenRangeMask = allRidBitsSet >> tokenRemainderBitCount; - - uint tokenRemainder = (uint)(desc.Flags3AndTokenRemainder & tokenRemainderMask); - uint tokenRange = ((uint)(chunk.FlagsAndTokenRange & tokenRangeMask)) << tokenRemainderBitCount; - - return 0x06000000 | tokenRange | tokenRemainder; - } } private class InstantiatedMethodDesc : IData From 2cb8e86e2e8fd245045515687c6daa69300e1f1a Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Aug 2024 12:06:03 -0400 Subject: [PATCH 41/66] fixup rebae; remove duplicate global --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 486bb75b3f2fe..20bbd951aa042 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -476,7 +476,6 @@ CDAC_GLOBAL(MethodDescAlignment, uint64, MethodDesc::ALIGNMENT) CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE) CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data::SyncBlockValue) CDAC_GLOBAL(StubCodeBlockLast, uint8, STUB_CODE_BLOCK_LAST) -CDAC_GLOBAL(MethodDescTokenRemainderBitCount, uint16, METHOD_TOKEN_REMAINDER_BIT_COUNT) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable) From f4852d2b21422e433232e4a7ca6adea453b7e339 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Aug 2024 15:37:43 -0400 Subject: [PATCH 42/66] checkpoint: works on some methods (NO REJIT) We're straight up returning incorrect info for cJittedRejitVersions and rejitDataCurrent and rejitDataRequested also it only works for jitted methods, not R2R --- src/coreclr/debug/daccess/request.cpp | 4 +- .../debug/runtimeinfo/datadescriptor.h | 1 + src/coreclr/vm/codeversion.h | 1 + .../src/Contracts/NativeCodePointers.cs | 12 +- .../NativeCodePointers_1.NativeCodeVersion.cs | 52 ++++++- .../src/Contracts/NativeCodePointers_1.cs | 21 ++- .../src/Contracts/RuntimeTypeSystem.cs | 3 +- .../RuntimeTypeSystem_1.NonValidated.cs | 26 ++-- .../src/Contracts/RuntimeTypeSystem_1.cs | 141 +++++++++++++++++- .../src/Data/MethodDescVersioningState.cs | 2 + .../cdacreader/src/Legacy/SOSDacImpl.cs | 20 +-- 11 files changed, 243 insertions(+), 40 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 7947988d0a48e..1b1d10552e0c1 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1097,7 +1097,9 @@ HRESULT ClrDataAccess::GetMethodDescData( _ASSERTE(methodDescData->GCStressCodeCopy == mdDataLocal.GCStressCodeCopy); _ASSERTE(methodDescData->managedDynamicMethodObject == mdDataLocal.managedDynamicMethodObject); _ASSERTE(methodDescData->requestedIP == mdDataLocal.requestedIP); - _ASSERTE(methodDescData->cJittedRejitVersions == mdDataLocal.cJittedRejitVersions); + // TODO[cdac]: cdacreader always returns 0 currently + _ASSERTE(methodDescData->cJittedRejitVersions == 0 || methodDescData->cJittedRejitVersions == mdDataLocal.cJittedRejitVersions); + // TODO[cdac]: compare rejitDataCurrent and rejitDataRequested, too if (rgRevertedRejitData != NULL) { _ASSERTE (cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData); diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 20bbd951aa042..a852da515d93e 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -357,6 +357,7 @@ CDAC_TYPE_END(MethodDescCodeData) CDAC_TYPE_BEGIN(MethodDescVersioningState) CDAC_TYPE_INDETERMINATE(MethodDescVersioningState) CDAC_TYPE_FIELD(MethodDescVersioningState, /*pointer*/, NativeCodeVersionNode, cdac_data::NativeCodeVersionNode) +CDAC_TYPE_FIELD(MethodDescVersioningState, /*uint8*/, Flags, cdac_data::Flags) CDAC_TYPE_END(MethodDescVersioningState) CDAC_TYPE_BEGIN(PrecodeMachineDescriptor) diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 484aa50480fab..4fd09826e82cd 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -499,6 +499,7 @@ template<> struct cdac_data { static constexpr size_t NativeCodeVersionNode = offsetof(MethodDescVersioningState, m_pFirstVersionNode); + static constexpr size_t Flags = offsetof(MethodDescVersioningState, m_flags); }; class ILCodeVersioningState diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index 1fa08564819f8..422ba2c308f5d 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -34,26 +34,26 @@ static IContract IContract.Create(Target target, int version) public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); - public virtual TargetPointer GetGCCoverageInfo(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); } internal struct NativeCodeVersionHandle { // no public constructors - internal readonly TargetPointer _methodDescAddress; - internal readonly TargetPointer _codeVersionNodeAddress; + internal readonly TargetPointer MethodDescAddress; + internal readonly TargetPointer CodeVersionNodeAddress; internal NativeCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer codeVersionNodeAddress) { if (methodDescAddress != TargetPointer.Null && codeVersionNodeAddress != TargetPointer.Null) { throw new ArgumentException("Only one of methodDescAddress and codeVersionNodeAddress can be non-null"); } - _methodDescAddress = methodDescAddress; - _codeVersionNodeAddress = codeVersionNodeAddress; + MethodDescAddress = methodDescAddress; + CodeVersionNodeAddress = codeVersionNodeAddress; } internal static NativeCodeVersionHandle Invalid => new(TargetPointer.Null, TargetPointer.Null); - public bool Valid => _methodDescAddress != TargetPointer.Null || _codeVersionNodeAddress != TargetPointer.Null; + public bool Valid => MethodDescAddress != TargetPointer.Null || CodeVersionNodeAddress != TargetPointer.Null; + } internal readonly struct NativeCodePointers : INativeCodePointers diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs index dcdf8b70ed220..94d58bcb4cf8b 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs @@ -36,6 +36,13 @@ internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; } + [Flags] + internal enum MethodDescVersioningStateFlags : byte + { + IsDefaultVersionActiveChildFlag = 0x4 + }; + + internal struct NativeCodeVersionContract { private readonly Target _target; @@ -110,9 +117,50 @@ public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint me return ILCodeVersionHandleFromState(ilState); } - public NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion) + private bool IsActiveNativeCodeVersion(NativeCodeVersionHandle nativeCodeVersion) + { + if (nativeCodeVersion.MethodDescAddress != TargetPointer.Null) + { + MethodDescHandle md = _target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(nativeCodeVersion.MethodDescAddress); + TargetPointer versioningStateAddress = _target.Contracts.RuntimeTypeSystem.GetMethodDescVersioningState(md); + if (versioningStateAddress == TargetPointer.Null) + { + return true; + } + Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd(versioningStateAddress); + return (((MethodDescVersioningStateFlags)versioningState.Flags) & MethodDescVersioningStateFlags.IsDefaultVersionActiveChildFlag) != 0; + } + else if (nativeCodeVersion.CodeVersionNodeAddress != TargetPointer.Null) + { + // NativeCodeVersionNode::IsActiveChildVersion + // Data.NativeCodeVersionNode codeVersion = _target.ProcessedData.GetOrAdd(nativeCodeVersion.CodeVersionNodeAddress); + // return codeVersion has flag IsActive + throw new NotImplementedException(); // TODO[cdac]: IsActiveNativeCodeVersion - explicit + } + else + { + throw new ArgumentException("Invalid NativeCodeVersionHandle"); + } + } + + public NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion, TargetPointer methodDescAddress) { - throw new NotImplementedException(); + if (methodDefActiveVersion.Module != TargetPointer.Null) + { + NativeCodeVersionHandle provisionalHandle = new NativeCodeVersionHandle(methodDescAddress: methodDescAddress, codeVersionNodeAddress: TargetPointer.Null); + if (IsActiveNativeCodeVersion(provisionalHandle)) + { + return provisionalHandle; + } + else + { + throw new NotImplementedException(); // TODO[cdac]: iterate through versioning state nodes + } + } + else + { + throw new NotImplementedException(); // TODO: [cdac] find explicit il code version + } } } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 14fad635d4ada..2b74522405e34 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -80,7 +80,7 @@ NativeCodeVersionHandle INativeCodePointers.GetActiveNativeCodeVersion(TargetPoi { return NativeCodeVersionHandle.Invalid; } - return _nativeCodeVersionContract.FindActiveNativeCodeVersion(methodDefActiveVersion); + return _nativeCodeVersionContract.FindActiveNativeCodeVersion(methodDefActiveVersion, methodDesc); } bool INativeCodePointers.IsReJITEnabled() @@ -107,8 +107,21 @@ bool INativeCodePointers.CodeVersionManagerSupportsMethod(TargetPointer methodDe return true; } - TargetCodePointer INativeCodePointers.GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); - - TargetPointer INativeCodePointers.GetGCCoverageInfo(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + TargetCodePointer INativeCodePointers.GetNativeCode(NativeCodeVersionHandle codeVersionHandle) + { + if (codeVersionHandle.MethodDescAddress != TargetPointer.Null) + { + MethodDescHandle md = _target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(codeVersionHandle.MethodDescAddress); + return _target.Contracts.RuntimeTypeSystem.GetNativeCode(md); + } + else if (codeVersionHandle.CodeVersionNodeAddress != TargetPointer.Null) + { + throw new NotImplementedException(); // TODO[cdac]: get native code from NativeCodeVersionNode + } + else + { + throw new ArgumentException("Invalid NativeCodeVersionHandle"); + } + } } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index d58d49017b3e3..133a47f107685 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -176,7 +176,8 @@ static IContract IContract.Create(Target target, int version) public virtual TargetPointer GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); - public virtual uint GetMemberDef(MethodDescHandle methodDesc) => throw new NotImplementedException(); + public virtual TargetCodePointer GetNativeCode(MethodDescHandle methodDesc) => throw new NotImplementedException(); + #endregion MethodDesc inspection APIs } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 0cea0a67c7c35..58e93d15559b7 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -98,19 +98,19 @@ internal MethodDesc(Target target, Data.MethodDesc desc, Data.MethodDescChunk ch _chunk = chunk; } - private bool HasFlag(MethodDescFlags flag) => (_desc.Flags & (ushort)flag) != 0; - private bool HasFlag(MethodDescEntryPointFlags flag) => (_desc.EntryPointFlags & (byte)flag) != 0; + private bool HasFlags(MethodDescFlags flag) => (_desc.Flags & (ushort)flag) != 0; + private bool HasFlags(MethodDescEntryPointFlags flag) => (_desc.EntryPointFlags & (byte)flag) != 0; - private bool HasFlag(MethodDescFlags3 flag) => (_desc.Flags3AndTokenRemainder & (ushort)flag) != 0; + private bool HasFlags(MethodDescFlags3 flag) => (_desc.Flags3AndTokenRemainder & (ushort)flag) != 0; internal byte ChunkIndex => _desc.ChunkIndex; internal TargetPointer MethodTable => _chunk.MethodTable; internal ushort Slot => _desc.Slot; - internal bool HasNonVtableSlot => HasFlag(MethodDescFlags.HasNonVtableSlot); - internal bool HasMethodImpl => HasFlag(MethodDescFlags.HasMethodImpl); - internal bool HasNativeCodeSlot => HasFlag(MethodDescFlags.HasNativeCodeSlot); + internal bool HasNonVtableSlot => HasFlags(MethodDescFlags.HasNonVtableSlot); + internal bool HasMethodImpl => HasFlags(MethodDescFlags.HasMethodImpl); + internal bool HasNativeCodeSlot => HasFlags(MethodDescFlags.HasNativeCodeSlot); - internal bool TemporaryEntryPointAssigned => HasFlag(MethodDescEntryPointFlags.TemporaryEntryPointAssigned); + internal bool TemporaryEntryPointAssigned => HasFlags(MethodDescEntryPointFlags.TemporaryEntryPointAssigned); internal TargetPointer CodeData => _desc.CodeData; @@ -150,8 +150,8 @@ internal int NativeCodeSlotIndex internal int AdditionalPointersCount => AdditionalPointersHelper(MethodDescFlags.MethodDescAdditionalPointersMask); #endregion Additional Pointers - internal bool HasStableEntryPoint => HasFlag(MethodDescFlags3.HasStableEntryPoint); - internal bool HasPrecode => HasFlag(MethodDescFlags3.HasPrecode); + internal bool HasStableEntryPoint => HasFlags(MethodDescFlags3.HasStableEntryPoint); + internal bool HasPrecode => HasFlags(MethodDescFlags3.HasPrecode); } @@ -306,14 +306,14 @@ private TargetCodePointer GetTemporaryEntryPointIfExists(NonValidated.MethodDesc private TargetPointer GetAddrOfNativeCodeSlot(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) { - uint offset = MethodDescAdditioinalPointersOffset(umd); + uint offset = MethodDescAdditionalPointersOffset(umd); offset += (uint)(_target.PointerSize * umd.NativeCodeSlotIndex); return methodDescPointer.Value + offset; } private TargetPointer GetAddresOfNonVtableSlot(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) { - uint offset = MethodDescAdditioinalPointersOffset(umd); + uint offset = MethodDescAdditionalPointersOffset(umd); offset += (uint)(_target.PointerSize * umd.NonVtableSlotIndex); return methodDescPointer.Value + offset; } @@ -366,7 +366,7 @@ private TargetCodePointer GetMethodEntryPointIfExists(TargetPointer methodDescAd return _target.ReadCodePointer(addrOfSlot); } - private uint MethodDescAdditioinalPointersOffset(NonValidated.MethodDesc umd) + private uint MethodDescAdditionalPointersOffset(NonValidated.MethodDesc umd) { MethodClassification cls = umd.Classification; switch (cls) @@ -394,7 +394,7 @@ private uint MethodDescAdditioinalPointersOffset(NonValidated.MethodDesc umd) internal uint GetMethodDescBaseSize(NonValidated.MethodDesc umd) { - uint baseSize = MethodDescAdditioinalPointersOffset(umd); + uint baseSize = MethodDescAdditionalPointersOffset(umd); baseSize += (uint)(_target.PointerSize * umd.AdditionalPointersCount); return baseSize; } diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index 5ecbe9e965f3c..e4c871160bdef 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -169,6 +169,7 @@ private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.Metho public MethodClassification Classification => (MethodClassification)((int)_desc.Flags & (int)MethodDescFlags.ClassificationMask); + private bool HasFlags(MethodDescFlags flags) => (_desc.Flags & (ushort)flags) != 0; internal bool HasFlags(MethodDescFlags3 flags) => (_desc.Flags3AndTokenRemainder & (ushort)flags) != 0; public bool IsEligibleForTieredCompilation => HasFlags(MethodDescFlags3.IsEligibleForTieredCompilation); @@ -179,6 +180,46 @@ private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.Metho public TargetPointer CodeData => _desc.CodeData; public bool IsIL => Classification == MethodClassification.IL || Classification == MethodClassification.Instantiated; + public bool HasNativeCodeSlot => HasFlags(MethodDescFlags.HasNativeCodeSlot); + internal bool HasNonVtableSlot => HasFlags(MethodDescFlags.HasNonVtableSlot); + internal bool HasMethodImpl => HasFlags(MethodDescFlags.HasMethodImpl); + + internal bool HasStableEntryPoint => HasFlags(MethodDescFlags3.HasStableEntryPoint); + internal bool HasPrecode => HasFlags(MethodDescFlags3.HasPrecode); + + #region Additional Pointers + private int AdditionalPointersHelper(MethodDescFlags extraFlags) + => int.PopCount(_desc.Flags & (ushort)extraFlags); + + // non-vtable slot, native code slot and MethodImpl slots are stored after the MethodDesc itself, packed tightly + // in the order: [non-vtable; methhod impl; native code]. + internal int NonVtableSlotIndex => HasNonVtableSlot ? 0 : throw new InvalidOperationException("no non-vtable slot"); + internal int MethodImplIndex + { + get + { + if (!HasMethodImpl) + { + throw new InvalidOperationException("no method impl slot"); + } + return AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot); + } + } + internal int NativeCodeSlotIndex + { + get + { + if (!HasNativeCodeSlot) + { + throw new InvalidOperationException("no native code slot"); + } + return AdditionalPointersHelper(MethodDescFlags.HasNonVtableSlot | MethodDescFlags.HasMethodImpl); + } + } + + internal int AdditionalPointersCount => AdditionalPointersHelper(MethodDescFlags.MethodDescAdditionalPointersMask); + #endregion Additional Pointers + } private class InstantiatedMethodDesc : IData @@ -915,12 +956,104 @@ uint IRuntimeTypeSystem.GetMethodToken(MethodDescHandle methodDescHandle) return methodDesc.Token; } - ushort IRuntimeTypeSystem.GetSlotNumber(MethodDescHandle methodDesc) => throw new NotImplementedException(); + ushort IRuntimeTypeSystem.GetSlotNumber(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + return md.Slot; + } + bool IRuntimeTypeSystem.HasNativeCodeSlot(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + return md.HasNativeCodeSlot; + } - bool IRuntimeTypeSystem.HasNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); + private uint MethodDescAdditionalPointersOffset(MethodDesc md) + { + MethodClassification cls = md.Classification; + switch (cls) + { + case MethodClassification.IL: + return _target.GetTypeInfo(DataType.MethodDesc).Size ?? throw new InvalidOperationException("size of MethodDesc not known"); + case MethodClassification.FCall: + throw new NotImplementedException(); + case MethodClassification.PInvoke: + throw new NotImplementedException(); + case MethodClassification.EEImpl: + throw new NotImplementedException(); + case MethodClassification.Array: + throw new NotImplementedException(); + case MethodClassification.Instantiated: + throw new NotImplementedException(); + case MethodClassification.ComInterop: + throw new NotImplementedException(); + case MethodClassification.Dynamic: + throw new NotImplementedException(); + default: + throw new InvalidOperationException($"Unexpected method classification 0x{cls:x2} for MethodDesc"); + } + } + + TargetPointer IRuntimeTypeSystem.GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + uint offset = MethodDescAdditionalPointersOffset(md); + offset += (uint)(_target.PointerSize * md.NativeCodeSlotIndex); + return methodDesc.Address + offset; + } + private TargetPointer GetAddresOfNonVtableSlot(TargetPointer methodDescPointer, MethodDesc md) + { + uint offset = MethodDescAdditionalPointersOffset(md); + offset += (uint)(_target.PointerSize * md.NonVtableSlotIndex); + return methodDescPointer.Value + offset; + } - TargetPointer IRuntimeTypeSystem.GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); + TargetCodePointer IRuntimeTypeSystem.GetNativeCode(MethodDescHandle methodDescHandle) + { + MethodDesc md = _methodDescs[methodDescHandle.Address]; + // TODO(cdac): _ASSERTE(!IsDefaultInterfaceMethod() || HasNativeCodeSlot()); + if (md.HasNativeCodeSlot) + { + // When profiler is enabled, profiler may ask to rejit a code even though we + // we have ngen code for this MethodDesc. (See MethodDesc::DoPrestub). + // This means that *ppCode is not stable. It can turn from non-zero to zero. + TargetPointer ppCode = ((IRuntimeTypeSystem)this).GetAddressOfNativeCodeSlot(methodDescHandle); + TargetCodePointer pCode = _target.ReadCodePointer(ppCode); + + // if arm32, set the thumb bit + Data.PrecodeMachineDescriptor precodeMachineDescriptor = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor)); + pCode = (TargetCodePointer)(pCode.Value | ~precodeMachineDescriptor.CodePointerToInstrPointerMask.Value); + + return pCode; + } - uint IRuntimeTypeSystem.GetMemberDef(MethodDescHandle methodDesc) => throw new NotImplementedException(); + if (!md.HasStableEntryPoint || md.HasPrecode) + return TargetCodePointer.Null; + + return GetStableEntryPoint(methodDescHandle.Address, md); + } + + private TargetCodePointer GetStableEntryPoint(TargetPointer methodDescAddress, MethodDesc md) + { + // TODO(cdac): _ASSERTE(HasStableEntryPoint()); + // TODO(cdac): _ASSERTE(!IsVersionableWithVtableSlotBackpatch()); + + return GetMethodEntryPointIfExists(methodDescAddress, md); + } + + private TargetCodePointer GetMethodEntryPointIfExists(TargetPointer methodDescAddress, MethodDesc md) + { + if (md.HasNonVtableSlot) + { + TargetPointer pSlot = GetAddresOfNonVtableSlot(methodDescAddress, md); + + return _target.ReadCodePointer(pSlot); + } + + TargetPointer methodTablePointer = md.MethodTable; + TypeHandle typeHandle = GetTypeHandle(methodTablePointer); + // TODO: cdac: _ASSERTE(GetMethodTable()->IsCanonicalMethodTable()); + TargetPointer addrOfSlot = GetAddressOfSlot(typeHandle, md.Slot); + return _target.ReadCodePointer(addrOfSlot); + } } diff --git a/src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs b/src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs index a8c9c0427a6ff..95b404afa2950 100644 --- a/src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs +++ b/src/native/managed/cdacreader/src/Data/MethodDescVersioningState.cs @@ -13,7 +13,9 @@ public MethodDescVersioningState(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.MethodDescVersioningState); NativeCodeVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(NativeCodeVersionNode)].Offset); + Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); } public TargetPointer NativeCodeVersionNode { get; init; } + public byte Flags { get; init; } } diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index 5892ffbad70f2..857321e8d7d2f 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -143,11 +143,12 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa if (nativeCodeAddr != TargetCodePointer.Null) { data->bHasNativeCode = 1; - data->NativeCodeAddr = 0xffffffff_fffffffful; + data->NativeCodeAddr = nativeCodeAddr; } else { data->bHasNativeCode = 0; + data->NativeCodeAddr = 0xffffffff_fffffffful; } if (rtsContract.HasNativeCodeSlot(methodDescHandle)) { @@ -157,29 +158,30 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa { data->AddressOfNativeCodeSlot = 0; } - data->MDToken = rtsContract.GetMemberDef(methodDescHandle); + data->MDToken = rtsContract.GetMethodToken(methodDescHandle); data->MethodDescPtr = methodDesc; TargetPointer methodTableAddr = rtsContract.GetMethodTable(methodDescHandle); data->MethodTablePtr = methodTableAddr; TypeHandle typeHandle = rtsContract.GetTypeHandle(methodTableAddr); data->ModulePtr = rtsContract.GetModule(typeHandle); - if (!nativeCodeContract.IsReJITEnabled()) - { - *pcNeededRevertedRejitData = 0; // TODO[cdac]: copy active code version data - } - else + + // TODO[cdac]: everything in the ReJIT TRY/CATCH in GetMethodDescDataImpl in request.cpp + if (pcNeededRevertedRejitData != null) { - return HResults.E_NOTIMPL; // TODO[cdac]: copy rejit data + + throw new NotImplementedException(); // TODO[cdac]: rejit stuff } +#if false // TODO[cdac]: HAVE_GCCOVER if (requestedNativeCodeVersion.Valid) { TargetPointer gcCoverAddr = nativeCodeContract.GetGCCoverageInfo(requestedNativeCodeVersion); if (gcCoverAddr != TargetPointer.Null) { - return HResults.E_NOTIMPL; // TODO[cdac]: copy gc cover data + return HResults.E_NOTIMPL; // TODO[cdac]: gc stress code copy } } +#endif if (data->bIsDynamic != 0) { From da7065e82135629a0337063740f7503e496bf4e6 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Aug 2024 15:54:00 -0400 Subject: [PATCH 43/66] remove JitManagerKind in the runtime the presence of RangeSection.R2RModule is a discriminator for whether we're looking at EE code or R2R code --- src/coreclr/debug/daccess/fntableaccess.h | 1 - .../debug/runtimeinfo/datadescriptor.h | 1 + src/coreclr/vm/codeman.cpp | 7 +++---- src/coreclr/vm/codeman.h | 21 ++----------------- .../NativeCodePointers_1.ExecutionManager.cs | 9 ++++---- .../cdacreader/src/Data/RangeSection.cs | 2 ++ 6 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/coreclr/debug/daccess/fntableaccess.h b/src/coreclr/debug/daccess/fntableaccess.h index 0cf1ca5fb477a..c4a72a6d93ded 100644 --- a/src/coreclr/debug/daccess/fntableaccess.h +++ b/src/coreclr/debug/daccess/fntableaccess.h @@ -22,7 +22,6 @@ struct FakeEEJitManager { LPVOID __VFN_table; LPVOID m_runtimeSupport; - uint32_t m_jitManagerKind; LPVOID m_pCodeHeap; // Nothing after this point matters: we only need the correct offset of m_pCodeHeap. }; diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index a852da515d93e..667136e12b00f 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -407,6 +407,7 @@ CDAC_TYPE_FIELD(RangeSection, /*pointer*/, NextForDelete, cdac_data::JitManager) CDAC_TYPE_FIELD(RangeSection, /*int32_t*/, Flags, cdac_data::Flags) CDAC_TYPE_FIELD(RangeSection, /*pointer*/, HeapList, cdac_data::HeapList) +CDAC_TYPE_FIELD(RangeSection, /*pointer*/, R2RModule, cdac_data::R2RModule) CDAC_TYPE_END(RangeSection) CDAC_TYPE_BEGIN(IJitManager) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 5db4c2ac418ab..18766814d54d7 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -918,12 +918,11 @@ BOOL IsFunctionFragment(TADDR baseAddress, PTR_RUNTIME_FUNCTION pFunctionEntry) //********************************************************************************** // IJitManager //********************************************************************************** -IJitManager::IJitManager(IJitManager::JitManagerKind kind) +IJitManager::IJitManager() { LIMITED_METHOD_CONTRACT; m_runtimeSupport = ExecutionManager::GetDefaultCodeManager(); - m_jitManagerKind = kind; } #endif // #ifndef DACCESS_COMPILE @@ -1208,7 +1207,7 @@ PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFuncti EEJitManager::EEJitManager() : - IJitManager (IJitManager::JitManagerKind::EE), + IJitManager (), // CRST_DEBUGGER_THREAD - We take this lock on debugger thread during EnC add method, among other things // CRST_TAKEN_DURING_SHUTDOWN - We take this lock during shutdown if ETW is on (to do rundown) m_CodeHeapCritSec( CrstSingleUseLock, @@ -5486,7 +5485,7 @@ int HotColdMappingLookupTable::LookupMappingForMethod(ReadyToRunInfo* pInfo, ULO #ifndef DACCESS_COMPILE ReadyToRunJitManager::ReadyToRunJitManager() - : IJitManager(IJitManager::JitManagerKind::ReadyToRun) + : IJitManager() { WRAPPER_NO_CONTRACT; } diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 4f499ff9d2795..f54ab9e0385bd 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -147,7 +147,6 @@ typedef struct _hpRealCodeHdr public: // if we're using the indirect codeheaders then all enumeration is done by the code header - } RealCodeHeader; typedef struct _hpCodeHdr @@ -641,6 +640,7 @@ template<> struct cdac_data static constexpr size_t JitManager = offsetof(RangeSection, _pjit); static constexpr size_t Flags = offsetof(RangeSection, _flags); static constexpr size_t HeapList = offsetof(RangeSection, _pHeapList); + static constexpr size_t R2RModule = offsetof(RangeSection, _pR2RModule); }; enum class RangeSectionLockState @@ -1555,11 +1555,7 @@ class IJitManager }; #ifndef DACCESS_COMPILE -protected: - enum class JitManagerKind : uint32_t; - IJitManager(JitManagerKind); - -public: + IJitManager(); #endif // !DACCESS_COMPILE virtual DWORD GetCodeType() = 0; @@ -1657,19 +1653,6 @@ class IJitManager protected: PTR_ICodeManager m_runtimeSupport; - enum class JitManagerKind : uint32_t { - EE = 0, - ReadyToRun = 1, - }; - JitManagerKind m_jitManagerKind; - - template friend struct ::cdac_data; -}; - -template<> -struct cdac_data -{ - static constexpr size_t JitManagerKind = offsetof(IJitManager, m_jitManagerKind); }; //----------------------------------------------------------------------------- diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs index 858ecd31541ee..878600dac4f59 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs @@ -148,17 +148,16 @@ public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddre return false; } TargetPointer jitManagerAddress = _rangeSection.JitManager; - // FIXME(cdac): prototype uses R2RModule to determine if the RangeSection belongs to the JIT or to R2R, - // we don't need an extra JitManagerKind field. - Data.IJitManager jitManager = target.ProcessedData.GetOrAdd(_rangeSection.JitManager); - switch ((JitManagerKind)jitManager.JitManagerKind) + TargetPointer r2rModule = _rangeSection.R2RModule; + JitManagerKind jitManagerKind = r2rModule == TargetPointer.Null ? JitManagerKind.EEJitManager : JitManagerKind.ReadyToRunJitManager; + switch (jitManagerKind) { case JitManagerKind.EEJitManager: return EEJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); case JitManagerKind.ReadyToRunJitManager: return ReadyToRunJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); default: - throw new InvalidOperationException($"Invalid JitManagerKind {jitManager.JitManagerKind}"); + throw new InvalidOperationException($"Invalid JitManagerKind"); } } diff --git a/src/native/managed/cdacreader/src/Data/RangeSection.cs b/src/native/managed/cdacreader/src/Data/RangeSection.cs index 050bfcbd48c10..2cd68418ce85c 100644 --- a/src/native/managed/cdacreader/src/Data/RangeSection.cs +++ b/src/native/managed/cdacreader/src/Data/RangeSection.cs @@ -17,6 +17,7 @@ public RangeSection(Target target, TargetPointer address) JitManager = target.ReadPointer(address + (ulong)type.Fields[nameof(JitManager)].Offset); Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); HeapList = target.ReadPointer(address + (ulong)type.Fields[nameof(HeapList)].Offset); + R2RModule = target.ReadPointer(address + (ulong)type.Fields[nameof(R2RModule)].Offset); } public TargetPointer RangeBegin { get; init; } @@ -25,4 +26,5 @@ public RangeSection(Target target, TargetPointer address) public TargetPointer JitManager { get; init; } public TargetPointer HeapList { get; init; } public int Flags { get; init; } + public TargetPointer R2RModule { get; init; } } From 818c21c0e53fafb30f49a535a6caae14cc4b44f4 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Aug 2024 15:55:45 -0400 Subject: [PATCH 44/66] remove more --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 5 ----- .../managed/cdacreader/src/Data/IJitManager.cs | 18 ------------------ src/native/managed/cdacreader/src/DataType.cs | 1 - 3 files changed, 24 deletions(-) delete mode 100644 src/native/managed/cdacreader/src/Data/IJitManager.cs diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 667136e12b00f..6c8dfdbc85696 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -410,11 +410,6 @@ CDAC_TYPE_FIELD(RangeSection, /*pointer*/, HeapList, cdac_data::He CDAC_TYPE_FIELD(RangeSection, /*pointer*/, R2RModule, cdac_data::R2RModule) CDAC_TYPE_END(RangeSection) -CDAC_TYPE_BEGIN(IJitManager) -CDAC_TYPE_INDETERMINATE(IJitManager) -CDAC_TYPE_FIELD(IJitManager, /*uint32*/, JitManagerKind, cdac_data::JitManagerKind) -CDAC_TYPE_END(IJitManager) - CDAC_TYPE_BEGIN(RealCodeHeader) CDAC_TYPE_INDETERMINATE(RealCodeHeader) CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, MethodDesc, offsetof(RealCodeHeader, phdrMDesc)) diff --git a/src/native/managed/cdacreader/src/Data/IJitManager.cs b/src/native/managed/cdacreader/src/Data/IJitManager.cs deleted file mode 100644 index cb0e5a9768781..0000000000000 --- a/src/native/managed/cdacreader/src/Data/IJitManager.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 IJitManager : IData -{ - static IJitManager IData.Create(Target target, TargetPointer address) - => new IJitManager(target, address); - - public IJitManager(Target target, TargetPointer address) - { - Target.TypeInfo type = target.GetTypeInfo(DataType.IJitManager); - JitManagerKind = target.Read(address + (ulong)type.Fields[nameof(JitManagerKind)].Offset); - } - - public uint JitManagerKind { get; init; } -} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 99ce454727553..a4c843d2241dd 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -58,7 +58,6 @@ public enum DataType RangeSectionMap, RangeSectionFragment, RangeSection, - IJitManager, RealCodeHeader, HeapList, MethodDescVersioningState, From 1f6a909bcc0ce6c83978d5c453becb0ef8f31f68 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Aug 2024 16:01:16 -0400 Subject: [PATCH 45/66] whitespace and comments --- src/coreclr/vm/appdomain.hpp | 1 - src/coreclr/vm/ceeload.h | 1 + src/coreclr/vm/codeman.cpp | 2 -- src/coreclr/vm/codeman.h | 2 -- src/coreclr/vm/precode.h | 8 ++++---- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 10bd274022a9a..d1ffe1e481dc7 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1819,7 +1819,6 @@ class AppDomain : public BaseDomain TieredCompilationManager m_tieredCompilationManager; #endif - }; // class AppDomain // Just a ref holder diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index bc3a232459d60..5fee2e09f4bf7 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -585,6 +585,7 @@ class ModuleBase // string helper void InitializeStringData(DWORD token, EEStringData *pstrData, CQuickBytes *pqb); #endif + }; // A code:Module represents a DLL or EXE file loaded from the disk. A module live in a code:Assembly diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 18766814d54d7..d019affc33b33 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1207,7 +1207,6 @@ PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFuncti EEJitManager::EEJitManager() : - IJitManager (), // CRST_DEBUGGER_THREAD - We take this lock on debugger thread during EnC add method, among other things // CRST_TAKEN_DURING_SHUTDOWN - We take this lock during shutdown if ETW is on (to do rundown) m_CodeHeapCritSec( CrstSingleUseLock, @@ -5485,7 +5484,6 @@ int HotColdMappingLookupTable::LookupMappingForMethod(ReadyToRunInfo* pInfo, ULO #ifndef DACCESS_COMPILE ReadyToRunJitManager::ReadyToRunJitManager() - : IJitManager() { WRAPPER_NO_CONTRACT; } diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index f54ab9e0385bd..ad69a91c98096 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -1464,8 +1464,6 @@ struct cdac_data }; }; - - struct RangeSectionMapData { BYTE Data[sizeof(RangeSectionMap)]; diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index a35596d1b47f3..55d68886af4da 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -14,8 +14,8 @@ #if defined(TARGET_AMD64) #define OFFSETOF_PRECODE_TYPE 0 -#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 // FIXME: unused -#define OFFSETOF_PRECODE_TYPE_MOV_R10 10 // FIXME: unused +#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 +#define OFFSETOF_PRECODE_TYPE_MOV_R10 10 #define SIZEOF_PRECODE_BASE 16 @@ -24,8 +24,8 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk(); #define OFFSETOF_PRECODE_TYPE 0 -#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 // FIXME: unuxed -#define OFFSETOF_PRECODE_TYPE_MOV_RM_R 6 // FIXME: unused +#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 +#define OFFSETOF_PRECODE_TYPE_MOV_RM_R 6 #define SIZEOF_PRECODE_BASE 8 From 04f41f640ea91bef2ac90092b77cdfabbcf5f9e0 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 10:01:04 -0400 Subject: [PATCH 46/66] remove instance field initialization from PrecodeMachineDescriptor PrecodeMachineDescriptor::Init() will initialize g_PrecodeMachineDescriptor --- src/coreclr/vm/precode.cpp | 3 +-- src/coreclr/vm/precode.h | 55 +++++++++++--------------------------- 2 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index cb708b428ef79..51d7d6953e064 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -672,7 +672,7 @@ void PrecodeMachineDescriptor::Init() // mask off the thumb bit g_PrecodeMachineDescriptor.CodePointerToInstrPointerMask = ~1; #endif - g_PrecodeMachineDescriptor.OffsetOfPrecodeType = OFFSETOF_PRECODE_TYPE; // FIXME(cdac): sometimes OFFSETOF_PRECODE_TYPE is undefined? + g_PrecodeMachineDescriptor.OffsetOfPrecodeType = OFFSETOF_PRECODE_TYPE; // cDAC will do (where N = 8*ReadWidthOfPrecodeType): // uintN_t PrecodeType = *(uintN_t*)(pPrecode + OffsetOfPrecodeType); // PrecodeType >>= ShiftOfPrecodeType; @@ -684,7 +684,6 @@ void PrecodeMachineDescriptor::Init() g_PrecodeMachineDescriptor.ReadWidthOfPrecodeType = 1; g_PrecodeMachineDescriptor.ShiftOfPrecodeType = 0; #endif - // uint8_t SizeOfPrecodeBase = SIZEOF_PRECODE_BASE; g_PrecodeMachineDescriptor.InvalidPrecodeType = InvalidPrecode::Type; g_PrecodeMachineDescriptor.StubPrecodeType = StubPrecode::Type; diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 55d68886af4da..662cb687630ca 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -601,50 +601,27 @@ static_assert_no_msg(sizeof(Precode) <= sizeof(ThisPtrRetBufPrecode)); // A summary of the precode layout for diagnostic purposes struct PrecodeMachineDescriptor { -#ifndef TARGET_ARM - uintptr_t CodePointerToInstrPointerMask = ~0; -#else - // mask off the thumb bit - uintptr_t CodePointerToInstrPointerMask = ~1; -#endif - uint8_t OffsetOfPrecodeType = OFFSETOF_PRECODE_TYPE; // FIXME(cdac): sometimes OFFSETOF_PRECODE_TYPE is undefined? + uintptr_t CodePointerToInstrPointerMask; + uint8_t OffsetOfPrecodeType; // cDAC will do (where N = 8*ReadWidthOfPrecodeType): // uintN_t PrecodeType = *(uintN_t*)(pPrecode + OffsetOfPrecodeType); // PrecodeType >>= ShiftOfPrecodeType; // return (byte)PrecodeType; -#ifdef TARGET_LOONGARCH64 - uint8_t ReadWidthOfPrecodeType = 2; - uint8_t ShiftOfPrecodeType = 5; -#else - uint8_t ReadWidthOfPrecodeType = 1; - uint8_t ShiftOfPrecodeType = 0; -#endif - // uint8_t SizeOfPrecodeBase = SIZEOF_PRECODE_BASE; + uint8_t ReadWidthOfPrecodeType; + uint8_t ShiftOfPrecodeType; - uint8_t InvalidPrecodeType = InvalidPrecode::Type; - uint8_t StubPrecodeType = StubPrecode::Type; -#ifdef HAS_NDIRECT_IMPORT_PRECODE - uint8_t HasNDirectImportPrecode = 1; - uint8_t NDirectImportPrecodeType = NDirectImportPrecode::Type; -#else - uint8_t HasNDirectImportPrecode = 0; - uint8_t NDirectImportPrecodeType = 0; -#endif // HAS_NDIRECT_IMPORT_PRECODE -#ifdef HAS_FIXUP_PRECODE - uint8_t HasFixupPrecode = 1; - uint8_t FixupPrecodeType = FixupPrecode::Type; -#else - uint8_t HasFixupPrecode = 0; - uint8_t FixupPrecodeType = 0; -#endif // HAS_FIXUP_PRECODE -#ifdef HAS_THISPTR_RETBUF_PRECODE - uint8_t HasThisPtrRetBufPrecode = 1; - uint8_t HasThisPointerRetBufPrecodeType = ThisPtrRetBufPrecode::Type; -#else - uint8_t HasThisPtrRetBufPrecode = 0; - uint8_t HasThisPointerRetBufPrecodeType = 0; -#endif // HAS_THISPTR_RETBUF_PRECODE - uint32_t StubCodePageSize = GetStubCodePageSize(); + uint8_t InvalidPrecodeType; + uint8_t StubPrecodeType; + uint8_t HasNDirectImportPrecode; + uint8_t NDirectImportPrecodeType; + + uint8_t HasFixupPrecode; + uint8_t FixupPrecodeType; + + uint8_t HasThisPtrRetBufPrecode; + uint8_t HasThisPointerRetBufPrecodeType; + + uint32_t StubCodePageSize; public: PrecodeMachineDescriptor() = default; PrecodeMachineDescriptor(const PrecodeMachineDescriptor&) = delete; From abf9df0e275b853f49f466b3a8e9317fdbe6fe94 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 10:03:28 -0400 Subject: [PATCH 47/66] suggestion from code review make m_IsCollectible a const BYTE --- src/coreclr/vm/loaderallocator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 6271692294550..99086cd3cd09d 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -332,7 +332,7 @@ class LoaderAllocator bool m_fTerminated; bool m_fMarked; int m_nGCCount; - BYTE m_IsCollectible; + const BYTE m_IsCollectible; // Pre-allocated blocks of heap for collectible assemblies. Will be set to NULL as soon as it is // used. See code in GetVSDHeapInitialBlock and GetCodeHeapInitialBlock From 71dee348ecb6dda76fce7779bb029d98be13e82e Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 11:11:39 -0400 Subject: [PATCH 48/66] fixup --- src/coreclr/vm/loaderallocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index c76746ca3e9de..81e5f92b16ca1 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -18,6 +18,7 @@ UINT64 LoaderAllocator::cLoaderAllocatorsCreated = 1; LoaderAllocator::LoaderAllocator(bool collectible) : + m_IsCollectible(collectible ? 1 : 0); m_stubPrecodeRangeList(STUB_CODE_BLOCK_STUBPRECODE, collectible), m_fixupPrecodeRangeList(STUB_CODE_BLOCK_FIXUPPRECODE, collectible) { @@ -68,7 +69,6 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_pLastUsedCodeHeap = NULL; m_pLastUsedDynamicCodeHeap = NULL; m_pJumpStubCache = NULL; - m_IsCollectible = collectible ? 1 : 0; m_pMarshalingData = NULL; From 2fbc89ea544fee6bad05747ec720bb4751ab12cb Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 11:19:45 -0400 Subject: [PATCH 49/66] Revert "fixup" This reverts commit bc45c00272b581008ccbefbc7c1c15c3bca0f6f7. --- src/coreclr/vm/loaderallocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 81e5f92b16ca1..c76746ca3e9de 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -18,7 +18,6 @@ UINT64 LoaderAllocator::cLoaderAllocatorsCreated = 1; LoaderAllocator::LoaderAllocator(bool collectible) : - m_IsCollectible(collectible ? 1 : 0); m_stubPrecodeRangeList(STUB_CODE_BLOCK_STUBPRECODE, collectible), m_fixupPrecodeRangeList(STUB_CODE_BLOCK_FIXUPPRECODE, collectible) { @@ -69,6 +68,7 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_pLastUsedCodeHeap = NULL; m_pLastUsedDynamicCodeHeap = NULL; m_pJumpStubCache = NULL; + m_IsCollectible = collectible ? 1 : 0; m_pMarshalingData = NULL; From 2e3b938230bd7ed53a5b09eaddf7cbeac79f0903 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 11:19:52 -0400 Subject: [PATCH 50/66] Revert "suggestion from code review make m_IsCollectible a const BYTE" This reverts commit b1c7c36d38083839c4a983446adced2771978a6a. --- src/coreclr/vm/loaderallocator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 99086cd3cd09d..6271692294550 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -332,7 +332,7 @@ class LoaderAllocator bool m_fTerminated; bool m_fMarked; int m_nGCCount; - const BYTE m_IsCollectible; + BYTE m_IsCollectible; // Pre-allocated blocks of heap for collectible assemblies. Will be set to NULL as soon as it is // used. See code in GetVSDHeapInitialBlock and GetCodeHeapInitialBlock From 1776abe32c751b8ee23c10d862b83e08db57e83a Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 12:45:14 -0400 Subject: [PATCH 51/66] move PrecodeStubs to a separate contract --- src/coreclr/debug/runtimeinfo/contracts.jsonc | 1 + .../src/Contracts/NativeCodePointers.cs | 5 +- .../Contracts/NativeCodePointers_1.Precode.cs | 172 ----------------- .../src/Contracts/NativeCodePointers_1.cs | 11 +- .../cdacreader/src/Contracts/PrecodeStubs.cs | 29 +++ .../src/Contracts/PrecodeStubs_1.cs | 173 ++++++++++++++++++ .../cdacreader/src/Contracts/Registry.cs | 1 + .../RuntimeTypeSystem_1.NonValidated.cs | 4 +- 8 files changed, 208 insertions(+), 188 deletions(-) delete mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs create mode 100644 src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs create mode 100644 src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/debug/runtimeinfo/contracts.jsonc index 235ce32ea0b11..12795badd112f 100644 --- a/src/coreclr/debug/runtimeinfo/contracts.jsonc +++ b/src/coreclr/debug/runtimeinfo/contracts.jsonc @@ -15,6 +15,7 @@ "Loader": 1, "NativeCodePointers": 1, "Object": 1, + "PrecodeStubs": 1, "RuntimeTypeSystem": 1, "Thread": 1 } diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index 422ba2c308f5d..f4b97ac3f3164 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -10,20 +10,17 @@ internal interface INativeCodePointers : IContract static string IContract.Name { get; } = nameof(NativeCodePointers); static IContract IContract.Create(Target target, int version) { - TargetPointer precodeMachineDescriptorAddress = target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor); - Data.PrecodeMachineDescriptor precodeMachineDescriptor = target.ProcessedData.GetOrAdd(precodeMachineDescriptorAddress); TargetPointer executionManagerCodeRangeMapAddress = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress); Data.RangeSectionMap rangeSectionMap = target.ProcessedData.GetOrAdd(executionManagerCodeRangeMapAddress); TargetPointer profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock); Data.ProfControlBlock profControlBlock = target.ProcessedData.GetOrAdd(profControlBlockAddress); return version switch { - 1 => new NativeCodePointers_1(target, precodeMachineDescriptor, rangeSectionMap, profControlBlock), + 1 => new NativeCodePointers_1(target, rangeSectionMap, profControlBlock), _ => default(NativeCodePointers), }; } - public virtual TargetPointer MethodDescFromStubAddress(TargetCodePointer codeAddress) => throw new NotImplementedException(); public virtual TargetPointer ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException(); diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs deleted file mode 100644 index 2374b4e2a5afe..0000000000000 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.Precode.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Microsoft.Diagnostics.DataContractReader.Data; - -namespace Microsoft.Diagnostics.DataContractReader.Contracts; - -internal readonly partial struct NativeCodePointers_1 : INativeCodePointers -{ - internal enum KnownPrecodeType - { - Stub = 1, - NDirectImport, - Fixup, - ThisPtrRetBuf, - } - - internal abstract class ValidPrecode - { - public TargetPointer InstrPointer { get; } - public KnownPrecodeType PrecodeType { get; } - - protected ValidPrecode(TargetPointer instrPointer, KnownPrecodeType precodeType) - { - InstrPointer = instrPointer; - PrecodeType = precodeType; - } - - internal abstract TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); - - } - - internal class StubPrecode : ValidPrecode - { - internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } - - internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) - { - TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; - Data.StubPrecodeData stubPrecodeData = target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); - return stubPrecodeData.MethodDesc; - } - } - - internal sealed class NDirectImportPrecode : StubPrecode - { - internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.NDirectImport) { } - } - - internal sealed class FixupPrecode : ValidPrecode - { - internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } - internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) - { - TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; - Data.FixupPrecodeData fixupPrecodeData = target.ProcessedData.GetOrAdd(fixupPrecodeDataAddress); - return fixupPrecodeData.MethodDesc; - - } - } - - internal sealed class ThisPtrRetBufPrecode : ValidPrecode // FIXME: is this a StubPrecode? - { - internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } - - internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) - { - throw new NotImplementedException(); // TODO(cdac) - } - } - - internal struct PrecodeContract - { - public readonly Target _target; - public readonly PrecodeMachineDescriptor _machineDescriptor; - - public PrecodeContract(Target target, PrecodeMachineDescriptor precodeMachineDescriptor) - { - _target = target; - _machineDescriptor = precodeMachineDescriptor; - } - - internal PrecodeMachineDescriptor MachineDescriptor => _machineDescriptor; - private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); - - private byte ReadPrecodeType(TargetPointer instrPointer) - { - if (_machineDescriptor.ReadWidthOfPrecodeType == 1) - { - byte precodeType = _target.Read(instrPointer + _machineDescriptor.OffsetOfPrecodeType); - return (byte)(precodeType >> _machineDescriptor.ShiftOfPrecodeType); - } - else if (_machineDescriptor.ReadWidthOfPrecodeType == 2) - { - ushort precodeType = _target.Read(instrPointer + _machineDescriptor.OffsetOfPrecodeType); - return (byte)(precodeType >> _machineDescriptor.ShiftOfPrecodeType); - } - else - { - throw new InvalidOperationException($"Invalid precode type width {_machineDescriptor.ReadWidthOfPrecodeType}"); - } - } - - private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) - { - TargetPointer stubPrecodeDataAddress = stubInstrPointer + _machineDescriptor.StubCodePageSize; - return _target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); - } - - private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) - { - // precode.h Precode::GetType() - byte precodeType = ReadPrecodeType(instrAddress); - if (precodeType == _machineDescriptor.StubPrecodeType) - { - // get the actual type from the StubPrecodeData - Data.StubPrecodeData stubPrecodeData = GetStubPrecodeData(instrAddress); - precodeType = stubPrecodeData.Type; - } - - if (precodeType == _machineDescriptor.StubPrecodeType) - { - return KnownPrecodeType.Stub; - } - else if (_machineDescriptor.NDirectImportPrecodeType is byte ndType && precodeType == ndType) - { - return KnownPrecodeType.NDirectImport; - } - else if (_machineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) - { - return KnownPrecodeType.Fixup; - } - // TODO: ThisPtrRetBuf - else - { - return null; - } - } - - internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) - { - // Mask off the thumb bit, if we're on arm32, to get the actual instruction pointer - ulong instrPointer = (ulong)codePointer.AsTargetPointer & _machineDescriptor.CodePointerToInstrPointerMask.Value; - return new TargetPointer(instrPointer); - } - - - internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint) - { - TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint); - if (IsAlignedInstrPointer(instrPointer) && TryGetKnownPrecodeType(instrPointer) is KnownPrecodeType precodeType) - { - switch (precodeType) - { - case KnownPrecodeType.Stub: - return new StubPrecode(instrPointer); - case KnownPrecodeType.Fixup: - return new FixupPrecode(instrPointer); - case KnownPrecodeType.NDirectImport: - return new NDirectImportPrecode(instrPointer); - case KnownPrecodeType.ThisPtrRetBuf: - return new ThisPtrRetBufPrecode(instrPointer); - default: - break; - } - } - throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}"); - } - - } -} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index 2b74522405e34..e78e6c38f92f1 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -8,26 +8,17 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly partial struct NativeCodePointers_1 : INativeCodePointers { private readonly Target _target; - private readonly PrecodeContract _precodeContract; private readonly ExecutionManagerContract _executionManagerContract; private readonly NativeCodeVersionContract _nativeCodeVersionContract; - public NativeCodePointers_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) + public NativeCodePointers_1(Target target, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) { _target = target; - _precodeContract = new PrecodeContract(target, precodeMachineDescriptor); _executionManagerContract = new ExecutionManagerContract(target, topRangeSectionMap, profControlBlock); _nativeCodeVersionContract = new NativeCodeVersionContract(target); } - TargetPointer INativeCodePointers.MethodDescFromStubAddress(TargetCodePointer entryPoint) - { - ValidPrecode precode = _precodeContract.GetPrecodeFromEntryPoint(entryPoint); - - return precode.GetMethodDesc(_target, _precodeContract.MachineDescriptor); - } - TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) { diff --git a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs new file mode 100644 index 0000000000000..288af4f03b69c --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal interface IPrecodeStubs : IContract +{ + static string IContract.Name { get; } = nameof(PrecodeStubs); + static IContract IContract.Create(Target target, int version) + { + TargetPointer precodeMachineDescriptorAddress = target.ReadGlobalPointer(Constants.Globals.PrecodeMachineDescriptor); + Data.PrecodeMachineDescriptor precodeMachineDescriptor = target.ProcessedData.GetOrAdd(precodeMachineDescriptorAddress); + return version switch + { + 1 => new PrecodeStubs_1(target, precodeMachineDescriptor), + _ => default(PrecodeStubs), + }; + } + + TargetPointer MethodDescFromStubAddress(TargetCodePointer entryPoint) => throw new NotImplementedException(); + +} + +internal readonly struct PrecodeStubs : IPrecodeStubs +{ + +} diff --git a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs new file mode 100644 index 0000000000000..ad16f07b7face --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs @@ -0,0 +1,173 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly struct PrecodeStubs_1 : IPrecodeStubs +{ + private readonly Target _target; + internal readonly Data.PrecodeMachineDescriptor MachineDescriptor; + + internal enum KnownPrecodeType + { + Stub = 1, + NDirectImport, + Fixup, + ThisPtrRetBuf, + } + + internal abstract class ValidPrecode + { + public TargetPointer InstrPointer { get; } + public KnownPrecodeType PrecodeType { get; } + + protected ValidPrecode(TargetPointer instrPointer, KnownPrecodeType precodeType) + { + InstrPointer = instrPointer; + PrecodeType = precodeType; + } + + internal abstract TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); + + } + + internal class StubPrecode : ValidPrecode + { + internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } + + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + Data.StubPrecodeData stubPrecodeData = target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); + return stubPrecodeData.MethodDesc; + } + } + + internal sealed class NDirectImportPrecode : StubPrecode + { + internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.NDirectImport) { } + } + + internal sealed class FixupPrecode : ValidPrecode + { + internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + Data.FixupPrecodeData fixupPrecodeData = target.ProcessedData.GetOrAdd(fixupPrecodeDataAddress); + return fixupPrecodeData.MethodDesc; + + } + } + + internal sealed class ThisPtrRetBufPrecode : ValidPrecode // FIXME: is this a StubPrecode? + { + internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } + + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + throw new NotImplementedException(); // TODO(cdac) + } + } + + private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); + + private byte ReadPrecodeType(TargetPointer instrPointer) + { + if (MachineDescriptor.ReadWidthOfPrecodeType == 1) + { + byte precodeType = _target.Read(instrPointer + MachineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> MachineDescriptor.ShiftOfPrecodeType); + } + else if (MachineDescriptor.ReadWidthOfPrecodeType == 2) + { + ushort precodeType = _target.Read(instrPointer + MachineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> MachineDescriptor.ShiftOfPrecodeType); + } + else + { + throw new InvalidOperationException($"Invalid precode type width {MachineDescriptor.ReadWidthOfPrecodeType}"); + } + } + + private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) + { + TargetPointer stubPrecodeDataAddress = stubInstrPointer + MachineDescriptor.StubCodePageSize; + return _target.ProcessedData.GetOrAdd(stubPrecodeDataAddress); + } + + private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) + { + // precode.h Precode::GetType() + byte precodeType = ReadPrecodeType(instrAddress); + if (precodeType == MachineDescriptor.StubPrecodeType) + { + // get the actual type from the StubPrecodeData + Data.StubPrecodeData stubPrecodeData = GetStubPrecodeData(instrAddress); + precodeType = stubPrecodeData.Type; + } + + if (precodeType == MachineDescriptor.StubPrecodeType) + { + return KnownPrecodeType.Stub; + } + else if (MachineDescriptor.NDirectImportPrecodeType is byte ndType && precodeType == ndType) + { + return KnownPrecodeType.NDirectImport; + } + else if (MachineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) + { + return KnownPrecodeType.Fixup; + } + // TODO: ThisPtrRetBuf + else + { + return null; + } + } + + internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) + { + // Mask off the thumb bit, if we're on arm32, to get the actual instruction pointer + ulong instrPointer = (ulong)codePointer.AsTargetPointer & MachineDescriptor.CodePointerToInstrPointerMask.Value; + return new TargetPointer(instrPointer); + } + + + internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint) + { + TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint); + if (IsAlignedInstrPointer(instrPointer) && TryGetKnownPrecodeType(instrPointer) is KnownPrecodeType precodeType) + { + switch (precodeType) + { + case KnownPrecodeType.Stub: + return new StubPrecode(instrPointer); + case KnownPrecodeType.Fixup: + return new FixupPrecode(instrPointer); + case KnownPrecodeType.NDirectImport: + return new NDirectImportPrecode(instrPointer); + case KnownPrecodeType.ThisPtrRetBuf: + return new ThisPtrRetBufPrecode(instrPointer); + default: + break; + } + } + throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}"); + } + public PrecodeStubs_1(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + _target = target; + MachineDescriptor = precodeMachineDescriptor; + } + + TargetPointer IPrecodeStubs.MethodDescFromStubAddress(TargetCodePointer entryPoint) + { + ValidPrecode precode = GetPrecodeFromEntryPoint(entryPoint); + + return precode.GetMethodDesc(_target, MachineDescriptor); + } + +} diff --git a/src/native/managed/cdacreader/src/Contracts/Registry.cs b/src/native/managed/cdacreader/src/Contracts/Registry.cs index 23088c95c556c..8b6ae31d4bcf8 100644 --- a/src/native/managed/cdacreader/src/Contracts/Registry.cs +++ b/src/native/managed/cdacreader/src/Contracts/Registry.cs @@ -26,6 +26,7 @@ public Registry(Target target) public IRuntimeTypeSystem RuntimeTypeSystem => GetContract(); public IDacStreams DacStreams => GetContract(); public INativeCodePointers NativeCodePointers => GetContract(); + public IPrecodeStubs PrecodeStubs => GetContract(); private T GetContract() where T : IContract { diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 58e93d15559b7..0f1bf35c46b4a 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -424,8 +424,8 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull TargetCodePointer temporaryEntryPoint = GetTemporaryEntryPointIfExists(umd); if (temporaryEntryPoint != TargetCodePointer.Null) { - Contracts.INativeCodePointers codePointers = _target.Contracts.NativeCodePointers; - TargetPointer methodDesc = codePointers.MethodDescFromStubAddress(temporaryEntryPoint); + Contracts.IPrecodeStubs precode = _target.Contracts.PrecodeStubs; + TargetPointer methodDesc = precode.MethodDescFromStubAddress(temporaryEntryPoint); if (methodDesc != methodDescPointer) { return false; From 099b5fa209327db23189538a3e4a9c4239de90bc Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 13:27:14 -0400 Subject: [PATCH 52/66] ExecutionManager contract --- src/coreclr/debug/runtimeinfo/contracts.jsonc | 1 + .../src/Contracts/ExecutionManager.cs | 41 +++ ...Map.cs => ExecutionManager_1.NibbleMap.cs} | 2 +- .../src/Contracts/ExecutionManager_1.cs | 339 ++++++++++++++++++ .../src/Contracts/NativeCodePointers.cs | 9 +- .../NativeCodePointers_1.ExecutionManager.cs | 306 ---------------- .../src/Contracts/NativeCodePointers_1.cs | 30 +- .../cdacreader/src/Contracts/Registry.cs | 1 + .../RuntimeTypeSystem_1.NonValidated.cs | 10 +- .../src/Contracts/RuntimeTypeSystem_1.cs | 2 +- 10 files changed, 399 insertions(+), 342 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs rename src/native/managed/cdacreader/src/Contracts/{NativeCodePointers_1.NibbleMap.cs => ExecutionManager_1.NibbleMap.cs} (98%) create mode 100644 src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs delete mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/debug/runtimeinfo/contracts.jsonc index 12795badd112f..315d7039ea617 100644 --- a/src/coreclr/debug/runtimeinfo/contracts.jsonc +++ b/src/coreclr/debug/runtimeinfo/contracts.jsonc @@ -12,6 +12,7 @@ "DacStreams": 1, "EcmaMetadata" : 1, "Exception": 1, + "ExecutionManager": 1, "Loader": 1, "NativeCodePointers": 1, "Object": 1, diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs new file mode 100644 index 0000000000000..0c3e955718b79 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal struct EECodeInfoHandle +{ + public readonly TargetPointer Address; + internal EECodeInfoHandle(TargetPointer address) => Address = address; +} + +internal interface IExecutionManager : IContract +{ + static string IContract.Name { get; } = nameof(ExecutionManager); + static IContract IContract.Create(Target target, int version) + { + TargetPointer executionManagerCodeRangeMapAddress = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress); + Data.RangeSectionMap rangeSectionMap = target.ProcessedData.GetOrAdd(executionManagerCodeRangeMapAddress); + TargetPointer profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock); + Data.ProfControlBlock profControlBlock = target.ProcessedData.GetOrAdd(profControlBlockAddress); + return version switch + { + 1 => new ExecutionManager_1(target, rangeSectionMap, profControlBlock), + _ => default(ExecutionManager), + }; + } + + EECodeInfoHandle? GetEECodeInfoHandle(TargetCodePointer ip) => throw new NotImplementedException(); + TargetPointer GetMethodDesc(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException(); + TargetCodePointer GetStartAddress(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException(); + + // TODO[cdac]: this should be on a ReJIT contract + bool IsReJITEnabled() => throw new NotImplementedException(); +} + +internal readonly struct ExecutionManager : IExecutionManager +{ + +} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.NibbleMap.cs similarity index 98% rename from src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs rename to src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.NibbleMap.cs index c69e1ae3a0840..b486b7c2523cf 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NibbleMap.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.NibbleMap.cs @@ -10,7 +10,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; #pragma warning disable SA1121 // Use built in alias -internal readonly partial struct NativeCodePointers_1 : INativeCodePointers +internal readonly partial struct ExecutionManager_1 : IExecutionManager { // Given a contiguous region of memory in which we lay out a collection of non-overlapping code blocks that are // not too small (so that two adjacent ones aren't too close together) and where the start of each code block is preceeded by a code header aligned on some power of 2, diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs new file mode 100644 index 0000000000000..41c3f61a08f85 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs @@ -0,0 +1,339 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly partial struct ExecutionManager_1 : IExecutionManager +{ + internal class EECodeInfo + { + private readonly int _codeHeaderOffset; + // maps EECodeInfoHandle.Address (which is the CodeHeaderAddress) to the EECodeInfo + + public TargetCodePointer StartAddress { get; } + // note: this is the address of the pointer to the "real code header", you need to + // dereference it to get the address of _codeHeaderData + public TargetPointer CodeHeaderAddress => StartAddress.Value - (ulong)_codeHeaderOffset; + private Data.RealCodeHeader _codeHeaderData; + public TargetPointer JitManagerAddress { get; } + public TargetNUInt RelativeOffset { get; } + public EECodeInfo(TargetCodePointer startAddress, int codeHeaderOffset, TargetNUInt relativeOffset, Data.RealCodeHeader codeHeaderData, TargetPointer jitManagerAddress) + { + _codeHeaderOffset = codeHeaderOffset; + StartAddress = startAddress; + _codeHeaderData = codeHeaderData; + RelativeOffset = relativeOffset; + JitManagerAddress = jitManagerAddress; + } + + public TargetPointer MethodDescAddress => _codeHeaderData.MethodDesc; + public bool Valid => JitManagerAddress != TargetPointer.Null; + } + + // RangeFragment and RangeSection pointers have a collectible flag on the lowest bit + private struct ExMgrPtr + { + public readonly TargetPointer RawValue; + + public TargetPointer Address => RawValue & ~1ul; + + public bool IsNull => Address == TargetPointer.Null; + + public static ExMgrPtr Null => new ExMgrPtr(TargetPointer.Null); + + public ExMgrPtr(TargetPointer value) + { + RawValue = value; + } + + public ExMgrPtr Offset(int stride, int idx) + { + return new ExMgrPtr(RawValue.Value + (ulong)(stride * idx)); + } + + public T Load(Target target) where T : Data.IData + { + return target.ProcessedData.GetOrAdd(Address); + } + + public ExMgrPtr LoadPointer(Target target) + { + return new ExMgrPtr(target.ReadPointer(Address)); + } + } + + private readonly struct TargetCodeManagerDescriptor + { + public int MapLevels { get; } + public int BitsPerLevel { get; } = 8; + public int MaxSetBit { get; } + public int EntriesPerMapLevel { get; } = 256; + + private TargetCodeManagerDescriptor(int mapLevels, int maxSetBit) + { + MapLevels = mapLevels; + MaxSetBit = maxSetBit; + } + public static TargetCodeManagerDescriptor Create(Target target) + { + if (target.PointerSize == 4) + { + return new(mapLevels: 2, maxSetBit: 31); // 0 indexed + } + else if (target.PointerSize == 8) + { + return new(mapLevels: 5, maxSetBit: 56); // 0 indexed + } + else + { + throw new InvalidOperationException("Invalid pointer size"); + } + } + } + + + internal readonly Target _target; + private readonly Dictionary _codeInfos = new(); + private readonly Data.ProfControlBlock _profControlBlock; + private readonly Data.RangeSectionMap _topRangeSectionMap; + private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; + + + internal enum JitManagerKind + { + EEJitManager = 0, + ReadyToRunJitManager = 1, + } + + public ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) + { + _target = target; + _topRangeSectionMap = topRangeSectionMap; + _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); + _profControlBlock = profControlBlock; + } + + [Flags] + private enum RangeSectionFlags : int + { + CodeHeap = 0x02, + RangeList = 0x04, + } + + private sealed class RangeSection + { + private readonly Data.RangeSection? _rangeSection; + + public RangeSection() + { + _rangeSection = default; + } + public RangeSection(Data.RangeSection rangeSection) + { + _rangeSection = rangeSection; + } + + private bool HasFlags(RangeSectionFlags mask) => (_rangeSection!.Flags & (int)mask) != 0; + private bool IsRangeList => HasFlags(RangeSectionFlags.RangeList); + private bool IsCodeHeap => HasFlags(RangeSectionFlags.CodeHeap); + + public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) + { + info = null; + if (_rangeSection == null) + { + return false; + } + TargetPointer jitManagerAddress = _rangeSection.JitManager; + TargetPointer r2rModule = _rangeSection.R2RModule; + JitManagerKind jitManagerKind = r2rModule == TargetPointer.Null ? JitManagerKind.EEJitManager : JitManagerKind.ReadyToRunJitManager; + switch (jitManagerKind) + { + case JitManagerKind.EEJitManager: + return EEJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); + case JitManagerKind.ReadyToRunJitManager: + return ReadyToRunJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); + default: + throw new InvalidOperationException($"Invalid JitManagerKind"); + } + } + + private bool EEJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) + { + info = null; + // EEJitManager::JitCodeToMethodInfo + if (IsRangeList) + { + return false; + } + TargetPointer start = EEFindMethodCode(target, jittedCodeAddress); + if (start == TargetPointer.Null) + { + return false; + } + Debug.Assert(start.Value <= jittedCodeAddress.Value); + TargetNUInt relativeOffset = new TargetNUInt(jittedCodeAddress.Value - start.Value); + int codeHeaderOffset = target.PointerSize; + TargetPointer codeHeaderIndirect = new TargetPointer(start - (ulong)codeHeaderOffset); + if (IsStubCodeBlock(target, codeHeaderIndirect)) + { + return false; + } + TargetPointer codeHeaderAddress = target.ReadPointer(codeHeaderIndirect); + Data.RealCodeHeader realCodeHeader = target.ProcessedData.GetOrAdd(codeHeaderAddress); + info = new EECodeInfo(jittedCodeAddress, codeHeaderOffset, relativeOffset, realCodeHeader, jitManagerAddress); + return true; + } + + private static bool IsStubCodeBlock(Target target, TargetPointer codeHeaderIndirect) + { + uint stubCodeBlockLast = target.ReadGlobal(Constants.Globals.StubCodeBlockLast); + return codeHeaderIndirect.Value <= stubCodeBlockLast; + } + + private TargetPointer EEFindMethodCode(Target target, TargetCodePointer jittedCodeAddress) + { + // EEJitManager::FindMethodCode + if (_rangeSection == null) + { + throw new InvalidOperationException(); + } + if (!IsCodeHeap) + { + throw new InvalidOperationException("RangeSection is not a code heap"); + } + TargetPointer heapListAddress = _rangeSection.HeapList; + Data.HeapList heapList = target.ProcessedData.GetOrAdd(heapListAddress); + if (jittedCodeAddress < heapList.StartAddress || jittedCodeAddress > heapList.EndAddress) + { + return TargetPointer.Null; + } + TargetPointer mapBase = heapList.MapBase; + TargetPointer mapStart = heapList.HeaderMap; + NibbleMap nibbleMap = NibbleMap.Create(target, (uint)target.PointerSize); + return nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); + + } + private bool ReadyToRunJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) + { + throw new NotImplementedException(); // TODO(cdac): ReadyToRunJitManager::JitCodeToMethodInfo + } + } + + + // note: level is 1-indexed + private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, TargetCodePointer address, int level) + { + ulong addressAsInt = address.Value; + ulong addressBitsUsedInMap = addressAsInt >> (descriptor.MaxSetBit + 1 - (descriptor.MapLevels * descriptor.BitsPerLevel)); + ulong addressBitsShifted = addressBitsUsedInMap >> ((level - 1) * descriptor.BitsPerLevel); + ulong addressBitsUsedInLevel = (ulong)(descriptor.EntriesPerMapLevel - 1) & addressBitsShifted; + return checked((int)addressBitsUsedInLevel); + } + + internal EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) + { + RangeSection range = LookupRangeSection(jittedCodeAddress); + range.JitCodeToMethodInfo(_target, jittedCodeAddress, out EECodeInfo? info); + return info; + } + + private static bool InRange(Data.RangeSectionFragment fragment, TargetCodePointer address) + { + return fragment.RangeBegin <= address && address < fragment.RangeEndOpen; + } + + private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) + { + ExMgrPtr rangeSectionFragmentPtr = GetRangeSectionForAddress(jittedCodeAddress); + if (rangeSectionFragmentPtr.IsNull) + { + return new RangeSection(); + } + while (!rangeSectionFragmentPtr.IsNull) + { + Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); + if (InRange(fragment, jittedCodeAddress)) + { + break; + } + rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); // TODO: load? + } + if (!rangeSectionFragmentPtr.IsNull) + { + Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); + Data.RangeSection rangeSection = _target.ProcessedData.GetOrAdd(fragment.RangeSection); + if (rangeSection.NextForDelete != TargetPointer.Null) + { + return new RangeSection(); + } + return new RangeSection(rangeSection); + } + return new RangeSection(); + } + + private ExMgrPtr /*PTR_RangeSectionFragment*/ GetRangeSectionForAddress(TargetCodePointer jittedCodeAddress) + { + /* The outer levels are all pointer arrays to the next level down. Level 1 is an array of pointers to a RangeSectionFragment */ + int topLevelIndex = EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, _targetCodeManagerDescriptor.MapLevels); + + ExMgrPtr top = new ExMgrPtr(_topRangeSectionMap.TopLevelData); + + ExMgrPtr nextLevelAddress = top.Offset(_target.PointerSize, topLevelIndex); + for (int level = _targetCodeManagerDescriptor.MapLevels - 1; level >= 1; level--) + { + ExMgrPtr rangeSectionL = nextLevelAddress.LoadPointer(_target); + if (rangeSectionL.IsNull) + return ExMgrPtr.Null; + nextLevelAddress = rangeSectionL.Offset(_target.PointerSize, EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, level)); + } + return nextLevelAddress; + } + + EECodeInfoHandle? IExecutionManager.GetEECodeInfoHandle(TargetCodePointer ip) + { + // TODO: some kind of cache based on ip, too? + // we don't know if the ip is the start of the code. + EECodeInfo? info = GetEECodeInfo(ip); + if (info == null || !info.Valid) + { + return null; + } + TargetPointer key = info.CodeHeaderAddress; + _codeInfos.TryAdd(key, info); + return new EECodeInfoHandle(key); + } + + TargetPointer IExecutionManager.GetMethodDesc(EECodeInfoHandle codeInfoHandle) + { + if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out EECodeInfo? info)) + { + throw new InvalidOperationException("EECodeInfo not found"); + } + return info.MethodDescAddress; + } + + TargetCodePointer IExecutionManager.GetStartAddress(EECodeInfoHandle codeInfoHandle) + { + if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out EECodeInfo? info)) + { + throw new InvalidOperationException("EECodeInfo not found"); + } + return info.StartAddress; + } + + bool IExecutionManager.IsReJITEnabled() + { + bool profEnabledReJIT = (_profControlBlock.GlobalEventMask & (ulong)Legacy.COR_PRF_MONITOR.COR_PRF_ENABLE_REJIT) != 0; + // FIXME: it is very likely this is always true in the DAC + // Most people don't set DOTNET_ProfAPI_RejitOnAttach = 0 + // See https://github.com/dotnet/runtime/issues/106148 + bool clrConfigEnabledReJIT = true; + return profEnabledReJIT || clrConfigEnabledReJIT; + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs index f4b97ac3f3164..e36efc7dbb801 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs @@ -10,23 +10,16 @@ internal interface INativeCodePointers : IContract static string IContract.Name { get; } = nameof(NativeCodePointers); static IContract IContract.Create(Target target, int version) { - TargetPointer executionManagerCodeRangeMapAddress = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress); - Data.RangeSectionMap rangeSectionMap = target.ProcessedData.GetOrAdd(executionManagerCodeRangeMapAddress); - TargetPointer profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock); - Data.ProfControlBlock profControlBlock = target.ProcessedData.GetOrAdd(profControlBlockAddress); return version switch { - 1 => new NativeCodePointers_1(target, rangeSectionMap, profControlBlock), + 1 => new NativeCodePointers_1(target), _ => default(NativeCodePointers), }; } - public virtual TargetPointer ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) => throw new NotImplementedException(); - public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException(); public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); - public virtual bool IsReJITEnabled() => throw new NotImplementedException(); public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs deleted file mode 100644 index 878600dac4f59..0000000000000 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.ExecutionManager.cs +++ /dev/null @@ -1,306 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; - -namespace Microsoft.Diagnostics.DataContractReader.Contracts; - -internal readonly partial struct NativeCodePointers_1 : INativeCodePointers -{ - internal class EECodeInfo - { - private readonly int _codeHeaderOffset; - public TargetCodePointer StartAddress { get; } - // note: this is the address of the pointer to the "real code header", you need to - // dereference it to get the address of _codeHeaderData - public TargetPointer CodeHeaderAddress => StartAddress.Value - (ulong)_codeHeaderOffset; - private Data.RealCodeHeader _codeHeaderData; - public TargetPointer JitManagerAddress { get; } - public TargetNUInt RelativeOffset { get; } - public EECodeInfo(TargetCodePointer startAddress, int codeHeaderOffset, TargetNUInt relativeOffset, Data.RealCodeHeader codeHeaderData, TargetPointer jitManagerAddress) - { - _codeHeaderOffset = codeHeaderOffset; - StartAddress = startAddress; - _codeHeaderData = codeHeaderData; - RelativeOffset = relativeOffset; - JitManagerAddress = jitManagerAddress; - } - - public TargetPointer MethodDescAddress => _codeHeaderData.MethodDesc; - public bool Valid => JitManagerAddress != TargetPointer.Null; - } - - // RangeFragment and RangeSection pointers have a collectible flag on the lowest bit - private struct ExMgrPtr - { - public readonly TargetPointer RawValue; - - public TargetPointer Address => RawValue & ~1ul; - - public bool IsNull => Address == TargetPointer.Null; - - public static ExMgrPtr Null => new ExMgrPtr(TargetPointer.Null); - - public ExMgrPtr(TargetPointer value) - { - RawValue = value; - } - - public ExMgrPtr Offset(int stride, int idx) - { - return new ExMgrPtr(RawValue.Value + (ulong)(stride * idx)); - } - - public T Load(Target target) where T : Data.IData - { - return target.ProcessedData.GetOrAdd(Address); - } - - public ExMgrPtr LoadPointer(Target target) - { - return new ExMgrPtr(target.ReadPointer(Address)); - } - } - - private readonly struct TargetCodeManagerDescriptor - { - public int MapLevels { get; } - public int BitsPerLevel { get; } = 8; - public int MaxSetBit { get; } - public int EntriesPerMapLevel { get; } = 256; - - private TargetCodeManagerDescriptor(int mapLevels, int maxSetBit) - { - MapLevels = mapLevels; - MaxSetBit = maxSetBit; - } - public static TargetCodeManagerDescriptor Create(Target target) - { - if (target.PointerSize == 4) - { - return new(mapLevels: 2, maxSetBit: 31); // 0 indexed - } - else if (target.PointerSize == 8) - { - return new(mapLevels: 5, maxSetBit: 56); // 0 indexed - } - else - { - throw new InvalidOperationException("Invalid pointer size"); - } - } - } - - - internal struct ExecutionManagerContract - { - internal readonly Target _target; - private readonly Data.ProfControlBlock _profControlBlock; - private readonly Data.RangeSectionMap _topRangeSectionMap; - private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; - - - internal enum JitManagerKind - { - EEJitManager = 0, - ReadyToRunJitManager = 1, - } - - public ExecutionManagerContract(Target target, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) - { - _target = target; - _topRangeSectionMap = topRangeSectionMap; - _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); - _profControlBlock = profControlBlock; - } - - [Flags] - private enum RangeSectionFlags : int - { - CodeHeap = 0x02, - RangeList = 0x04, - } - - private sealed class RangeSection - { - private readonly Data.RangeSection? _rangeSection; - - public RangeSection() - { - _rangeSection = default; - } - public RangeSection(Data.RangeSection rangeSection) - { - _rangeSection = rangeSection; - } - - private bool HasFlags(RangeSectionFlags mask) => (_rangeSection!.Flags & (int)mask) != 0; - private bool IsRangeList => HasFlags(RangeSectionFlags.RangeList); - private bool IsCodeHeap => HasFlags(RangeSectionFlags.CodeHeap); - - public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) - { - info = null; - if (_rangeSection == null) - { - return false; - } - TargetPointer jitManagerAddress = _rangeSection.JitManager; - TargetPointer r2rModule = _rangeSection.R2RModule; - JitManagerKind jitManagerKind = r2rModule == TargetPointer.Null ? JitManagerKind.EEJitManager : JitManagerKind.ReadyToRunJitManager; - switch (jitManagerKind) - { - case JitManagerKind.EEJitManager: - return EEJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); - case JitManagerKind.ReadyToRunJitManager: - return ReadyToRunJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); - default: - throw new InvalidOperationException($"Invalid JitManagerKind"); - } - } - - private bool EEJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) - { - info = null; - // EEJitManager::JitCodeToMethodInfo - if (IsRangeList) - { - return false; - } - TargetPointer start = EEFindMethodCode(target, jittedCodeAddress); - if (start == TargetPointer.Null) - { - return false; - } - Debug.Assert(start.Value <= jittedCodeAddress.Value); - TargetNUInt relativeOffset = new TargetNUInt(jittedCodeAddress.Value - start.Value); - int codeHeaderOffset = target.PointerSize; - TargetPointer codeHeaderIndirect = new TargetPointer(start - (ulong)codeHeaderOffset); - if (IsStubCodeBlock(target, codeHeaderIndirect)) - { - return false; - } - TargetPointer codeHeaderAddress = target.ReadPointer(codeHeaderIndirect); - Data.RealCodeHeader realCodeHeader = target.ProcessedData.GetOrAdd(codeHeaderAddress); - info = new EECodeInfo(jittedCodeAddress, codeHeaderOffset, relativeOffset, realCodeHeader, jitManagerAddress); - return true; - } - - private static bool IsStubCodeBlock(Target target, TargetPointer codeHeaderIndirect) - { - uint stubCodeBlockLast = target.ReadGlobal(Constants.Globals.StubCodeBlockLast); - return codeHeaderIndirect.Value <= stubCodeBlockLast; - } - - private TargetPointer EEFindMethodCode(Target target, TargetCodePointer jittedCodeAddress) - { - // EEJitManager::FindMethodCode - if (_rangeSection == null) - { - throw new InvalidOperationException(); - } - if (!IsCodeHeap) - { - throw new InvalidOperationException("RangeSection is not a code heap"); - } - TargetPointer heapListAddress = _rangeSection.HeapList; - Data.HeapList heapList = target.ProcessedData.GetOrAdd(heapListAddress); - if (jittedCodeAddress < heapList.StartAddress || jittedCodeAddress > heapList.EndAddress) - { - return TargetPointer.Null; - } - TargetPointer mapBase = heapList.MapBase; - TargetPointer mapStart = heapList.HeaderMap; - NibbleMap nibbleMap = NibbleMap.Create(target, (uint)target.PointerSize); - return nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); - - } - private bool ReadyToRunJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) - { - throw new NotImplementedException(); // TODO(cdac): ReadyToRunJitManager::JitCodeToMethodInfo - } - } - - - // note: level is 1-indexed - private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, TargetCodePointer address, int level) - { - ulong addressAsInt = address.Value; - ulong addressBitsUsedInMap = addressAsInt >> (descriptor.MaxSetBit + 1 - (descriptor.MapLevels * descriptor.BitsPerLevel)); - ulong addressBitsShifted = addressBitsUsedInMap >> ((level - 1) * descriptor.BitsPerLevel); - ulong addressBitsUsedInLevel = (ulong)(descriptor.EntriesPerMapLevel - 1) & addressBitsShifted; - return checked((int)addressBitsUsedInLevel); - } - - internal EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) - { - RangeSection range = LookupRangeSection(jittedCodeAddress); - range.JitCodeToMethodInfo(_target, jittedCodeAddress, out EECodeInfo? info); - return info; - } - - private static bool InRange(Data.RangeSectionFragment fragment, TargetCodePointer address) - { - return fragment.RangeBegin <= address && address < fragment.RangeEndOpen; - } - - private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) - { - ExMgrPtr rangeSectionFragmentPtr = GetRangeSectionForAddress(jittedCodeAddress); - if (rangeSectionFragmentPtr.IsNull) - { - return new RangeSection(); - } - while (!rangeSectionFragmentPtr.IsNull) - { - Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); - if (InRange(fragment, jittedCodeAddress)) - { - break; - } - rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); // TODO: load? - } - if (!rangeSectionFragmentPtr.IsNull) - { - Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); - Data.RangeSection rangeSection = _target.ProcessedData.GetOrAdd(fragment.RangeSection); - if (rangeSection.NextForDelete != TargetPointer.Null) - { - return new RangeSection(); - } - return new RangeSection(rangeSection); - } - return new RangeSection(); - } - - private ExMgrPtr /*PTR_RangeSectionFragment*/ GetRangeSectionForAddress(TargetCodePointer jittedCodeAddress) - { - /* The outer levels are all pointer arrays to the next level down. Level 1 is an array of pointers to a RangeSectionFragment */ - int topLevelIndex = EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, _targetCodeManagerDescriptor.MapLevels); - - ExMgrPtr top = new ExMgrPtr(_topRangeSectionMap.TopLevelData); - - ExMgrPtr nextLevelAddress = top.Offset(_target.PointerSize, topLevelIndex); - for (int level = _targetCodeManagerDescriptor.MapLevels - 1; level >= 1; level--) - { - ExMgrPtr rangeSectionL = nextLevelAddress.LoadPointer(_target); - if (rangeSectionL.IsNull) - return ExMgrPtr.Null; - nextLevelAddress = rangeSectionL.Offset(_target.PointerSize, EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, level)); - } - return nextLevelAddress; - } - - internal bool IsReJITEnabled() - { - bool profEnabledReJIT = (_profControlBlock.GlobalEventMask & (ulong)Legacy.COR_PRF_MONITOR.COR_PRF_ENABLE_REJIT) != 0; - // FIXME: it is very likely this is always true in the DAC - // Most people don't set DOTNET_ProfAPI_RejitOnAttach = 0 - // See https://github.com/dotnet/runtime/issues/106148 - bool clrConfigEnabledReJIT = true; - return profEnabledReJIT || clrConfigEnabledReJIT; - } - } -} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs index e78e6c38f92f1..aaac596ef41fc 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs @@ -8,38 +8,26 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly partial struct NativeCodePointers_1 : INativeCodePointers { private readonly Target _target; - private readonly ExecutionManagerContract _executionManagerContract; private readonly NativeCodeVersionContract _nativeCodeVersionContract; - public NativeCodePointers_1(Target target, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) + public NativeCodePointers_1(Target target) { _target = target; - _executionManagerContract = new ExecutionManagerContract(target, topRangeSectionMap, profControlBlock); _nativeCodeVersionContract = new NativeCodeVersionContract(target); } - - TargetPointer INativeCodePointers.ExecutionManagerGetCodeMethodDesc(TargetCodePointer jittedCodeAddress) - { - EECodeInfo? info = _executionManagerContract.GetEECodeInfo(jittedCodeAddress); - if (info == null || !info.Valid) - { - throw new InvalidOperationException($"Failed to get EECodeInfo for {jittedCodeAddress}"); - } - return info.MethodDescAddress; - } - NativeCodeVersionHandle INativeCodePointers.GetSpecificNativeCodeVersion(TargetCodePointer ip) { // ExecutionManager::GetNativeCodeVersion(PCODE ip)) // and EECodeInfo::GetNativeCodeVersion - EECodeInfo? info = _executionManagerContract.GetEECodeInfo(ip); - if (info == null || !info.Valid) + Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager; + EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip); + if (!info.HasValue) { return NativeCodeVersionHandle.Invalid; } - TargetPointer methodDescAddress = info.MethodDescAddress; + TargetPointer methodDescAddress = executionManager.GetMethodDesc(info.Value); if (methodDescAddress == TargetPointer.Null) { return NativeCodeVersionHandle.Invalid; @@ -52,7 +40,8 @@ NativeCodeVersionHandle INativeCodePointers.GetSpecificNativeCodeVersion(TargetC } else { - return _nativeCodeVersionContract.GetSpecificNativeCodeVersion(rts, md, info.StartAddress); + TargetCodePointer startAddress = executionManager.GetStartAddress(info.Value); + return _nativeCodeVersionContract.GetSpecificNativeCodeVersion(rts, md, startAddress); } } @@ -74,11 +63,6 @@ NativeCodeVersionHandle INativeCodePointers.GetActiveNativeCodeVersion(TargetPoi return _nativeCodeVersionContract.FindActiveNativeCodeVersion(methodDefActiveVersion, methodDesc); } - bool INativeCodePointers.IsReJITEnabled() - { - return _executionManagerContract.IsReJITEnabled(); - } - bool INativeCodePointers.CodeVersionManagerSupportsMethod(TargetPointer methodDescAddress) { IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; diff --git a/src/native/managed/cdacreader/src/Contracts/Registry.cs b/src/native/managed/cdacreader/src/Contracts/Registry.cs index 8b6ae31d4bcf8..411edcfcc2cff 100644 --- a/src/native/managed/cdacreader/src/Contracts/Registry.cs +++ b/src/native/managed/cdacreader/src/Contracts/Registry.cs @@ -27,6 +27,7 @@ public Registry(Target target) public IDacStreams DacStreams => GetContract(); public INativeCodePointers NativeCodePointers => GetContract(); public IPrecodeStubs PrecodeStubs => GetContract(); + public IExecutionManager ExecutionManager => GetContract(); private T GetContract() where T : IContract { diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 0f1bf35c46b4a..da391a3a31599 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -435,9 +435,13 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull if (HasNativeCode(methodDescPointer, umd) && !umd.IsFCall) { TargetCodePointer jitCodeAddr = GetCodePointer(methodDescPointer, umd); - //FIXME: this is the wrong code. - - TargetPointer methodDesc = _target.Contracts.NativeCodePointers.ExecutionManagerGetCodeMethodDesc(jitCodeAddr); + Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager; + EECodeInfoHandle? codeInfo = executionManager.GetEECodeInfoHandle(jitCodeAddr); + if (!codeInfo.HasValue) + { + return false; + } + TargetPointer methodDesc = executionManager.GetMethodDesc(codeInfo.Value); if (methodDesc == TargetPointer.Null) { return false; diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index e4c871160bdef..1612c19d7db9b 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -931,7 +931,7 @@ bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) if (md.IsEligibleForTieredCompilation) return true; // MethodDesc::IsEligibleForReJIT - if (_target.Contracts.NativeCodePointers.IsReJITEnabled()) + if (_target.Contracts.ExecutionManager.IsReJITEnabled()) { if (!md.IsIL) return false; From 50046b8bce24e90f5e8cfbac4d1a66daba411332 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 13:37:13 -0400 Subject: [PATCH 53/66] rename contract NativeCodePointers => CodeVersions --- src/coreclr/debug/runtimeinfo/contracts.jsonc | 2 +- ...{NativeCodePointers.cs => CodeVersions.cs} | 8 +- .../src/Contracts/CodeVersions_1.cs | 243 ++++++++++++++++++ .../NativeCodePointers_1.NativeCodeVersion.cs | 167 ------------ .../src/Contracts/NativeCodePointers_1.cs | 102 -------- .../cdacreader/src/Contracts/Registry.cs | 2 +- .../src/Contracts/RuntimeTypeSystem_1.cs | 2 +- .../cdacreader/src/Legacy/SOSDacImpl.cs | 2 +- 8 files changed, 251 insertions(+), 277 deletions(-) rename src/native/managed/cdacreader/src/Contracts/{NativeCodePointers.cs => CodeVersions.cs} (88%) create mode 100644 src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs delete mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs delete mode 100644 src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/debug/runtimeinfo/contracts.jsonc index 315d7039ea617..888a051556902 100644 --- a/src/coreclr/debug/runtimeinfo/contracts.jsonc +++ b/src/coreclr/debug/runtimeinfo/contracts.jsonc @@ -9,12 +9,12 @@ // cdac-build-tool can take multiple "-c contract_file" arguments // so to conditionally include contracts, put additional contracts in a separate file { + "CodeVersions": 1, "DacStreams": 1, "EcmaMetadata" : 1, "Exception": 1, "ExecutionManager": 1, "Loader": 1, - "NativeCodePointers": 1, "Object": 1, "PrecodeStubs": 1, "RuntimeTypeSystem": 1, diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs b/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs similarity index 88% rename from src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs rename to src/native/managed/cdacreader/src/Contracts/CodeVersions.cs index e36efc7dbb801..30b69021fadef 100644 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers.cs +++ b/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs @@ -5,15 +5,15 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; -internal interface INativeCodePointers : IContract +internal interface ICodeVersions : IContract { - static string IContract.Name { get; } = nameof(NativeCodePointers); + static string IContract.Name { get; } = nameof(CodeVersions); static IContract IContract.Create(Target target, int version) { return version switch { 1 => new NativeCodePointers_1(target), - _ => default(NativeCodePointers), + _ => default(CodeVersions), }; } @@ -46,7 +46,7 @@ internal NativeCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer } -internal readonly struct NativeCodePointers : INativeCodePointers +internal readonly struct CodeVersions : ICodeVersions { // throws NotImplementedException for all methods } diff --git a/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs b/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs new file mode 100644 index 0000000000000..d626777075e54 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs @@ -0,0 +1,243 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly partial struct NativeCodePointers_1 : ICodeVersions +{ + private readonly Target _target; + + + public NativeCodePointers_1(Target target) + { + _target = target; + } + + NativeCodeVersionHandle ICodeVersions.GetSpecificNativeCodeVersion(TargetCodePointer ip) + { + // ExecutionManager::GetNativeCodeVersion(PCODE ip)) + // and EECodeInfo::GetNativeCodeVersion + Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager; + EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip); + if (!info.HasValue) + { + return NativeCodeVersionHandle.Invalid; + } + TargetPointer methodDescAddress = executionManager.GetMethodDesc(info.Value); + if (methodDescAddress == TargetPointer.Null) + { + return NativeCodeVersionHandle.Invalid; + } + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); + if (!rts.IsVersionable(md)) + { + return new NativeCodeVersionHandle(methodDescAddress, codeVersionNodeAddress: TargetPointer.Null); + } + else + { + TargetCodePointer startAddress = executionManager.GetStartAddress(info.Value); + return GetSpecificNativeCodeVersion(rts, md, startAddress); + } + } + + NativeCodeVersionHandle ICodeVersions.GetActiveNativeCodeVersion(TargetPointer methodDesc) + { + // CodeVersionManager::GetActiveILCodeVersion + // then ILCodeVersion::GetActiveNativeCodeVersion + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); + TargetPointer mtAddr = rts.GetMethodTable(md); + TypeHandle typeHandle = rts.GetTypeHandle(mtAddr); + TargetPointer module = rts.GetModule(typeHandle); + uint methodDefToken = rts.GetMethodToken(md); + ILCodeVersionHandle methodDefActiveVersion = FindActiveILCodeVersion(module, methodDefToken); + if (!methodDefActiveVersion.IsValid) + { + return NativeCodeVersionHandle.Invalid; + } + return FindActiveNativeCodeVersion(methodDefActiveVersion, methodDesc); + } + bool ICodeVersions.CodeVersionManagerSupportsMethod(TargetPointer methodDescAddress) + { + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); + if (rts.IsDynamicMethod(md)) + return false; + if (rts.IsCollectibleMethod(md)) + return false; + TargetPointer mtAddr = rts.GetMethodTable(md); + TypeHandle mt = rts.GetTypeHandle(mtAddr); + TargetPointer modAddr = rts.GetModule(mt); + ILoader loader = _target.Contracts.Loader; + ModuleHandle mod = loader.GetModuleHandle(modAddr); + ModuleFlags modFlags = loader.GetFlags(mod); + if (modFlags.HasFlag(ModuleFlags.EditAndContinue)) + return false; + return true; + } + + TargetCodePointer ICodeVersions.GetNativeCode(NativeCodeVersionHandle codeVersionHandle) + { + if (codeVersionHandle.MethodDescAddress != TargetPointer.Null) + { + MethodDescHandle md = _target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(codeVersionHandle.MethodDescAddress); + return _target.Contracts.RuntimeTypeSystem.GetNativeCode(md); + } + else if (codeVersionHandle.CodeVersionNodeAddress != TargetPointer.Null) + { + throw new NotImplementedException(); // TODO[cdac]: get native code from NativeCodeVersionNode + } + else + { + throw new ArgumentException("Invalid NativeCodeVersionHandle"); + } + } + + internal struct ILCodeVersionHandle + { + internal readonly TargetPointer Module; + internal uint MethodDefinition; + internal readonly TargetPointer ILCodeVersionNode; + internal readonly uint RejitId; + + internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress) + { + Module = module; + MethodDefinition = methodDef; + ILCodeVersionNode = ilCodeVersionNodeAddress; + if (Module != TargetPointer.Null && ILCodeVersionNode != TargetPointer.Null) + { + throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null"); + + } + if (Module != TargetPointer.Null && MethodDefinition == 0) + { + throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null"); + } + } + public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null); + public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; + } + + [Flags] + internal enum MethodDescVersioningStateFlags : byte + { + IsDefaultVersionActiveChildFlag = 0x4 + }; + + + private NativeCodeVersionHandle GetSpecificNativeCodeVersion(IRuntimeTypeSystem rts, MethodDescHandle md, TargetCodePointer startAddress) + { + TargetPointer methodDescVersioningStateAddress = rts.GetMethodDescVersioningState(md); + if (methodDescVersioningStateAddress == TargetPointer.Null) + { + return NativeCodeVersionHandle.Invalid; + } + Data.MethodDescVersioningState methodDescVersioningStateData = _target.ProcessedData.GetOrAdd(methodDescVersioningStateAddress); + // CodeVersionManager::GetNativeCodeVersion(PTR_MethodDesc, PCODE startAddress) + return FindFirstCodeVersion(methodDescVersioningStateData, (codeVersion) => + { + return codeVersion.MethodDesc == md.Address && codeVersion.NativeCode == startAddress; + }); + } + + private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningState versioningState, Func predicate) + { + // NativeCodeVersion::Next, heavily inlined + TargetPointer currentAddress = versioningState.NativeCodeVersionNode; + while (currentAddress != TargetPointer.Null) + { + Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd(currentAddress); + if (predicate(current)) + { + return new NativeCodeVersionHandle(methodDescAddress: TargetPointer.Null, currentAddress); + } + currentAddress = current.Next; + } + return NativeCodeVersionHandle.Invalid; + } + + + private enum ILCodeVersionKind + { + Unknown = 0, + Explicit = 1, // means Node is set + Synthetic = 2, // means Module and Token are set + } + private static ILCodeVersionHandle ILCodeVersionHandleFromState(Data.ILCodeVersioningState ilState) + { + switch ((ILCodeVersionKind)ilState.ActiveVersionKind) + { + case ILCodeVersionKind.Explicit: + return new ILCodeVersionHandle(module: TargetPointer.Null, methodDef: 0, ilState.ActiveVersionNode); + case ILCodeVersionKind.Synthetic: + case ILCodeVersionKind.Unknown: + return new ILCodeVersionHandle(ilState.ActiveVersionModule, ilState.ActiveVersionMethodDef, TargetPointer.Null); + default: + throw new InvalidOperationException($"Unknown ILCodeVersionKind {ilState.ActiveVersionKind}"); + } + } + + private ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint methodDefinition) + { + ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); + TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; + TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefinition, out var _); + if (ilVersionStateAddress == TargetPointer.Null) + { + return new ILCodeVersionHandle(module, methodDefinition, TargetPointer.Null); + } + Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd(ilVersionStateAddress); + return ILCodeVersionHandleFromState(ilState); + } + + private bool IsActiveNativeCodeVersion(NativeCodeVersionHandle nativeCodeVersion) + { + if (nativeCodeVersion.MethodDescAddress != TargetPointer.Null) + { + MethodDescHandle md = _target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(nativeCodeVersion.MethodDescAddress); + TargetPointer versioningStateAddress = _target.Contracts.RuntimeTypeSystem.GetMethodDescVersioningState(md); + if (versioningStateAddress == TargetPointer.Null) + { + return true; + } + Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd(versioningStateAddress); + return (((MethodDescVersioningStateFlags)versioningState.Flags) & MethodDescVersioningStateFlags.IsDefaultVersionActiveChildFlag) != 0; + } + else if (nativeCodeVersion.CodeVersionNodeAddress != TargetPointer.Null) + { + // NativeCodeVersionNode::IsActiveChildVersion + // Data.NativeCodeVersionNode codeVersion = _target.ProcessedData.GetOrAdd(nativeCodeVersion.CodeVersionNodeAddress); + // return codeVersion has flag IsActive + throw new NotImplementedException(); // TODO[cdac]: IsActiveNativeCodeVersion - explicit + } + else + { + throw new ArgumentException("Invalid NativeCodeVersionHandle"); + } + } + + private NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion, TargetPointer methodDescAddress) + { + if (methodDefActiveVersion.Module != TargetPointer.Null) + { + NativeCodeVersionHandle provisionalHandle = new NativeCodeVersionHandle(methodDescAddress: methodDescAddress, codeVersionNodeAddress: TargetPointer.Null); + if (IsActiveNativeCodeVersion(provisionalHandle)) + { + return provisionalHandle; + } + else + { + throw new NotImplementedException(); // TODO[cdac]: iterate through versioning state nodes + } + } + else + { + throw new NotImplementedException(); // TODO: [cdac] find explicit il code version + } + } + +} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs deleted file mode 100644 index 94d58bcb4cf8b..0000000000000 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.NativeCodeVersion.cs +++ /dev/null @@ -1,167 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Data; - -namespace Microsoft.Diagnostics.DataContractReader.Contracts; - - -internal readonly partial struct NativeCodePointers_1 : INativeCodePointers -{ - - internal struct ILCodeVersionHandle - { - internal readonly TargetPointer Module; - internal uint MethodDefinition; - internal readonly TargetPointer ILCodeVersionNode; - internal readonly uint RejitId; - - internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress) - { - Module = module; - MethodDefinition = methodDef; - ILCodeVersionNode = ilCodeVersionNodeAddress; - if (Module != TargetPointer.Null && ILCodeVersionNode != TargetPointer.Null) - { - throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null"); - - } - if (Module != TargetPointer.Null && MethodDefinition == 0) - { - throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null"); - } - } - public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null); - public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; - } - - [Flags] - internal enum MethodDescVersioningStateFlags : byte - { - IsDefaultVersionActiveChildFlag = 0x4 - }; - - - internal struct NativeCodeVersionContract - { - private readonly Target _target; - - public NativeCodeVersionContract(Target target) - { - _target = target; - } - - public NativeCodeVersionHandle GetSpecificNativeCodeVersion(IRuntimeTypeSystem rts, MethodDescHandle md, TargetCodePointer startAddress) - { - TargetPointer methodDescVersioningStateAddress = rts.GetMethodDescVersioningState(md); - if (methodDescVersioningStateAddress == TargetPointer.Null) - { - return NativeCodeVersionHandle.Invalid; - } - Data.MethodDescVersioningState methodDescVersioningStateData = _target.ProcessedData.GetOrAdd(methodDescVersioningStateAddress); - // CodeVersionManager::GetNativeCodeVersion(PTR_MethodDesc, PCODE startAddress) - return FindFirstCodeVersion(methodDescVersioningStateData, (codeVersion) => - { - return codeVersion.MethodDesc == md.Address && codeVersion.NativeCode == startAddress; - }); - } - - private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningState versioningState, Func predicate) - { - // NativeCodeVersion::Next, heavily inlined - TargetPointer currentAddress = versioningState.NativeCodeVersionNode; - while (currentAddress != TargetPointer.Null) - { - Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd(currentAddress); - if (predicate(current)) - { - return new NativeCodeVersionHandle(methodDescAddress: TargetPointer.Null, currentAddress); - } - currentAddress = current.Next; - } - return NativeCodeVersionHandle.Invalid; - } - - - private enum ILCodeVersionKind - { - Unknown = 0, - Explicit = 1, // means Node is set - Synthetic = 2, // means Module and Token are set - } - private static ILCodeVersionHandle ILCodeVersionHandleFromState(Data.ILCodeVersioningState ilState) - { - switch ((ILCodeVersionKind)ilState.ActiveVersionKind) - { - case ILCodeVersionKind.Explicit: - return new ILCodeVersionHandle(module: TargetPointer.Null, methodDef: 0, ilState.ActiveVersionNode); - case ILCodeVersionKind.Synthetic: - case ILCodeVersionKind.Unknown: - return new ILCodeVersionHandle(ilState.ActiveVersionModule, ilState.ActiveVersionMethodDef, TargetPointer.Null); - default: - throw new InvalidOperationException($"Unknown ILCodeVersionKind {ilState.ActiveVersionKind}"); - } - } - - public ILCodeVersionHandle FindActiveILCodeVersion(TargetPointer module, uint methodDefinition) - { - ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); - TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; - TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefinition, out var _); - if (ilVersionStateAddress == TargetPointer.Null) - { - return new ILCodeVersionHandle(module, methodDefinition, TargetPointer.Null); - } - Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd(ilVersionStateAddress); - return ILCodeVersionHandleFromState(ilState); - } - - private bool IsActiveNativeCodeVersion(NativeCodeVersionHandle nativeCodeVersion) - { - if (nativeCodeVersion.MethodDescAddress != TargetPointer.Null) - { - MethodDescHandle md = _target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(nativeCodeVersion.MethodDescAddress); - TargetPointer versioningStateAddress = _target.Contracts.RuntimeTypeSystem.GetMethodDescVersioningState(md); - if (versioningStateAddress == TargetPointer.Null) - { - return true; - } - Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd(versioningStateAddress); - return (((MethodDescVersioningStateFlags)versioningState.Flags) & MethodDescVersioningStateFlags.IsDefaultVersionActiveChildFlag) != 0; - } - else if (nativeCodeVersion.CodeVersionNodeAddress != TargetPointer.Null) - { - // NativeCodeVersionNode::IsActiveChildVersion - // Data.NativeCodeVersionNode codeVersion = _target.ProcessedData.GetOrAdd(nativeCodeVersion.CodeVersionNodeAddress); - // return codeVersion has flag IsActive - throw new NotImplementedException(); // TODO[cdac]: IsActiveNativeCodeVersion - explicit - } - else - { - throw new ArgumentException("Invalid NativeCodeVersionHandle"); - } - } - - public NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion, TargetPointer methodDescAddress) - { - if (methodDefActiveVersion.Module != TargetPointer.Null) - { - NativeCodeVersionHandle provisionalHandle = new NativeCodeVersionHandle(methodDescAddress: methodDescAddress, codeVersionNodeAddress: TargetPointer.Null); - if (IsActiveNativeCodeVersion(provisionalHandle)) - { - return provisionalHandle; - } - else - { - throw new NotImplementedException(); // TODO[cdac]: iterate through versioning state nodes - } - } - else - { - throw new NotImplementedException(); // TODO: [cdac] find explicit il code version - } - } - - } -} diff --git a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs b/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs deleted file mode 100644 index aaac596ef41fc..0000000000000 --- a/src/native/managed/cdacreader/src/Contracts/NativeCodePointers_1.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace Microsoft.Diagnostics.DataContractReader.Contracts; - -internal readonly partial struct NativeCodePointers_1 : INativeCodePointers -{ - private readonly Target _target; - private readonly NativeCodeVersionContract _nativeCodeVersionContract; - - - public NativeCodePointers_1(Target target) - { - _target = target; - _nativeCodeVersionContract = new NativeCodeVersionContract(target); - } - - NativeCodeVersionHandle INativeCodePointers.GetSpecificNativeCodeVersion(TargetCodePointer ip) - { - // ExecutionManager::GetNativeCodeVersion(PCODE ip)) - // and EECodeInfo::GetNativeCodeVersion - Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager; - EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip); - if (!info.HasValue) - { - return NativeCodeVersionHandle.Invalid; - } - TargetPointer methodDescAddress = executionManager.GetMethodDesc(info.Value); - if (methodDescAddress == TargetPointer.Null) - { - return NativeCodeVersionHandle.Invalid; - } - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); - if (!rts.IsVersionable(md)) - { - return new NativeCodeVersionHandle(methodDescAddress, codeVersionNodeAddress: TargetPointer.Null); - } - else - { - TargetCodePointer startAddress = executionManager.GetStartAddress(info.Value); - return _nativeCodeVersionContract.GetSpecificNativeCodeVersion(rts, md, startAddress); - } - } - - NativeCodeVersionHandle INativeCodePointers.GetActiveNativeCodeVersion(TargetPointer methodDesc) - { - // CodeVersionManager::GetActiveILCodeVersion - // then ILCodeVersion::GetActiveNativeCodeVersion - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); - TargetPointer mtAddr = rts.GetMethodTable(md); - TypeHandle typeHandle = rts.GetTypeHandle(mtAddr); - TargetPointer module = rts.GetModule(typeHandle); - uint methodDefToken = rts.GetMethodToken(md); - ILCodeVersionHandle methodDefActiveVersion = _nativeCodeVersionContract.FindActiveILCodeVersion(module, methodDefToken); - if (!methodDefActiveVersion.IsValid) - { - return NativeCodeVersionHandle.Invalid; - } - return _nativeCodeVersionContract.FindActiveNativeCodeVersion(methodDefActiveVersion, methodDesc); - } - - bool INativeCodePointers.CodeVersionManagerSupportsMethod(TargetPointer methodDescAddress) - { - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); - if (rts.IsDynamicMethod(md)) - return false; - if (rts.IsCollectibleMethod(md)) - return false; - TargetPointer mtAddr = rts.GetMethodTable(md); - TypeHandle mt = rts.GetTypeHandle(mtAddr); - TargetPointer modAddr = rts.GetModule(mt); - ILoader loader = _target.Contracts.Loader; - ModuleHandle mod = loader.GetModuleHandle(modAddr); - ModuleFlags modFlags = loader.GetFlags(mod); - if (modFlags.HasFlag(ModuleFlags.EditAndContinue)) - return false; - return true; - } - - TargetCodePointer INativeCodePointers.GetNativeCode(NativeCodeVersionHandle codeVersionHandle) - { - if (codeVersionHandle.MethodDescAddress != TargetPointer.Null) - { - MethodDescHandle md = _target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(codeVersionHandle.MethodDescAddress); - return _target.Contracts.RuntimeTypeSystem.GetNativeCode(md); - } - else if (codeVersionHandle.CodeVersionNodeAddress != TargetPointer.Null) - { - throw new NotImplementedException(); // TODO[cdac]: get native code from NativeCodeVersionNode - } - else - { - throw new ArgumentException("Invalid NativeCodeVersionHandle"); - } - } - -} diff --git a/src/native/managed/cdacreader/src/Contracts/Registry.cs b/src/native/managed/cdacreader/src/Contracts/Registry.cs index 411edcfcc2cff..452110f852c84 100644 --- a/src/native/managed/cdacreader/src/Contracts/Registry.cs +++ b/src/native/managed/cdacreader/src/Contracts/Registry.cs @@ -25,7 +25,7 @@ public Registry(Target target) public IThread Thread => GetContract(); public IRuntimeTypeSystem RuntimeTypeSystem => GetContract(); public IDacStreams DacStreams => GetContract(); - public INativeCodePointers NativeCodePointers => GetContract(); + public ICodeVersions CodeVersions => GetContract(); public IPrecodeStubs PrecodeStubs => GetContract(); public IExecutionManager ExecutionManager => GetContract(); diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index 1612c19d7db9b..a53df5f468d23 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -937,7 +937,7 @@ bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) return false; if (IsWrapperStub(md)) return false; - return _target.Contracts.NativeCodePointers.CodeVersionManagerSupportsMethod(methodDesc.Address); + return _target.Contracts.CodeVersions.CodeVersionManagerSupportsMethod(methodDesc.Address); } return false; } diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index 857321e8d7d2f..07d80f46a0a07 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -109,7 +109,7 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa { Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; Contracts.MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(methodDesc); - Contracts.INativeCodePointers nativeCodeContract = _target.Contracts.NativeCodePointers; + Contracts.ICodeVersions nativeCodeContract = _target.Contracts.CodeVersions; if (rgRevertedRejitData != null) { From e2d637b0e97022e0c81a5827a7c13f686741e19b Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 15 Aug 2024 13:57:47 -0400 Subject: [PATCH 54/66] ReJIT contract --- src/coreclr/debug/runtimeinfo/contracts.jsonc | 1 + .../src/Contracts/ExecutionManager.cs | 2 -- .../src/Contracts/ExecutionManager_1.cs | 10 ------- .../managed/cdacreader/src/Contracts/ReJIT.cs | 29 +++++++++++++++++++ .../cdacreader/src/Contracts/ReJIT_1.cs | 28 ++++++++++++++++++ .../cdacreader/src/Contracts/Registry.cs | 1 + .../src/Contracts/RuntimeTypeSystem_1.cs | 2 +- 7 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Contracts/ReJIT.cs create mode 100644 src/native/managed/cdacreader/src/Contracts/ReJIT_1.cs diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/debug/runtimeinfo/contracts.jsonc index 888a051556902..3483a6a5b733a 100644 --- a/src/coreclr/debug/runtimeinfo/contracts.jsonc +++ b/src/coreclr/debug/runtimeinfo/contracts.jsonc @@ -17,6 +17,7 @@ "Loader": 1, "Object": 1, "PrecodeStubs": 1, + "ReJIT": 1, "RuntimeTypeSystem": 1, "Thread": 1 } diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs index 0c3e955718b79..75e1beffd155d 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs @@ -31,8 +31,6 @@ static IContract IContract.Create(Target target, int version) TargetPointer GetMethodDesc(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException(); TargetCodePointer GetStartAddress(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException(); - // TODO[cdac]: this should be on a ReJIT contract - bool IsReJITEnabled() => throw new NotImplementedException(); } internal readonly struct ExecutionManager : IExecutionManager diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs index 41c3f61a08f85..6aa21fd1542ae 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs @@ -326,14 +326,4 @@ TargetCodePointer IExecutionManager.GetStartAddress(EECodeInfoHandle codeInfoHan } return info.StartAddress; } - - bool IExecutionManager.IsReJITEnabled() - { - bool profEnabledReJIT = (_profControlBlock.GlobalEventMask & (ulong)Legacy.COR_PRF_MONITOR.COR_PRF_ENABLE_REJIT) != 0; - // FIXME: it is very likely this is always true in the DAC - // Most people don't set DOTNET_ProfAPI_RejitOnAttach = 0 - // See https://github.com/dotnet/runtime/issues/106148 - bool clrConfigEnabledReJIT = true; - return profEnabledReJIT || clrConfigEnabledReJIT; - } } diff --git a/src/native/managed/cdacreader/src/Contracts/ReJIT.cs b/src/native/managed/cdacreader/src/Contracts/ReJIT.cs new file mode 100644 index 0000000000000..00c174e6a18f9 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/ReJIT.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + + +internal interface IReJIT : IContract +{ + static string IContract.Name { get; } = nameof(ReJIT); + static IContract IContract.Create(Target target, int version) + { + TargetPointer profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock); + Data.ProfControlBlock profControlBlock = target.ProcessedData.GetOrAdd(profControlBlockAddress); + return version switch + { + 1 => new ReJIT_1(target, profControlBlock), + _ => default(ExecutionManager), + }; + } + + bool IsEnabled() => throw new NotImplementedException(); +} + +internal readonly struct ReJIT : IExecutionManager +{ + +} diff --git a/src/native/managed/cdacreader/src/Contracts/ReJIT_1.cs b/src/native/managed/cdacreader/src/Contracts/ReJIT_1.cs new file mode 100644 index 0000000000000..c75aa4a2affcb --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/ReJIT_1.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly partial struct ReJIT_1 : IReJIT +{ + internal readonly Target _target; + private readonly Data.ProfControlBlock _profControlBlock; + + public ReJIT_1(Target target, Data.ProfControlBlock profControlBlock) + { + _target = target; + _profControlBlock = profControlBlock; + } + + bool IReJIT.IsEnabled() + { + bool profEnabledReJIT = (_profControlBlock.GlobalEventMask & (ulong)Legacy.COR_PRF_MONITOR.COR_PRF_ENABLE_REJIT) != 0; + // FIXME: it is very likely this is always true in the DAC + // Most people don't set DOTNET_ProfAPI_RejitOnAttach = 0 + // See https://github.com/dotnet/runtime/issues/106148 + bool clrConfigEnabledReJIT = true; + return profEnabledReJIT || clrConfigEnabledReJIT; + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/Registry.cs b/src/native/managed/cdacreader/src/Contracts/Registry.cs index 452110f852c84..9b3f6aa9a6715 100644 --- a/src/native/managed/cdacreader/src/Contracts/Registry.cs +++ b/src/native/managed/cdacreader/src/Contracts/Registry.cs @@ -28,6 +28,7 @@ public Registry(Target target) public ICodeVersions CodeVersions => GetContract(); public IPrecodeStubs PrecodeStubs => GetContract(); public IExecutionManager ExecutionManager => GetContract(); + public IReJIT ReJIT => GetContract(); private T GetContract() where T : IContract { diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index a53df5f468d23..aa62d51541233 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -931,7 +931,7 @@ bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) if (md.IsEligibleForTieredCompilation) return true; // MethodDesc::IsEligibleForReJIT - if (_target.Contracts.ExecutionManager.IsReJITEnabled()) + if (_target.Contracts.ReJIT.IsEnabled()) { if (!md.IsIL) return false; From 7724fa8fc7259bd3144ad07fae43d28bf3beb6f2 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 16 Aug 2024 11:32:54 -0400 Subject: [PATCH 55/66] formatting, comments and whitespace --- src/coreclr/debug/runtimeinfo/.editorconfig | 2 ++ src/native/managed/cdacreader/src/Contracts/CodeVersions.cs | 2 +- src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs | 4 ++-- .../managed/cdacreader/src/Contracts/ExecutionManager_1.cs | 2 +- .../managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs | 1 - 5 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 src/coreclr/debug/runtimeinfo/.editorconfig diff --git a/src/coreclr/debug/runtimeinfo/.editorconfig b/src/coreclr/debug/runtimeinfo/.editorconfig new file mode 100644 index 0000000000000..ce2ce7b8d1ec5 --- /dev/null +++ b/src/coreclr/debug/runtimeinfo/.editorconfig @@ -0,0 +1,2 @@ +[contracts.jsonc] +indent_size = 2 diff --git a/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs b/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs index 30b69021fadef..e6eea4cd7cd45 100644 --- a/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs +++ b/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs @@ -12,7 +12,7 @@ static IContract IContract.Create(Target target, int version) { return version switch { - 1 => new NativeCodePointers_1(target), + 1 => new CodeVersions_1(target), _ => default(CodeVersions), }; } diff --git a/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs b/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs index d626777075e54..aacd982e58b7c 100644 --- a/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs @@ -5,12 +5,12 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; -internal readonly partial struct NativeCodePointers_1 : ICodeVersions +internal readonly partial struct CodeVersions_1 : ICodeVersions { private readonly Target _target; - public NativeCodePointers_1(Target target) + public CodeVersions_1(Target target) { _target = target; } diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs index 6aa21fd1542ae..ea16027336a07 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs @@ -262,7 +262,7 @@ private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) { break; } - rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); // TODO: load? + rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); } if (!rangeSectionFragmentPtr.IsNull) { diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index aa62d51541233..d5b0a966a6990 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -845,7 +845,6 @@ public bool IsILStub(MethodDescHandle methodDescHandle) return AsDynamicMethodDesc(methodDesc).IsILStub; } - // FIXME: move to RuntimeT private TargetPointer GetAddressOfSlot(TypeHandle typeHandle, uint slotNum) { if (!typeHandle.IsMethodTable()) From a53b3aefc8c07e2a2eafb4b77cb32eeb299e29f7 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 16 Aug 2024 11:49:09 -0400 Subject: [PATCH 56/66] cleanup --- src/native/managed/cdacreader/src/Constants.cs | 10 ++++++++++ .../cdacreader/src/Contracts/ExecutionManager.cs | 4 +--- .../cdacreader/src/Contracts/ExecutionManager_1.cs | 9 ++++----- .../managed/cdacreader/src/Contracts/Loader_1.cs | 4 ++-- .../cdacreader/src/Contracts/RuntimeTypeSystem_1.cs | 5 +++-- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs index 4b9a218d0276e..3ca4c46326f3d 100644 --- a/src/native/managed/cdacreader/src/Constants.cs +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -45,4 +45,14 @@ internal static class Globals internal const string StubCodeBlockLast = nameof(StubCodeBlockLast); internal const string ProfilerControlBlock = nameof(ProfilerControlBlock); } + + internal static class EcmaMetadata + { + internal const int RowIdBitCount = 24; + internal const uint RIDMask = (1 << RowIdBitCount) - 1; + + internal static uint GetRowId(uint token) => token & RIDMask; + + internal static uint MakeToken(uint rid, uint table) => rid | (table << RowIdBitCount); + } } diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs index 75e1beffd155d..131b7bf992acf 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager.cs @@ -18,11 +18,9 @@ static IContract IContract.Create(Target target, int version) { TargetPointer executionManagerCodeRangeMapAddress = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress); Data.RangeSectionMap rangeSectionMap = target.ProcessedData.GetOrAdd(executionManagerCodeRangeMapAddress); - TargetPointer profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock); - Data.ProfControlBlock profControlBlock = target.ProcessedData.GetOrAdd(profControlBlockAddress); return version switch { - 1 => new ExecutionManager_1(target, rangeSectionMap, profControlBlock), + 1 => new ExecutionManager_1(target, rangeSectionMap), _ => default(ExecutionManager), }; } diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs index ea16027336a07..37821c0162072 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs @@ -10,10 +10,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly partial struct ExecutionManager_1 : IExecutionManager { - internal class EECodeInfo + private class EECodeInfo { private readonly int _codeHeaderOffset; - // maps EECodeInfoHandle.Address (which is the CodeHeaderAddress) to the EECodeInfo public TargetCodePointer StartAddress { get; } // note: this is the address of the pointer to the "real code header", you need to @@ -98,8 +97,9 @@ public static TargetCodeManagerDescriptor Create(Target target) internal readonly Target _target; + // maps EECodeInfoHandle.Address (which is the CodeHeaderAddress) to the EECodeInfo + private readonly Dictionary _codeInfos = new(); - private readonly Data.ProfControlBlock _profControlBlock; private readonly Data.RangeSectionMap _topRangeSectionMap; private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; @@ -110,12 +110,11 @@ internal enum JitManagerKind ReadyToRunJitManager = 1, } - public ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionMap, Data.ProfControlBlock profControlBlock) + public ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionMap) { _target = target; _topRangeSectionMap = topRangeSectionMap; _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); - _profControlBlock = profControlBlock; } [Flags] diff --git a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs index 96f62a83cb181..b94ab88413ff7 100644 --- a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs @@ -92,9 +92,9 @@ ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle) module.MethodDefToILCodeVersioningStateMap); } - TargetPointer ILoader.GetModuleLookupMapElement(TargetPointer table, uint rid, out TargetNUInt flags) + TargetPointer ILoader.GetModuleLookupMapElement(TargetPointer table, uint token, out TargetNUInt flags) { - rid &= 0x00FFFFFF; // FIXME: do we have a util that does this? + uint rid = Constants.EcmaMetadata.GetRowId(token); ArgumentOutOfRangeException.ThrowIfZero(rid); flags = new TargetNUInt(0); if (table == TargetPointer.Null) diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs index d5b0a966a6990..560a95d0c42c1 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Text; using System.Reflection; +using System.Reflection.Metadata; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -156,8 +157,8 @@ internal MethodDesc(Target target, TargetPointer methodDescPointer, Data.MethodD private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.MethodDescChunk chunk) { int tokenRemainderBitCount = target.ReadGlobal(Constants.Globals.MethodDescTokenRemainderBitCount); - int tokenRangeBitCount = 24 - tokenRemainderBitCount; - uint allRidBitsSet = 0xFFFFFF; + int tokenRangeBitCount = Constants.EcmaMetadata.RowIdBitCount - tokenRemainderBitCount; + uint allRidBitsSet = Constants.EcmaMetadata.RIDMask; uint tokenRemainderMask = allRidBitsSet >> tokenRangeBitCount; uint tokenRangeMask = allRidBitsSet >> tokenRemainderBitCount; From 124ee6ab8895e68d059b619beac314007b29b2a9 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 16 Aug 2024 11:53:47 -0400 Subject: [PATCH 57/66] "NDirect" -> "PInvoke" in descriptor and contracts --- src/coreclr/debug/runtimeinfo/datadescriptor.h | 4 ++-- src/coreclr/vm/precode.cpp | 8 ++++---- src/coreclr/vm/precode.h | 4 ++-- .../cdacreader/src/Contracts/PrecodeStubs_1.cs | 14 +++++++------- .../src/Data/PrecodeMachineDescriptor.cs | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 6c8dfdbc85696..a4be9b825744c 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -368,8 +368,8 @@ CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, ShiftOfPrecodeType, offseto CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, OffsetOfPrecodeType, offsetof(PrecodeMachineDescriptor, OffsetOfPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, InvalidPrecodeType, offsetof(PrecodeMachineDescriptor, InvalidPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, StubPrecodeType, offsetof(PrecodeMachineDescriptor, StubPrecodeType)) -CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, HasNDirectImportPrecode, offsetof(PrecodeMachineDescriptor, HasNDirectImportPrecode)) -CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, NDirectImportPrecodeType, offsetof(PrecodeMachineDescriptor, NDirectImportPrecodeType)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, HasPInvokeImportPrecode, offsetof(PrecodeMachineDescriptor, HasPInvokeImportPrecode)) +CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, PInvokeImportPrecodeType, offsetof(PrecodeMachineDescriptor, PInvokeImportPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, HasFixupPrecode, offsetof(PrecodeMachineDescriptor, HasFixupPrecode)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint8*/, FixupPrecodeType, offsetof(PrecodeMachineDescriptor, FixupPrecodeType)) CDAC_TYPE_FIELD(PrecodeMachineDescriptor, /*uint32*/, StubCodePageSize, offsetof(PrecodeMachineDescriptor, StubCodePageSize)) diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index 51d7d6953e064..d8c69a03cb9f7 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -688,11 +688,11 @@ void PrecodeMachineDescriptor::Init() g_PrecodeMachineDescriptor.InvalidPrecodeType = InvalidPrecode::Type; g_PrecodeMachineDescriptor.StubPrecodeType = StubPrecode::Type; #ifdef HAS_NDIRECT_IMPORT_PRECODE - g_PrecodeMachineDescriptor.HasNDirectImportPrecode = 1; - g_PrecodeMachineDescriptor.NDirectImportPrecodeType = NDirectImportPrecode::Type; + g_PrecodeMachineDescriptor.HasPInvokeImportPrecode = 1; + g_PrecodeMachineDescriptor.PInvokeImportPrecodeType = NDirectImportPrecode::Type; #else - g_PrecodeMachineDescriptor.HasNDirectImportPrecode = 0; - g_PrecodeMachineDescriptor.NDirectImportPrecodeType = 0; + g_PrecodeMachineDescriptor.HasPInvokeImportPrecode = 0; + g_PrecodeMachineDescriptor.PInvokeImportPrecodeType = 0; #endif // HAS_NDIRECT_IMPORT_PRECODE #ifdef HAS_FIXUP_PRECODE g_PrecodeMachineDescriptor.HasFixupPrecode = 1; diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 662cb687630ca..b1f7ff9e118b6 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -612,8 +612,8 @@ struct PrecodeMachineDescriptor uint8_t InvalidPrecodeType; uint8_t StubPrecodeType; - uint8_t HasNDirectImportPrecode; - uint8_t NDirectImportPrecodeType; + uint8_t HasPInvokeImportPrecode; + uint8_t PInvokeImportPrecodeType; uint8_t HasFixupPrecode; uint8_t FixupPrecodeType; diff --git a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs index ad16f07b7face..e30011d899ac4 100644 --- a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs @@ -13,7 +13,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal enum KnownPrecodeType { Stub = 1, - NDirectImport, + PInvokeImport, // also known as NDirectImport in the runtime Fixup, ThisPtrRetBuf, } @@ -45,9 +45,9 @@ internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachine } } - internal sealed class NDirectImportPrecode : StubPrecode + internal sealed class PInvokeImportPrecode : StubPrecode { - internal NDirectImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.NDirectImport) { } + internal PInvokeImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.PInvokeImport) { } } internal sealed class FixupPrecode : ValidPrecode @@ -113,9 +113,9 @@ private Data.StubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) { return KnownPrecodeType.Stub; } - else if (MachineDescriptor.NDirectImportPrecodeType is byte ndType && precodeType == ndType) + else if (MachineDescriptor.PInvokeImportPrecodeType is byte ndType && precodeType == ndType) { - return KnownPrecodeType.NDirectImport; + return KnownPrecodeType.PInvokeImport; } else if (MachineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) { @@ -147,8 +147,8 @@ internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint) return new StubPrecode(instrPointer); case KnownPrecodeType.Fixup: return new FixupPrecode(instrPointer); - case KnownPrecodeType.NDirectImport: - return new NDirectImportPrecode(instrPointer); + case KnownPrecodeType.PInvokeImport: + return new PInvokeImportPrecode(instrPointer); case KnownPrecodeType.ThisPtrRetBuf: return new ThisPtrRetBufPrecode(instrPointer); default: diff --git a/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs index e61080d5f3fbf..6861e21e8ac31 100644 --- a/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs +++ b/src/native/managed/cdacreader/src/Data/PrecodeMachineDescriptor.cs @@ -17,9 +17,9 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) ShiftOfPrecodeType = target.Read(address + (ulong)type.Fields[nameof(ShiftOfPrecodeType)].Offset); InvalidPrecodeType = target.Read(address + (ulong)type.Fields[nameof(InvalidPrecodeType)].Offset); StubPrecodeType = target.Read(address + (ulong)type.Fields[nameof(StubPrecodeType)].Offset); - if (target.Read(address + (ulong)type.Fields[nameof(HasNDirectImportPrecode)].Offset) == 1) + if (target.Read(address + (ulong)type.Fields[nameof(HasPInvokeImportPrecode)].Offset) == 1) { - NDirectImportPrecodeType = target.Read(address + (ulong)type.Fields[nameof(NDirectImportPrecodeType)].Offset); + PInvokeImportPrecodeType = target.Read(address + (ulong)type.Fields[nameof(PInvokeImportPrecodeType)].Offset); } if (target.Read(address + (ulong)type.Fields[nameof(HasFixupPrecode)].Offset) == 1) { @@ -34,10 +34,10 @@ public PrecodeMachineDescriptor(Target target, TargetPointer address) public byte ShiftOfPrecodeType { get; init; } public byte InvalidPrecodeType { get; init; } public byte StubPrecodeType { get; init; } - public byte? NDirectImportPrecodeType { get; init; } + public byte? PInvokeImportPrecodeType { get; init; } public byte? FixupPrecodeType { get; init; } public uint StubCodePageSize { get; init; } - private const string HasNDirectImportPrecode = nameof(HasNDirectImportPrecode); + private const string HasPInvokeImportPrecode = nameof(HasPInvokeImportPrecode); private const string HasFixupPrecode = nameof(HasFixupPrecode); } From fb1676b907484c147b4e051bcb234ff08f77b523 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 16 Aug 2024 13:29:46 -0400 Subject: [PATCH 58/66] WIP: contract writeups --- docs/design/datacontracts/CodeVersions.md | 149 ++++++++++++++++++++++ docs/design/datacontracts/ReJIT.md | 37 ++++++ 2 files changed, 186 insertions(+) create mode 100644 docs/design/datacontracts/CodeVersions.md create mode 100644 docs/design/datacontracts/ReJIT.md diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md new file mode 100644 index 0000000000000..3e96713428afc --- /dev/null +++ b/docs/design/datacontracts/CodeVersions.md @@ -0,0 +1,149 @@ +# Contract CodeVersions + +This contract encapsulates support for [code versioning](../features/code-versioning.md) in the runtime. + +## APIs of contract + +```csharp +internal struct NativeCodeVersionHandle +{ + // no public constructors + internal readonly TargetPointer MethodDescAddress; + internal readonly TargetPointer CodeVersionNodeAddress; + internal NativeCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer codeVersionNodeAddress) + { + if (methodDescAddress != TargetPointer.Null && codeVersionNodeAddress != TargetPointer.Null) + { + throw new ArgumentException("Only one of methodDescAddress and codeVersionNodeAddress can be non-null"); + } + MethodDescAddress = methodDescAddress; + CodeVersionNodeAddress = codeVersionNodeAddress; + } + + internal static NativeCodeVersionHandle Invalid => new(TargetPointer.Null, TargetPointer.Null); + public bool Valid => MethodDescAddress != TargetPointer.Null || CodeVersionNodeAddress != TargetPointer.Null; +} +``` + +```csharp + // Return a handle to the version of the native code that includes the given instruction pointer + public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException(); + // Return a handle to the active version of the native code for a given method descriptor + public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); + + // returns true if the given method descriptor supports multiple code versions + public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); + + // Return the instruction pointer corresponding to the start of the given native code version + public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); +``` + +## Version 1 + +Data descriptors used: +| Data Descriptor Name | Field | Meaning | +| --- | --- | --- | +| MethodDescVersioningState | ? | ? | +| NativeCodeVersionNode | ? | ? | +| ILCodeVersioningState | ? | ? | + + +Global variables used: +| Global Name | Type | Purpose | +| --- | --- | --- | + +Contracts used: +| Contract Name | +| --- | +| ExecutionManager | +| Loader | +| RuntimeTypeSystem | + +### Finding the start of a specific native code version + +```csharp + NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) + { + Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager; + EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip); + if (!info.HasValue) + { + return NativeCodeVersionHandle.Invalid; + } + TargetPointer methodDescAddress = executionManager.GetMethodDesc(info.Value); + if (methodDescAddress == TargetPointer.Null) + { + return NativeCodeVersionHandle.Invalid; + } + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); + if (!rts.IsVersionable(md)) + { + return new NativeCodeVersionHandle(methodDescAddress, codeVersionNodeAddress: TargetPointer.Null); + } + else + { + TargetCodePointer startAddress = executionManager.GetStartAddress(info.Value); + return GetSpecificNativeCodeVersion(md, startAddress); + } + } + + private NativeCodeVersionHandle GetSpecificNativeCodeVersion(MethodDescHandle md, TargetCodePointer startAddress) + { + TargetPointer methodDescVersioningStateAddress = target.Contracts.RuntimeTypeSystem.GetMethodDescVersioningState(md); + if (methodDescVersioningStateAddress == TargetPointer.Null) + { + return NativeCodeVersionHandle.Invalid; + } + Data.MethodDescVersioningState methodDescVersioningStateData = _target.ProcessedData.GetOrAdd(methodDescVersioningStateAddress); + // CodeVersionManager::GetNativeCodeVersion(PTR_MethodDesc, PCODE startAddress) + return FindFirstCodeVersion(methodDescVersioningStateData, (codeVersion) => + { + return codeVersion.MethodDesc == md.Address && codeVersion.NativeCode == startAddress; + }); + } + + private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningState versioningState, Func predicate) + { + // NativeCodeVersion::Next, heavily inlined + TargetPointer currentAddress = versioningState.NativeCodeVersionNode; + while (currentAddress != TargetPointer.Null) + { + Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd(currentAddress); + if (predicate(current)) + { + return new NativeCodeVersionHandle(methodDescAddress: TargetPointer.Null, currentAddress); + } + currentAddress = current.Next; + } + return NativeCodeVersionHandle.Invalid; + } +``` + +### Finding the active native code version of a method descriptor + +```csharp + NativeCodeVersionHandle ICodeVersions.GetActiveNativeCodeVersion(TargetPointer methodDesc) + { + // CodeVersionManager::GetActiveILCodeVersion + // then ILCodeVersion::GetActiveNativeCodeVersion + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); + TargetPointer mtAddr = rts.GetMethodTable(md); + TypeHandle typeHandle = rts.GetTypeHandle(mtAddr); + TargetPointer module = rts.GetModule(typeHandle); + uint methodDefToken = rts.GetMethodToken(md); + ILCodeVersionHandle methodDefActiveVersion = FindActiveILCodeVersion(module, methodDefToken); + if (!methodDefActiveVersion.IsValid) + { + return NativeCodeVersionHandle.Invalid; + } + return FindActiveNativeCodeVersion(methodDefActiveVersion, methodDesc); + } +``` + +**FIXME** + +### Determining whether a method descriptor supports code versioning + +**TODO** diff --git a/docs/design/datacontracts/ReJIT.md b/docs/design/datacontracts/ReJIT.md new file mode 100644 index 0000000000000..dd93a2e2e5ab1 --- /dev/null +++ b/docs/design/datacontracts/ReJIT.md @@ -0,0 +1,37 @@ +# Contract ReJIT + +This contract encapsulates support for [ReJIT](../features/code-versioning.md) in the runtime. + +## APIs of contract + +```csharp +bool IsEnabled(); +``` + +## Version 1 + +Data descriptors used: +| Data Descriptor Name | Field | Meaning | +| --- | --- | --- | +| ProfControlBlock | GlobalEventMask | an `ICorProfiler` `COR_PRF_MONITOR` value | + +Global variables used: +| Global Name | Type | Purpose | +| --- | --- | --- | +|ProfilerControlBlock | TargetPointer | pointer to the `ProfControlBlock` | + +Contracts used: +| Contract Name | +| --- | + +```csharp +bool IsEnabled() +{ + TargetPointer address = target.ReadGlobalPointer("ProfilerControlBlock"); + ulong globalEventMask = target.Read(address + /* ProfControlBlock::GlobalEventMask offset*/); + bool profEnabledReJIT = (GlobalEventMask & (ulong)COR_PRF_MONITOR.COR_PRF_ENABLE_REJIT) != 0; + bool clrConfigEnabledReJit = /* host process does not have environment variable DOTNET_ProfAPI_ReJitOnAttach set to 0 */; + // See https://github.com/dotnet/runtime/issues/106148 + return profEnabledReJIT || clrConfigEnabledReJIT; +} +``` From f1d757e5ac84646b9a3b8507558e66e88c4fae4c Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 16 Aug 2024 14:35:35 -0400 Subject: [PATCH 59/66] fix build --- .../managed/cdacreader/src/Contracts/ExecutionManager_1.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs index 37821c0162072..60ce5c36f2c0e 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs @@ -235,7 +235,7 @@ private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, return checked((int)addressBitsUsedInLevel); } - internal EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) + private EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) { RangeSection range = LookupRangeSection(jittedCodeAddress); range.JitCodeToMethodInfo(_target, jittedCodeAddress, out EECodeInfo? info); From f1d7be8aefb17bcf4fd2af33641571cf2c70bba3 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 16 Aug 2024 15:05:15 -0400 Subject: [PATCH 60/66] placeholder ExecutionManager contract --- docs/design/datacontracts/ExecutionManager.md | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/design/datacontracts/ExecutionManager.md diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md new file mode 100644 index 0000000000000..ec5faa399273f --- /dev/null +++ b/docs/design/datacontracts/ExecutionManager.md @@ -0,0 +1,55 @@ +# Contract ExecutionManager + +This contract + + +## APIs of contract + +```csharp +internal struct EECodeInfoHandle +{ + // no public constructor + public readonly TargetPointer Address; + internal EECodeInfoHandle(TargetPointer address) => Address = address; +} +``` + +```csharp + // Collect execution engine info for a code block that includes the given instruction pointer. + // Return a handle for the information, or null if an owning code block cannot be found. + EECodeInfoHandle? GetEECodeInfoHandle(TargetCodePointer ip); + // Get the method descriptor corresponding to the given code block + TargetPointer GetMethodDesc(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException(); + // Get the instruction pointer address of the start of the code block + TargetCodePointer GetStartAddress(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException(); +``` + +## Version 1 + +Data descriptors used: +| Data Descriptor Name | Field | Meaning | +| --- | --- | --- | +| RangeSectionMap | TopLevelData | pointer to the outermost RangeSection | +| RangeSectionFragment| ? | ? | +| RangeSection | ? | ? | +| RealCodeHeader | ? | ? | +| HeapList | ? | ? | + + + +Global variables used: +| Global Name | Type | Purpose | +| --- | --- | --- | +| ExecutionManagerCodeRangeMapAddress | TargetPointer | Pointer to the global RangeSectionMap +| StubCodeBlockLast | uint8 | Maximum sentinel code header value indentifying a stub code block + +Contracts used: +| Contract Name | +| --- | + +```csharp +``` + +### NibbleMap + +**TODO** From ebb4a67845559f4663dcff8f730dfa2cf0a9e647 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 16 Aug 2024 15:47:20 -0400 Subject: [PATCH 61/66] placeholder ExecutionManager contract; updates to RTS and Loader --- docs/design/datacontracts/ExecutionManager.md | 2 + docs/design/datacontracts/Loader.md | 9 ++++ .../design/datacontracts/RuntimeTypeSystem.md | 41 +++++++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index ec5faa399273f..276dfa6cb11ae 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -50,6 +50,8 @@ Contracts used: ```csharp ``` +**TODO** Methods + ### NibbleMap **TODO** diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index d0fe390b5ad39..be9a563bb1f56 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -38,6 +38,9 @@ TargetPointer GetLoaderAllocator(ModuleHandle handle); TargetPointer GetThunkHeap(ModuleHandle handle); TargetPointer GetILBase(ModuleHandle handle); ModuleLookupTables GetLookupTables(ModuleHandle handle); +TargetPointer GetModuleLookupMapElement(TargetPointer table, uint rid, out TargetNUInt flags); +bool IsCollectibleLoaderAllocator(ModuleHandle handle); + ``` ## Version 1 @@ -58,6 +61,10 @@ Data descriptors used: | `Module` | `TypeDefToMethodTableMap` | Mapping table | | `Module` | `TypeRefToMethodTableMap` | Mapping table | | `ModuleLookupMap` | `TableData` | Start of the mapping table's data | +| `ModuleLookupMap` | `SupportedFlagsMask` | Mask for flag bits on lookup map entries | +| `ModuleLookupMap` | `Count` | Number of TargetPointer sized entries in this section of the map | +| `ModuleLookupMap` | `Next` | Pointer to next ModuleLookupMap segment for this map +| `LoaderAllocator` | `IsCollectible` | Flag indicating if this is loader allocator may be collected ``` csharp ModuleHandle GetModuleHandle(TargetPointer modulePointer) @@ -110,3 +117,5 @@ ModuleLookupTables GetLookupTables(ModuleHandle handle) Module::MethodDefToILCodeVersioningState */)); } ``` + +**TODO* pseudocode for IsCollectibleLoaderAllocator and LookupTableMap element lookup diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 3e6fefa079073..d7098c141c02e 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -137,6 +137,31 @@ partial interface IRuntimeTypeSystem : IContract // Return true if a MethodDesc represents an IL Stub dynamically generated by the runtime // A IL Stub method is also a StoredSigMethodDesc, and a NoMetadataMethod public virtual bool IsILStub(MethodDescHandle methodDesc); + + // Return true if a MethodDesc is in a collectible module + public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc); + + // Return true if a MethodDesc is in a module that supports Edit-And-Continue + public virtual bool InEnCEnabledModule(MethodDescHandle methodDesc); + + // Return true if a MethodDesc supports mulitiple code versions + public virtual bool IsVersionable(MethodDescHandle methodDesc); + + // Return a pointer to the IL versioning state of the MethodDesc + public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc); + + // Return the MethodTable slot number of the MethodDesc + public virtual ushort GetSlotNumber(MethodDescHandle methodDesc); + + // Return true if the MethodDesc has space associated with it for storing a pointer to a code block + public virtual bool HasNativeCodeSlot(MethodDescHandle methodDesc); + + // Return the address of the space that stores a pointer to a code block associated with the MethodDesc + public virtual TargetPointer GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc); + + // Get an instruction pointer that can be called to cause the MethodDesc to be executed + public virtual TargetCodePointer GetNativeCode(MethodDescHandle methodDesc); + } ``` @@ -605,6 +630,7 @@ The version 1 `MethodDesc` APIs depend on the `MethodDescAlignment` global and t | `MethodDescAlignment` | `MethodDescChunk` trailing data is allocated in multiples of this constant. The size (in bytes) of each `MethodDesc` (or subclass) instance is a multiple of this constant. | | `MethodDescTokenRemainderBitCount` | Number of bits in the token remainder in `MethodDesc` | +**TODO** MethodDesc code pointers additions In the runtime a `MethodDesc` implicitly belongs to a single `MethodDescChunk` and some common data is shared between method descriptors that belong to the same chunk. A single method table will typically have multiple chunks. There are subkinds of MethodDescs at runtime of varying sizes (but the sizes must be mutliples of `MethodDescAlignment`) and each chunk contains method descriptors of the same size. @@ -629,6 +655,15 @@ We depend on the following data descriptors: | `StoredSigMethodDesc` | `ExtendedFlags` | Flags field for the `StoredSigMethodDesc` | | `DynamicMethodDesc` | `MethodName` | Pointer to Null-terminated UTF8 string describing the Method desc | +**TODO** MethodDesc code pointers additions + +The contract depends on the following other contracts + +| Contract | +| --- | +| Loader | +| ReJIT | +| CodeVersions | And the following enumeration definitions @@ -708,9 +743,9 @@ And the various apis are implemented with the following algorithms public uint GetMethodToken(MethodDescHandle methodDescHandle) { MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; - + TargetPointer methodDescChunk = // Using ChunkIndex from methodDesc, compute the wrapping MethodDescChunk - + ushort Flags3AndTokenRemainder = // Read Flags3AndTokenRemainder field from MethodDesc contract using address methodDescHandle.Address ushort FlagsAndTokenRange = // Read FlagsAndTokenRange field from MethodDescChunk contract using address methodDescChunk @@ -819,4 +854,4 @@ And the various apis are implemented with the following algorithms return ((DynamicMethodDescExtendedFlags)ExtendedFlags).HasFlag(DynamicMethodDescExtendedFlags.IsILStub); } ``` -**TODO(cdac)** +**TODO(cdac)** additional code pointers methods on MethodDesc From aac3faf0a3fe5014aa01185455caaa1b0147a2e8 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 19 Aug 2024 11:15:03 -0400 Subject: [PATCH 62/66] refactor ExecutionManager --- .../ExecutionManager_1.EEJitManager.cs | 71 +++++ .../Contracts/ExecutionManager_1.NibbleMap.cs | 3 +- .../src/Contracts/ExecutionManager_1.cs | 276 ++++++++---------- .../src/Data/RangeSectionFragment.cs | 3 + 4 files changed, 194 insertions(+), 159 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.EEJitManager.cs diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.EEJitManager.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.EEJitManager.cs new file mode 100644 index 0000000000000..8969d150f6589 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.EEJitManager.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly partial struct ExecutionManager_1 : IExecutionManager +{ + private class EEJitManager : JitManager + { + private readonly NibbleMap _nibbleMap; + public EEJitManager(Target target, NibbleMap nibbleMap) : base(target) + { + _nibbleMap = nibbleMap; + } + + public override bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) + { + info = null; + // EEJitManager::JitCodeToMethodInfo + if (rangeSection.IsRangeList) + { + return false; + } + TargetPointer start = FindMethodCode(rangeSection, jittedCodeAddress); + if (start == TargetPointer.Null) + { + return false; + } + Debug.Assert(start.Value <= jittedCodeAddress.Value); + TargetNUInt relativeOffset = new TargetNUInt(jittedCodeAddress.Value - start.Value); + int codeHeaderOffset = Target.PointerSize; + TargetPointer codeHeaderIndirect = new TargetPointer(start - (ulong)codeHeaderOffset); + if (RangeSection.IsStubCodeBlock(Target, codeHeaderIndirect)) + { + return false; + } + TargetPointer codeHeaderAddress = Target.ReadPointer(codeHeaderIndirect); + Data.RealCodeHeader realCodeHeader = Target.ProcessedData.GetOrAdd(codeHeaderAddress); + info = new EECodeInfo(jittedCodeAddress, codeHeaderOffset, relativeOffset, realCodeHeader, rangeSection.Data!.JitManager); + return true; + } + + private TargetPointer FindMethodCode(RangeSection rangeSection, TargetCodePointer jittedCodeAddress) + { + // EEJitManager::FindMethodCode + if (rangeSection.Data == null) + { + throw new InvalidOperationException(); + } + if (!rangeSection.IsCodeHeap) + { + throw new InvalidOperationException("RangeSection is not a code heap"); + } + TargetPointer heapListAddress = rangeSection.Data.HeapList; + Data.HeapList heapList = Target.ProcessedData.GetOrAdd(heapListAddress); + if (jittedCodeAddress < heapList.StartAddress || jittedCodeAddress > heapList.EndAddress) + { + return TargetPointer.Null; + } + TargetPointer mapBase = heapList.MapBase; + TargetPointer mapStart = heapList.HeaderMap; + return _nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); + } + + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.NibbleMap.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.NibbleMap.cs index b486b7c2523cf..77e0e6d660994 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.NibbleMap.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.NibbleMap.cs @@ -28,8 +28,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal sealed class NibbleMap { - public static NibbleMap Create(Target target, uint codeHeaderSize) + public static NibbleMap Create(Target target) { + uint codeHeaderSize = (uint)target.PointerSize; return new NibbleMap(target, codeHeaderSize); } diff --git a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs index 60ce5c36f2c0e..8cdd844fce83e 100644 --- a/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/ExecutionManager_1.cs @@ -3,13 +3,31 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly partial struct ExecutionManager_1 : IExecutionManager { + internal readonly Target _target; + + // maps EECodeInfoHandle.Address (which is the CodeHeaderAddress) to the EECodeInfo + private readonly Dictionary _codeInfos = new(); + private readonly Data.RangeSectionMap _topRangeSectionMap; + private readonly RangeSectionLookupAlgorithm _rangeSectionLookupAlgorithm; + private readonly EEJitManager _eeJitManager; + private readonly ReadyToRunJitManager _r2rJitManager; + + public ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionMap) + { + _target = target; + _topRangeSectionMap = topRangeSectionMap; + _rangeSectionLookupAlgorithm = RangeSectionLookupAlgorithm.Create(target); + NibbleMap nibbleMap = NibbleMap.Create(target); + _eeJitManager = new EEJitManager(target, nibbleMap); + _r2rJitManager = new ReadyToRunJitManager(target); + } + private class EECodeInfo { private readonly int _codeHeaderOffset; @@ -34,7 +52,8 @@ public EECodeInfo(TargetCodePointer startAddress, int codeHeaderOffset, TargetNU public bool Valid => JitManagerAddress != TargetPointer.Null; } - // RangeFragment and RangeSection pointers have a collectible flag on the lowest bit + // "ExecutionManagerPointer": a pointer to a RangeFragment and RangeSection. + // The pointers have a collectible flag on the lowest bit private struct ExMgrPtr { public readonly TargetPointer RawValue; @@ -66,19 +85,19 @@ public ExMgrPtr LoadPointer(Target target) } } - private readonly struct TargetCodeManagerDescriptor + private readonly struct RangeSectionLookupAlgorithm { - public int MapLevels { get; } - public int BitsPerLevel { get; } = 8; - public int MaxSetBit { get; } - public int EntriesPerMapLevel { get; } = 256; + private int MapLevels { get; } + private int BitsPerLevel { get; } = 8; + private int MaxSetBit { get; } + private int EntriesPerMapLevel { get; } = 256; - private TargetCodeManagerDescriptor(int mapLevels, int maxSetBit) + private RangeSectionLookupAlgorithm(int mapLevels, int maxSetBit) { MapLevels = mapLevels; MaxSetBit = maxSetBit; } - public static TargetCodeManagerDescriptor Create(Target target) + public static RangeSectionLookupAlgorithm Create(Target target) { if (target.PointerSize == 4) { @@ -93,28 +112,34 @@ public static TargetCodeManagerDescriptor Create(Target target) throw new InvalidOperationException("Invalid pointer size"); } } - } - - - internal readonly Target _target; - // maps EECodeInfoHandle.Address (which is the CodeHeaderAddress) to the EECodeInfo - private readonly Dictionary _codeInfos = new(); - private readonly Data.RangeSectionMap _topRangeSectionMap; - private readonly TargetCodeManagerDescriptor _targetCodeManagerDescriptor; + // note: level is 1-indexed + private int EffectiveBitsForLevel(TargetCodePointer address, int level) + { + ulong addressAsInt = address.Value; + ulong addressBitsUsedInMap = addressAsInt >> (MaxSetBit + 1 - (MapLevels * BitsPerLevel)); + ulong addressBitsShifted = addressBitsUsedInMap >> ((level - 1) * BitsPerLevel); + ulong addressBitsUsedInLevel = (ulong)(EntriesPerMapLevel - 1) & addressBitsShifted; + return checked((int)addressBitsUsedInLevel); + } + internal ExMgrPtr /*PTR_RangeSectionFragment*/ FindFragment(Target target, Data.RangeSectionMap topRangeSectionMap, TargetCodePointer jittedCodeAddress) + { + /* The outer levels are all pointer arrays to the next level down. Level 1 is an array of pointers to a RangeSectionFragment */ + int topLevelIndex = EffectiveBitsForLevel(jittedCodeAddress, MapLevels); - internal enum JitManagerKind - { - EEJitManager = 0, - ReadyToRunJitManager = 1, - } + ExMgrPtr top = new ExMgrPtr(topRangeSectionMap.TopLevelData); - public ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionMap) - { - _target = target; - _topRangeSectionMap = topRangeSectionMap; - _targetCodeManagerDescriptor = TargetCodeManagerDescriptor.Create(target); + ExMgrPtr nextLevelAddress = top.Offset(target.PointerSize, topLevelIndex); + for (int level = MapLevels - 1; level >= 1; level--) + { + ExMgrPtr rangeSectionL = nextLevelAddress.LoadPointer(target); + if (rangeSectionL.IsNull) + return ExMgrPtr.Null; + nextLevelAddress = rangeSectionL.Offset(target.PointerSize, EffectiveBitsForLevel(jittedCodeAddress, level)); + } + return nextLevelAddress; + } } [Flags] @@ -123,177 +148,112 @@ private enum RangeSectionFlags : int CodeHeap = 0x02, RangeList = 0x04, } - - private sealed class RangeSection + private abstract class JitManager { - private readonly Data.RangeSection? _rangeSection; + public Target Target { get; } - public RangeSection() + protected JitManager(Target target) { - _rangeSection = default; + Target = target; } - public RangeSection(Data.RangeSection rangeSection) + + public abstract bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info); + + } + + private class ReadyToRunJitManager : JitManager + { + public ReadyToRunJitManager(Target target) : base(target) { - _rangeSection = rangeSection; } + public override bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) + { + throw new NotImplementedException(); // TODO(cdac): ReadyToRunJitManager::JitCodeToMethodInfo + } + } - private bool HasFlags(RangeSectionFlags mask) => (_rangeSection!.Flags & (int)mask) != 0; - private bool IsRangeList => HasFlags(RangeSectionFlags.RangeList); - private bool IsCodeHeap => HasFlags(RangeSectionFlags.CodeHeap); + private sealed class RangeSection + { + public readonly Data.RangeSection? Data; - public bool JitCodeToMethodInfo(Target target, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) + public RangeSection() { - info = null; - if (_rangeSection == null) - { - return false; - } - TargetPointer jitManagerAddress = _rangeSection.JitManager; - TargetPointer r2rModule = _rangeSection.R2RModule; - JitManagerKind jitManagerKind = r2rModule == TargetPointer.Null ? JitManagerKind.EEJitManager : JitManagerKind.ReadyToRunJitManager; - switch (jitManagerKind) - { - case JitManagerKind.EEJitManager: - return EEJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); - case JitManagerKind.ReadyToRunJitManager: - return ReadyToRunJitCodeToMethodInfo(target, jitManagerAddress, jittedCodeAddress, out info); - default: - throw new InvalidOperationException($"Invalid JitManagerKind"); - } + Data = default; } - - private bool EEJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) + public RangeSection(Data.RangeSection rangeSection) { - info = null; - // EEJitManager::JitCodeToMethodInfo - if (IsRangeList) - { - return false; - } - TargetPointer start = EEFindMethodCode(target, jittedCodeAddress); - if (start == TargetPointer.Null) - { - return false; - } - Debug.Assert(start.Value <= jittedCodeAddress.Value); - TargetNUInt relativeOffset = new TargetNUInt(jittedCodeAddress.Value - start.Value); - int codeHeaderOffset = target.PointerSize; - TargetPointer codeHeaderIndirect = new TargetPointer(start - (ulong)codeHeaderOffset); - if (IsStubCodeBlock(target, codeHeaderIndirect)) - { - return false; - } - TargetPointer codeHeaderAddress = target.ReadPointer(codeHeaderIndirect); - Data.RealCodeHeader realCodeHeader = target.ProcessedData.GetOrAdd(codeHeaderAddress); - info = new EECodeInfo(jittedCodeAddress, codeHeaderOffset, relativeOffset, realCodeHeader, jitManagerAddress); - return true; + Data = rangeSection; } - private static bool IsStubCodeBlock(Target target, TargetPointer codeHeaderIndirect) + private bool HasFlags(RangeSectionFlags mask) => (Data!.Flags & (int)mask) != 0; + internal bool IsRangeList => HasFlags(RangeSectionFlags.RangeList); + internal bool IsCodeHeap => HasFlags(RangeSectionFlags.CodeHeap); + + internal static bool IsStubCodeBlock(Target target, TargetPointer codeHeaderIndirect) { uint stubCodeBlockLast = target.ReadGlobal(Constants.Globals.StubCodeBlockLast); return codeHeaderIndirect.Value <= stubCodeBlockLast; } - private TargetPointer EEFindMethodCode(Target target, TargetCodePointer jittedCodeAddress) + internal static RangeSection Find(Target target, Data.RangeSectionMap topRangeSectionMap, RangeSectionLookupAlgorithm rangeSectionLookup, TargetCodePointer jittedCodeAddress) { - // EEJitManager::FindMethodCode - if (_rangeSection == null) + ExMgrPtr rangeSectionFragmentPtr = rangeSectionLookup.FindFragment(target, topRangeSectionMap, jittedCodeAddress); + if (rangeSectionFragmentPtr.IsNull) { - throw new InvalidOperationException(); + return new RangeSection(); } - if (!IsCodeHeap) + while (!rangeSectionFragmentPtr.IsNull) { - throw new InvalidOperationException("RangeSection is not a code heap"); + Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(target); + if (fragment.Contains(jittedCodeAddress)) + { + break; + } + rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); } - TargetPointer heapListAddress = _rangeSection.HeapList; - Data.HeapList heapList = target.ProcessedData.GetOrAdd(heapListAddress); - if (jittedCodeAddress < heapList.StartAddress || jittedCodeAddress > heapList.EndAddress) + if (!rangeSectionFragmentPtr.IsNull) { - return TargetPointer.Null; + Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(target); + Data.RangeSection rangeSection = target.ProcessedData.GetOrAdd(fragment.RangeSection); + if (rangeSection.NextForDelete != TargetPointer.Null) + { + return new RangeSection(); + } + return new RangeSection(rangeSection); } - TargetPointer mapBase = heapList.MapBase; - TargetPointer mapStart = heapList.HeaderMap; - NibbleMap nibbleMap = NibbleMap.Create(target, (uint)target.PointerSize); - return nibbleMap.FindMethodCode(mapBase, mapStart, jittedCodeAddress); - - } - private bool ReadyToRunJitCodeToMethodInfo(Target target, TargetPointer jitManagerAddress, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out EECodeInfo? info) - { - throw new NotImplementedException(); // TODO(cdac): ReadyToRunJitManager::JitCodeToMethodInfo + return new RangeSection(); } } - - // note: level is 1-indexed - private static int EffectiveBitsForLevel(TargetCodeManagerDescriptor descriptor, TargetCodePointer address, int level) + private JitManager GetJitManager(Data.RangeSection rangeSectionData) { - ulong addressAsInt = address.Value; - ulong addressBitsUsedInMap = addressAsInt >> (descriptor.MaxSetBit + 1 - (descriptor.MapLevels * descriptor.BitsPerLevel)); - ulong addressBitsShifted = addressBitsUsedInMap >> ((level - 1) * descriptor.BitsPerLevel); - ulong addressBitsUsedInLevel = (ulong)(descriptor.EntriesPerMapLevel - 1) & addressBitsShifted; - return checked((int)addressBitsUsedInLevel); + if (rangeSectionData.R2RModule == TargetPointer.Null) + { + return _eeJitManager; + } + else + { + return _r2rJitManager; + } } private EECodeInfo? GetEECodeInfo(TargetCodePointer jittedCodeAddress) { - RangeSection range = LookupRangeSection(jittedCodeAddress); - range.JitCodeToMethodInfo(_target, jittedCodeAddress, out EECodeInfo? info); - return info; - } - - private static bool InRange(Data.RangeSectionFragment fragment, TargetCodePointer address) - { - return fragment.RangeBegin <= address && address < fragment.RangeEndOpen; - } - - private RangeSection LookupRangeSection(TargetCodePointer jittedCodeAddress) - { - ExMgrPtr rangeSectionFragmentPtr = GetRangeSectionForAddress(jittedCodeAddress); - if (rangeSectionFragmentPtr.IsNull) - { - return new RangeSection(); - } - while (!rangeSectionFragmentPtr.IsNull) + RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionLookupAlgorithm, jittedCodeAddress); + if (range.Data == null) { - Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); - if (InRange(fragment, jittedCodeAddress)) - { - break; - } - rangeSectionFragmentPtr = new ExMgrPtr(fragment.Next); + return null; } - if (!rangeSectionFragmentPtr.IsNull) + JitManager jitManager = GetJitManager(range.Data); + if (jitManager.GetMethodInfo(range, jittedCodeAddress, out EECodeInfo? info)) { - Data.RangeSectionFragment fragment = rangeSectionFragmentPtr.Load(_target); - Data.RangeSection rangeSection = _target.ProcessedData.GetOrAdd(fragment.RangeSection); - if (rangeSection.NextForDelete != TargetPointer.Null) - { - return new RangeSection(); - } - return new RangeSection(rangeSection); + return info; } - return new RangeSection(); - } - - private ExMgrPtr /*PTR_RangeSectionFragment*/ GetRangeSectionForAddress(TargetCodePointer jittedCodeAddress) - { - /* The outer levels are all pointer arrays to the next level down. Level 1 is an array of pointers to a RangeSectionFragment */ - int topLevelIndex = EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, _targetCodeManagerDescriptor.MapLevels); - - ExMgrPtr top = new ExMgrPtr(_topRangeSectionMap.TopLevelData); - - ExMgrPtr nextLevelAddress = top.Offset(_target.PointerSize, topLevelIndex); - for (int level = _targetCodeManagerDescriptor.MapLevels - 1; level >= 1; level--) + else { - ExMgrPtr rangeSectionL = nextLevelAddress.LoadPointer(_target); - if (rangeSectionL.IsNull) - return ExMgrPtr.Null; - nextLevelAddress = rangeSectionL.Offset(_target.PointerSize, EffectiveBitsForLevel(_targetCodeManagerDescriptor, jittedCodeAddress, level)); + return null; } - return nextLevelAddress; } - EECodeInfoHandle? IExecutionManager.GetEECodeInfoHandle(TargetCodePointer ip) { // TODO: some kind of cache based on ip, too? diff --git a/src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs b/src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs index 5ae05ec16910f..b6c1540978c0d 100644 --- a/src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs +++ b/src/native/managed/cdacreader/src/Data/RangeSectionFragment.cs @@ -21,4 +21,7 @@ public RangeSectionFragment(Target target, TargetPointer address) public TargetPointer RangeEndOpen { get; init; } public TargetPointer RangeSection { get; init; } public TargetPointer Next { get; init; } + + public bool Contains(TargetCodePointer address) + => RangeBegin <= address && address < RangeEndOpen; } From ef51f0e5c4ecbdcf1d91e0b53499f0ccf279dbb6 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 22 Aug 2024 13:42:14 -0400 Subject: [PATCH 63/66] remove dead method from contract --- docs/design/datacontracts/RuntimeTypeSystem.md | 3 --- .../managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs | 1 - 2 files changed, 4 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index d7098c141c02e..b6b2d15a6d81f 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -141,9 +141,6 @@ partial interface IRuntimeTypeSystem : IContract // Return true if a MethodDesc is in a collectible module public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc); - // Return true if a MethodDesc is in a module that supports Edit-And-Continue - public virtual bool InEnCEnabledModule(MethodDescHandle methodDesc); - // Return true if a MethodDesc supports mulitiple code versions public virtual bool IsVersionable(MethodDescHandle methodDesc); diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index 133a47f107685..2610b92b43d3a 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -165,7 +165,6 @@ static IContract IContract.Create(Target target, int version) public virtual bool IsILStub(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc) => throw new NotImplementedException(); - public virtual bool InEnCEnabledModule(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); From 92764a244de1d915fe58b63dfed6a8cb8e056c1d Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 22 Aug 2024 16:19:31 -0400 Subject: [PATCH 64/66] fix typo --- .../src/Contracts/RuntimeTypeSystem_1.NonValidated.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index da391a3a31599..2fc020770b0d4 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -311,7 +311,7 @@ private TargetPointer GetAddrOfNativeCodeSlot(TargetPointer methodDescPointer, N return methodDescPointer.Value + offset; } - private TargetPointer GetAddresOfNonVtableSlot(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) + private TargetPointer GetAddressOfNonVtableSlot(TargetPointer methodDescPointer, NonValidated.MethodDesc umd) { uint offset = MethodDescAdditionalPointersOffset(umd); offset += (uint)(_target.PointerSize * umd.NonVtableSlotIndex); @@ -354,7 +354,7 @@ private TargetCodePointer GetMethodEntryPointIfExists(TargetPointer methodDescAd { if (umd.HasNonVtableSlot) { - TargetPointer pSlot = GetAddresOfNonVtableSlot(methodDescAddress, umd); + TargetPointer pSlot = GetAddressOfNonVtableSlot(methodDescAddress, umd); return _target.ReadCodePointer(pSlot); } From 037c3494a19269984c2920838dd88d80c9cef74e Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 23 Aug 2024 12:32:21 -0400 Subject: [PATCH 65/66] Apply suggestions from code review --- docs/design/datacontracts/CodeVersions.md | 10 +++++----- src/coreclr/vm/codeversion.h | 8 +------- .../managed/cdacreader/src/Contracts/CodeVersions.cs | 2 +- .../managed/cdacreader/src/Contracts/CodeVersions_1.cs | 2 +- .../managed/cdacreader/src/Contracts/PrecodeStubs.cs | 2 +- .../managed/cdacreader/src/Contracts/PrecodeStubs_1.cs | 2 +- .../src/Contracts/RuntimeTypeSystem_1.NonValidated.cs | 2 +- src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs | 2 +- 8 files changed, 12 insertions(+), 18 deletions(-) diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 3e96713428afc..efd838181cbbb 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -27,15 +27,15 @@ internal struct NativeCodeVersionHandle ```csharp // Return a handle to the version of the native code that includes the given instruction pointer - public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException(); + public virtual NativeCodeVersionHandle GetNativeCodeVersionForIP(TargetCodePointer ip); // Return a handle to the active version of the native code for a given method descriptor - public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); + public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc); // returns true if the given method descriptor supports multiple code versions - public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); + public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc); // Return the instruction pointer corresponding to the start of the given native code version - public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle); ``` ## Version 1 @@ -62,7 +62,7 @@ Contracts used: ### Finding the start of a specific native code version ```csharp - NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) + NativeCodeVersionHandle GetNativeCodeVersionForIP(TargetCodePointer ip) { Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager; EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip); diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 4fd09826e82cd..8976991d65c32 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -249,16 +249,10 @@ class ILCodeVersion } m_synthetic; }; + // cDAC accesses fields via ILCodeVersioningState.m_activeVersion template friend struct ::cdac_data; }; -template<> -struct cdac_data -{ - // All fields are accessed via ILCodeVersioningState.m_activeVersion -}; - - class NativeCodeVersionNode { friend NativeCodeVersionIterator; diff --git a/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs b/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs index e6eea4cd7cd45..1dcd6732ad6f5 100644 --- a/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs +++ b/src/native/managed/cdacreader/src/Contracts/CodeVersions.cs @@ -17,7 +17,7 @@ static IContract IContract.Create(Target target, int version) }; } - public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException(); + public virtual NativeCodeVersionHandle GetNativeCodeVersionForIP(TargetCodePointer ip) => throw new NotImplementedException(); public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs b/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs index aacd982e58b7c..b22d507e638b5 100644 --- a/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/CodeVersions_1.cs @@ -15,7 +15,7 @@ public CodeVersions_1(Target target) _target = target; } - NativeCodeVersionHandle ICodeVersions.GetSpecificNativeCodeVersion(TargetCodePointer ip) + NativeCodeVersionHandle ICodeVersions.GetNativeCodeVersionForIP(TargetCodePointer ip) { // ExecutionManager::GetNativeCodeVersion(PCODE ip)) // and EECodeInfo::GetNativeCodeVersion diff --git a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs index 288af4f03b69c..753d21b73e8c8 100644 --- a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs +++ b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs.cs @@ -19,7 +19,7 @@ static IContract IContract.Create(Target target, int version) }; } - TargetPointer MethodDescFromStubAddress(TargetCodePointer entryPoint) => throw new NotImplementedException(); + TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint) => throw new NotImplementedException(); } diff --git a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs index e30011d899ac4..d2ae91a1f27a9 100644 --- a/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/PrecodeStubs_1.cs @@ -163,7 +163,7 @@ public PrecodeStubs_1(Target target, Data.PrecodeMachineDescriptor precodeMachin MachineDescriptor = precodeMachineDescriptor; } - TargetPointer IPrecodeStubs.MethodDescFromStubAddress(TargetCodePointer entryPoint) + TargetPointer IPrecodeStubs.GetMethodDescFromStubAddress(TargetCodePointer entryPoint) { ValidPrecode precode = GetPrecodeFromEntryPoint(entryPoint); diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs index 2fc020770b0d4..039bdeb875ff9 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_1.NonValidated.cs @@ -425,7 +425,7 @@ private bool ValidateMethodDescPointer(TargetPointer methodDescPointer, [NotNull if (temporaryEntryPoint != TargetCodePointer.Null) { Contracts.IPrecodeStubs precode = _target.Contracts.PrecodeStubs; - TargetPointer methodDesc = precode.MethodDescFromStubAddress(temporaryEntryPoint); + TargetPointer methodDesc = precode.GetMethodDescFromStubAddress(temporaryEntryPoint); if (methodDesc != methodDescPointer) { return false; diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index 07d80f46a0a07..c95cb6b2307f9 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -124,7 +124,7 @@ public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDescDa NativeCodeVersionHandle? activeNativeCodeVersion = null; if (ip != 0) { - requestedNativeCodeVersion = nativeCodeContract.GetSpecificNativeCodeVersion(new TargetCodePointer(ip)); + requestedNativeCodeVersion = nativeCodeContract.GetNativeCodeVersionForIP(new TargetCodePointer(ip)); } else { From 25d834312bb46ed68a1dfc30f0ce89d42ceadd5f Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 23 Aug 2024 12:37:16 -0400 Subject: [PATCH 66/66] Add PrecodeStubs contract writeup --- docs/design/datacontracts/PrecodeStubs.md | 230 ++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 docs/design/datacontracts/PrecodeStubs.md diff --git a/docs/design/datacontracts/PrecodeStubs.md b/docs/design/datacontracts/PrecodeStubs.md new file mode 100644 index 0000000000000..9f1de75dbd6de --- /dev/null +++ b/docs/design/datacontracts/PrecodeStubs.md @@ -0,0 +1,230 @@ +# Contract PrecodeStubs + +This contract provides support for examining [precode](../coreclr/botr/method-descriptor.md#precode): small fragments of code used to implement temporary entry points and an efficient wrapper for stubs. + +## APIs of contract + +```csharp + // Gets a pointer to the MethodDesc for a given stub entrypoint + TargetPointer GetMethodDescFromStubAddress(TargetCodePointer entryPoint); +``` + +## Version 1 + +Data descriptors used: +| Data Descriptor Name | Field | Meaning | +| --- | --- | --- | +| PrecodeMachineDescriptor | OffsetOfPrecodeType | See `ReadPrecodeType` | +| PrecodeMachineDescriptor | ShiftOfPrecodeType | See `ReadPrecodeType` | +| PrecodeMachineDescriptor | ReadWidthOfPrecodeType | See `ReadPrecodeType` | +| PrecodeMachineDescriptor | StubCodePageSize | Size of a precode code page (in bytes) | +| PrecodeMachineDescriptor | CodePointerToInstrPointerMask | mask to apply to code pointers to get an address (see arm32 note) +| PrecodeMachineDescriptor | StubPrecodeType | precode sort byte for stub precodes | +| PrecodeMachineDescriptor | HasPInvokeImportPrecode | 1 if platform supports PInvoke precode stubs | +| PrecodeMachineDescriptor | PInvokeImportPrecodeType| precode sort byte for PInvoke precode stubs, if supported | +| PrecodeMachineDescriptor | HasFixupPrecode | 1 if platform supports fixup precode stubs | +| PrecodeMachineDescriptor | FixupPrecodeType| precode sort byte for fixup precode stubs, if supported | +| StubPrecodeData | MethodDesc | pointer to the MethodDesc associated with this stub precode | +| StubPrecodeData | Type | precise sort of stub precode | +| FixupPrecodeData | MethodDesc | pointer to the MethodDesc associated with this fixup precode | + +arm32 note: the `CodePointerToInstrPointerMask` is used to convert IP values that may include an arm Thumb bit (for example extracted from disassembling a call instruction or from a snapshot of the registers) into an address. On other architectures applying the mask is a no-op. + + +Global variables used: +| Global Name | Type | Purpose | +| --- | --- | --- | +| PrecodeMachineDescriptor | pointer | address of the `PrecodeMachineDescriptor` data | + +Contracts used: +| Contract Name | +| --- | +| *none* | + +### Determining the precode type + +An initial approximation of the precode type relies on a particular pattern at a known offset from the precode entrypoint. +The precode type is expected to be encoded as an immediate. On some platforms the value is spread over multiple instructon bytes and may need to be right-shifted. + +``` + private byte ReadPrecodeType(TargetPointer instrPointer) + { + if (MachineDescriptor.ReadWidthOfPrecodeType == 1) + { + byte precodeType = _target.Read(instrPointer + MachineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> MachineDescriptor.ShiftOfPrecodeType); + } + else if (MachineDescriptor.ReadWidthOfPrecodeType == 2) + { + ushort precodeType = _target.Read(instrPointer + MachineDescriptor.OffsetOfPrecodeType); + return (byte)(precodeType >> MachineDescriptor.ShiftOfPrecodeType); + } + else + { + throw new InvalidOperationException($"Invalid precode type width {MachineDescriptor.ReadWidthOfPrecodeType}"); + } + } +``` + +After the initial precode type is determined, for stub precodes a refined precode type is extracted from the stub precode data. + +```csharp + private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) + { + // precode.h Precode::GetType() + byte precodeType = ReadPrecodeType(instrAddress); + if (precodeType == MachineDescriptor.StubPrecodeType) + { + // get the actual type from the StubPrecodeData + Data.StubPrecodeData stubPrecodeData = GetStubPrecodeData(instrAddress); + precodeType = stubPrecodeData.Type; + } + + if (precodeType == MachineDescriptor.StubPrecodeType) + { + return KnownPrecodeType.Stub; + } + else if (MachineDescriptor.PInvokeImportPrecodeType is byte ndType && precodeType == ndType) + { + return KnownPrecodeType.PInvokeImport; + } + else if (MachineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) + { + return KnownPrecodeType.Fixup; + } + // TODO: ThisPtrRetBuf + else + { + return null; + } + } +``` + +### `MethodDescFromStubAddress` + +```csharp + internal enum KnownPrecodeType + { + Stub = 1, + PInvokeImport, // also known as NDirectImport in the runtime + Fixup, + ThisPtrRetBuf, + } + + internal abstract class ValidPrecode + { + public TargetPointer InstrPointer { get; } + public KnownPrecodeType PrecodeType { get; } + + protected ValidPrecode(TargetPointer instrPointer, KnownPrecodeType precodeType) + { + InstrPointer = instrPointer; + PrecodeType = precodeType; + } + + internal abstract TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); + + } + + internal class StubPrecode : ValidPrecode + { + internal StubPrecode(TargetPointer instrPointer, KnownPrecodeType type = KnownPrecodeType.Stub) : base(instrPointer, type) { } + + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + TargetPointer stubPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + return target.ReadPointer (stubPrecodeDataAddress + /* offset of StubPrecodeData.MethodDesc */ ); + } + } + + internal sealed class PInvokeImportPrecode : StubPrecode + { + internal PInvokeImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.PInvokeImport) { } + } + + internal sealed class FixupPrecode : ValidPrecode + { + internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + TargetPointer fixupPrecodeDataAddress = InstrPointer + precodeMachineDescriptor.StubCodePageSize; + return target.ReadPointer (fixupPrecodeDataAddress + /* offset of FixupPrecodeData.MethodDesc */); + } + } + + internal sealed class ThisPtrRetBufPrecode : ValidPrecode + { + internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } + + internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) + { + throw new NotImplementedException(); // TODO(cdac) + } + } + + private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) + { + // precode.h Precode::GetType() + byte precodeType = ReadPrecodeType(instrAddress); + if (precodeType == MachineDescriptor.StubPrecodeType) + { + // get the actual type from the StubPrecodeData + precodeType = target.Read(instrAddress + MachineDescriptor.CodePageSize + /* offset of StubPrecodeData.Type */); + } + + if (precodeType == MachineDescriptor.StubPrecodeType) + { + return KnownPrecodeType.Stub; + } + else if (MachineDescriptor.PInvokeImportPrecodeType is byte ndType && precodeType == ndType) + { + return KnownPrecodeType.PInvokeImport; + } + else if (MachineDescriptor.FixupPrecodeType is byte fixupType && precodeType == fixupType) + { + return KnownPrecodeType.Fixup; + } + // TODO: ThisPtrRetBuf + else + { + return null; + } + } + + internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) + { + // Mask off the thumb bit, if we're on arm32, to get the actual instruction pointer + ulong instrPointer = (ulong)codePointer.AsTargetPointer & MachineDescriptor.CodePointerToInstrPointerMask.Value; + return new TargetPointer(instrPointer); + } + + + internal ValidPrecode GetPrecodeFromEntryPoint(TargetCodePointer entryPoint) + { + TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint); + if (IsAlignedInstrPointer(instrPointer) && TryGetKnownPrecodeType(instrPointer) is KnownPrecodeType precodeType) + { + switch (precodeType) + { + case KnownPrecodeType.Stub: + return new StubPrecode(instrPointer); + case KnownPrecodeType.Fixup: + return new FixupPrecode(instrPointer); + case KnownPrecodeType.PInvokeImport: + return new PInvokeImportPrecode(instrPointer); + case KnownPrecodeType.ThisPtrRetBuf: + return new ThisPtrRetBufPrecode(instrPointer); + default: + break; + } + } + throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}"); + } + + TargetPointer IPrecodeStubs.GetMethodDescFromStubAddress(TargetCodePointer entryPoint) + { + ValidPrecode precode = GetPrecodeFromEntryPoint(entryPoint); + + return precode.GetMethodDesc(_target, MachineDescriptor); + } +```