File: Contracts\StackWalk\Context\ARM\LookupValues.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.Collections.Immutable;

namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers.ARM;

internal static class LookupValues
{
    /// <summary>
    /// This table provides the register mask described by the given C/L/R/Reg bit
    /// combinations in the compact pdata format, along with the number of VFP
    /// registers to save in bits 16-19.
    /// </summary>
    public static ReadOnlySpan<uint> RegisterMaskLookup =>
    [                // C L R Reg
        0x00010,     // 0 0 0 000
        0x00030,     // 0 0 0 001
        0x00070,     // 0 0 0 010
        0x000f0,     // 0 0 0 011
        0x001f0,     // 0 0 0 100
        0x003f0,     // 0 0 0 101
        0x007f0,     // 0 0 0 110
        0x00ff0,     // 0 0 0 111

        0x10000,     // 0 0 1 000
        0x20000,     // 0 0 1 001
        0x30000,     // 0 0 1 010
        0x40000,     // 0 0 1 011
        0x50000,     // 0 0 1 100
        0x60000,     // 0 0 1 101
        0x70000,     // 0 0 1 110
        0x00000,     // 0 0 1 111

        0x04010,     // 0 1 0 000
        0x04030,     // 0 1 0 001
        0x04070,     // 0 1 0 010
        0x040f0,     // 0 1 0 011
        0x041f0,     // 0 1 0 100
        0x043f0,     // 0 1 0 101
        0x047f0,     // 0 1 0 110
        0x04ff0,     // 0 1 0 111

        0x14000,     // 0 1 1 000
        0x24000,     // 0 1 1 001
        0x34000,     // 0 1 1 010
        0x44000,     // 0 1 1 011
        0x54000,     // 0 1 1 100
        0x64000,     // 0 1 1 101
        0x74000,     // 0 1 1 110
        0x04000,     // 0 1 1 111

        0x00810,     // 1 0 0 000
        0x00830,     // 1 0 0 001
        0x00870,     // 1 0 0 010
        0x008f0,     // 1 0 0 011
        0x009f0,     // 1 0 0 100
        0x00bf0,     // 1 0 0 101
        0x00ff0,     // 1 0 0 110
        0x0ffff,     // 1 0 0 111

        0x1ffff,     // 1 0 1 000
        0x2ffff,     // 1 0 1 001
        0x3ffff,     // 1 0 1 010
        0x4ffff,     // 1 0 1 011
        0x5ffff,     // 1 0 1 100
        0x6ffff,     // 1 0 1 101
        0x7ffff,     // 1 0 1 110
        0x0ffff,     // 1 0 1 111

        0x04810,     // 1 1 0 000
        0x04830,     // 1 1 0 001
        0x04870,     // 1 1 0 010
        0x048f0,     // 1 1 0 011
        0x049f0,     // 1 1 0 100
        0x04bf0,     // 1 1 0 101
        0x04ff0,     // 1 1 0 110
        0x0ffff,     // 1 1 0 111

        0x14800,     // 1 1 1 000
        0x24800,     // 1 1 1 001
        0x34800,     // 1 1 1 010
        0x44800,     // 1 1 1 011
        0x54800,     // 1 1 1 100
        0x64800,     // 1 1 1 101
        0x74800,     // 1 1 1 110
        0x04800,     // 1 1 1 111
    ];

    /// <summary>
    /// This table describes the size of each unwind code, in bytes (lower nibble),
    /// along with the size of the corresponding machine code, in halfwords
    /// (upper nibble).
    /// </summary>
    public static ReadOnlySpan<byte> UnwindOpTable =>
    [
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,

        0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
        0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
        0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
        0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,   0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
        0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,   0x22, 0x22, 0x22, 0x22, 0x12, 0x12, 0x02, 0x22,
        0x01, 0x01, 0x01, 0x01, 0x01, 0x22, 0x22, 0x13,   0x14, 0x23, 0x24, 0x11, 0x21, 0x10, 0x20, 0x00
    ];

    private const ushort NSET_MASK = 0xff00;
    private const ushort ZSET_MASK = 0xf0f0;
    private const ushort CSET_MASK = 0xcccc;
    private const ushort VSET_MASK = 0xaaaa;
    private const ushort NEQUALV_MASK = unchecked((ushort)((NSET_MASK & VSET_MASK) | (~NSET_MASK & ~VSET_MASK)));

    /// <summary>
    /// The ConditionTable is used to look up the state of a condition
    /// based on the CPSR flags N,Z,C,V, which reside in the upper 4
    /// bits. To use this table, take the condition you are interested
    /// in and use it as the index to look up the UINT16 from the table.
    /// Then right-shift that value by the upper 4 bits of the CPSR,
    /// and the low bit will be the result.
    ///
    /// The bits in the CPSR are ordered (MSB to LSB): N,Z,C,V. Taken
    /// together, this is called the CpsrFlags.
    ///
    /// The macros below are defined such that:
    ///
    ///    N = (NSET_MASK >> CpsrFlags) & 1
    ///    Z = (ZSET_MASK >> CpsrFlags) & 1
    ///    C = (CSET_MASK >> CpsrFlags) & 1
    ///    V = (VSET_MASK >> CpsrFlags) & 1
    ///
    /// Also:
    ///
    ///    (N == V) = (NEQUALV_MASK >> CpsrFlags) & 1
    /// </summary>
    public static ReadOnlySpan<ushort> ConditionTable =>
    [
        // EQ: Z
        ZSET_MASK,
        // NE: !Z
        unchecked((ushort)~ZSET_MASK),
        // CS: C
        CSET_MASK,
        // CC: !C
        unchecked((ushort)~CSET_MASK),
        // MI: N
        NSET_MASK,
        // PL: !N
        unchecked((ushort)~NSET_MASK),
        // VS: V
        VSET_MASK,
        // VC: !V
        unchecked((ushort)~VSET_MASK),
        // HI: C & !Z
        CSET_MASK & ~ZSET_MASK,
        // LO: !C | Z
        unchecked((short)~CSET_MASK | ZSET_MASK),
        // GE: N == V
        NEQUALV_MASK,
        // LT: N != V
        unchecked((ushort)~NEQUALV_MASK),
        // GT: (N == V) & !Z
        NEQUALV_MASK & ~ZSET_MASK,
        // LE: (N != V) | Z
        unchecked((ushort)~NEQUALV_MASK | ZSET_MASK),
        // AL: always
        0xffff,
        // NV: never
        0x0000
    ];


    public const ushort OFFSET_NONE = ushort.MaxValue;
    public readonly struct ARM_CONTEXT_OFFSETS(
        ushort alignment,
        ushort totalSize,
        ImmutableArray<ushort> regOffset,
        ImmutableArray<ushort> fpRegOffset,
        ushort spOffset,
        ushort lrOffset,
        ushort pcOffset,
        ushort cpsrOffset,
        ushort fpscrOffset)
    {
        public readonly ushort Alignment = alignment;
        public readonly ushort TotalSize = totalSize;
        public readonly ImmutableArray<ushort> RegOffset = regOffset;
        public readonly ImmutableArray<ushort> FpRegOffset = fpRegOffset;
        public readonly ushort SpOffset = spOffset;
        public readonly ushort LrOffset = lrOffset;
        public readonly ushort PcOffset = pcOffset;
        public readonly ushort CpsrOffset = cpsrOffset;
        public readonly ushort FpscrOffset = fpscrOffset;
    }

    public static readonly ARM_CONTEXT_OFFSETS TrapFrameOffsets =
        new(
            alignment: 8,
            totalSize: 272,
            regOffset: [248, 252, 256, 260, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, 72],
            fpRegOffset: [184, 192, 200, 208, 216, 224, 232, 240, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE,
                OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE,
                OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE],
            spOffset: 64,
            lrOffset: 68,
            pcOffset: 264,
            cpsrOffset: 268,
            fpscrOffset: 176);


    public static readonly ARM_CONTEXT_OFFSETS MachineFrameOffsets =
        new(
            alignment: 8,
            totalSize: 8,
            regOffset: [OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE],
            fpRegOffset: [OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE,
                OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE,
                OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE, OFFSET_NONE],
            spOffset: 0,
            lrOffset: OFFSET_NONE,
            pcOffset: 4,
            cpsrOffset: OFFSET_NONE,
            fpscrOffset: OFFSET_NONE);

    public static readonly ARM_CONTEXT_OFFSETS ContextOffsets =
        new(
            alignment: 16,
            totalSize: 416,
            regOffset: [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52],
            fpRegOffset: [80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328],
            spOffset: 56,
            lrOffset: 60,
            pcOffset: 64,
            cpsrOffset: 68,
            fpscrOffset: 72);
}