File: Contracts\PrecodeStubs_3.cs
Web Access
Project: src\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;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal struct PrecodeStubs_3_Impl : IPrecodeStubsContractCommonApi<Data.StubPrecodeData_2>
{
    public static TargetPointer StubPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
    {
        // Version 3 of this contract behaves just like version 2
        return PrecodeStubs_2_Impl.StubPrecode_GetMethodDesc(instrPointer, target, precodeMachineDescriptor);
    }

    public static TargetPointer FixupPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
    {
        // Version 3 of this contract behaves just like version 1
        return PrecodeStubs_1_Impl.FixupPrecode_GetMethodDesc(instrPointer, target, precodeMachineDescriptor);
    }

    public static TargetPointer ThisPtrRetBufPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
    {
        // Version 3 of this contract behaves just like version 2
        return PrecodeStubs_2_Impl.ThisPtrRetBufPrecode_GetMethodDesc(instrPointer, target, precodeMachineDescriptor);
    }

    public static TargetPointer InterpreterPrecode_GetMethodDesc(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
    {
        TargetPointer dataAddr = instrPointer + precodeMachineDescriptor.StubCodePageSize;
        Data.InterpreterPrecodeData precodeData = target.ProcessedData.GetOrAdd<Data.InterpreterPrecodeData>(dataAddr);
        Data.InterpByteCodeStart byteCodeStart = target.ProcessedData.GetOrAdd<Data.InterpByteCodeStart>(precodeData.ByteCodeAddr);
        Data.InterpMethod interpMethod = target.ProcessedData.GetOrAdd<Data.InterpMethod>(byteCodeStart.Method);

        return interpMethod.MethodDesc;
    }

    public static byte StubPrecodeData_GetType(Data.StubPrecodeData_2 stubPrecodeData)
    {
        // Version 3 of this contract behaves just like version 2
        return PrecodeStubs_2_Impl.StubPrecodeData_GetType(stubPrecodeData);
    }

    private static Data.StubPrecodeData_2 GetStubPrecodeData(TargetPointer stubInstrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
    {
        TargetPointer stubPrecodeDataAddress = stubInstrPointer + precodeMachineDescriptor.StubCodePageSize;
        return target.ProcessedData.GetOrAdd<Data.StubPrecodeData_2>(stubPrecodeDataAddress);
    }

    public static KnownPrecodeType? TryGetKnownPrecodeType(TargetPointer instrPointer, Target target, Data.PrecodeMachineDescriptor precodeMachineDescriptor)
    {
        if (ReadBytesAndCompare(instrPointer, precodeMachineDescriptor.StubBytes!, precodeMachineDescriptor.StubIgnoredBytes!, target))
        {
            // get the actual type from the StubPrecodeData
            Data.StubPrecodeData_2 stubPrecodeData = GetStubPrecodeData(instrPointer, target, precodeMachineDescriptor);
            byte exactPrecodeType = stubPrecodeData.Type;
            if (exactPrecodeType == 0)
                return null;

            if (exactPrecodeType == precodeMachineDescriptor.StubPrecodeType)
            {
                return KnownPrecodeType.Stub;
            }
            else if (precodeMachineDescriptor.PInvokeImportPrecodeType is byte compareByte1 && compareByte1 == exactPrecodeType)
            {
                return KnownPrecodeType.PInvokeImport;
            }
            else if (precodeMachineDescriptor.ThisPointerRetBufPrecodeType is byte compareByte2 && compareByte2 == exactPrecodeType)
            {
                return KnownPrecodeType.ThisPtrRetBuf;
            }
            else if (precodeMachineDescriptor.UMEntryPrecodeType is byte compareByte3 && compareByte3 == exactPrecodeType)
            {
                return KnownPrecodeType.UMEntry;
            }
            else if (precodeMachineDescriptor.InterpreterPrecodeType is byte compareByte4 && compareByte4 == exactPrecodeType)
            {
                return KnownPrecodeType.Interpreter;
            }
            else if (precodeMachineDescriptor.DynamicHelperPrecodeType is byte compareByte5 && compareByte5 == exactPrecodeType)
            {
                return KnownPrecodeType.DynamicHelper;
            }
        }
        else if (ReadBytesAndCompare(instrPointer, precodeMachineDescriptor.FixupBytes!, precodeMachineDescriptor.FixupIgnoredBytes!, target))
        {
            return KnownPrecodeType.Fixup;
        }
        return null;

        static bool ReadBytesAndCompare(TargetPointer instrAddress, byte[] expectedBytePattern, byte[] bytesToIgnore, Target target)
        {
            for (ulong i = 0; i < (ulong)expectedBytePattern.Length; i++)
            {
                if (bytesToIgnore[i] == 0)
                {
                    byte targetBytePattern = target.Read<byte>(new TargetPointer((instrAddress.Value + (ulong)i)));
                    if (expectedBytePattern[i] != targetBytePattern)
                    {
                        return false;
                    }
                }
            }

            return true;
        }
    }
}

internal sealed class PrecodeStubs_3 : PrecodeStubsCommon<PrecodeStubs_3_Impl, Data.StubPrecodeData_2>
{
    public PrecodeStubs_3(Target target) : base(target) { }
}