Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

R2RDump - Output in XML format #18425

Merged
merged 8 commits into from
Jun 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 63 additions & 41 deletions src/tools/r2rdump/Amd64/UnwindInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,24 @@ public enum UnwindOpCodes
UWOP_SET_FPREG_LARGE,
}

struct UnwindCode
public enum UnwindFlags
{
public byte CodeOffset { get; }
public UnwindOpCodes UnwindOp { get; } //4 bits
public byte OpInfo { get; } //4 bits
UNW_FLAG_NHANDLER = 0x0,
UNW_FLAG_EHANDLER = 0x1,
UNW_FLAG_UHANDLER = 0x2,
UNW_FLAG_CHAININFO = 0x4,
}

public struct UnwindCode
{
public byte CodeOffset { get; set; }
public UnwindOpCodes UnwindOp { get; set; } //4 bits
public byte OpInfo { get; set; } //4 bits

public byte OffsetLow { get; }
public byte OffsetHigh { get; } //4 bits
public byte OffsetLow { get; set; }
public byte OffsetHigh { get; set; } //4 bits

public uint FrameOffset { get; }
public uint FrameOffset { get; set; }

public UnwindCode(byte[] image, ref int offset)
{
Expand All @@ -48,20 +56,20 @@ public UnwindCode(byte[] image, ref int offset)
}
}

struct UnwindInfo : BaseUnwindInfo
public struct UnwindInfo : BaseUnwindInfo
{
private const int _sizeofUnwindCode = 2;
private const int _offsetofUnwindCode = 4;

public byte Version { get; } //3 bits
public byte Flags { get; } //5 bits
public byte SizeOfProlog { get; }
public byte CountOfUnwindCodes { get; }
public Amd64Registers FrameRegister { get; } //4 bits
public byte FrameOffset { get; } //4 bits
public UnwindCode[] UnwindCode { get; }
public uint PersonalityRoutineRVA { get; }
public int Size { get; }
public byte Version { get; set; } //3 bits
public byte Flags { get; set; } //5 bits
public byte SizeOfProlog { get; set; }
public byte CountOfUnwindCodes { get; set; }
public Amd64Registers FrameRegister { get; set; } //4 bits
public byte FrameOffset { get; set; } //4 bits
public UnwindCode[] UnwindCode { get; set; }
public uint PersonalityRoutineRVA { get; set; }
public int Size { get; set; }

public UnwindInfo(byte[] image, int offset)
{
Expand Down Expand Up @@ -92,7 +100,22 @@ public override string ToString()
StringBuilder sb = new StringBuilder();

sb.AppendLine($"\tVersion: {Version}");
sb.AppendLine($"\tFlags: 0x{Flags:X8}");
sb.Append($"\tFlags: 0x{Flags:X8} (");
if (Flags == (byte)UnwindFlags.UNW_FLAG_NHANDLER)
{
sb.Append(" UNW_FLAG_NHANDLER");
}
else
{
if ((Flags & (byte)UnwindFlags.UNW_FLAG_EHANDLER) != 0)
sb.Append(" UNW_FLAG_EHANDLER");
if ((Flags & (byte)UnwindFlags.UNW_FLAG_UHANDLER) != 0)
sb.Append(" UNW_FLAG_UHANDLER");
if ((Flags & (byte)UnwindFlags.UNW_FLAG_CHAININFO) != 0)
sb.Append(" UNW_FLAG_CHAININFO");
}
sb.AppendLine(" )");

sb.AppendLine($"\tSizeOfProlog: {SizeOfProlog}");
sb.AppendLine($"\tCountOfUnwindCodes: {CountOfUnwindCodes}");
sb.AppendLine($"\tFrameRegister: {FrameRegister}");
Expand All @@ -113,24 +136,23 @@ public override string ToString()
private string GetUnwindCode(ref int i)
{
StringBuilder sb = new StringBuilder();
string tab2 = new string(' ', 8);

sb.AppendLine($"{tab2}CodeOffset: 0x{UnwindCode[i].CodeOffset:X2}");
sb.AppendLine($"{tab2}UnwindOp: {UnwindCode[i].UnwindOp}({(byte)UnwindCode[i].UnwindOp})");
sb.AppendLine($"\t\tCodeOffset: 0x{UnwindCode[i].CodeOffset:X2}");
sb.AppendLine($"\t\tUnwindOp: {UnwindCode[i].UnwindOp}({(byte)UnwindCode[i].UnwindOp})");

switch (UnwindCode[i].UnwindOp)
{
case UnwindOpCodes.UWOP_PUSH_NONVOL:
sb.AppendLine($"{tab2}OpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
sb.AppendLine($"\t\tOpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
break;
case UnwindOpCodes.UWOP_ALLOC_LARGE:
sb.Append($"{tab2}OpInfo: {UnwindCode[i].OpInfo} - ");
sb.Append($"\t\tOpInfo: {UnwindCode[i].OpInfo} - ");
if (UnwindCode[i].OpInfo == 0)
{
i++;
sb.AppendLine("Scaled small");
uint frameOffset = UnwindCode[i].FrameOffset * 8;
sb.AppendLine($"{tab2}FrameOffset: {UnwindCode[i].FrameOffset} * 8 = {frameOffset} = 0x{frameOffset:X5})");
sb.AppendLine($"\t\tFrameOffset: {UnwindCode[i].FrameOffset} * 8 = {frameOffset} = 0x{frameOffset:X5})");
}
else if (UnwindCode[i].OpInfo == 1)
{
Expand All @@ -139,7 +161,7 @@ private string GetUnwindCode(ref int i)
uint offset = UnwindCode[i].FrameOffset;
i++;
offset = ((UnwindCode[i].FrameOffset << 16) | offset);
sb.AppendLine($"{tab2}FrameOffset: 0x{offset:X8})");
sb.AppendLine($"\t\tFrameOffset: 0x{offset:X8})");
}
else
{
Expand All @@ -148,19 +170,19 @@ private string GetUnwindCode(ref int i)
break;
case UnwindOpCodes.UWOP_ALLOC_SMALL:
int opInfo = UnwindCode[i].OpInfo * 8 + 8;
sb.AppendLine($"{tab2}OpInfo: {UnwindCode[i].OpInfo} * 8 + 8 = {opInfo} = 0x{opInfo:X2}");
sb.AppendLine($"\t\tOpInfo: {UnwindCode[i].OpInfo} * 8 + 8 = {opInfo} = 0x{opInfo:X2}");
break;
case UnwindOpCodes.UWOP_SET_FPREG:
sb.AppendLine($"{tab2}OpInfo: Unused({UnwindCode[i].OpInfo})");
sb.AppendLine($"\t\tOpInfo: Unused({UnwindCode[i].OpInfo})");
break;
case UnwindOpCodes.UWOP_SET_FPREG_LARGE:
{
sb.AppendLine($"{tab2}OpInfo: Unused({UnwindCode[i].OpInfo})");
sb.AppendLine($"\t\tOpInfo: Unused({UnwindCode[i].OpInfo})");
i++;
uint offset = UnwindCode[i].FrameOffset;
i++;
offset = ((UnwindCode[i].FrameOffset << 16) | offset);
sb.AppendLine($"{tab2}Scaled Offset: {offset} * 16 = {offset * 16} = 0x{(offset * 16):X8}");
sb.AppendLine($"\t\tScaled Offset: {offset} * 16 = {offset * 16} = 0x{(offset * 16):X8}");
if ((UnwindCode[i].FrameOffset & 0xF0000000) != 0)
{
R2RDump.WriteWarning("Illegal unwindInfo unscaled offset: too large");
Expand All @@ -169,51 +191,51 @@ private string GetUnwindCode(ref int i)
break;
case UnwindOpCodes.UWOP_SAVE_NONVOL:
{
sb.AppendLine($"{tab2}OpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
sb.AppendLine($"\t\tOpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
i++;
uint offset = UnwindCode[i].FrameOffset * 8;
sb.AppendLine($"{tab2}Scaled Offset: {UnwindCode[i].FrameOffset} * 8 = {offset} = 0x{offset:X5}");
sb.AppendLine($"\t\tScaled Offset: {UnwindCode[i].FrameOffset} * 8 = {offset} = 0x{offset:X5}");
}
break;
case UnwindOpCodes.UWOP_SAVE_NONVOL_FAR:
{
sb.AppendLine($"{tab2}OpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
sb.AppendLine($"\t\tOpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
i++;
uint offset = UnwindCode[i].FrameOffset;
i++;
offset = ((UnwindCode[i].FrameOffset << 16) | offset);
sb.AppendLine($"{tab2}Unscaled Large Offset: 0x{offset:X8}");
sb.AppendLine($"\t\tUnscaled Large Offset: 0x{offset:X8}");
}
break;
case UnwindOpCodes.UWOP_SAVE_XMM128:
{
sb.AppendLine($"{tab2}OpInfo: XMM{UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
sb.AppendLine($"\t\tOpInfo: XMM{UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
i++;
uint offset = UnwindCode[i].FrameOffset * 16;
sb.AppendLine($"{tab2}Scaled Offset: {UnwindCode[i].FrameOffset} * 16 = {offset} = 0x{offset:X5}");
sb.AppendLine($"\t\tScaled Offset: {UnwindCode[i].FrameOffset} * 16 = {offset} = 0x{offset:X5}");
}
break;

case UnwindOpCodes.UWOP_SAVE_XMM128_FAR:
{
sb.AppendLine($"{tab2}OpInfo: XMM{UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
sb.AppendLine($"\t\tOpInfo: XMM{UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})");
i++;
uint offset = UnwindCode[i].FrameOffset;
i++;
offset = ((UnwindCode[i].FrameOffset << 16) | offset);
sb.AppendLine($"{tab2}Unscaled Large Offset: 0x{offset:X8}");
sb.AppendLine($"\t\tUnscaled Large Offset: 0x{offset:X8}");
}
break;
case UnwindOpCodes.UWOP_EPILOG:
case UnwindOpCodes.UWOP_SPARE_CODE:
case UnwindOpCodes.UWOP_PUSH_MACHFRAME:
default:
sb.AppendLine($"{tab2}OpInfo: {UnwindCode[i].OpInfo}");
sb.AppendLine($"\t\tOpInfo: {UnwindCode[i].OpInfo}");
sb.AppendLine();
sb.AppendLine($"{tab2}OffsetLow: {UnwindCode[i].OffsetLow}");
sb.AppendLine($"{tab2}OffsetHigh: {UnwindCode[i].OffsetHigh}");
sb.AppendLine($"\t\tOffsetLow: {UnwindCode[i].OffsetLow}");
sb.AppendLine($"\t\tOffsetHigh: {UnwindCode[i].OffsetHigh}");
sb.AppendLine();
sb.AppendLine($"{tab2}FrameOffset: {FrameOffset}");
sb.AppendLine($"\t\tFrameOffset: {FrameOffset}");
break;
}
return sb.ToString();
Expand Down
35 changes: 8 additions & 27 deletions src/tools/r2rdump/CoreDisTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,36 +42,17 @@ public enum TargetArch
[DllImport(_dll)]
public static extern void FinishDisasm(IntPtr Disasm);

public unsafe static string GetCodeBlock(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image)
public unsafe static int GetInstruction(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, int rtfOffset, byte[] image, out string instr)
{
StringBuilder sb = new StringBuilder();

int rtfOffset = 0;
int codeOffset = rtf.CodeOffset;
Dictionary<int, GcInfo.GcTransition> transitions = rtf.Method.GcInfo.Transitions;
GcSlotTable slotTable = rtf.Method.GcInfo.SlotTable;
while (rtfOffset < rtf.Size)
int instrSize = 1;
fixed (byte* p = image)
{
int instrSize = 1;
fixed (byte* p = image)
{
IntPtr ptr = (IntPtr)(p + imageOffset + rtfOffset);
instrSize = DumpInstruction(Disasm, (ulong)(rtf.StartAddress + rtfOffset), ptr, rtf.Size);
}
IntPtr pBuffer = GetOutputBuffer();
string instr = Marshal.PtrToStringAnsi(pBuffer);

sb.Append(instr);
if (transitions.ContainsKey(codeOffset))
{
sb.AppendLine($"\t\t\t\t{transitions[codeOffset].GetSlotState(slotTable)}");
}

ClearOutputBuffer();
rtfOffset += instrSize;
codeOffset += instrSize;
IntPtr ptr = (IntPtr)(p + imageOffset + rtfOffset);
instrSize = DumpInstruction(Disasm, (ulong)(rtf.StartAddress + rtfOffset), ptr, rtf.Size);
}
return sb.ToString();
IntPtr pBuffer = GetOutputBuffer();
instr = Marshal.PtrToStringAnsi(pBuffer);
return instrSize;
}

public static IntPtr GetDisasm(Machine machine)
Expand Down
65 changes: 36 additions & 29 deletions src/tools/r2rdump/GCInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
using System.Collections.Generic;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Xml.Serialization;

namespace R2RDump
{
class GcInfo
public class GcInfo
{
private enum GcInfoHeaderFlags
{
Expand All @@ -33,8 +34,8 @@ private enum GcInfoHeaderFlags

public struct InterruptibleRange
{
public uint StartOffset { get; }
public uint StopOffset { get; }
public uint StartOffset { get; set; }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you make all the properties publicly writeable? I thought the idea was they get set as we read each data structure from the image and from then on these should all be immutable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XmlSerializer required the properties to have a public setter. When it didn't have one, it didn't serialize those properties

public uint StopOffset { get; set; }
public InterruptibleRange(uint start, uint stop)
{
StartOffset = start;
Expand All @@ -45,9 +46,11 @@ public InterruptibleRange(uint start, uint stop)
public class GcTransition
{
public int CodeOffset { get; set; }
public int SlotId { get; }
public bool IsLive { get; }
public int ChunkId { get; }
public int SlotId { get; set; }
public bool IsLive { get; set; }
public int ChunkId { get; set; }

public GcTransition() { }

public GcTransition(int codeOffset, int slotId, bool isLive, int chunkId)
{
Expand Down Expand Up @@ -104,27 +107,31 @@ public string GetSlotState(GcSlotTable slotTable)
private Machine _machine;
private GcInfoTypes _gcInfoTypes;

public int Version { get; }
public int CodeLength { get; }
public ReturnKinds ReturnKind { get; }
public uint ValidRangeStart { get; }
public uint ValidRangeEnd { get; }
public int SecurityObjectStackSlot { get; }
public int GSCookieStackSlot { get; }
public int PSPSymStackSlot { get; }
public int GenericsInstContextStackSlot { get; }
public uint StackBaseRegister { get; }
public uint SizeOfEditAndContinuePreservedArea { get; }
public int ReversePInvokeFrameStackSlot { get; }
public uint SizeOfStackOutgoingAndScratchArea { get; }
public uint NumSafePoints { get; }
public uint NumInterruptibleRanges { get; }
public IEnumerable<uint> SafePointOffsets { get; }
public IEnumerable<InterruptibleRange> InterruptibleRanges { get; }
public GcSlotTable SlotTable { get; }
public int Size { get; }
public int Offset { get; }
public Dictionary<int, GcTransition> Transitions { get; }
public int Version { get; set; }
public int CodeLength { get; set; }
public ReturnKinds ReturnKind { get; set; }
public uint ValidRangeStart { get; set; }
public uint ValidRangeEnd { get; set; }
public int SecurityObjectStackSlot { get; set; }
public int GSCookieStackSlot { get; set; }
public int PSPSymStackSlot { get; set; }
public int GenericsInstContextStackSlot { get; set; }
public uint StackBaseRegister { get; set; }
public uint SizeOfEditAndContinuePreservedArea { get; set; }
public int ReversePInvokeFrameStackSlot { get; set; }
public uint SizeOfStackOutgoingAndScratchArea { get; set; }
public uint NumSafePoints { get; set; }
public uint NumInterruptibleRanges { get; set; }
public List<uint> SafePointOffsets { get; set; }
public List<InterruptibleRange> InterruptibleRanges { get; set; }
public GcSlotTable SlotTable { get; set; }
public int Size { get; set; }
public int Offset { get; set; }

[XmlIgnore]
public Dictionary<int, GcTransition> Transitions { get; set; }

public GcInfo() { }

public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion)
{
Expand Down Expand Up @@ -335,7 +342,7 @@ private void ParseHeaderFlags(byte[] image, ref int bitOffset)
_wantsReportOnlyLeaf = ((headerFlags & GcInfoHeaderFlags.GC_INFO_WANTS_REPORT_ONLY_LEAF) != 0);
}

private IEnumerable<uint> EnumerateSafePoints(byte[] image, ref int bitOffset)
private List<uint> EnumerateSafePoints(byte[] image, ref int bitOffset)
{
List<uint> safePoints = new List<uint>();
uint numBitsPerOffset = GcInfoTypes.CeilOfLog2(CodeLength);
Expand All @@ -347,7 +354,7 @@ private IEnumerable<uint> EnumerateSafePoints(byte[] image, ref int bitOffset)
return safePoints;
}

private IEnumerable<InterruptibleRange> EnumerateInterruptibleRanges(byte[] image, int interruptibleRangeDelta1EncBase, int interruptibleRangeDelta2EncBase, ref int bitOffset)
private List<InterruptibleRange> EnumerateInterruptibleRanges(byte[] image, int interruptibleRangeDelta1EncBase, int interruptibleRangeDelta2EncBase, ref int bitOffset)
{
List<InterruptibleRange> ranges = new List<InterruptibleRange>();
uint lastinterruptibleRangeStopOffset = 0;
Expand Down
9 changes: 6 additions & 3 deletions src/tools/r2rdump/GCInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace R2RDump
{
class GcInfoTypes
public class GcInfoTypes
{
private Machine _target;

Expand Down Expand Up @@ -196,8 +196,11 @@ public enum GcStackSlotBase

public class GcStackSlot
{
public int SpOffset { get; }
public GcStackSlotBase Base { get; }
public int SpOffset { get; set; }
public GcStackSlotBase Base { get; set; }

public GcStackSlot() { }

public GcStackSlot(int spOffset, GcStackSlotBase stackSlotBase)
{
SpOffset = spOffset;
Expand Down
Loading