// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Reflection.PortableExecutable;
using System.Text;
namespace R2RDump
{
///
/// based on src\inc\gcinfotypes.h infoHdrAdjustConstants
///
enum InfoHdrAdjustConstants
{
// Constants
SET_FRAMESIZE_MAX = 7,
SET_ARGCOUNT_MAX = 8,
SET_PROLOGSIZE_MAX = 16,
SET_EPILOGSIZE_MAX = 10,
SET_EPILOGCNT_MAX = 4,
SET_UNTRACKED_MAX = 3,
SET_RET_KIND_MAX = 4,
ADJ_ENCODING_MAX = 0x7f,
MORE_BYTES_TO_FOLLOW = 0x80
};
///
/// Enum to define codes that are used to incrementally adjust the InfoHdr structure.
/// based on src\inc\gcinfotypes.h infoHdrAdjustConstants
///
enum InfoHdrAdjust
{
SET_FRAMESIZE = 0, // 0x00
SET_ARGCOUNT = SET_FRAMESIZE + InfoHdrAdjustConstants.SET_FRAMESIZE_MAX + 1, // 0x08
SET_PROLOGSIZE = SET_ARGCOUNT + InfoHdrAdjustConstants.SET_ARGCOUNT_MAX + 1, // 0x11
SET_EPILOGSIZE = SET_PROLOGSIZE + InfoHdrAdjustConstants.SET_PROLOGSIZE_MAX + 1, // 0x22
SET_EPILOGCNT = SET_EPILOGSIZE + InfoHdrAdjustConstants.SET_EPILOGSIZE_MAX + 1, // 0x2d
SET_UNTRACKED = SET_EPILOGCNT + (InfoHdrAdjustConstants.SET_EPILOGCNT_MAX + 1) * 2, // 0x37
FIRST_FLIP = SET_UNTRACKED + InfoHdrAdjustConstants.SET_UNTRACKED_MAX + 1,
FLIP_EDI_SAVED = FIRST_FLIP, // 0x3b
FLIP_ESI_SAVED, // 0x3c
FLIP_EBX_SAVED, // 0x3d
FLIP_EBP_SAVED, // 0x3e
FLIP_EBP_FRAME, // 0x3f
FLIP_INTERRUPTIBLE, // 0x40
FLIP_DOUBLE_ALIGN, // 0x41
FLIP_SECURITY, // 0x42
FLIP_HANDLERS, // 0x43
FLIP_LOCALLOC, // 0x44
FLIP_EDITnCONTINUE, // 0x45
FLIP_VAR_PTR_TABLE_SZ, // 0x46 Flip whether a table-size exits after the header encoding
FFFF_UNTRACKED_CNT, // 0x47 There is a count (>SET_UNTRACKED_MAX) after the header encoding
FLIP_VARARGS, // 0x48
FLIP_PROF_CALLBACKS, // 0x49
FLIP_HAS_GS_COOKIE, // 0x4A - The offset of the GuardStack cookie follows after the header encoding
FLIP_SYNC, // 0x4B
FLIP_HAS_GENERICS_CONTEXT,// 0x4C
FLIP_GENERICS_CONTEXT_IS_METHODDESC,// 0x4D
FLIP_REV_PINVOKE_FRAME, // 0x4E
NEXT_OPCODE, // 0x4F -- see next Adjustment enumeration
NEXT_FOUR_START = 0x50,
NEXT_FOUR_FRAMESIZE = 0x50,
NEXT_FOUR_ARGCOUNT = 0x60,
NEXT_THREE_PROLOGSIZE = 0x70,
NEXT_THREE_EPILOGSIZE = 0x78
};
///
/// based on macros defined in src\inc\gcinfotypes.h
///
public class GcInfoTypes
{
private Machine _target;
internal int SIZE_OF_RETURN_KIND_SLIM { get; } = 2;
internal int SIZE_OF_RETURN_KIND_FAT { get; } = 2;
internal int CODE_LENGTH_ENCBASE { get; } = 8;
internal int NORM_PROLOG_SIZE_ENCBASE { get; } = 5;
internal int NORM_EPILOG_SIZE_ENCBASE { get; } = 3;
internal int SECURITY_OBJECT_STACK_SLOT_ENCBASE { get; } = 6;
internal int GS_COOKIE_STACK_SLOT_ENCBASE { get; } = 6;
internal int PSP_SYM_STACK_SLOT_ENCBASE { get; } = 6;
internal int GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE { get; } = 6;
internal int STACK_BASE_REGISTER_ENCBASE { get; } = 3;
internal int SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE { get; } = 4;
internal int REVERSE_PINVOKE_FRAME_ENCBASE { get; } = 6;
internal int SIZE_OF_STACK_AREA_ENCBASE { get; } = 3;
internal int NUM_SAFE_POINTS_ENCBASE { get; } = 3;
internal int NUM_INTERRUPTIBLE_RANGES_ENCBASE { get; } = 1;
internal int INTERRUPTIBLE_RANGE_DELTA1_ENCBASE { get; } = 6;
internal int INTERRUPTIBLE_RANGE_DELTA2_ENCBASE { get; } = 6;
internal int MAX_PREDECODED_SLOTS { get; } = 64;
internal int NUM_REGISTERS_ENCBASE { get; } = 2;
internal int NUM_STACK_SLOTS_ENCBASE { get; } = 2;
internal int NUM_UNTRACKED_SLOTS_ENCBASE { get; } = 1;
internal int REGISTER_ENCBASE { get; } = 3;
internal int REGISTER_DELTA_ENCBASE { get; } = 2;
internal int STACK_SLOT_ENCBASE { get; } = 6;
internal int STACK_SLOT_DELTA_ENCBASE { get; } = 4;
internal int POINTER_SIZE_ENCBASE { get; } = 3;
internal int NUM_NORM_CODE_OFFSETS_PER_CHUNK { get; } = 64;
internal int LIVESTATE_RLE_RUN_ENCBASE { get; } = 2;
internal int LIVESTATE_RLE_SKIP_ENCBASE { get; } = 4;
internal int NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 { get; } = 6;
internal GcInfoTypes(Machine machine)
{
_target = machine;
switch (machine)
{
case Machine.Amd64:
SIZE_OF_RETURN_KIND_FAT = 4;
NUM_SAFE_POINTS_ENCBASE = 2;
break;
case Machine.ArmThumb2:
CODE_LENGTH_ENCBASE = 7;
SECURITY_OBJECT_STACK_SLOT_ENCBASE = 5;
GS_COOKIE_STACK_SLOT_ENCBASE = 5;
PSP_SYM_STACK_SLOT_ENCBASE = 5;
GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE = 5;
STACK_BASE_REGISTER_ENCBASE = 1;
SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE = 3;
REVERSE_PINVOKE_FRAME_ENCBASE = 5;
NUM_INTERRUPTIBLE_RANGES_ENCBASE = 2;
INTERRUPTIBLE_RANGE_DELTA1_ENCBASE = 4;
NUM_STACK_SLOTS_ENCBASE = 3;
NUM_UNTRACKED_SLOTS_ENCBASE = 3;
REGISTER_ENCBASE = 2;
REGISTER_DELTA_ENCBASE = 1;
break;
case Machine.Arm64:
SIZE_OF_RETURN_KIND_FAT = 4;
STACK_BASE_REGISTER_ENCBASE = 2;
NUM_REGISTERS_ENCBASE = 3;
break;
case Machine.I386:
CODE_LENGTH_ENCBASE = 6;
NORM_PROLOG_SIZE_ENCBASE = 4;
SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE = 3;
SIZE_OF_STACK_AREA_ENCBASE = 6;
NUM_SAFE_POINTS_ENCBASE = 4;
INTERRUPTIBLE_RANGE_DELTA1_ENCBASE = 5;
INTERRUPTIBLE_RANGE_DELTA2_ENCBASE = 5;
NUM_REGISTERS_ENCBASE = 3;
NUM_STACK_SLOTS_ENCBASE = 5;
NUM_UNTRACKED_SLOTS_ENCBASE = 5;
REGISTER_DELTA_ENCBASE = 3;
break;
}
}
internal int DenormalizeCodeLength(int x)
{
switch (_target)
{
case Machine.ArmThumb2:
return (x << 1);
case Machine.Arm64:
return (x << 2);
}
return x;
}
internal int DenormalizeStackSlot(int x)
{
switch (_target)
{
case Machine.Amd64:
return (x << 3);
case Machine.ArmThumb2:
return (x << 2);
case Machine.Arm64:
return (x << 3);
}
return x;
}
internal uint DenormalizeStackBaseRegister(uint x)
{
switch (_target)
{
case Machine.Amd64:
return (x ^ 5);
case Machine.ArmThumb2:
return ((x ^ 7) + 4);
case Machine.Arm64:
return (x ^ 29);
}
return x;
}
internal uint DenormalizeSizeOfStackArea(uint x)
{
switch (_target)
{
case Machine.Amd64:
return (x << 3);
case Machine.ArmThumb2:
return (x << 2);
case Machine.Arm64:
return (x << 3);
}
return x;
}
internal static uint CeilOfLog2(int x)
{
if (x == 0)
return 0;
uint result = (uint)((x & (x - 1)) != 0 ? 1 : 0);
while (x != 1)
{
result++;
x >>= 1;
}
return result;
}
}
public enum ReturnKinds
{
RT_Scalar = 0,
RT_Object = 1,
RT_ByRef = 2,
RT_Unset = 3, // Encoding 3 means RT_Float on X86
RT_Scalar_Obj = RT_Object << 2 | RT_Scalar,
RT_Scalar_ByRef = RT_ByRef << 2 | RT_Scalar,
RT_Obj_Obj = RT_Object << 2 | RT_Object,
RT_Obj_ByRef = RT_ByRef << 2 | RT_Object,
RT_ByRef_Obj = RT_Object << 2 | RT_ByRef,
RT_ByRef_ByRef = RT_ByRef << 2 | RT_ByRef,
RT_Illegal = 0xFF
};
public enum GcSlotFlags
{
GC_SLOT_BASE = 0x0,
GC_SLOT_INTERIOR = 0x1,
GC_SLOT_PINNED = 0x2,
GC_SLOT_UNTRACKED = 0x4,
};
public enum GcStackSlotBase
{
GC_CALLER_SP_REL = 0x0,
GC_SP_REL = 0x1,
GC_FRAMEREG_REL = 0x2,
GC_SPBASE_FIRST = GC_CALLER_SP_REL,
GC_SPBASE_LAST = GC_FRAMEREG_REL,
};
public class GcStackSlot
{
public int SpOffset { get; set; }
public GcStackSlotBase Base { get; set; }
public GcStackSlot() { }
public GcStackSlot(int spOffset, GcStackSlotBase stackSlotBase)
{
SpOffset = spOffset;
Base = stackSlotBase;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"\t\t\t\tSpOffset: {SpOffset}");
sb.Append($"\t\t\t\tBase: {Enum.GetName(typeof(GcStackSlotBase), Base)}");
return sb.ToString();
}
};
}