| File: Contracts\PrecodeStubs_Common.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts) |
// 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 Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal enum KnownPrecodeType { Stub = 1, PInvokeImport, Fixup, ThisPtrRetBuf, UMEntry, Interpreter, DynamicHelper } // Interface used to abstract behavior which may be different between multiple versions of the precode stub implementations internal interface IPrecodeStubsContractCommonApi<TStubPrecodeData> { public static abstract TargetPointer StubPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); public static abstract TargetPointer ThisPtrRetBufPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); public static abstract TargetPointer FixupPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); public static abstract TargetPointer InterpreterPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); public static abstract byte StubPrecodeData_GetType(TStubPrecodeData stubPrecodeData); public static abstract KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor); } internal class PrecodeStubsCommon<TPrecodeStubsImplementation, TStubPrecodeData> : IPrecodeStubs where TPrecodeStubsImplementation : IPrecodeStubsContractCommonApi<TStubPrecodeData> where TStubPrecodeData : IData<TStubPrecodeData> { private readonly Target _target; private readonly CodePointerFlags _codePointerFlags; internal readonly Data.PrecodeMachineDescriptor MachineDescriptor; 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) { return TPrecodeStubsImplementation.StubPrecode_GetMethodDesc(InstrPointer, target, precodeMachineDescriptor); } } internal sealed class InterpreterPrecode : ValidPrecode { internal InterpreterPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Interpreter) { } internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) { return TPrecodeStubsImplementation.InterpreterPrecode_GetMethodDesc(InstrPointer, target, precodeMachineDescriptor); } } public sealed class PInvokeImportPrecode : StubPrecode { internal PInvokeImportPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.PInvokeImport) { } } public sealed class FixupPrecode : ValidPrecode { internal FixupPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.Fixup) { } internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) { return TPrecodeStubsImplementation.FixupPrecode_GetMethodDesc(InstrPointer, target, precodeMachineDescriptor); } } public sealed class ThisPtrRetBufPrecode : ValidPrecode { internal ThisPtrRetBufPrecode(TargetPointer instrPointer) : base(instrPointer, KnownPrecodeType.ThisPtrRetBuf) { } internal override TargetPointer GetMethodDesc(Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor) { return TPrecodeStubsImplementation.ThisPtrRetBufPrecode_GetMethodDesc(InstrPointer, target, precodeMachineDescriptor); } } private bool IsAlignedInstrPointer(TargetPointer instrPointer) => _target.IsAlignedToPointerSize(instrPointer); private TStubPrecodeData GetStubPrecodeData(TargetPointer stubInstrPointer) { TargetPointer stubPrecodeDataAddress = stubInstrPointer + MachineDescriptor.StubCodePageSize; return _target.ProcessedData.GetOrAdd<TStubPrecodeData>(stubPrecodeDataAddress); } private KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrAddress) { return TPrecodeStubsImplementation.TryGetKnownPrecodeType(instrAddress, _target, MachineDescriptor); } internal TargetPointer CodePointerReadableInstrPointer(TargetCodePointer codePointer) { if (_codePointerFlags.HasFlag(CodePointerFlags.HasArm32ThumbBit)) { return codePointer.AsTargetPointer & ~1ul; } if (_codePointerFlags.HasFlag(CodePointerFlags.HasArm64PtrAuth)) { throw new NotImplementedException("CodePointerReadableInstrPointer for ARM64 with pointer authentication"); } Debug.Assert(_codePointerFlags == 0); return codePointer.AsTargetPointer; } 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); case KnownPrecodeType.Interpreter: return new InterpreterPrecode(instrPointer); default: break; } } throw new InvalidOperationException($"Invalid precode type 0x{instrPointer:x16}"); } public PrecodeStubsCommon(Target target) { _target = target; IPlatformMetadata pm = target.Contracts.PlatformMetadata; TargetPointer descAddr = pm.GetPrecodeMachineDescriptor(); MachineDescriptor = target.ProcessedData.GetOrAdd<Data.PrecodeMachineDescriptor>(descAddr); _codePointerFlags = pm.GetCodePointerFlags(); } TargetPointer IPrecodeStubs.GetMethodDescFromStubAddress(TargetCodePointer entryPoint) { ValidPrecode precode = GetPrecodeFromEntryPoint(entryPoint); return precode.GetMethodDesc(_target, MachineDescriptor); } TargetPointer IPrecodeStubs.GetPrecodeEntryPointFromInteriorAddress(TargetCodePointer interiorAddress, bool isFixupPrecode) { TargetPointer instrPointer = CodePointerReadableInstrPointer(interiorAddress); uint stubSize; if (isFixupPrecode) { if (MachineDescriptor.FixupStubPrecodeSize is not byte fixupSize || fixupSize == 0) throw new InvalidOperationException("FixupPrecode size not available"); stubSize = fixupSize; } else { if (MachineDescriptor.StubPrecodeSize is not byte stubPrecodeSize || stubPrecodeSize == 0) throw new InvalidOperationException("StubPrecode size not available"); stubSize = stubPrecodeSize; } ulong pageMask = MachineDescriptor.StubCodePageSize - 1; ulong pageBase = instrPointer.Value & ~pageMask; ulong offset = instrPointer.Value - pageBase; ulong entryPointAddress = pageBase + (offset / stubSize) * stubSize; return new TargetPointer(entryPointAddress); } TargetCodePointer IPrecodeStubs.GetInterpreterCodeFromInterpreterPrecodeIfPresent(TargetCodePointer entryPoint) { try { TargetPointer instrPointer = CodePointerReadableInstrPointer(entryPoint); if (!IsAlignedInstrPointer(instrPointer)) return entryPoint; if (TryGetKnownPrecodeType(instrPointer) is not KnownPrecodeType.Interpreter) return entryPoint; TargetPointer dataAddr = instrPointer + MachineDescriptor.StubCodePageSize; Data.InterpreterPrecodeData precodeData = _target.ProcessedData.GetOrAdd<Data.InterpreterPrecodeData>(dataAddr); if (precodeData.ByteCodeAddr == TargetPointer.Null) return entryPoint; return new TargetCodePointer(precodeData.ByteCodeAddr); } catch (VirtualReadException) { return entryPoint; } } }