{
Offset = offset;
_gcInfoTypes = new GcInfoTypes(machine);
+ _machine = machine;
SecurityObjectStackSlot = -1;
GSCookieStackSlot = -1;
Transitions = GetTranstions(image, ref bitOffset);
Size = bitOffset - startBitOffset;
-
- _machine = machine;
}
public override string ToString()
string slotStr = "";
if (slot.StackSlot == null)
{
- Type regType = typeof(Amd64.Registers);
- if (machine == Machine.ArmThumb2)
+ Type regType;
+ switch (machine)
{
- regType = typeof(Arm.Registers);
- }
- else
- {
- regType = typeof(Arm64.Registers);
+ case Machine.ArmThumb2:
+ regType = typeof(Arm.Registers);
+ break;
+
+ case Machine.Arm64:
+ regType = typeof(Arm64.Registers);
+ break;
+
+ case Machine.Amd64:
+ regType = typeof(Amd64.Registers);
+ break;
+
+ default:
+ throw new NotImplementedException();
}
slotStr = Enum.GetName(regType, slot.RegisterNumber);
}
UnwindCodes[UnwindCodeArray[i].CodeOffset].Add(UnwindCodeArray[i]);
}
- PersonalityRoutineRVA = NativeReader.ReadUInt32(image, ref offset);
-
Size = _offsetofUnwindCode + CountOfUnwindCodes * _sizeofUnwindCode;
- int alignmentPad = ((Size + sizeof(int) - 1) & ~(sizeof(int) - 1)) - Size;
- Size += (alignmentPad + sizeof(uint));
+ int alignmentPad = -Size & 3;
+ Size += alignmentPad + sizeof(uint);
+
+ // Personality routine RVA must be at 4-aligned address
+ offset += alignmentPad;
+ PersonalityRoutineRVA = NativeReader.ReadUInt32(image, ref offset);
}
public override string ToString()
}
}
+ /// <summary>
+ /// Helper class for converting machine instructions to textual representation.
+ /// </summary>
public class Disassembler : IDisposable
{
- private readonly IntPtr _disasm;
-
- private readonly byte[] _image;
+ /// <summary>
+ /// R2R reader is used to access architecture info, the PE image data and symbol table.
+ /// </summary>
+ private readonly R2RReader _reader;
- private readonly Machine _machine;
+ /// <summary>
+ /// COM interface to the native disassembler in the CoreDisTools.dll library.
+ /// </summary>
+ private readonly IntPtr _disasm;
- public Disassembler(byte[] image, Machine machine)
+ /// <summary>
+ /// Store the R2R reader and construct the disassembler for the appropriate architecture.
+ /// </summary>
+ /// <param name="reader"></param>
+ public Disassembler(R2RReader reader)
{
- _disasm = CoreDisTools.GetDisasm(machine);
- _image = image;
- _machine = machine;
+ _reader = reader;
+ _disasm = CoreDisTools.GetDisasm(_reader.Machine);
}
+ /// <summary>
+ /// Shut down the native disassembler interface.
+ /// </summary>
public void Dispose()
{
if (_disasm != IntPtr.Zero)
}
}
+ /// <summary>
+ /// Parse a single instruction and return the RVA of the next instruction.
+ /// </summary>
+ /// <param name="rtf">Runtime function to parse</param>
+ /// <param name="imageOffset">Offset within the PE image byte array</param>
+ /// <param name="rtfOffset">Instruction offset within the runtime function</param>
+ /// <param name="instruction">Output text representation of the instruction</param>
+ /// <returns>Instruction size in bytes - i.o.w. the next instruction starts at rtfOffset + (the return value)</returns>
public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, out string instruction)
{
if (_disasm == IntPtr.Zero)
return rtf.Size;
}
- int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _image, out instruction);
+ int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _reader.Image, out instruction);
+ instruction = instruction.Replace('\t', ' ');
- switch (_machine)
+ switch (_reader.Machine)
{
case Machine.Amd64:
case Machine.IA64:
const string RelIPTag = "[rip ";
+ /// <summary>
+ /// Translate RIP-relative offsets to RVA's and convert cell addresses to symbol names
+ /// </summary>
+ /// <param name="rtf">Runtime function</param>
+ /// <param name="imageOffset">Offset within the image byte array</param>
+ /// <param name="rtfOffset">Offset within the runtime function</param>
+ /// <param name="instrSize">Instruction size</param>
+ /// <param name="instruction">Textual representation of the instruction</param>
private void ProbeX64Quirks(RuntimeFunction rtf, int imageOffset, int rtfOffset, int instrSize, ref string instruction)
{
int relip = instruction.IndexOf(RelIPTag);
offset = -offset;
}
int target = rtf.StartAddress + rtfOffset + instrSize + offset;
- instruction = instruction.Substring(0, start) + $@"[0x{target:x4}]" + instruction.Substring(relip);
+ int newline = instruction.LastIndexOf('\n');
+ StringBuilder translated = new StringBuilder();
+ translated.Append(instruction, 0, start);
+ translated.AppendFormat("[0x{0:x4}]", target);
+ translated.Append(instruction, relip, newline - relip);
+ String targetName;
+ if (_reader.ImportCellNames.TryGetValue(target, out targetName))
+ {
+ int fill = 61 - translated.Length;
+ if (fill > 0)
+ {
+ translated.Append(' ', fill);
+ }
+ translated.Append(" // ");
+ translated.Append(targetName);
+ }
+ translated.Append(instruction, newline, instruction.Length - newline);
+ instruction = translated.ToString();
}
}
}
+ else if (instrSize == 2 && IsIntelJumpInstructionWithByteOffset(imageOffset + rtfOffset))
+ {
+ sbyte offset = (sbyte)_reader.Image[imageOffset + rtfOffset + 1];
+ int target = rtf.StartAddress + rtfOffset + instrSize + offset;
+ ReplaceRelativeOffset(ref instruction, target);
+ }
+ else if (instrSize == 5 && IsIntel1ByteJumpInstructionWithIntOffset(imageOffset + rtfOffset))
+ {
+ int offset = BitConverter.ToInt32(_reader.Image, imageOffset + rtfOffset + 1);
+ int target = rtf.StartAddress + rtfOffset + instrSize + offset;
+ ReplaceRelativeOffset(ref instruction, target);
+ }
+ else if (instrSize == 6 && IsIntel2ByteJumpInstructionWithIntOffset(imageOffset + rtfOffset))
+ {
+ int offset = BitConverter.ToInt32(_reader.Image, imageOffset + rtfOffset + 2);
+ int target = rtf.StartAddress + rtfOffset + instrSize + offset;
+ ReplaceRelativeOffset(ref instruction, target);
+ }
+ }
+
+ /// <summary>
+ /// Replace relative offset in the disassembled instruction with the true target RVA.
+ /// </summary>
+ /// <param name="instruction"></param>
+ /// <param name="target"></param>
+ private void ReplaceRelativeOffset(ref string instruction, int target)
+ {
+ int numberEnd = instruction.IndexOf('\n');
+ int number = numberEnd;
+ while (number > 0)
+ {
+ char c = instruction[number - 1];
+ if (c >= ' ' && !Char.IsDigit(c) && c != '-')
+ {
+ break;
+ }
+ number--;
+ }
+
+ StringBuilder translated = new StringBuilder();
+ translated.Append(instruction, 0, number);
+ translated.AppendFormat("0x{0:x4}", target);
+ translated.Append(instruction, numberEnd, instruction.Length - numberEnd);
+ instruction = translated.ToString();
+ }
+
+ /// <summary>
+ /// Returns true when this is one of the x86 / amd64 opcodes used for branch instructions
+ /// with single-byte offset.
+ /// </summary>
+ /// <param name="imageOffset">Offset within the PE image byte array</param>
+ private bool IsIntelJumpInstructionWithByteOffset(int imageOffset)
+ {
+ byte opCode = _reader.Image[imageOffset];
+ return
+ (opCode >= 0x70 && opCode <= 0x7F) // short conditional jumps
+ || opCode == 0xE3 // JCXZ
+ || opCode == 0xEB // JMP
+ ;
+ }
+
+ /// <summary>
+ /// Returns true when this is one of the x86 / amd64 near jump / call opcodes
+ /// with signed 4-byte offset.
+ /// </summary>
+ /// <param name="imageOffset">Offset within the PE image byte array</param>
+ private bool IsIntel1ByteJumpInstructionWithIntOffset(int imageOffset)
+ {
+ byte opCode = _reader.Image[imageOffset];
+ return opCode == 0xE8 // call near
+ || opCode == 0xE9 // jmp near
+ ;
+ }
+
+ /// <summary>
+ /// Returns true when this is one of the x86 / amd64 conditional near jump
+ /// opcodes with signed 4-byte offset.
+ /// </summary>
+ /// <param name="imageOffset">Offset within the PE image byte array</param>
+ private bool IsIntel2ByteJumpInstructionWithIntOffset(int imageOffset)
+ {
+ byte opCode1 = _reader.Image[imageOffset];
+ byte opCode2 = _reader.Image[imageOffset + 1];
+ return opCode1 == 0x0F &&
+ (opCode2 >= 0x80 && opCode2 <= 0x8F); // near conditional jumps
}
}
}
namespace R2RDump
{
- internal class DisassemblingGenericContext
+ public class DisassemblingGenericContext
{
public DisassemblingGenericContext(string[] typeParameters, string[] methodParameters)
{
// Test implementation of ISignatureTypeProvider<TType, TGenericContext> that uses strings in ilasm syntax as TType.
// A real provider in any sort of perf constraints would not want to allocate strings freely like this, but it keeps test code simple.
- internal class DisassemblingTypeProvider : ISignatureTypeProvider<string, DisassemblingGenericContext>
+ public class DisassemblingTypeProvider : ISignatureTypeProvider<string, DisassemblingGenericContext>
{
public virtual string GetPrimitiveType(PrimitiveTypeCode typeCode)
{
return "[" + reader.GetString(assemblyReference.Name) + "]" + name;
case HandleKind.TypeReference:
- return GetTypeFromReference(reader, (TypeReferenceHandle)scope) + "/" + name;
+ return GetTypeFromReference(reader, (TypeReferenceHandle)scope) + "+" + name;
default:
return name;
{
if (index >= genericContext.MethodParameters.Length)
{
- R2RDump.WriteWarning("GenericMethodParameters index out of bounds");
- return "";
+ return "!!" + index.ToString();
}
return genericContext.MethodParameters[index];
}
{
if (index >= genericContext.TypeParameters.Length)
{
- R2RDump.WriteWarning("GenericTypeParameter index out of bounds");
- return "";
+ return "!" + index.ToString();
}
return genericContext.TypeParameters[index];
}
--- /dev/null
+// 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;
+
+namespace R2RDump
+{
+ /// <summary>
+ /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/inc/corcompile.h">src/inc/corcompile.h</a> CorCompileImportType
+ /// </summary>
+ public enum CorCompileImportType
+ {
+ CORCOMPILE_IMPORT_TYPE_UNKNOWN = 0,
+ CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD = 1,
+ CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH = 2,
+ CORCOMPILE_IMPORT_TYPE_STRING_HANDLE = 3,
+ CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE = 4,
+ CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE = 5,
+ CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD = 6,
+ };
+
+ /// <summary>
+ /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/inc/corcompile.h">src/inc/corcompile.h</a> CorCompileImportFlags
+ /// </summary>
+ public enum CorCompileImportFlags
+ {
+ CORCOMPILE_IMPORT_FLAGS_UNKNOWN = 0x0000,
+ CORCOMPILE_IMPORT_FLAGS_EAGER = 0x0001, // Section at module load time.
+ CORCOMPILE_IMPORT_FLAGS_CODE = 0x0002, // Section contains code.
+ CORCOMPILE_IMPORT_FLAGS_PCODE = 0x0004, // Section contains pointers to code.
+ };
+
+ /// <summary>
+ /// Constants for method and field encoding
+ /// </summary>
+ [Flags]
+ public enum ReadyToRunMethodSigFlags : byte
+ {
+ READYTORUN_METHOD_SIG_None = 0x00,
+ READYTORUN_METHOD_SIG_UnboxingStub = 0x01,
+ READYTORUN_METHOD_SIG_InstantiatingStub = 0x02,
+ READYTORUN_METHOD_SIG_MethodInstantiation = 0x04,
+ READYTORUN_METHOD_SIG_SlotInsteadOfToken = 0x08,
+ READYTORUN_METHOD_SIG_MemberRefToken = 0x10,
+ READYTORUN_METHOD_SIG_Constrained = 0x20,
+ READYTORUN_METHOD_SIG_OwnerType = 0x40,
+ }
+
+ [Flags]
+ public enum ReadyToRunFieldSigFlags : byte
+ {
+ READYTORUN_FIELD_SIG_IndexInsteadOfToken = 0x08,
+ READYTORUN_FIELD_SIG_MemberRefToken = 0x10,
+ READYTORUN_FIELD_SIG_OwnerType = 0x40,
+ }
+
+ [Flags]
+ public enum ReadyToRunTypeLayoutFlags : byte
+ {
+ READYTORUN_LAYOUT_HFA = 0x01,
+ READYTORUN_LAYOUT_Alignment = 0x02,
+ READYTORUN_LAYOUT_Alignment_Native = 0x04,
+ READYTORUN_LAYOUT_GCLayout = 0x08,
+ READYTORUN_LAYOUT_GCLayout_Empty = 0x10,
+ }
+
+ public enum ReadyToRunFixupKind
+ {
+ READYTORUN_FIXUP_ThisObjDictionaryLookup = 0x07,
+ READYTORUN_FIXUP_TypeDictionaryLookup = 0x08,
+ READYTORUN_FIXUP_MethodDictionaryLookup = 0x09,
+
+ READYTORUN_FIXUP_TypeHandle = 0x10,
+ READYTORUN_FIXUP_MethodHandle = 0x11,
+ READYTORUN_FIXUP_FieldHandle = 0x12,
+
+ READYTORUN_FIXUP_MethodEntry = 0x13, /* For calling a method entry point */
+ READYTORUN_FIXUP_MethodEntry_DefToken = 0x14, /* Smaller version of MethodEntry - method is def token */
+ READYTORUN_FIXUP_MethodEntry_RefToken = 0x15, /* Smaller version of MethodEntry - method is ref token */
+
+ READYTORUN_FIXUP_VirtualEntry = 0x16, /* For invoking a virtual method */
+ READYTORUN_FIXUP_VirtualEntry_DefToken = 0x17, /* Smaller version of VirtualEntry - method is def token */
+ READYTORUN_FIXUP_VirtualEntry_RefToken = 0x18, /* Smaller version of VirtualEntry - method is ref token */
+ READYTORUN_FIXUP_VirtualEntry_Slot = 0x19, /* Smaller version of VirtualEntry - type & slot */
+
+ READYTORUN_FIXUP_Helper = 0x1A, /* Helper */
+ READYTORUN_FIXUP_StringHandle = 0x1B, /* String handle */
+
+ READYTORUN_FIXUP_NewObject = 0x1C, /* Dynamically created new helper */
+ READYTORUN_FIXUP_NewArray = 0x1D,
+
+ READYTORUN_FIXUP_IsInstanceOf = 0x1E, /* Dynamically created casting helper */
+ READYTORUN_FIXUP_ChkCast = 0x1F,
+
+ READYTORUN_FIXUP_FieldAddress = 0x20, /* For accessing a cross-module static fields */
+ READYTORUN_FIXUP_CctorTrigger = 0x21, /* Static constructor trigger */
+
+ READYTORUN_FIXUP_StaticBaseNonGC = 0x22, /* Dynamically created static base helpers */
+ READYTORUN_FIXUP_StaticBaseGC = 0x23,
+ READYTORUN_FIXUP_ThreadStaticBaseNonGC = 0x24,
+ READYTORUN_FIXUP_ThreadStaticBaseGC = 0x25,
+
+ READYTORUN_FIXUP_FieldBaseOffset = 0x26, /* Field base offset */
+ READYTORUN_FIXUP_FieldOffset = 0x27, /* Field offset */
+
+ READYTORUN_FIXUP_TypeDictionary = 0x28,
+ READYTORUN_FIXUP_MethodDictionary = 0x29,
+
+ READYTORUN_FIXUP_Check_TypeLayout = 0x2A, /* size, alignment, HFA, reference map */
+ READYTORUN_FIXUP_Check_FieldOffset = 0x2B,
+
+ READYTORUN_FIXUP_DelegateCtor = 0x2C, /* optimized delegate ctor */
+ READYTORUN_FIXUP_DeclaringTypeHandle = 0x2D,
+ }
+
+ //
+ // Intrinsics and helpers
+ //
+
+ [Flags]
+ public enum ReadyToRunHelper
+ {
+ READYTORUN_HELPER_Invalid = 0x00,
+
+ // Not a real helper - handle to current module passed to delay load helpers.
+ READYTORUN_HELPER_Module = 0x01,
+ READYTORUN_HELPER_GSCookie = 0x02,
+
+ //
+ // Delay load helpers
+ //
+
+ // All delay load helpers use custom calling convention:
+ // - scratch register - address of indirection cell. 0 = address is inferred from callsite.
+ // - stack - section index, module handle
+ READYTORUN_HELPER_DelayLoad_MethodCall = 0x08,
+
+ READYTORUN_HELPER_DelayLoad_Helper = 0x10,
+ READYTORUN_HELPER_DelayLoad_Helper_Obj = 0x11,
+ READYTORUN_HELPER_DelayLoad_Helper_ObjObj = 0x12,
+
+ // JIT helpers
+
+ // Exception handling helpers
+ READYTORUN_HELPER_Throw = 0x20,
+ READYTORUN_HELPER_Rethrow = 0x21,
+ READYTORUN_HELPER_Overflow = 0x22,
+ READYTORUN_HELPER_RngChkFail = 0x23,
+ READYTORUN_HELPER_FailFast = 0x24,
+ READYTORUN_HELPER_ThrowNullRef = 0x25,
+ READYTORUN_HELPER_ThrowDivZero = 0x26,
+
+ // Write barriers
+ READYTORUN_HELPER_WriteBarrier = 0x30,
+ READYTORUN_HELPER_CheckedWriteBarrier = 0x31,
+ READYTORUN_HELPER_ByRefWriteBarrier = 0x32,
+
+ // Array helpers
+ READYTORUN_HELPER_Stelem_Ref = 0x38,
+ READYTORUN_HELPER_Ldelema_Ref = 0x39,
+
+ READYTORUN_HELPER_MemSet = 0x40,
+ READYTORUN_HELPER_MemCpy = 0x41,
+
+ // Get string handle lazily
+ READYTORUN_HELPER_GetString = 0x50,
+
+ // Used by /Tuning for Profile optimizations
+ READYTORUN_HELPER_LogMethodEnter = 0x51,
+
+ // Reflection helpers
+ READYTORUN_HELPER_GetRuntimeTypeHandle = 0x54,
+ READYTORUN_HELPER_GetRuntimeMethodHandle = 0x55,
+ READYTORUN_HELPER_GetRuntimeFieldHandle = 0x56,
+
+ READYTORUN_HELPER_Box = 0x58,
+ READYTORUN_HELPER_Box_Nullable = 0x59,
+ READYTORUN_HELPER_Unbox = 0x5A,
+ READYTORUN_HELPER_Unbox_Nullable = 0x5B,
+ READYTORUN_HELPER_NewMultiDimArr = 0x5C,
+ READYTORUN_HELPER_NewMultiDimArr_NonVarArg = 0x5D,
+
+ // Helpers used with generic handle lookup cases
+ READYTORUN_HELPER_NewObject = 0x60,
+ READYTORUN_HELPER_NewArray = 0x61,
+ READYTORUN_HELPER_CheckCastAny = 0x62,
+ READYTORUN_HELPER_CheckInstanceAny = 0x63,
+ READYTORUN_HELPER_GenericGcStaticBase = 0x64,
+ READYTORUN_HELPER_GenericNonGcStaticBase = 0x65,
+ READYTORUN_HELPER_GenericGcTlsBase = 0x66,
+ READYTORUN_HELPER_GenericNonGcTlsBase = 0x67,
+ READYTORUN_HELPER_VirtualFuncPtr = 0x68,
+
+ // Long mul/div/shift ops
+ READYTORUN_HELPER_LMul = 0xC0,
+ READYTORUN_HELPER_LMulOfv = 0xC1,
+ READYTORUN_HELPER_ULMulOvf = 0xC2,
+ READYTORUN_HELPER_LDiv = 0xC3,
+ READYTORUN_HELPER_LMod = 0xC4,
+ READYTORUN_HELPER_ULDiv = 0xC5,
+ READYTORUN_HELPER_ULMod = 0xC6,
+ READYTORUN_HELPER_LLsh = 0xC7,
+ READYTORUN_HELPER_LRsh = 0xC8,
+ READYTORUN_HELPER_LRsz = 0xC9,
+ READYTORUN_HELPER_Lng2Dbl = 0xCA,
+ READYTORUN_HELPER_ULng2Dbl = 0xCB,
+
+ // 32-bit division helpers
+ READYTORUN_HELPER_Div = 0xCC,
+ READYTORUN_HELPER_Mod = 0xCD,
+ READYTORUN_HELPER_UDiv = 0xCE,
+ READYTORUN_HELPER_UMod = 0xCF,
+
+ // Floating point conversions
+ READYTORUN_HELPER_Dbl2Int = 0xD0,
+ READYTORUN_HELPER_Dbl2IntOvf = 0xD1,
+ READYTORUN_HELPER_Dbl2Lng = 0xD2,
+ READYTORUN_HELPER_Dbl2LngOvf = 0xD3,
+ READYTORUN_HELPER_Dbl2UInt = 0xD4,
+ READYTORUN_HELPER_Dbl2UIntOvf = 0xD5,
+ READYTORUN_HELPER_Dbl2ULng = 0xD6,
+ READYTORUN_HELPER_Dbl2ULngOvf = 0xD7,
+
+ // Floating point ops
+ READYTORUN_HELPER_DblRem = 0xE0,
+ READYTORUN_HELPER_FltRem = 0xE1,
+ READYTORUN_HELPER_DblRound = 0xE2,
+ READYTORUN_HELPER_FltRound = 0xE3,
+
+ // Personality rountines
+ READYTORUN_HELPER_PersonalityRoutine = 0xF0,
+ READYTORUN_HELPER_PersonalityRoutineFilterFunclet = 0xF1,
+
+ //
+ // Deprecated/legacy
+ //
+
+ // JIT32 x86-specific write barriers
+ READYTORUN_HELPER_WriteBarrier_EAX = 0x100,
+ READYTORUN_HELPER_WriteBarrier_EBX = 0x101,
+ READYTORUN_HELPER_WriteBarrier_ECX = 0x102,
+ READYTORUN_HELPER_WriteBarrier_ESI = 0x103,
+ READYTORUN_HELPER_WriteBarrier_EDI = 0x104,
+ READYTORUN_HELPER_WriteBarrier_EBP = 0x105,
+ READYTORUN_HELPER_CheckedWriteBarrier_EAX = 0x106,
+ READYTORUN_HELPER_CheckedWriteBarrier_EBX = 0x107,
+ READYTORUN_HELPER_CheckedWriteBarrier_ECX = 0x108,
+ READYTORUN_HELPER_CheckedWriteBarrier_ESI = 0x109,
+ READYTORUN_HELPER_CheckedWriteBarrier_EDI = 0x10A,
+ READYTORUN_HELPER_CheckedWriteBarrier_EBP = 0x10B,
+
+ // JIT32 x86-specific exception handling
+ READYTORUN_HELPER_EndCatch = 0x110,
+
+ // A flag to indicate that a helper call uses VSD
+ READYTORUN_HELPER_FLAG_VSD = 0x10000000,
+ }
+
+ public enum CorElementType : byte
+ {
+ Invalid = 0,
+ ELEMENT_TYPE_VOID = 1,
+ ELEMENT_TYPE_BOOLEAN = 2,
+ ELEMENT_TYPE_CHAR = 3,
+ ELEMENT_TYPE_I1 = 4,
+ ELEMENT_TYPE_U1 = 5,
+ ELEMENT_TYPE_I2 = 6,
+ ELEMENT_TYPE_U2 = 7,
+ ELEMENT_TYPE_I4 = 8,
+ ELEMENT_TYPE_U4 = 9,
+ ELEMENT_TYPE_I8 = 10,
+ ELEMENT_TYPE_U8 = 11,
+ ELEMENT_TYPE_R4 = 12,
+ ELEMENT_TYPE_R8 = 13,
+ ELEMENT_TYPE_STRING = 14,
+ ELEMENT_TYPE_PTR = 15,
+ ELEMENT_TYPE_BYREF = 16,
+ ELEMENT_TYPE_VALUETYPE = 17,
+ ELEMENT_TYPE_CLASS = 18,
+ ELEMENT_TYPE_VAR = 19,
+ ELEMENT_TYPE_ARRAY = 20,
+ ELEMENT_TYPE_GENERICINST = 21,
+ ELEMENT_TYPE_TYPEDBYREF = 22,
+ ELEMENT_TYPE_I = 24,
+ ELEMENT_TYPE_U = 25,
+ ELEMENT_TYPE_FNPTR = 27,
+ ELEMENT_TYPE_OBJECT = 28,
+ ELEMENT_TYPE_SZARRAY = 29,
+ ELEMENT_TYPE_MVAR = 30,
+ ELEMENT_TYPE_CMOD_REQD = 31,
+ ELEMENT_TYPE_CMOD_OPT = 32,
+
+ // ZapSig encoding for ELEMENT_TYPE_VAR and ELEMENT_TYPE_MVAR. It is always followed
+ // by the RID of a GenericParam token, encoded as a compressed integer.
+ ELEMENT_TYPE_VAR_ZAPSIG = 0x3b,
+
+ // ZapSig encoding for an array MethodTable to allow it to remain such after decoding
+ // (rather than being transformed into the TypeHandle representing that array)
+ //
+ // The element is always followed by ELEMENT_TYPE_SZARRAY or ELEMENT_TYPE_ARRAY
+ ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG = 0x3c,
+
+ // ZapSig encoding for native value types in IL stubs. IL stub signatures may contain
+ // ELEMENT_TYPE_INTERNAL followed by ParamTypeDesc with ELEMENT_TYPE_VALUETYPE element
+ // type. It acts like a modifier to the underlying structure making it look like its
+ // unmanaged view (size determined by unmanaged layout, blittable, no GC pointers).
+ //
+ // ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG is used when encoding such types to NGEN images.
+ // The signature looks like this: ET_NATIVE_VALUETYPE_ZAPSIG ET_VALUETYPE <token>.
+ // See code:ZapSig.GetSignatureForTypeHandle and code:SigPointer.GetTypeHandleThrowing
+ // where the encoding/decoding takes place.
+ ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG = 0x3d,
+
+ ELEMENT_TYPE_CANON_ZAPSIG = 0x3e, // zapsig encoding for [mscorlib]System.__Canon
+ ELEMENT_TYPE_MODULE_ZAPSIG = 0x3f, // zapsig encoding for external module id#
+
+ ELEMENT_TYPE_HANDLE = 64,
+ ELEMENT_TYPE_SENTINEL = 65,
+ ELEMENT_TYPE_PINNED = 69,
+ }
+
+ public enum CorTokenType
+ {
+ mdtModule = 0x00000000,
+ mdtTypeRef = 0x01000000,
+ mdtTypeDef = 0x02000000,
+ mdtFieldDef = 0x04000000,
+ mdtMethodDef = 0x06000000,
+ mdtParamDef = 0x08000000,
+ mdtInterfaceImpl = 0x09000000,
+ mdtMemberRef = 0x0a000000,
+ mdtCustomAttribute = 0x0c000000,
+ mdtPermission = 0x0e000000,
+ mdtSignature = 0x11000000,
+ mdtEvent = 0x14000000,
+ mdtProperty = 0x17000000,
+ mdtMethodImpl = 0x19000000,
+ mdtModuleRef = 0x1a000000,
+ mdtTypeSpec = 0x1b000000,
+ mdtAssembly = 0x20000000,
+ mdtAssemblyRef = 0x23000000,
+ mdtFile = 0x26000000,
+ mdtExportedType = 0x27000000,
+ mdtManifestResource = 0x28000000,
+ mdtGenericParam = 0x2a000000,
+ mdtMethodSpec = 0x2b000000,
+ mdtGenericParamConstraint = 0x2c000000,
+
+ mdtString = 0x70000000,
+ mdtName = 0x71000000,
+ mdtBaseType = 0x72000000,
+ }
+}
{
if (r2r.InputArchitectureSupported() && r2r.DisassemblerArchitectureSupported())
{
- disassembler = new Disassembler(r2r.Image, r2r.Machine);
+ disassembler = new Disassembler(r2r);
}
else
{
/// </summary>
public struct R2RImportSection
{
- /// <summary>
- /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/inc/corcompile.h">src/inc/corcompile.h</a> CorCompileImportType
- /// </summary>
- public enum CorCompileImportType
- {
- CORCOMPILE_IMPORT_TYPE_UNKNOWN = 0,
- CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD = 1,
- CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH = 2,
- CORCOMPILE_IMPORT_TYPE_STRING_HANDLE = 3,
- CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE = 4,
- CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE = 5,
- CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD = 6,
- };
-
- /// <summary>
- /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/inc/corcompile.h">src/inc/corcompile.h</a> CorCompileImportFlags
- /// </summary>
- public enum CorCompileImportFlags
- {
- CORCOMPILE_IMPORT_FLAGS_UNKNOWN = 0x0000,
- CORCOMPILE_IMPORT_FLAGS_EAGER = 0x0001, // Section at module load time.
- CORCOMPILE_IMPORT_FLAGS_CODE = 0x0002, // Section contains code.
- CORCOMPILE_IMPORT_FLAGS_PCODE = 0x0004, // Section contains pointers to code.
- };
-
public struct ImportSectionEntry
{
[XmlAttribute("Index")]
public int StartOffset { get; set; }
public long Section { get; set; }
public uint SignatureRVA { get; set; }
- public byte[] SignatureSample { get; set; }
- public ImportSectionEntry(int index, int startOffset, long section, uint signatureRVA, byte[] signatureSample)
+ public string Signature { get; set; }
+ public ImportSectionEntry(int index, int startOffset, long section, uint signatureRVA, string signature)
{
Index = index;
StartOffset = startOffset;
Section = section;
SignatureRVA = signatureRVA;
- SignatureSample = signatureSample;
+ Signature = signature;
}
public override string ToString()
{
- StringBuilder sb = new StringBuilder();
- sb.Append($@"+{StartOffset:X4} Section: 0x{Section:X8} SignatureRVA: 0x{SignatureRVA:X8} ");
- foreach (byte b in SignatureSample)
- {
- sb.AppendFormat("{0:X2} ", b);
- }
- sb.Append("...");
- return sb.ToString();
+ StringBuilder builder = new StringBuilder();
+ builder.AppendFormat("+{0:X4}", StartOffset);
+ builder.AppendFormat(" Section: 0x{0:X8}", Section);
+ builder.AppendFormat(" SignatureRVA: 0x{0:X8}", SignatureRVA);
+ builder.AppendFormat(" {0}", Signature);
+ return builder.ToString();
}
}
sb.AppendLine($"Size: {Size} bytes");
}
sb.AppendLine($"UnwindRVA: 0x{UnwindRVA:X8}");
+ if (UnwindInfo is Amd64.UnwindInfo amd64UnwindInfo)
+ {
+ string parsedFlags = "";
+ if ((amd64UnwindInfo.Flags & (int)Amd64.UnwindFlags.UNW_FLAG_EHANDLER) != 0)
+ {
+ parsedFlags += " EHANDLER";
+ }
+ if ((amd64UnwindInfo.Flags & (int)Amd64.UnwindFlags.UNW_FLAG_UHANDLER) != 0)
+ {
+ parsedFlags += " UHANDLER";
+ }
+ if ((amd64UnwindInfo.Flags & (int)Amd64.UnwindFlags.UNW_FLAG_CHAININFO) != 0)
+ {
+ parsedFlags += " CHAININFO";
+ }
+ if (parsedFlags.Length == 0)
+ {
+ parsedFlags = " NHANDLER";
+ }
+ sb.AppendLine($"Version: {amd64UnwindInfo.Version}");
+ sb.AppendLine($"Flags: 0x{amd64UnwindInfo.Flags:X2}{parsedFlags}");
+ sb.AppendLine($"SizeOfProlog: 0x{amd64UnwindInfo.SizeOfProlog:X4}");
+ sb.AppendLine($"CountOfUnwindCodes: {amd64UnwindInfo.CountOfUnwindCodes}");
+ sb.AppendLine($"FrameRegister: {amd64UnwindInfo.FrameRegister}");
+ sb.AppendLine($"FrameOffset: 0x{amd64UnwindInfo.FrameOffset}");
+ sb.AppendLine($"PersonalityRVA: 0x{amd64UnwindInfo.PersonalityRoutineRVA:X4}");
+
+ for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++)
+ {
+ Amd64.UnwindCode unwindCode = amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex];
+ sb.Append($"UnwindCode[{unwindCode.Index}]: ");
+ sb.Append($"CodeOffset 0x{unwindCode.CodeOffset:X4} ");
+ sb.Append($"FrameOffset 0x{unwindCode.FrameOffset:X4} ");
+ sb.Append($"NextOffset 0x{unwindCode.NextFrameOffset} ");
+ sb.Append($"Op {unwindCode.OpInfoStr}");
+ sb.AppendLine();
+ }
+ }
+ sb.AppendLine();
return sb.ToString();
}
/// </summary>
private Dictionary<string, string> _genericParamInstanceMap;
- [Flags]
- public enum EncodeMethodSigFlags
- {
- NONE = 0x00,
- ENCODE_METHOD_SIG_UnboxingStub = 0x01,
- ENCODE_METHOD_SIG_InstantiatingStub = 0x02,
- ENCODE_METHOD_SIG_MethodInstantiation = 0x04,
- ENCODE_METHOD_SIG_SlotInsteadOfToken = 0x08,
- ENCODE_METHOD_SIG_MemberRefToken = 0x10,
- ENCODE_METHOD_SIG_Constrained = 0x20,
- ENCODE_METHOD_SIG_OwnerType = 0x40,
- };
-
- public enum GenericElementTypes
- {
- __Canon = 0x3e,
- Void = 0x01,
- Boolean = 0x02,
- Char = 0x03,
- Int8 = 0x04,
- UInt8 = 0x05,
- Int16 = 0x06,
- UInt16 = 0x07,
- Int32 = 0x08,
- UInt32 = 0x09,
- Int64 = 0x0a,
- UInt64 = 0x0b,
- Float = 0x0c,
- Double = 0x0d,
- String = 0x0e,
- ValueType = 0x11,
- Object = 0x1c,
- Array = 0x1d,
- };
-
public R2RMethod() { }
/// <summary>
/// Extracts the method signature from the metadata by rid
/// </summary>
- public R2RMethod(int index, MetadataReader mdReader, uint rid, int entryPointId, GenericElementTypes[] instanceArgs, uint[] tok, FixupCell[] fixups)
+ public R2RMethod(int index, MetadataReader mdReader, uint rid, int entryPointId, CorElementType[] instanceArgs, uint[] tok, FixupCell[] fixups)
{
Index = index;
Token = _mdtMethodDef | rid;
BlobReader signatureReader = mdReader.GetBlobReader(_methodDef.Signature);
TypeDefinitionHandle declaringTypeHandle = _methodDef.GetDeclaringType();
- DeclaringType = R2RReader.GetTypeDefFullName(mdReader, declaringTypeHandle);
+ DeclaringType = MetadataNameFormatter.FormatHandle(mdReader, declaringTypeHandle);
SignatureHeader signatureHeader = signatureReader.ReadSignatureHeader();
IsGeneric = signatureHeader.IsGeneric;
/// <summary>
/// Initialize map of generic parameters names to the type in the instance
/// </summary>
- private void InitGenericInstances(GenericParameterHandleCollection genericParams, GenericElementTypes[] instanceArgs, uint[] tok)
+ private void InitGenericInstances(GenericParameterHandleCollection genericParams, CorElementType[] instanceArgs, uint[] tok)
{
if (instanceArgs.Length != genericParams.Count || tok.Length != genericParams.Count)
{
{
string key = _mdReader.GetString(_mdReader.GetGenericParameter(genericParams.ElementAt(i)).Name); // name of the generic param, eg. "T"
string type = instanceArgs[i].ToString(); // type of the generic param instance
- if (instanceArgs[i] == GenericElementTypes.ValueType)
+ if (instanceArgs[i] == CorElementType.ELEMENT_TYPE_VALUETYPE)
{
var t = _mdReader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle((int)tok[i]));
type = _mdReader.GetString(t.Name); // name of the struct
/// </summary>
public string CompilerIdentifier { get; }
+ /// <summary>
+ /// List of import sections present in the R2R executable.
+ /// </summary>
public IList<R2RImportSection> ImportSections { get; }
+ /// <summary>
+ /// Map from import cell addresses to their symbolic names.
+ /// </summary>
+ public Dictionary<int, string> ImportCellNames { get; }
+
public unsafe R2RReader() { }
/// <summary>
{
int runtimeFunctionSize = CalculateRuntimeFunctionSize();
R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS];
+
uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
bool[] isEntryPoint = new bool[nRuntimeFunctions];
CompilerIdentifier = ParseCompilerIdentifier();
ImportSections = new List<R2RImportSection>();
+ ImportCellNames = new Dictionary<int, string>();
ParseImportSections();
}
}
{
uint methodFlags = curParser.GetCompressedData();
uint rid = curParser.GetCompressedData();
- if ((methodFlags & (byte)R2RMethod.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation) != 0)
+ if ((methodFlags & (byte)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0)
{
uint nArgs = curParser.GetCompressedData();
- R2RMethod.GenericElementTypes[] args = new R2RMethod.GenericElementTypes[nArgs];
+ CorElementType[] args = new CorElementType[nArgs];
uint[] tokens = new uint[nArgs];
for (int i = 0; i < nArgs; i++)
{
- args[i] = (R2RMethod.GenericElementTypes)curParser.GetByte();
- if (args[i] == R2RMethod.GenericElementTypes.ValueType)
+ args[i] = (CorElementType)curParser.GetByte();
+ if (args[i] == CorElementType.ELEMENT_TYPE_VALUETYPE)
{
tokens[i] = curParser.GetCompressedData();
tokens[i] = (tokens[i] >> 2);
continue;
TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid);
- string typeDefName = GetTypeDefFullName(MetadataReader, typeDefHandle);
+ string typeDefName = MetadataNameFormatter.FormatHandle(MetadataReader, typeDefHandle);
ExportedTypeHandle exportedTypeHandle = MetadataTokens.ExportedTypeHandle((int)rid);
string exportedTypeName = GetExportedTypeFullName(MetadataReader, exportedTypeHandle);
if (typeDefName == null && exportedTypeName == null)
int sectionOffset = GetOffset(rva);
int startOffset = sectionOffset;
int size = NativeReader.ReadInt32(Image, ref offset);
- R2RImportSection.CorCompileImportFlags flags = (R2RImportSection.CorCompileImportFlags)NativeReader.ReadUInt16(Image, ref offset);
+ CorCompileImportFlags flags = (CorCompileImportFlags)NativeReader.ReadUInt16(Image, ref offset);
byte type = NativeReader.ReadByte(Image, ref offset);
byte entrySize = NativeReader.ReadByte(Image, ref offset);
if (entrySize == 0)
signatureOffset = GetOffset(signatureRVA);
}
List<R2RImportSection.ImportSectionEntry> entries = new List<R2RImportSection.ImportSectionEntry>();
- switch (flags)
+ for (int i = 0; i < entryCount; i++)
{
- case R2RImportSection.CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_EAGER:
- {
- int tempSignatureOffset = signatureOffset;
- int firstSigRva = NativeReader.ReadInt32(Image, ref tempSignatureOffset);
- uint sigRva = 0;
- while (sigRva != firstSigRva)
- {
- int entryOffset = sectionOffset - startOffset;
- sigRva = NativeReader.ReadUInt32(Image, ref signatureOffset);
- long section = NativeReader.ReadInt64(Image, ref sectionOffset);
- int sigOff = GetOffset((int)sigRva);
- int sigSampleLength = Math.Min(8, Image.Length - sigOff);
- byte[] signatureSample = new byte[sigSampleLength];
- Array.Copy(Image, sigOff, signatureSample, 0, sigSampleLength);
- entries.Add(new R2RImportSection.ImportSectionEntry(entries.Count, entryOffset, section, sigRva, signatureSample));
- }
- }
- break;
- default:
- for (int i = 0; i < entryCount; i++)
- {
- int entryOffset = sectionOffset - startOffset;
- long section = NativeReader.ReadInt64(Image, ref sectionOffset);
- uint sigRva = NativeReader.ReadUInt32(Image, ref signatureOffset);
- int sigOff = GetOffset((int)sigRva);
- int sigSampleLength = Math.Min(8, Image.Length - sigOff);
- byte[] signatureSample = new byte[sigSampleLength];
- Array.Copy(Image, sigOff, signatureSample, 0, sigSampleLength);
- entries.Add(new R2RImportSection.ImportSectionEntry(entries.Count, entryOffset, section, sigRva, signatureSample));
- }
- break;
+ int entryOffset = sectionOffset - startOffset;
+ long section = NativeReader.ReadInt64(Image, ref sectionOffset);
+ uint sigRva = NativeReader.ReadUInt32(Image, ref signatureOffset);
+ int sigOffset = GetOffset((int)sigRva);
+ string cellName = MetadataNameFormatter.FormatSignature(this, sigOffset);
+ entries.Add(new R2RImportSection.ImportSectionEntry(entries.Count, entryOffset, section, sigRva, cellName));
+ ImportCellNames.Add(rva + entrySize * i, cellName);
}
int auxDataRVA = NativeReader.ReadInt32(Image, ref offset);
}
/// <summary>
- /// Get the full name of a type, including parent classes and namespace
- /// </summary>
- public static string GetTypeDefFullName(MetadataReader mdReader, TypeDefinitionHandle handle)
- {
- string typeNamespace = "";
- string typeStr = "";
- do
- {
- try
- {
- TypeDefinition typeDef = mdReader.GetTypeDefinition(handle);
- typeStr = "." + mdReader.GetString(typeDef.Name) + typeStr;
- handle = typeDef.GetDeclaringType();
- if (handle.IsNil)
- typeNamespace = mdReader.GetString(typeDef.Namespace);
- }
- catch (BadImageFormatException)
- {
- return null;
- }
- }
- while (!handle.IsNil);
-
- return typeNamespace + typeStr;
- }
-
- /// <summary>
/// Get the full name of an ExportedType, including namespace
/// </summary>
public static string GetExportedTypeFullName(MetadataReader mdReader, ExportedTypeHandle handle)
--- /dev/null
+// 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.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Reflection.PortableExecutable;
+using System.Text;
+using System.Xml.Serialization;
+
+namespace R2RDump
+{
+ /// <summary>
+ /// Helper class for converting metadata tokens into their textual representation.
+ /// </summary>
+ public class MetadataNameFormatter : DisassemblingTypeProvider
+ {
+ /// <summary>
+ /// Metadata reader used for the purpose of metadata-based name formatting.
+ /// </summary>
+ private readonly MetadataReader _metadataReader;
+
+ public MetadataNameFormatter(MetadataReader metadataReader)
+ {
+ _metadataReader = metadataReader;
+ }
+
+ /// <summary>
+ /// Construct the textual representation of a given metadata handle.
+ /// </summary>
+ /// <param name="metadataReader">Metadata reader corresponding to the handle</param>
+ /// <param name="handle">Metadata handle to parse</param>
+ /// <param name="namespaceQualified">Include namespace in type names</param>
+ public static string FormatHandle(MetadataReader metadataReader, Handle handle, bool namespaceQualified = true)
+ {
+ MetadataNameFormatter formatter = new MetadataNameFormatter(metadataReader);
+ return formatter.EmitHandleName(handle, namespaceQualified);
+ }
+
+ public static string FormatSignature(R2RReader r2rReader, int imageOffset)
+ {
+ SignatureDecoder decoder = new SignatureDecoder(r2rReader, imageOffset);
+ string result = decoder.ReadR2RSignature();
+ return result;
+ }
+
+ /// <summary>
+ /// Emit a given token to a specified string builder.
+ /// </summary>
+ /// <param name="methodToken">ECMA token to provide string representation for</param>
+ private string EmitHandleName(Handle handle, bool namespaceQualified)
+ {
+ switch (handle.Kind)
+ {
+ case HandleKind.MemberReference:
+ return EmitMemberReferenceName((MemberReferenceHandle)handle);
+
+ case HandleKind.MethodSpecification:
+ return EmitMethodSpecificationName((MethodSpecificationHandle)handle);
+
+ case HandleKind.MethodDefinition:
+ return EmitMethodDefinitionName((MethodDefinitionHandle)handle);
+
+ case HandleKind.TypeReference:
+ return EmitTypeReferenceName((TypeReferenceHandle)handle, namespaceQualified);
+
+ case HandleKind.TypeSpecification:
+ return EmitTypeSpecificationName((TypeSpecificationHandle)handle, namespaceQualified);
+
+ case HandleKind.TypeDefinition:
+ return EmitTypeDefinitionName((TypeDefinitionHandle)handle, namespaceQualified);
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Emit a method specification.
+ /// </summary>
+ /// <param name="methodSpecHandle">Method specification handle</param>
+ private string EmitMethodSpecificationName(MethodSpecificationHandle methodSpecHandle)
+ {
+ MethodSpecification methodSpec = _metadataReader.GetMethodSpecification(methodSpecHandle);
+ DisassemblingGenericContext genericContext = new DisassemblingGenericContext(Array.Empty<string>(), Array.Empty<string>());
+ return EmitHandleName(methodSpec.Method, namespaceQualified: true) + methodSpec.DecodeSignature<string, DisassemblingGenericContext>(this, genericContext);
+ }
+
+ /// <summary>
+ /// Emit a method reference.
+ /// </summary>
+ /// <param name="memberRefHandle">Member reference handle</param>
+ private string EmitMemberReferenceName(MemberReferenceHandle memberRefHandle)
+ {
+ MemberReference methodRef = _metadataReader.GetMemberReference(memberRefHandle);
+ StringBuilder builder = new StringBuilder();
+ DisassemblingGenericContext genericContext = new DisassemblingGenericContext(Array.Empty<string>(), Array.Empty<string>());
+ MethodSignature<String> methodSig = methodRef.DecodeMethodSignature<string, DisassemblingGenericContext>(this, genericContext);
+ builder.Append(methodSig.ReturnType);
+ builder.Append(" ");
+ builder.Append(EmitContainingTypeAndMethodName(methodRef));
+ builder.Append(EmitMethodSignature(methodSig));
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Emit a method definition.
+ /// </summary>
+ /// <param name="methodSpecHandle">Method definition handle</param>
+ private string EmitMethodDefinitionName(MethodDefinitionHandle methodDefinitionHandle)
+ {
+ MethodDefinition methodDef = _metadataReader.GetMethodDefinition(methodDefinitionHandle);
+ DisassemblingGenericContext genericContext = new DisassemblingGenericContext(Array.Empty<string>(), Array.Empty<string>());
+ MethodSignature<string> methodSig = methodDef.DecodeSignature<string, DisassemblingGenericContext>(this, genericContext);
+ StringBuilder builder = new StringBuilder();
+ builder.Append(methodSig.ReturnType);
+ builder.Append(" ");
+ builder.Append(EmitHandleName(methodDef.GetDeclaringType(), namespaceQualified: true));
+ builder.Append(".");
+ builder.Append(EmitString(methodDef.Name));
+ builder.Append(EmitMethodSignature(methodSig));
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Emit method generic arguments and parameter list.
+ /// </summary>
+ /// <param name="methodSignature">Method signature to format</param>
+ private string EmitMethodSignature(MethodSignature<string> methodSignature)
+ {
+ StringBuilder builder = new StringBuilder();
+ if (methodSignature.GenericParameterCount != 0)
+ {
+ builder.Append("<");
+ bool firstTypeArg = true;
+ for (int typeArgIndex = 0; typeArgIndex < methodSignature.GenericParameterCount; typeArgIndex++)
+ {
+ if (firstTypeArg)
+ {
+ firstTypeArg = false;
+ }
+ else
+ {
+ builder.Append(", ");
+ }
+ builder.Append("!!");
+ builder.Append(typeArgIndex);
+ }
+ builder.Append(">");
+ }
+ builder.Append("(");
+ bool firstMethodArg = true;
+ foreach (string paramType in methodSignature.ParameterTypes)
+ {
+ if (firstMethodArg)
+ {
+ firstMethodArg = false;
+ }
+ else
+ {
+ builder.Append(", ");
+ }
+ builder.Append(paramType);
+ }
+ builder.Append(")");
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Emit containing type and method name and extract the method signature from a method reference.
+ /// </summary>
+ /// <param name="methodRef">Method reference to format</param>
+ /// <param name="methodSignature">Output method signature</param>
+ private string EmitContainingTypeAndMethodName(MemberReference methodRef)
+ {
+ return EmitHandleName(methodRef.Parent, namespaceQualified: true) + "." + EmitString(methodRef.Name);
+ }
+
+ /// <summary>
+ /// Emit type reference.
+ /// </summary>
+ /// <param name="typeRefHandle">Type reference handle</param>
+ /// <param name="namespaceQualified">When set to true, include namespace information</param>
+ private string EmitTypeReferenceName(TypeReferenceHandle typeRefHandle, bool namespaceQualified)
+ {
+ TypeReference typeRef = _metadataReader.GetTypeReference(typeRefHandle);
+ string typeName = EmitString(typeRef.Name);
+ string output = "";
+ if (typeRef.ResolutionScope.Kind != HandleKind.AssemblyReference)
+ {
+ // Nested type - format enclosing type followed by the nested type
+ return EmitHandleName(typeRef.ResolutionScope, namespaceQualified) + "+" + typeName;
+ }
+ if (namespaceQualified)
+ {
+ output = EmitString(typeRef.Namespace);
+ if (!string.IsNullOrEmpty(output))
+ {
+ output += ".";
+ }
+ }
+ return output + typeName;
+ }
+
+ /// <summary>
+ /// Emit a type definition.
+ /// </summary>
+ /// <param name="typeDefHandle">Type definition handle</param>
+ /// <param name="namespaceQualified">true = prefix type name with namespace information</param>
+ /// <returns></returns>
+ private string EmitTypeDefinitionName(TypeDefinitionHandle typeDefHandle, bool namespaceQualified)
+ {
+ TypeDefinition typeDef = _metadataReader.GetTypeDefinition(typeDefHandle);
+ string typeName = EmitString(typeDef.Name);
+ if (typeDef.IsNested)
+ {
+ // Nested type
+ return EmitHandleName(typeDef.GetDeclaringType(), namespaceQualified) + "+" + typeName;
+ }
+
+ string output;
+ if (namespaceQualified)
+ {
+ output = EmitString(typeDef.Namespace);
+ if (!string.IsNullOrEmpty(output))
+ {
+ output += ".";
+ }
+ }
+ else
+ {
+ output = "";
+ }
+ return output + typeName;
+ }
+
+ /// <summary>
+ /// Emit an arbitrary type specification.
+ /// </summary>
+ /// <param name="typeSpecHandle">Type specification handle</param>
+ /// <param name="namespaceQualified">When set to true, include namespace information</param>
+ private string EmitTypeSpecificationName(TypeSpecificationHandle typeSpecHandle, bool namespaceQualified)
+ {
+ TypeSpecification typeSpec = _metadataReader.GetTypeSpecification(typeSpecHandle);
+ DisassemblingGenericContext genericContext = new DisassemblingGenericContext(Array.Empty<string>(), Array.Empty<string>());
+ return typeSpec.DecodeSignature<string, DisassemblingGenericContext>(this, genericContext);
+ }
+
+ private string EmitString(StringHandle handle)
+ {
+ return _metadataReader.GetString(handle);
+ }
+ }
+
+ /// <summary>
+ /// Helper class used as state machine for decoding a single signature.
+ /// </summary>
+ public class SignatureDecoder
+ {
+ /// <summary>
+ /// Metadata reader is used to access the embedded MSIL metadata blob in the R2R file.
+ /// </summary>
+ private readonly MetadataReader _metadataReader;
+
+ /// <summary>
+ /// Byte array representing the R2R PE file read from disk.
+ /// </summary>
+ private readonly byte[] _image;
+
+ /// <summary>
+ /// Offset within the image file.
+ /// </summary>
+ private int _offset;
+
+ /// <summary>
+ /// Query signature parser for the current offset.
+ /// </summary>
+ public int Offset => _offset;
+
+ /// <summary>
+ /// Construct the signature decoder by storing the image byte array and offset within the array.
+ /// </summary>
+ /// <param name="reader">R2RReader object representing the R2R PE file</param>
+ /// <param name="offset">Signature offset within the array</param>
+ public SignatureDecoder(R2RReader reader, int offset)
+ {
+ _image = reader.Image;
+ _metadataReader = reader.MetadataReader;
+ _offset = offset;
+ }
+
+ /// <summary>
+ /// Read a single byte from the signature stream and advances the current offset.
+ /// </summary>
+ public byte ReadByte()
+ {
+ return _image[_offset++];
+ }
+
+ /// <summary>
+ /// Read a single unsigned 32-bit in from the signature stream. Adapted from CorSigUncompressData,
+ /// <a href="">https://github.com/dotnet/coreclr/blob/master/src/inc/cor.h</a>.
+ /// </summary>
+ /// <param name="data"></param>
+ public uint ReadUInt()
+ {
+ // Handle smallest data inline.
+ byte firstByte = ReadByte();
+ if ((firstByte & 0x80) == 0x00) // 0??? ????
+ return firstByte;
+
+ uint res;
+ // Medium.
+ if ((firstByte & 0xC0) == 0x80) // 10?? ????
+ {
+ res = ((uint)(firstByte & 0x3f) << 8);
+ res |= ReadByte();
+ }
+ else // 110? ????
+ {
+ res = (uint)(firstByte & 0x1f) << 24;
+ res |= (uint)ReadByte() << 16;
+ res |= (uint)ReadByte() << 8;
+ res |= (uint)ReadByte();
+ }
+ return res;
+ }
+
+ /// <summary>
+ /// Read a signed integer from the signature stream. Signed integer is basically encoded
+ /// as an unsigned integer after converting it to the unsigned number 2 * abs(x) + (x >= 0 ? 0 : 1).
+ /// Adapted from CorSigUncompressSignedInt, <a href="">https://github.com/dotnet/coreclr/blob/master/src/inc/cor.h</a>.
+ /// </summary>
+ public int ReadInt()
+ {
+ uint rawData = ReadUInt();
+ int data = (int)(rawData >> 1);
+ return ((rawData & 1) == 0 ? +data : -data);
+ }
+
+ /// <summary>
+ /// Read an encoded token from the stream. This encoding left-shifts the token RID twice and
+ /// fills in the two least-important bits with token type (typeDef, typeRef, typeSpec, baseType).
+ /// </summary>
+ public uint ReadToken()
+ {
+ uint encodedToken = ReadUInt();
+ uint rid = encodedToken >> 2;
+ CorTokenType type;
+ switch (encodedToken & 3)
+ {
+ case 0:
+ type = CorTokenType.mdtTypeDef;
+ break;
+
+ case 1:
+ type = CorTokenType.mdtTypeRef;
+ break;
+
+ case 2:
+ type = CorTokenType.mdtTypeSpec;
+ break;
+
+ case 3:
+ type = CorTokenType.mdtBaseType;
+ break;
+
+ default:
+ // This should never happen
+ throw new NotImplementedException();
+ }
+ return (uint)type | rid;
+ }
+
+ /// <summary>
+ /// Read a single element type from the signature stream. Adapted from CorSigUncompressElementType,
+ /// <a href="">https://github.com/dotnet/coreclr/blob/master/src/inc/cor.h</a>.
+ /// </summary>
+ /// <returns></returns>
+ public CorElementType ReadElementType()
+ {
+ return (CorElementType)(ReadByte() & 0x7F);
+ }
+
+ /// <summary>
+ /// Decode a R2R import signature. The signature starts with the fixup type followed
+ /// by custom encoding per fixup type.
+ /// </summary>
+ /// <returns></returns>
+ public string ReadR2RSignature()
+ {
+ StringBuilder builder = new StringBuilder();
+ ParseSignature(builder);
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Parse the signature into a given output string builder.
+ /// </summary>
+ /// <param name="builder"></param>
+ private void ParseSignature(StringBuilder builder)
+ {
+ uint fixupType = ReadUInt();
+ switch ((ReadyToRunFixupKind)fixupType)
+ {
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_ThisObjDictionaryLookup:
+ builder.Append("THIS_OBJ_DICTIONARY_LOOKUP");
+ // TODO
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionaryLookup:
+ builder.Append("TYPE_DICTIONARY_LOOKUP");
+ // TODO
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionaryLookup:
+ builder.Append("METHOD_DICTIONARY_LOOKUP");
+ // TODO
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_TypeHandle:
+ ParseType(builder);
+ builder.Append(" (TYPE_HANDLE)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodHandle:
+ builder.Append("METHOD_HANDLE");
+ // TODO
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldHandle:
+ builder.Append("FIELD_HANDLE");
+ // TODO
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry:
+ ParseMethod(builder);
+ builder.Append(" (METHOD_ENTRY)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_DefToken:
+ ParseMethodDefToken(builder);
+ builder.Append(" (METHOD_ENTRY_DEF_TOKEN)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_RefToken:
+ ParseMethodRefToken(builder);
+ builder.Append(" (METHOD_ENTRY_REF_TOKEN)");
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry:
+ ParseMethod(builder);
+ builder.Append(" (VIRTUAL_ENTRY)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_DefToken:
+ ParseMethodDefToken(builder);
+ builder.Append(" (VIRTUAL_ENTRY_DEF_TOKEN)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_RefToken:
+ ParseMethodRefToken(builder);
+ builder.Append(" (VIRTUAL_ENTRY_REF_TOKEN)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_Slot:
+ builder.Append("VIRTUAL_ENTRY_SLOT");
+ // TODO
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_Helper:
+ ParseHelper(builder);
+ builder.Append(" (HELPER)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_StringHandle:
+ ParseStringHandle(builder);
+ builder.Append(" (STRING_HANDLE)");
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_NewObject:
+ ParseType(builder);
+ builder.Append(" (NEW_OBJECT)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_NewArray:
+ ParseType(builder);
+ builder.Append(" (NEW_ARRAY)");
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_IsInstanceOf:
+ ParseType(builder);
+ builder.Append(" (IS_INSTANCE_OF)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_ChkCast:
+ ParseType(builder);
+ builder.Append(" (CHK_CAST)");
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldAddress:
+ builder.Append("FIELD_ADDRESS");
+ // TODO
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_CctorTrigger:
+ builder.Append("CCTOR_TRIGGER");
+ // TODO
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_StaticBaseNonGC:
+ ParseType(builder);
+ builder.Append(" (STATIC_BASE_NON_GC)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_StaticBaseGC:
+ ParseType(builder);
+ builder.Append(" (STATIC_BASE_GC)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_ThreadStaticBaseNonGC:
+ ParseType(builder);
+ builder.Append(" (THREAD_STATIC_BASE_NON_GC)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_ThreadStaticBaseGC:
+ ParseType(builder);
+ builder.Append(" (THREAD_STATIC_BASE_GC)");
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldBaseOffset:
+ builder.Append("FIELD_BASE_OFFSET");
+ // TODO
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_FieldOffset:
+ builder.Append("FIELD_OFFSET");
+ // TODO
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionary:
+ ParseType(builder);
+ builder.Append(" (TYPE_DICTIONARY)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionary:
+ ParseMethod(builder);
+ builder.Append(" (METHOD_DICTIONARY)");
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_Check_TypeLayout:
+ ParseType(builder);
+ builder.Append(" (CHECK_TYPE_LAYOUT)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_Check_FieldOffset:
+ builder.Append("CHECK_FIELD_OFFSET");
+ // TODO
+ break;
+
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_DelegateCtor:
+ ParseMethod(builder);
+ builder.Append(" => ");
+ ParseType(builder);
+ builder.Append(" (DELEGATE_CTOR)");
+ break;
+
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_DeclaringTypeHandle:
+ ParseType(builder);
+ builder.Append(" (DECLARING_TYPE_HANDLE)");
+ break;
+
+
+ default:
+ builder.Append(string.Format("Unknown fixup type: {0:X2}", fixupType));
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Decode a type from the signature stream.
+ /// </summary>
+ /// <param name="builder"></param>
+ private void ParseType(StringBuilder builder)
+ {
+ CorElementType corElemType = ReadElementType();
+ switch (corElemType)
+ {
+ case CorElementType.ELEMENT_TYPE_VOID:
+ builder.Append("void");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_BOOLEAN:
+ builder.Append("bool");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_CHAR:
+ builder.Append("char");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_I1:
+ builder.Append("sbyte");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_U1:
+ builder.Append("byte");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_I2:
+ builder.Append("short");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_U2:
+ builder.Append("ushort");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_I4:
+ builder.Append("int");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_U4:
+ builder.Append("uint");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_I8:
+ builder.Append("long");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_U8:
+ builder.Append("ulong");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_R4:
+ builder.Append("float");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_R8:
+ builder.Append("double");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_STRING:
+ builder.Append("string");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_PTR:
+ builder.Append("ptr");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_BYREF:
+ builder.Append("byref");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_VALUETYPE:
+ case CorElementType.ELEMENT_TYPE_CLASS:
+ ParseTypeToken(builder);
+ break;
+
+ case CorElementType.ELEMENT_TYPE_VAR:
+ builder.Append("var");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_ARRAY:
+ builder.Append("array");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_GENERICINST:
+ ParseGenericTypeInstance(builder);
+ break;
+
+ case CorElementType.ELEMENT_TYPE_TYPEDBYREF:
+ builder.Append("typedbyref");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_I:
+ builder.Append("IntPtr");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_U:
+ builder.Append("UIntPtr");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_FNPTR:
+ builder.Append("fnptr");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_OBJECT:
+ builder.Append("object");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_SZARRAY:
+ builder.Append("szarray");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_MVAR:
+ builder.Append("mvar");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_CMOD_REQD:
+ builder.Append("cmod_reqd");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_CMOD_OPT:
+ builder.Append("cmod_opt");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_HANDLE:
+ builder.Append("handle");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_SENTINEL:
+ builder.Append("sentinel");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_PINNED:
+ builder.Append("pinned");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_VAR_ZAPSIG:
+ builder.Append("var_zapsig");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG:
+ builder.Append("native_array_template_zapsig");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG:
+ builder.Append("native_valuetype_zapsig");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_CANON_ZAPSIG:
+ builder.Append("canon_zapsig");
+ break;
+
+ case CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG:
+ builder.Append("module_zapsig");
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ private void ParseGenericTypeInstance(StringBuilder builder)
+ {
+ ParseType(builder);
+ uint typeArgCount = ReadUInt();
+ builder.Append("<");
+ for (uint paramIndex = 0; paramIndex < typeArgCount; paramIndex++)
+ {
+ if (paramIndex > 0)
+ {
+ builder.Append(", ");
+ }
+ ParseType(builder);
+ }
+ builder.Append(">");
+ }
+
+ private void ParseTypeToken(StringBuilder builder)
+ {
+ uint token = ReadToken();
+ builder.Append(MetadataNameFormatter.FormatHandle(_metadataReader, MetadataTokens.Handle((int)token)));
+ }
+
+ /// <summary>
+ /// Parse an arbitrary method signature.
+ /// </summary>
+ /// <param name="builder">Output string builder to receive the textual signature representation</param>
+ private void ParseMethod(StringBuilder builder)
+ {
+ uint methodFlags = ReadUInt();
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0)
+ {
+ ParseType(builder);
+ }
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_SlotInsteadOfToken) != 0)
+ {
+ throw new NotImplementedException();
+ }
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken) != 0)
+ {
+ ParseMethodRefToken(builder);
+ }
+ else
+ {
+ ParseMethodDefToken(builder);
+ }
+
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0)
+ {
+ uint typeArgCount = ReadUInt();
+ builder.Append("<");
+ for (int typeArgIndex = 0; typeArgIndex < typeArgCount; typeArgIndex++)
+ {
+ if (typeArgIndex != 0)
+ {
+ builder.Append(", ");
+ }
+ ParseType(builder);
+ }
+ builder.Append(">");
+ }
+
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_Constrained) != 0)
+ {
+ builder.Append(" @ ");
+ ParseType(builder);
+ }
+ }
+
+ /// <summary>
+ /// Read a methodDef token from the signature and output the corresponding object to the builder.
+ /// </summary>
+ /// <param name="builder">Output string builder</param>
+ private void ParseMethodDefToken(StringBuilder builder)
+ {
+ uint methodDefToken = ReadUInt() | (uint)CorTokenType.mdtMethodDef;
+ builder.Append(MetadataNameFormatter.FormatHandle(_metadataReader, MetadataTokens.Handle((int)methodDefToken)));
+ }
+
+ /// <summary>
+ /// Read a memberRef token from the signature and output the corresponding object to the builder.
+ /// </summary>
+ /// <param name="builder">Output string builder</param>
+ private void ParseMethodRefToken(StringBuilder builder)
+ {
+ uint methodRefToken = ReadUInt() | (uint)CorTokenType.mdtMemberRef;
+ builder.Append(MetadataNameFormatter.FormatHandle(_metadataReader, MetadataTokens.Handle((int)methodRefToken)));
+ }
+
+ /// <summary>
+ /// Read R2R helper signature.
+ /// </summary>
+ /// <returns></returns>
+ private void ParseHelper(StringBuilder builder)
+ {
+ uint helperType = ReadUInt();
+ if ((helperType & (uint)ReadyToRunHelper.READYTORUN_HELPER_FLAG_VSD) != 0)
+ {
+ builder.Append("VSD_");
+ }
+
+ switch ((ReadyToRunHelper)(helperType & ~(uint)ReadyToRunHelper.READYTORUN_HELPER_FLAG_VSD))
+ {
+ case ReadyToRunHelper.READYTORUN_HELPER_Invalid:
+ builder.Append("INVALID");
+ break;
+
+ // Not a real helper - handle to current module passed to delay load helpers.
+ case ReadyToRunHelper.READYTORUN_HELPER_Module:
+ builder.Append("MODULE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_GSCookie:
+ builder.Append("GC_COOKIE");
+ break;
+
+
+ //
+ // Delay load helpers
+ //
+
+ // All delay load helpers use custom calling convention:
+ // - scratch register - address of indirection cell. 0 = address is inferred from callsite.
+ // - stack - section index, module handle
+ case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_MethodCall:
+ builder.Append("DELAYLOAD_METHODCALL");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper:
+ builder.Append("DELAYLOAD_HELPER");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper_Obj:
+ builder.Append("DELAYLOAD_HELPER_OBJ");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
+ builder.Append("DELAYLOAD_HELPER_OBJ_OBJ");
+ break;
+
+ // JIT helpers
+
+ // Exception handling helpers
+ case ReadyToRunHelper.READYTORUN_HELPER_Throw:
+ builder.Append("THROW");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Rethrow:
+ builder.Append("RETHROW");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Overflow:
+ builder.Append("OVERFLOW");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_RngChkFail:
+ builder.Append("RNG_CHK_FAIL");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_FailFast:
+ builder.Append("FAIL_FAST");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_ThrowNullRef:
+ builder.Append("THROW_NULL_REF");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_ThrowDivZero:
+ builder.Append("THROW_DIV_ZERO");
+ break;
+
+ // Write barriers
+ case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier:
+ builder.Append("WRITE_BARRIER");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier:
+ builder.Append("CHECKED_WRITE_BARRIER");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_ByRefWriteBarrier:
+ builder.Append("BYREF_WRITE_BARRIER");
+ break;
+
+ // Array helpers
+ case ReadyToRunHelper.READYTORUN_HELPER_Stelem_Ref:
+ builder.Append("STELEM_REF");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Ldelema_Ref:
+ builder.Append("LDELEMA_REF");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_MemSet:
+ builder.Append("MEM_SET");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_MemCpy:
+ builder.Append("MEM_CPY");
+ break;
+
+ // Get string handle lazily
+ case ReadyToRunHelper.READYTORUN_HELPER_GetString:
+ builder.Append("GET_STRING");
+ break;
+
+ // Used by /Tuning for Profile optimizations
+ case ReadyToRunHelper.READYTORUN_HELPER_LogMethodEnter:
+ builder.Append("LOG_METHOD_ENTER");
+ break;
+
+ // Reflection helpers
+ case ReadyToRunHelper.READYTORUN_HELPER_GetRuntimeTypeHandle:
+ builder.Append("GET_RUNTIME_TYPE_HANDLE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_GetRuntimeMethodHandle:
+ builder.Append("GET_RUNTIME_METHOD_HANDLE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_GetRuntimeFieldHandle:
+ builder.Append("GET_RUNTIME_FIELD_HANDLE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Box:
+ builder.Append("BOX");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Box_Nullable:
+ builder.Append("BOX_NULLABLE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Unbox:
+ builder.Append("UNBOX");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Unbox_Nullable:
+ builder.Append("UNBOX_NULLABLE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_NewMultiDimArr:
+ builder.Append("NEW_MULTI_DIM_ARR");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_NewMultiDimArr_NonVarArg:
+ builder.Append("NEW_MULTI_DIM_ARR__NON_VAR_ARG");
+ break;
+
+ // Helpers used with generic handle lookup cases
+ case ReadyToRunHelper.READYTORUN_HELPER_NewObject:
+ builder.Append("NEW_OBJECT");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_NewArray:
+ builder.Append("NEW_ARRAY");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckCastAny:
+ builder.Append("CHECK_CAST_ANY");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckInstanceAny:
+ builder.Append("CHECK_INSTANCE_ANY");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_GenericGcStaticBase:
+ builder.Append("GENERIC_GC_STATIC_BASE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_GenericNonGcStaticBase:
+ builder.Append("GENERIC_NON_GC_STATIC_BASE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_GenericGcTlsBase:
+ builder.Append("GENERIC_GC_TLS_BASE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_GenericNonGcTlsBase:
+ builder.Append("GENERIC_NON_GC_TLS_BASE");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_VirtualFuncPtr:
+ builder.Append("VIRTUAL_FUNC_PTR");
+ break;
+
+ // Long mul/div/shift ops
+ case ReadyToRunHelper.READYTORUN_HELPER_LMul:
+ builder.Append("LMUL");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_LMulOfv:
+ builder.Append("LMUL_OFV");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_ULMulOvf:
+ builder.Append("ULMUL_OVF");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_LDiv:
+ builder.Append("LDIV");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_LMod:
+ builder.Append("LMOD");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_ULDiv:
+ builder.Append("ULDIV");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_ULMod:
+ builder.Append("ULMOD");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_LLsh:
+ builder.Append("LLSH");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_LRsh:
+ builder.Append("LRSH");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_LRsz:
+ builder.Append("LRSZ");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Lng2Dbl:
+ builder.Append("LNG2DBL");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_ULng2Dbl:
+ builder.Append("ULNG2DBL");
+ break;
+
+ // 32-bit division helpers
+ case ReadyToRunHelper.READYTORUN_HELPER_Div:
+ builder.Append("DIV");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Mod:
+ builder.Append("MOD");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_UDiv:
+ builder.Append("UDIV");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_UMod:
+ builder.Append("UMOD");
+ break;
+
+ // Floating point conversions
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2Int:
+ builder.Append("DBL2INT");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2IntOvf:
+ builder.Append("DBL2INTOVF");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2Lng:
+ builder.Append("DBL2LNG");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2LngOvf:
+ builder.Append("DBL2LNGOVF");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2UInt:
+ builder.Append("DBL2UINT");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2UIntOvf:
+ builder.Append("DBL2UINTOVF");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2ULng:
+ builder.Append("DBL2ULNG");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_Dbl2ULngOvf:
+ builder.Append("DBL2ULNGOVF");
+ break;
+
+ // Floating point ops
+ case ReadyToRunHelper.READYTORUN_HELPER_DblRem:
+ builder.Append("DBL_REM");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_FltRem:
+ builder.Append("FLT_REM");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_DblRound:
+ builder.Append("DBL_ROUND");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_FltRound:
+ builder.Append("FLT_ROUND");
+ break;
+
+ // Personality rountines
+ case ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutine:
+ builder.Append("PERSONALITY_ROUTINE");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutineFilterFunclet:
+ builder.Append("PERSONALITY_ROUTINE_FILTER_FUNCLET");
+ break;
+
+ //
+ // Deprecated/legacy
+ //
+
+ // JIT32 x86-specific write barriers
+ case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EAX:
+ builder.Append("WRITE_BARRIER_EAX");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EBX:
+ builder.Append("WRITE_BARRIER_EBX");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_ECX:
+ builder.Append("WRITE_BARRIER_ECX");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_ESI:
+ builder.Append("WRITE_BARRIER_ESI");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EDI:
+ builder.Append("WRITE_BARRIER_EDI");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_WriteBarrier_EBP:
+ builder.Append("WRITE_BARRIER_EBP");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EAX:
+ builder.Append("CHECKED_WRITE_BARRIER_EAX");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EBX:
+ builder.Append("CHECKED_WRITE_BARRIER_EBX");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_ECX:
+ builder.Append("CHECKED_WRITE_BARRIER_ECX");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_ESI:
+ builder.Append("CHECKED_WRITE_BARRIER_ESI");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EDI:
+ builder.Append("CHECKED_WRITE_BARRIER_EDI");
+ break;
+ case ReadyToRunHelper.READYTORUN_HELPER_CheckedWriteBarrier_EBP:
+ builder.Append("CHECKED_WRITE_BARRIER_EBP");
+ break;
+
+ // JIT32 x86-specific exception handling
+ case ReadyToRunHelper.READYTORUN_HELPER_EndCatch:
+ builder.Append("END_CATCH");
+ break;
+
+ default:
+ builder.Append(string.Format("Unknown helper: {0:X2}", helperType));
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Read a string token from the signature stream and convert it to the actual string.
+ /// </summary>
+ /// <returns></returns>
+ private void ParseStringHandle(StringBuilder builder)
+ {
+ uint rid = ReadUInt();
+ UserStringHandle stringHandle = MetadataTokens.UserStringHandle((int)rid);
+ builder.Append(_metadataReader.GetUserString(stringHandle));
+ }
+ }
+}
List<Amd64.UnwindCode> codes = ((Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes[codeOffset];
foreach (Amd64.UnwindCode code in codes)
{
- _writer.Write($"\t\t\t\t{code.UnwindOp} {code.OpInfoStr}");
+ _writer.Write($" {code.UnwindOp} {code.OpInfoStr}");
if (code.NextFrameOffset != -1)
{
- _writer.WriteLine($" - {code.NextFrameOffset}");
+ _writer.WriteLine($" {code.NextFrameOffset}");
}
_writer.WriteLine();
}
{
foreach (BaseGcTransition transition in rtf.Method.GcInfo.Transitions[codeOffset])
{
- _writer.WriteLine($"\t\t\t\t{transition.ToString()}");
+ _writer.WriteLine($" {transition.ToString()}");
}
}