line[colon + 2] == ' ')
{
colon += 3;
- }
- nakedInstruction.Append(new string(' ', 32) + line.Substring(colon).TrimStart());
+ }
+
+ nakedInstruction.Append($"{(rtfOffset + rtf.CodeOffset),8:x4}:");
+ nakedInstruction.Append(" ");
+ nakedInstruction.Append(line.Substring(colon).TrimStart());
nakedInstruction.Append('\n');
}
else
{
- nakedInstruction.Append(line);
+ nakedInstruction.Append(' ', 7);
+ nakedInstruction.Append(line.TrimStart());
nakedInstruction.Append('\n');
}
}
switch (_reader.Machine)
{
case Machine.Amd64:
- case Machine.IA64:
ProbeX64Quirks(rtf, imageOffset, rtfOffset, instrSize, ref instruction);
break;
{
sbyte offset = (sbyte)_reader.Image[imageOffset + rtfOffset + 1];
int target = rtf.StartAddress + rtfOffset + instrSize + offset;
- ReplaceRelativeOffset(ref instruction, target);
+ ReplaceRelativeOffset(ref instruction, target, rtf);
}
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);
+ ReplaceRelativeOffset(ref instruction, target, rtf);
}
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);
+ ReplaceRelativeOffset(ref instruction, target, rtf);
}
}
/// </summary>
/// <param name="instruction"></param>
/// <param name="target"></param>
- private void ReplaceRelativeOffset(ref string instruction, int target)
+ private void ReplaceRelativeOffset(ref string instruction, int target, RuntimeFunction rtf)
{
int numberEnd = instruction.IndexOf('\n');
int number = numberEnd;
StringBuilder translated = new StringBuilder();
translated.Append(instruction, 0, number);
- translated.AppendFormat("0x{0:x4}", target);
+ int outputOffset = target;
+ if (_options.Naked)
+ {
+ outputOffset -= rtf.StartAddress;
+ }
+ translated.AppendFormat("0x{0:x4}", outputOffset);
translated.Append(instruction, numberEnd, instruction.Length - numberEnd);
instruction = translated.ToString();
}
--- /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.Diagnostics;
+using System.Runtime.InteropServices;
+using System.IO;
+
+namespace R2RDump
+{
+ public enum CORCOMPILE_GCREFMAP_TOKENS
+ {
+ GCREFMAP_SKIP = 0,
+ GCREFMAP_REF = 1,
+ GCREFMAP_INTERIOR = 2,
+ GCREFMAP_METHOD_PARAM = 3,
+ GCREFMAP_TYPE_PARAM = 4,
+ GCREFMAP_VASIG_COOKIE = 5,
+ }
+
+ public struct GCRefMapEntry
+ {
+ public readonly int Offset;
+ public readonly CORCOMPILE_GCREFMAP_TOKENS Token;
+
+ public GCRefMapEntry(int offset, CORCOMPILE_GCREFMAP_TOKENS token)
+ {
+ Offset = offset;
+ Token = token;
+ }
+ }
+
+ public class GCRefMap
+ {
+ public const int GCREFMAP_LOOKUP_STRIDE = 1024;
+
+ public const uint InvalidStackPop = ~0u;
+
+ public readonly uint StackPop;
+ public readonly GCRefMapEntry[] Entries;
+
+ public GCRefMap(uint stackPop, GCRefMapEntry[] entries)
+ {
+ StackPop = stackPop;
+ Entries = entries;
+ }
+
+ public void WriteTo(TextWriter writer)
+ {
+ if (StackPop != InvalidStackPop)
+ {
+ writer.Write(@"POP(0x{StackPop:X}) ");
+ }
+ for (int entryIndex = 0; entryIndex < Entries.Length; entryIndex++)
+ {
+ GCRefMapEntry entry = Entries[entryIndex];
+ if (entryIndex == 0 || entry.Token != Entries[entryIndex - 1].Token)
+ {
+ if (entryIndex != 0)
+ {
+ writer.Write(") ");
+ }
+ switch (entry.Token)
+ {
+ case CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_REF:
+ writer.Write("R");
+ break;
+ case CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_INTERIOR:
+ writer.Write("I");
+ break;
+ case CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_METHOD_PARAM:
+ writer.Write("M");
+ break;
+ case CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_TYPE_PARAM:
+ writer.Write("T");
+ break;
+ case CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_VASIG_COOKIE:
+ writer.Write("V");
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ writer.Write("(");
+ }
+ else
+ {
+ writer.Write(" ");
+ }
+ writer.Write($"{entry.Offset:X2}");
+ }
+ writer.Write(")");
+ }
+ }
+
+ /// <summary>
+ /// Helper class for decoding the bit-oriented GC ref map format.
+ /// </summary>
+ public class GCRefMapDecoder
+ {
+ private readonly R2RReader _reader;
+ private int _offset;
+ private int _pendingByte;
+ private int _pos;
+
+ public GCRefMapDecoder(R2RReader reader, int offset)
+ {
+ _reader = reader;
+ _offset = offset;
+ _pendingByte = 0x80;
+ _pos = 0;
+ }
+
+ public int GetBit()
+ {
+ int x = _pendingByte;
+ if ((x & 0x80) != 0)
+ {
+ x = _reader.Image[_offset++];
+ x |= ((x & 0x80) << 7);
+ }
+ _pendingByte = x >> 1;
+ return x & 1;
+ }
+
+ public int GetTwoBit()
+ {
+ int result = GetBit();
+ result |= GetBit() << 1;
+ return result;
+ }
+
+ public int GetInt()
+ {
+ int result = 0;
+
+ int bit = 0;
+ do
+ {
+ result |= GetBit() << (bit++);
+ result |= GetBit() << (bit++);
+ result |= GetBit() << (bit++);
+ }
+ while (GetBit() != 0);
+
+ return result;
+ }
+
+ public bool AtEnd()
+ {
+ return _pendingByte == 0;
+ }
+
+ public int GetOffset()
+ {
+ return _offset;
+ }
+
+ public uint ReadStackPop()
+ {
+ Debug.Assert(_reader.Architecture == Architecture.X86);
+
+ int x = GetTwoBit();
+
+ if (x == 3)
+ x = GetInt() + 3;
+
+ return (uint)x;
+ }
+
+ public int CurrentPos()
+ {
+ return _pos;
+ }
+
+ public CORCOMPILE_GCREFMAP_TOKENS ReadToken()
+ {
+ int val = GetTwoBit();
+ if (val == 3)
+ {
+ int ext = GetInt();
+ if ((ext & 1) == 0)
+ {
+ _pos += (ext >> 1) + 4;
+ return CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_SKIP;
+ }
+ else
+ {
+ _pos++;
+ return (CORCOMPILE_GCREFMAP_TOKENS)((ext >> 1) + 3);
+ }
+ }
+ _pos++;
+ return (CORCOMPILE_GCREFMAP_TOKENS)val;
+ }
+
+ public GCRefMap ReadMap()
+ {
+ TransitionBlock transitionBlock = TransitionBlock.FromReader(_reader);
+
+ List<GCRefMapEntry> entries = new List<GCRefMapEntry>();
+ uint stackPop = GCRefMap.InvalidStackPop;
+
+ if (_reader.Architecture == Architecture.X86)
+ {
+ stackPop = ReadStackPop();
+ }
+
+ while (!AtEnd())
+ {
+ int pos = CurrentPos();
+ CORCOMPILE_GCREFMAP_TOKENS token = ReadToken();
+ if (token != CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_SKIP)
+ {
+ int offset = transitionBlock.OffsetFromGCRefMapPos(pos);
+ entries.Add(new GCRefMapEntry(offset, token));
+ }
+ }
+
+ if (stackPop != GCRefMap.InvalidStackPop || entries.Count > 0)
+ {
+ return new GCRefMap(stackPop, entries.ToArray());
+ }
+
+ return null;
+ }
+ }
+}
using System;
using System.Collections.Generic;
+using System.IO;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Xml.Serialization;
/// </summary>
public struct R2RImportSection
{
- public struct ImportSectionEntry
+ public class ImportSectionEntry
{
[XmlAttribute("Index")]
public int Index { get; set; }
public long Section { get; set; }
public uint SignatureRVA { get; set; }
public string Signature { get; set; }
+ public GCRefMap GCRefMap { get; set; }
+
public ImportSectionEntry(int index, int startOffset, int startRVA, long section, uint signatureRVA, string signature)
{
Index = index;
Signature = signature;
}
- public override string ToString()
+ public void WriteTo(TextWriter writer, DumpOptions options)
{
- StringBuilder builder = new StringBuilder();
- builder.AppendFormat("+{0:X4}", StartOffset);
- builder.AppendFormat(" ({0:X4})", StartRVA);
- builder.AppendFormat(" Section: 0x{0:X8}", Section);
- builder.AppendFormat(" SignatureRVA: 0x{0:X8}", SignatureRVA);
- builder.AppendFormat(" {0}", Signature);
- return builder.ToString();
+ if (!options.Naked)
+ {
+ writer.Write($"+{StartOffset:X4}");
+ writer.Write($" ({StartRVA:X4})");
+ writer.Write($" Section: 0x{Section:X8}");
+ writer.Write($" SignatureRVA: 0x{SignatureRVA:X8}");
+ writer.Write(" ");
+ }
+ writer.Write(Signature);
+ if (GCRefMap != null)
+ {
+ writer.Write(" -- ");
+ GCRefMap.WriteTo(writer);
+ }
}
}
/// RVA of optional auxiliary data (typically GC info)
/// </summary>
public int AuxiliaryDataRVA { get; set; }
- [XmlIgnore]
- public BaseGcInfo AuxiliaryData { get; set; }
- public R2RImportSection(int index, byte[] image, int rva, int size, CorCompileImportFlags flags, byte type, byte entrySize, int signatureRVA, List<ImportSectionEntry> entries, int auxDataRVA, int auxDataOffset, Machine machine, ushort majorVersion)
+ public int AuxiliaryDataSize { get; set; }
+
+ public R2RImportSection(
+ int index,
+ R2RReader reader,
+ int rva,
+ int size,
+ CorCompileImportFlags flags,
+ byte type,
+ byte entrySize,
+ int signatureRVA,
+ List<ImportSectionEntry> entries,
+ int auxDataRVA,
+ int auxDataOffset,
+ Machine machine,
+ ushort majorVersion)
{
Index = index;
SectionRVA = rva;
Entries = entries;
AuxiliaryDataRVA = auxDataRVA;
- AuxiliaryData = null;
+ AuxiliaryDataSize = 0;
if (AuxiliaryDataRVA != 0)
{
- if (machine == Machine.Amd64)
- {
- AuxiliaryData = new Amd64.GcInfo(image, auxDataOffset, machine, majorVersion);
- }
- else if (machine == Machine.I386)
+ int startOffset = auxDataOffset + BitConverter.ToInt32(reader.Image, auxDataOffset);
+
+ for (int i = 0; i < Entries.Count; i++)
{
- AuxiliaryData = new x86.GcInfo(image, auxDataOffset, machine, majorVersion);
+ GCRefMapDecoder decoder = new GCRefMapDecoder(reader, startOffset);
+ Entries[i].GCRefMap = decoder.ReadMap();
+ startOffset = decoder.GetOffset();
}
+
+ AuxiliaryDataSize = startOffset - auxDataOffset;
}
}
+ public void WriteTo(TextWriter writer)
+ {
+ writer.WriteLine($"SectionRVA: 0x{SectionRVA:X8} ({SectionRVA})");
+ writer.WriteLine($"SectionSize: {SectionSize} bytes");
+ writer.WriteLine($"Flags: {Flags}");
+ writer.WriteLine($"Type: {Type}");
+ writer.WriteLine($"EntrySize: {EntrySize}");
+ writer.WriteLine($"SignatureRVA: 0x{SignatureRVA:X8} ({SignatureRVA})");
+ writer.WriteLine($"AuxiliaryDataRVA: 0x{AuxiliaryDataRVA:X8} ({AuxiliaryDataRVA})");
+ }
+
public override string ToString()
{
- StringBuilder sb = new StringBuilder();
- sb.AppendLine($"SectionRVA: 0x{SectionRVA:X8} ({SectionRVA})");
- sb.AppendLine($"SectionSize: {SectionSize} bytes");
- sb.AppendLine($"Flags: {Flags}");
- sb.AppendLine($"Type: {Type}");
- sb.AppendLine($"EntrySize: {EntrySize}");
- sb.AppendLine($"SignatureRVA: 0x{SignatureRVA:X8} ({SignatureRVA})");
- sb.AppendLine($"AuxiliaryDataRVA: 0x{AuxiliaryDataRVA:X8} ({AuxiliaryDataRVA})");
- if (AuxiliaryDataRVA != 0 && AuxiliaryData != null)
- {
- sb.AppendLine("AuxiliaryData:");
- sb.AppendLine(AuxiliaryData.ToString());
- }
- return sb.ToString();
+ throw new NotImplementedException();
}
}
}
public void WriteTo(TextWriter writer, DumpOptions options)
{
- writer.WriteLine($"Id: {Id}");
- writer.WriteLine($"StartAddress: 0x{StartAddress:X8}");
+ if (!options.Naked)
+ {
+ writer.WriteLine($"Id: {Id}");
+ writer.WriteLine($"StartAddress: 0x{StartAddress:X8}");
+ }
if (Size == -1)
{
writer.WriteLine("Size: Unavailable");
{
writer.WriteLine($"Size: {Size} bytes");
}
- writer.WriteLine($"UnwindRVA: 0x{UnwindRVA:X8}");
+ if (!options.Naked)
+ {
+ writer.WriteLine($"UnwindRVA: 0x{UnwindRVA:X8}");
+ }
if (UnwindInfo is Amd64.UnwindInfo amd64UnwindInfo)
{
string parsedFlags = "";
writer.WriteLine($"CountOfUnwindCodes: {amd64UnwindInfo.CountOfUnwindCodes}");
writer.WriteLine($"FrameRegister: {amd64UnwindInfo.FrameRegister}");
writer.WriteLine($"FrameOffset: 0x{amd64UnwindInfo.FrameOffset}");
- writer.WriteLine($"PersonalityRVA: 0x{amd64UnwindInfo.PersonalityRoutineRVA:X4}");
+ if (!options.Naked)
+ {
+ writer.WriteLine($"PersonalityRVA: 0x{amd64UnwindInfo.PersonalityRoutineRVA:X4}");
+ }
for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++)
{
writer.WriteLine($"Handle: 0x{MetadataTokens.GetToken(R2RReader.MetadataReader, MethodHandle):X8}");
writer.WriteLine($"Rid: {MetadataTokens.GetRowNumber(R2RReader.MetadataReader, MethodHandle)}");
- writer.WriteLine($"EntryPointRuntimeFunctionId: {EntryPointRuntimeFunctionId}");
+ if (!options.Naked)
+ {
+ writer.WriteLine($"EntryPointRuntimeFunctionId: {EntryPointRuntimeFunctionId}");
+ }
writer.WriteLine($"Number of RuntimeFunctions: {RuntimeFunctions.Count}");
if (Fixups != null)
{
foreach (FixupCell cell in fixups)
{
- writer.WriteLine($" TableIndex {cell.TableIndex}, Offset {cell.CellOffset:X4}: {cell.Signature}");
+ writer.Write(" ");
+ if (!options.Naked)
+ {
+ writer.WriteLine($"TableIndex {cell.TableIndex}, Offset {cell.CellOffset:X4}: ");
+ }
+ writer.WriteLine(cell.Signature);
}
}
}
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
+using System.Runtime.InteropServices;
using System.Text;
using System.Xml.Serialization;
/// </summary>
public Machine Machine { get; set; }
+ /// <summary>
+ /// Targeting operating system for the R2R executable
+ /// </summary>
public OperatingSystem OS { get; set; }
/// <summary>
+ /// Targeting processor architecture of the R2R executable
+ /// </summary>
+ public Architecture Architecture { get; set; }
+
+ /// <summary>
+ /// Pointer size in bytes for the target architecture
+ /// </summary>
+ public int PointerSize { get; set; }
+
+ /// <summary>
/// The preferred address of the first byte of image when loaded into memory;
/// must be a multiple of 64K.
/// </summary>
{
throw new BadImageFormatException($"Invalid Machine: {machine}");
}
+
+ switch (Machine)
+ {
+ case Machine.I386:
+ Architecture = Architecture.X86;
+ PointerSize = 4;
+ break;
+
+ case Machine.Amd64:
+ Architecture = Architecture.X64;
+ PointerSize = 8;
+ break;
+
+ case Machine.Arm:
+ case Machine.Thumb:
+ case Machine.ArmThumb2:
+ Architecture = Architecture.Arm;
+ PointerSize = 4;
+ break;
+
+ case Machine.Arm64:
+ Architecture = Architecture.Arm64;
+ PointerSize = 8;
+ break;
+
+ default:
+ throw new NotImplementedException(Machine.ToString());
+ }
+
+
ImageBase = PEReader.PEHeaders.PEHeader.ImageBase;
// initialize R2RHeader
break;
case Machine.Amd64:
- case Machine.IA64:
case Machine.Arm64:
entrySize = 8;
break;
{
auxDataOffset = GetOffset(auxDataRVA);
}
- ImportSections.Add(new R2RImportSection(ImportSections.Count, Image, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, R2RHeader.MajorVersion));
+ ImportSections.Add(new R2RImportSection(ImportSections.Count, this, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, R2RHeader.MajorVersion));
}
}
using System;
using System.Collections.Generic;
+using System.IO;
using System.Text;
using System.Xml.Serialization;
Size = size;
}
+ public void WriteTo(TextWriter writer, DumpOptions options)
+ {
+ writer.WriteLine($"Type: {Enum.GetName(typeof(SectionType), Type)} ({Type:D})");
+ if (!options.Naked)
+ {
+ writer.WriteLine($"RelativeVirtualAddress: 0x{RelativeVirtualAddress:X8}");
+ }
+ writer.WriteLine($"Size: {Size} bytes");
+ }
+
public override string ToString()
{
- StringBuilder sb = new StringBuilder();
- sb.AppendLine($"Type: {Enum.GetName(typeof(SectionType), Type)} ({Type:D})");
- sb.AppendLine($"RelativeVirtualAddress: 0x{RelativeVirtualAddress:X8}");
- sb.AppendLine($"Size: {Size} bytes");
- return sb.ToString();
+ throw new NotImplementedException();
}
}
}
foreach (R2RSection section in NormalizedSections())
{
- DumpSection(section);
+ DumpSection(section, parentNode: null);
}
}
SkipLine();
internal override void DumpSection(R2RSection section, XmlNode parentNode = null)
{
WriteSubDivider();
- _writer.WriteLine(section.ToString());
+ section.WriteTo(_writer, _options);
if (_options.Raw)
{
}
if (_options.SectionContents)
{
- DumpSectionContents(section);
+ DumpSectionContents(section, parentNode);
SkipLine();
}
}
/// </summary>
internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset, XmlNode parentNode = null)
{
+ int indent = (_options.Naked ? 11 : 32);
+ string indentString = new string(' ', indent);
int rtfOffset = 0;
int codeOffset = rtf.CodeOffset;
while (rtfOffset < rtf.Size)
List<Amd64.UnwindCode> codes = ((Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes[codeOffset];
foreach (Amd64.UnwindCode code in codes)
{
- _writer.Write($" {code.UnwindOp} {code.OpInfoStr}");
+ _writer.Write($"{indentString}{code.UnwindOp} {code.OpInfoStr}");
if (code.NextFrameOffset != -1)
{
- _writer.WriteLine($" {code.NextFrameOffset}");
+ _writer.WriteLine($"{indentString}{code.NextFrameOffset}");
}
_writer.WriteLine();
}
{
foreach (BaseGcTransition transition in rtf.Method.GcInfo.Transitions[codeOffset])
{
- _writer.WriteLine($" {transition.ToString()}");
+ _writer.WriteLine($"{indentString}{transition}");
}
}
{
foreach (R2RImportSection importSection in _r2r.ImportSections)
{
- _writer.Write(importSection.ToString());
+ importSection.WriteTo(_writer);
if (_options.Raw && importSection.Entries.Count != 0)
{
if (importSection.SectionRVA != 0)
_writer.WriteLine("Signature Bytes:");
DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int));
}
- if (importSection.AuxiliaryDataRVA != 0 && importSection.AuxiliaryData != null)
+ if (importSection.AuxiliaryDataRVA != 0 && importSection.AuxiliaryDataSize != 0)
{
_writer.WriteLine("AuxiliaryData Bytes:");
- DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size);
+ DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryDataSize);
}
}
foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries)
{
- _writer.WriteLine(entry.ToString());
+ entry.WriteTo(_writer, _options);
+ _writer.WriteLine();
}
_writer.WriteLine();
}
private void DumpNakedImportSections()
{
- List<string> importSignatures = new List<string>();
+ List<R2RImportSection.ImportSectionEntry> entries = new List<R2RImportSection.ImportSectionEntry>();
foreach (R2RImportSection importSection in _r2r.ImportSections)
{
- foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries)
- {
- importSignatures.Add(entry.Signature);
- }
+ entries.AddRange(importSection.Entries);
}
- importSignatures.Sort();
- foreach (string sig in importSignatures)
+ entries.Sort((e1, e2) => e1.Signature.CompareTo(e2.Signature));
+ foreach (R2RImportSection.ImportSectionEntry entry in entries)
{
- _writer.WriteLine(sig);
+ entry.WriteTo(_writer, _options);
+ _writer.WriteLine();
}
}
--- /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.Reflection.PortableExecutable;
+using System.Runtime.InteropServices;
+using System.IO;
+
+namespace R2RDump
+{
+ public abstract class TransitionBlock
+ {
+ public R2RReader _reader;
+
+ public static TransitionBlock FromReader(R2RReader reader)
+ {
+ switch (reader.Architecture)
+ {
+ case Architecture.X86:
+ return X86TransitionBlock.Instance;
+
+ case Architecture.X64:
+ return reader.OS == OperatingSystem.Windows ? X64WindowsTransitionBlock.Instance : X64UnixTransitionBlock.Instance;
+
+ case Architecture.Arm:
+ return ArmTransitionBlock.Instance;
+
+ case Architecture.Arm64:
+ return Arm64TransitionBlock.Instance;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+
+ public abstract int PointerSize { get; }
+
+ public abstract int NumArgumentRegisters { get; }
+
+ public int SizeOfArgumentRegisters => NumArgumentRegisters * PointerSize;
+
+ public abstract int NumCalleeSavedRegisters { get; }
+
+ public int SizeOfCalleeSavedRegisters => NumCalleeSavedRegisters * PointerSize;
+
+ public abstract int SizeOfTransitionBlock { get; }
+
+ public abstract int OffsetOfArgumentRegisters { get; }
+
+ /// <summary>
+ /// Recalculate pos in GC ref map to actual offset. This is the default implementation for all architectures
+ /// except for X86 where it's overridden to supply a more complex algorithm.
+ /// </summary>
+ /// <param name="pos"></param>
+ /// <returns></returns>
+ public virtual int OffsetFromGCRefMapPos(int pos)
+ {
+ return OffsetOfArgumentRegisters + pos * PointerSize;
+ }
+
+ /// <summary>
+ /// The transition block should define everything pushed by callee. The code assumes in number of places that
+ /// end of the transition block is caller's stack pointer.
+ /// </summary>
+ public int OffsetOfArgs => SizeOfTransitionBlock;
+
+ private sealed class X86TransitionBlock : TransitionBlock
+ {
+ public static readonly TransitionBlock Instance = new X86TransitionBlock();
+
+ public override int PointerSize => 4;
+ public override int NumArgumentRegisters => 2;
+ public override int NumCalleeSavedRegisters => 4;
+ // Argument registers, callee-save registers, return address
+ public override int SizeOfTransitionBlock => SizeOfArgumentRegisters + SizeOfCalleeSavedRegisters + PointerSize;
+ public override int OffsetOfArgumentRegisters => 0;
+
+ public override int OffsetFromGCRefMapPos(int pos)
+ {
+ if (pos < NumArgumentRegisters)
+ {
+ return OffsetOfArgumentRegisters + SizeOfArgumentRegisters - (pos + 1) * PointerSize;
+ }
+ else
+ {
+ return OffsetOfArgs + (pos - NumArgumentRegisters) * PointerSize;
+ }
+ }
+ }
+
+ private sealed class X64WindowsTransitionBlock : TransitionBlock
+ {
+ public static readonly TransitionBlock Instance = new X64WindowsTransitionBlock();
+
+ public override int PointerSize => 8;
+ // RCX, RDX, R8, R9
+ public override int NumArgumentRegisters => 4;
+ // RDI, RSI, RBX, RBP, R12, R13, R14, R15
+ public override int NumCalleeSavedRegisters => 8;
+ // Callee-saved registers, return address
+ public override int SizeOfTransitionBlock => SizeOfCalleeSavedRegisters + PointerSize;
+ public override int OffsetOfArgumentRegisters => SizeOfTransitionBlock;
+ }
+
+ private sealed class X64UnixTransitionBlock : TransitionBlock
+ {
+ public static readonly TransitionBlock Instance = new X64UnixTransitionBlock();
+
+ public override int PointerSize => 8;
+ // RDI, RSI, RDX, RCX, R8, R9
+ public override int NumArgumentRegisters => 6;
+ // R12, R13, R14, R15, RBX, RBP
+ public override int NumCalleeSavedRegisters => 6;
+ // Argument registers, callee-saved registers, return address
+ public override int SizeOfTransitionBlock => SizeOfArgumentRegisters + SizeOfCalleeSavedRegisters + PointerSize;
+ public override int OffsetOfArgumentRegisters => 0;
+ }
+
+ private sealed class ArmTransitionBlock : TransitionBlock
+ {
+ public static readonly TransitionBlock Instance = new ArmTransitionBlock();
+
+ public override int PointerSize => 4;
+ // R0, R1, R2, R3
+ public override int NumArgumentRegisters => 4;
+ // R4, R5, R6, R7, R8, R9, R10, R11, R14
+ public override int NumCalleeSavedRegisters => 9;
+ // Callee-saves, argument registers
+ public override int SizeOfTransitionBlock => SizeOfCalleeSavedRegisters + SizeOfArgumentRegisters;
+ public override int OffsetOfArgumentRegisters => SizeOfCalleeSavedRegisters;
+ }
+
+ private sealed class Arm64TransitionBlock : TransitionBlock
+ {
+ public static readonly TransitionBlock Instance = new Arm64TransitionBlock();
+
+ public override int PointerSize => 8;
+ // X0 .. X7
+ public override int NumArgumentRegisters => 8;
+ // X29, X30, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28
+ public override int NumCalleeSavedRegisters => 12;
+ // Callee-saves, padding, m_x8RetBuffReg, argument registers
+ public override int SizeOfTransitionBlock => SizeOfCalleeSavedRegisters + 2 * PointerSize + SizeOfArgumentRegisters;
+ public override int OffsetOfArgumentRegisters => SizeOfCalleeSavedRegisters + 2 * PointerSize;
+ }
+ }
+
+}
+
}
if (importSection.AuxiliaryDataRVA != 0)
{
- DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, importSectionsNode, "AuxiliaryDataBytes");
+ DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryDataSize, importSectionsNode, "AuxiliaryDataBytes");
}
}
foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries)