From 600dc1b49623d96e9b950756c229af637a6a7187 Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Mon, 11 Jun 2018 16:01:39 -0700 Subject: [PATCH 1/8] Add public to classes and set accessor to properties needed for serialization --- src/tools/r2rdump/GCInfo.cs | 10 ++++----- src/tools/r2rdump/GCInfoTypes.cs | 9 +++++--- src/tools/r2rdump/GCSlotTable.cs | 20 +++++++++-------- src/tools/r2rdump/R2RHeader.cs | 22 +++++++++--------- src/tools/r2rdump/R2RImportSection.cs | 2 +- src/tools/r2rdump/R2RMethod.cs | 32 ++++++++++++++++----------- src/tools/r2rdump/R2RReader.cs | 14 +++++++----- src/tools/r2rdump/R2RSection.cs | 8 +++---- 8 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/tools/r2rdump/GCInfo.cs b/src/tools/r2rdump/GCInfo.cs index cf57db62ac97..de2ce66bb169 100644 --- a/src/tools/r2rdump/GCInfo.cs +++ b/src/tools/r2rdump/GCInfo.cs @@ -9,7 +9,7 @@ namespace R2RDump { - class GcInfo + public class GcInfo { private enum GcInfoHeaderFlags { @@ -33,8 +33,8 @@ private enum GcInfoHeaderFlags public struct InterruptibleRange { - public uint StartOffset { get; } - public uint StopOffset { get; } + public uint StartOffset { get; set; } + public uint StopOffset { get; set; } public InterruptibleRange(uint start, uint stop) { StartOffset = start; @@ -335,7 +335,7 @@ private void ParseHeaderFlags(byte[] image, ref int bitOffset) _wantsReportOnlyLeaf = ((headerFlags & GcInfoHeaderFlags.GC_INFO_WANTS_REPORT_ONLY_LEAF) != 0); } - private IEnumerable EnumerateSafePoints(byte[] image, ref int bitOffset) + private List EnumerateSafePoints(byte[] image, ref int bitOffset) { List safePoints = new List(); uint numBitsPerOffset = GcInfoTypes.CeilOfLog2(CodeLength); @@ -347,7 +347,7 @@ private IEnumerable EnumerateSafePoints(byte[] image, ref int bitOffset) return safePoints; } - private IEnumerable EnumerateInterruptibleRanges(byte[] image, int interruptibleRangeDelta1EncBase, int interruptibleRangeDelta2EncBase, ref int bitOffset) + private List EnumerateInterruptibleRanges(byte[] image, int interruptibleRangeDelta1EncBase, int interruptibleRangeDelta2EncBase, ref int bitOffset) { List ranges = new List(); uint lastinterruptibleRangeStopOffset = 0; diff --git a/src/tools/r2rdump/GCInfoTypes.cs b/src/tools/r2rdump/GCInfoTypes.cs index 9b44a595a8ee..a285ebba5a19 100644 --- a/src/tools/r2rdump/GCInfoTypes.cs +++ b/src/tools/r2rdump/GCInfoTypes.cs @@ -8,7 +8,7 @@ namespace R2RDump { - class GcInfoTypes + public class GcInfoTypes { private Machine _target; @@ -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; diff --git a/src/tools/r2rdump/GCSlotTable.cs b/src/tools/r2rdump/GCSlotTable.cs index f2ebf414c688..d788f4dce288 100644 --- a/src/tools/r2rdump/GCSlotTable.cs +++ b/src/tools/r2rdump/GCSlotTable.cs @@ -9,13 +9,13 @@ namespace R2RDump { - class GcSlotTable + public class GcSlotTable { public struct GcSlot { - public int RegisterNumber { get; } - public GcStackSlot StackSlot { get; } - public GcSlotFlags Flags { get; } + public int RegisterNumber { get; set; } + public GcStackSlot StackSlot { get; set; } + public GcSlotFlags Flags { get; set; } public GcSlot(int registerNumber, GcStackSlot stack, GcSlotFlags flags, bool isUntracked = false) { @@ -50,11 +50,13 @@ public override string ToString() } } - public uint NumRegisters { get; } - public uint NumStackSlots { get; } - public uint NumUntracked { get; } - public uint NumSlots { get; } - public List GcSlots { get; } + public uint NumRegisters { get; set; } + public uint NumStackSlots { get; set; } + public uint NumUntracked { get; set; } + public uint NumSlots { get; set; } + public List GcSlots { get; set; } + + public GcSlotTable() { } public GcSlotTable(byte[] image, Machine machine, GcInfoTypes gcInfoTypes, ref int bitOffset) { diff --git a/src/tools/r2rdump/R2RHeader.cs b/src/tools/r2rdump/R2RHeader.cs index 96eacd583a92..cf7e65a0e968 100644 --- a/src/tools/r2rdump/R2RHeader.cs +++ b/src/tools/r2rdump/R2RHeader.cs @@ -8,7 +8,7 @@ namespace R2RDump { - class R2RHeader + public class R2RHeader { [Flags] public enum ReadyToRunFlag @@ -26,35 +26,37 @@ public enum ReadyToRunFlag /// /// RVA to the begining of the ReadyToRun header /// - public int RelativeVirtualAddress { get; } + public int RelativeVirtualAddress { get; set; } /// /// Size of the ReadyToRun header /// - public int Size { get; } + public int Size { get; set; } /// /// Signature of the header in string and hex formats /// - public string SignatureString { get; } - public uint Signature { get; } + public string SignatureString { get; set; } + public uint Signature { get; set; } /// /// The ReadyToRun version /// - public ushort MajorVersion { get; } - public ushort MinorVersion { get; } + public ushort MajorVersion { get; set; } + public ushort MinorVersion { get; set; } /// /// Flags in the header /// eg. PLATFORM_NEUTRAL_SOURCE, SKIP_TYPE_VALIDATION /// - public uint Flags { get; } + public uint Flags { get; set; } /// /// The ReadyToRun section RVAs and sizes /// - public Dictionary Sections { get; } + public IDictionary Sections { get; } + + public R2RHeader() { } /// /// Initializes the fields of the R2RHeader @@ -70,7 +72,7 @@ public R2RHeader(byte[] image, int rva, int curOffset) byte[] signature = new byte[sizeof(uint)]; Array.Copy(image, curOffset, signature, 0, sizeof(uint)); - SignatureString = System.Text.Encoding.UTF8.GetString(signature); + SignatureString = Encoding.UTF8.GetString(signature).Replace("\0", string.Empty); ; Signature = NativeReader.ReadUInt32(image, ref curOffset); if (Signature != READYTORUN_SIGNATURE) { diff --git a/src/tools/r2rdump/R2RImportSection.cs b/src/tools/r2rdump/R2RImportSection.cs index aa567d51e82c..e91ef3495eb7 100644 --- a/src/tools/r2rdump/R2RImportSection.cs +++ b/src/tools/r2rdump/R2RImportSection.cs @@ -9,7 +9,7 @@ namespace R2RDump { - struct R2RImportSection + public struct R2RImportSection { public enum CorCompileImportType { diff --git a/src/tools/r2rdump/R2RMethod.cs b/src/tools/r2rdump/R2RMethod.cs index 448b5b73e8f0..3851085045cf 100644 --- a/src/tools/r2rdump/R2RMethod.cs +++ b/src/tools/r2rdump/R2RMethod.cs @@ -9,6 +9,7 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Text; +using System.Xml.Serialization; namespace R2RDump { @@ -17,17 +18,17 @@ interface BaseUnwindInfo } - class RuntimeFunction + public class RuntimeFunction { /// /// The index of the runtime function /// - public int Id { get; } + public int Id { get; set; } /// /// The relative virtual address to the start of the code block /// - public int StartAddress { get; } + public int StartAddress { get; set; } /// /// The size of the code block in bytes @@ -36,12 +37,12 @@ class RuntimeFunction /// The EndAddress field in the runtime functions section is conditional on machine type /// Size is -1 for images without the EndAddress field /// - public int Size { get; } + public int Size { get; set; } /// /// The relative virtual address to the unwind info /// - public int UnwindRVA { get; } + public int UnwindRVA { get; set; } public int CodeOffset { get; set; } @@ -52,6 +53,8 @@ class RuntimeFunction public BaseUnwindInfo UnwindInfo { get; } + public RuntimeFunction() { } + public RuntimeFunction(int id, int startRva, int endRva, int unwindRva, int codeOffset, R2RMethod method, BaseUnwindInfo unwindInfo, GcInfo gcInfo) { Id = id; @@ -91,7 +94,7 @@ public override string ToString() } } - class R2RMethod + public class R2RMethod { private const int _mdtMethodDef = 0x06000000; @@ -101,31 +104,31 @@ class R2RMethod /// /// The name of the method /// - public string Name { get; } + public string Name { get; set; } /// /// The signature with format: namespace.class.methodName(S, T, ...) /// - public string SignatureString { get; } + public string SignatureString { get; set; } - public bool IsGeneric { get; } + public bool IsGeneric { get; set; } public MethodSignature Signature { get; } /// /// The type that the method belongs to /// - public string DeclaringType { get; } + public string DeclaringType { get; set; } /// /// The token of the method consisting of the table code (0x06) and row id /// - public uint Token { get; } + public uint Token { get; set; } /// /// The row id of the method /// - public uint Rid { get; } + public uint Rid { get; set; } /// /// All the runtime functions of this method @@ -135,8 +138,9 @@ class R2RMethod /// /// The id of the entrypoint runtime function /// - public int EntryPointRuntimeFunctionId { get; } + public int EntryPointRuntimeFunctionId { get; set; } + [XmlIgnore] public GcInfo GcInfo { get; set; } /// @@ -179,6 +183,8 @@ public enum GenericElementTypes Array = 0x1d, }; + public R2RMethod() { } + /// /// Extracts the method signature from the metadata by rid /// diff --git a/src/tools/r2rdump/R2RReader.cs b/src/tools/r2rdump/R2RReader.cs index b5d150b59750..56539dadbbfd 100644 --- a/src/tools/r2rdump/R2RReader.cs +++ b/src/tools/r2rdump/R2RReader.cs @@ -32,7 +32,7 @@ public enum Amd64Registers E15 = 15, } - class R2RReader + public class R2RReader { private readonly PEReader _peReader; private readonly MetadataReader _mdReader; @@ -45,23 +45,23 @@ class R2RReader /// /// Name of the image file /// - public string Filename { get; } + public string Filename { get; set; } /// /// True if the image is ReadyToRun /// - public bool IsR2R { get; } + public bool IsR2R { get; set; } /// /// The type of target machine /// - public Machine Machine { get; } + public Machine Machine { get; set; } /// /// The preferred address of the first byte of image when loaded into memory; /// must be a multiple of 64K. /// - public ulong ImageBase { get; } + public ulong ImageBase { get; set; } /// /// The ReadyToRun header @@ -85,6 +85,8 @@ class R2RReader public IList ImportSections { get; } + public unsafe R2RReader() { } + /// /// Initializes the fields of the R2RHeader and R2RMethods /// @@ -313,7 +315,7 @@ private string ParseCompilerIdentifier() byte[] identifier = new byte[compilerIdentifierSection.Size]; int identifierOffset = GetOffset(compilerIdentifierSection.RelativeVirtualAddress); Array.Copy(Image, identifierOffset, identifier, 0, compilerIdentifierSection.Size); - return Encoding.UTF8.GetString(identifier); + return Encoding.UTF8.GetString(identifier).Replace("\0", string.Empty); } private void ParseImportSections() diff --git a/src/tools/r2rdump/R2RSection.cs b/src/tools/r2rdump/R2RSection.cs index 8d6d7cf99c57..77cf24d98f11 100644 --- a/src/tools/r2rdump/R2RSection.cs +++ b/src/tools/r2rdump/R2RSection.cs @@ -8,7 +8,7 @@ namespace R2RDump { - struct R2RSection + public struct R2RSection { public enum SectionType { @@ -28,17 +28,17 @@ public enum SectionType /// /// The ReadyToRun section type /// - public SectionType Type { get; } + public SectionType Type { get; set; } /// /// The RVA to the section /// - public int RelativeVirtualAddress { get; } + public int RelativeVirtualAddress { get; set; } /// /// The size of the section /// - public int Size { get; } + public int Size { get; set; } public R2RSection(SectionType type, int rva, int size) { From dd9b69122d9daa136403fde86ee1ce023dfce792 Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Mon, 11 Jun 2018 16:02:50 -0700 Subject: [PATCH 2/8] Output in xml format with XmlSerializer --- src/tools/r2rdump/R2RDump.cs | 378 +++++++++++++++++++++++++++-------- 1 file changed, 297 insertions(+), 81 deletions(-) diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs index b909c1389a89..6546ed6c6093 100644 --- a/src/tools/r2rdump/R2RDump.cs +++ b/src/tools/r2rdump/R2RDump.cs @@ -6,6 +6,9 @@ using System.Collections.Generic; using System.CommandLine; using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; namespace R2RDump { @@ -14,6 +17,8 @@ class R2RDump private bool _help; private IReadOnlyList _inputFilenames = Array.Empty(); private string _outputFilename = null; + private bool _xml; + private XmlDocument _xmlDocument; private bool _raw; private bool _header; private bool _disasm; @@ -45,6 +50,7 @@ private ArgumentSyntax ParseCommandLine(string[] args) syntax.DefineOption("h|help", ref _help, "Help message for R2RDump"); syntax.DefineOptionList("i|in", ref _inputFilenames, "Input file(s) to dump. Expects them to by ReadyToRun images"); syntax.DefineOption("o|out", ref _outputFilename, "Output file path. Dumps everything to the specified file except help message and exception messages"); + syntax.DefineOption("x|xml", ref _xml, "Output in XML format"); syntax.DefineOption("raw", ref _raw, "Dump the raw bytes of each section or runtime function"); syntax.DefineOption("header", ref _header, "Dump R2R header"); syntax.DefineOption("d|disasm", ref _disasm, "Show disassembly of methods or runtime functions"); @@ -103,116 +109,216 @@ public static void WriteWarning(string warning) private void WriteDivider(string title) { + if (_xml) + return; int len = 61 - title.Length - 2; _writer.WriteLine(new String('=', len/2) + " " + title + " " + new String('=', (int)Math.Ceiling(len/2.0))); - _writer.WriteLine(); + SkipLine(); } private void WriteSubDivider() { + if(_xml) + return; _writer.WriteLine("_______________________________________________"); + SkipLine(); + } + + private void SkipLine() + { + if (_xml) + return; _writer.WriteLine(); } /// /// Dumps the R2RHeader and all the sections in the header /// - private void DumpHeader(R2RReader r2r, bool dumpSections) + private void DumpHeader(R2RReader r2r, bool dumpSections, XmlNode parentNode) { - _writer.WriteLine(r2r.R2RHeader.ToString()); + XmlNode headerNode = null; + if (_xml) + { + headerNode = _xmlDocument.CreateNode("element", "Header", ""); + parentNode.AppendChild(headerNode); + Serialize(r2r.R2RHeader, headerNode); + } + else + { + _writer.WriteLine(r2r.R2RHeader.ToString()); + } if (_raw) { - DumpBytes(r2r, r2r.R2RHeader.RelativeVirtualAddress, (uint)r2r.R2RHeader.Size); + DumpBytes(r2r, r2r.R2RHeader.RelativeVirtualAddress, (uint)r2r.R2RHeader.Size, headerNode); } - _writer.WriteLine(); + SkipLine(); if (dumpSections) { - WriteDivider("R2R Sections"); - _writer.WriteLine($"{r2r.R2RHeader.Sections.Count} sections"); - _writer.WriteLine(); + XmlNode sectionsNode = null; + if (_xml) + { + sectionsNode = _xmlDocument.CreateNode("element", "Sections", ""); + parentNode.AppendChild(sectionsNode); + AddXMLNode("Count", r2r.R2RHeader.Sections.Count.ToString(), sectionsNode); + } + else + { + WriteDivider("R2R Sections"); + _writer.WriteLine($"{r2r.R2RHeader.Sections.Count} sections"); + SkipLine(); + } foreach (R2RSection section in r2r.R2RHeader.Sections.Values) { - DumpSection(r2r, section); + DumpSection(r2r, section, sectionsNode); } } - _writer.WriteLine(); + SkipLine(); } /// /// Dumps one R2RSection /// - private void DumpSection(R2RReader r2r, R2RSection section) + private void DumpSection(R2RReader r2r, R2RSection section, XmlNode parentNode) { - WriteSubDivider(); - _writer.WriteLine(section.ToString()); + XmlNode sectionNode = null; + if (_xml) + { + sectionNode = _xmlDocument.CreateNode("element", "Section", ""); + parentNode.AppendChild(sectionNode); + Serialize(section, sectionNode); + } + else + { + WriteSubDivider(); + _writer.WriteLine(section.ToString()); + } + if (_raw) { - DumpBytes(r2r, section.RelativeVirtualAddress, (uint)section.Size); - _writer.WriteLine(); + DumpBytes(r2r, section.RelativeVirtualAddress, (uint)section.Size, sectionNode); + SkipLine(); } if (_sectionContents) { - DumpSectionContents(r2r, section); - _writer.WriteLine(); + DumpSectionContents(r2r, section, sectionNode); + SkipLine(); } } /// /// Dumps one R2RMethod. /// - private void DumpMethod(R2RReader r2r, R2RMethod method) + private void DumpMethod(R2RReader r2r, R2RMethod method, XmlNode parentNode) { - WriteSubDivider(); - _writer.WriteLine(method.ToString()); + XmlNode methodNode = null; + if (_xml) + { + methodNode = _xmlDocument.CreateNode("element", "Method", ""); + parentNode.AppendChild(methodNode); + Serialize(method, methodNode); + } + else + { + WriteSubDivider(); + _writer.WriteLine(method.ToString()); + } if (_gc) { - _writer.WriteLine("GcInfo:"); - _writer.Write(method.GcInfo); + if (_xml) + { + XmlNode gcNode = _xmlDocument.CreateNode("element", "GcInfo", ""); + methodNode.AppendChild(gcNode); + Serialize(method.GcInfo, gcNode); + } + else + { + _writer.WriteLine("GcInfo:"); + _writer.Write(method.GcInfo); + } + if (_raw) { - DumpBytes(r2r, method.GcInfo.Offset, (uint)method.GcInfo.Size, false); + DumpBytes(r2r, method.GcInfo.Offset, (uint)method.GcInfo.Size, methodNode, false); } } - _writer.WriteLine(); + SkipLine(); + XmlNode rtfsNode = null; + if (_xml) + { + rtfsNode = _xmlDocument.CreateNode("element", "RuntimeFunctions", ""); + methodNode.AppendChild(rtfsNode); + } foreach (RuntimeFunction runtimeFunction in method.RuntimeFunctions) { - DumpRuntimeFunction(r2r, runtimeFunction); + DumpRuntimeFunction(r2r, runtimeFunction, rtfsNode); } } /// /// Dumps one runtime function. /// - private void DumpRuntimeFunction(R2RReader r2r, RuntimeFunction rtf) + private void DumpRuntimeFunction(R2RReader r2r, RuntimeFunction rtf, XmlNode parentNode) { - _writer.Write($"{rtf}"); + XmlNode rtfNode = null; + if (_xml) + { + rtfNode = _xmlDocument.CreateNode("element", "RuntimeFunction", ""); + parentNode.AppendChild(rtfNode); + AddXMLNode("MethodRid", rtf.Method.Rid.ToString(), rtfNode); + Serialize(rtf, rtfNode); + } + if (_disasm) { - _writer.Write(CoreDisTools.GetCodeBlock(_disassembler, rtf, r2r.GetOffset(rtf.StartAddress), r2r.Image)); + string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf.StartAddress, r2r.GetOffset(rtf.StartAddress), r2r.Image, rtf.Size); + if (_xml) + { + AddXMLNode("Disassembly", disassembly, rtfNode); + } + else + { + _writer.WriteLine($"Id: {rtf.Id}"); + _writer.Write(disassembly); + } + } + else if (!_xml) + { + _writer.Write($"{rtf}"); } if (_raw) { - _writer.WriteLine("Raw Bytes:"); - DumpBytes(r2r, rtf.StartAddress, (uint)rtf.Size); + if (!_xml) + _writer.WriteLine("Raw Bytes:"); + DumpBytes(r2r, rtf.StartAddress, (uint)rtf.Size, rtfNode); } if (_unwind) { - _writer.WriteLine("UnwindInfo:"); - _writer.Write(rtf.UnwindInfo); + XmlNode unwindNode = null; + if (_xml) + { + unwindNode = _xmlDocument.CreateNode("element", "UnwindInfo", ""); + rtfNode.AppendChild(unwindNode); + Serialize(rtf.UnwindInfo, unwindNode); + } + else + { + _writer.WriteLine("UnwindInfo:"); + _writer.Write(rtf.UnwindInfo); + } if (_raw) { - DumpBytes(r2r, rtf.UnwindRVA, (uint)((Amd64.UnwindInfo)rtf.UnwindInfo).Size); + DumpBytes(r2r, rtf.UnwindRVA, (uint)((Amd64.UnwindInfo)rtf.UnwindInfo).Size, unwindNode); } } - _writer.WriteLine(); + SkipLine(); } /// /// Prints a formatted string containing a block of bytes from the relative virtual address and size /// - public void DumpBytes(R2RReader r2r, int rva, uint size, bool convertToOffset = true) + public void DumpBytes(R2RReader r2r, int rva, uint size, XmlNode parentNode, bool convertToOffset = true) { int start = rva; if (convertToOffset) @@ -221,6 +327,19 @@ public void DumpBytes(R2RReader r2r, int rva, uint size, bool convertToOffset = { throw new IndexOutOfRangeException(); } + + if (_xml && parentNode != null) + { + StringBuilder sb = new StringBuilder(); + sb.Append($"{r2r.Image[start]:X2}"); + for (uint i = 1; i < size; i++) + { + sb.Append($" {r2r.Image[start + i]:X2}"); + } + AddXMLNode("Raw", sb.ToString(), parentNode); + return; + } + _writer.Write(" "); if (rva % 16 != 0) { @@ -237,26 +356,42 @@ public void DumpBytes(R2RReader r2r, int rva, uint size, bool convertToOffset = _writer.Write($" {r2r.Image[start + i]:X2}"); if ((rva + i) % 16 == 15 && i != size - 1) { - _writer.WriteLine(); + SkipLine(); _writer.Write(" "); } } - _writer.WriteLine(); + SkipLine(); } - private void DumpSectionContents(R2RReader r2r, R2RSection section) + private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode parentNode) { + XmlNode contentsNode = null; + if (_xml) + { + contentsNode = _xmlDocument.CreateNode("element", "Contents", ""); + parentNode.AppendChild(contentsNode); + } switch (section.Type) { case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: - uint availableTypesSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); - NativeParser availableTypesParser = new NativeParser(r2r.Image, availableTypesSectionOffset); - NativeHashtable availableTypes = new NativeHashtable(r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); - _writer.WriteLine(availableTypes.ToString()); + if(!_xml) + { + uint availableTypesSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); + NativeParser availableTypesParser = new NativeParser(r2r.Image, availableTypesSectionOffset); + NativeHashtable availableTypes = new NativeHashtable(r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); + _writer.WriteLine(availableTypes.ToString()); + } foreach (string name in r2r.AvailableTypes) { - _writer.WriteLine(name); + if (_xml) + { + AddXMLNode("AvailableType", name, contentsNode); + } + else + { + _writer.WriteLine(name); + } } break; case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: @@ -323,7 +458,7 @@ private void DumpSectionContents(R2RReader r2r, R2RSection section) /// The title to print, "R2R Methods by Query" or "R2R Methods by Keyword" /// The keywords/ids to search for /// Specifies whether to look for methods with names/signatures/ids matching the method exactly or partially - private void QueryMethod(R2RReader r2r, string title, IReadOnlyList queries, bool exact) + private void QueryMethod(R2RReader r2r, string title, IReadOnlyList queries, bool exact, XmlNode parentNode) { if (queries.Count > 0) { @@ -332,12 +467,22 @@ private void QueryMethod(R2RReader r2r, string title, IReadOnlyList quer foreach (string q in queries) { IList res = FindMethod(r2r, q, exact); - - _writer.WriteLine(res.Count + " result(s) for \"" + q + "\""); - _writer.WriteLine(); + XmlNode queryNode = null; + if (_xml) + { + queryNode = _xmlDocument.CreateNode("element", "Methods", ""); + parentNode.AppendChild(queryNode); + AddXMLNode("Query", q, queryNode); + AddXMLNode("Count", res.Count.ToString(), queryNode); + } + else + { + _writer.WriteLine(res.Count + " result(s) for \"" + q + "\""); + SkipLine(); + } foreach (R2RMethod method in res) { - DumpMethod(r2r, method); + DumpMethod(r2r, method, queryNode); } } } @@ -347,7 +492,7 @@ private void QueryMethod(R2RReader r2r, string title, IReadOnlyList quer /// /// Contains all the extracted info about the ReadyToRun image /// The names/values to search for - private void QuerySection(R2RReader r2r, IReadOnlyList queries) + private void QuerySection(R2RReader r2r, IReadOnlyList queries, XmlNode parentNode) { if (queries.Count > 0) { @@ -356,12 +501,22 @@ private void QuerySection(R2RReader r2r, IReadOnlyList queries) foreach (string q in queries) { IList res = FindSection(r2r, q); - - _writer.WriteLine(res.Count + " result(s) for \"" + q + "\""); - _writer.WriteLine(); + XmlNode queryNode = null; + if (_xml) + { + queryNode = _xmlDocument.CreateNode("element", "Sections", ""); + parentNode.AppendChild(queryNode); + AddXMLNode("Query", q, queryNode); + AddXMLNode("Count", res.Count.ToString(), queryNode); + } + else + { + _writer.WriteLine(res.Count + " result(s) for \"" + q + "\""); + SkipLine(); + } foreach (R2RSection section in res) { - DumpSection(r2r, section); + DumpSection(r2r, section, queryNode); } } } @@ -372,7 +527,7 @@ private void QuerySection(R2RReader r2r, IReadOnlyList queries) /// /// Contains all the extracted info about the ReadyToRun image /// The ids to search for - private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries) + private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries, XmlNode parentNode) { if (queries.Count > 0) { @@ -387,8 +542,19 @@ private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries) WriteWarning("Unable to find by id " + q); continue; } - _writer.WriteLine(rtf.Method.SignatureString); - DumpRuntimeFunction(r2r, rtf); + XmlNode queryNode = null; + if (_xml) + { + queryNode = _xmlDocument.CreateNode("element", "RuntimeFunctions", ""); + parentNode.AppendChild(queryNode); + AddXMLNode("Query", q.ToString(), queryNode); + AddXMLNode("Count", "1", queryNode); + } + else + { + _writer.WriteLine(rtf.Method.SignatureString); + } + DumpRuntimeFunction(r2r, rtf, queryNode); } } @@ -398,24 +564,44 @@ private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries) /// The structure containing the info of the ReadyToRun image public void Dump(R2RReader r2r) { - _writer.WriteLine($"Filename: {r2r.Filename}"); - _writer.WriteLine($"Machine: {r2r.Machine}"); - _writer.WriteLine($"ImageBase: 0x{r2r.ImageBase:X8}"); - _writer.WriteLine(); + XmlNode rootNode = null; + if (_xml) + { + rootNode = _xmlDocument.CreateNode("element", "R2RDump", ""); + _xmlDocument.AppendChild(rootNode); + Serialize(r2r, rootNode); + } + else + { + _writer.WriteLine($"Filename: {r2r.Filename}"); + _writer.WriteLine($"Machine: {r2r.Machine}"); + _writer.WriteLine($"ImageBase: 0x{r2r.ImageBase:X8}"); + SkipLine(); + } if (_queries.Count == 0 && _keywords.Count == 0 && _runtimeFunctions.Count == 0 && _sections.Count == 0) //dump all sections and methods { WriteDivider("R2R Header"); - DumpHeader(r2r, true); + DumpHeader(r2r, true, rootNode); if (!_header) { - WriteDivider("R2R Methods"); - _writer.WriteLine($"{r2r.R2RMethods.Count} methods"); - _writer.WriteLine(); + XmlNode methodsNode = null; + if (_xml) + { + methodsNode = _xmlDocument.CreateNode("element", "Methods", ""); + rootNode.AppendChild(methodsNode); + AddXMLNode("Count", r2r.R2RMethods.Count.ToString(), methodsNode); + } + else + { + WriteDivider("R2R Methods"); + _writer.WriteLine($"{r2r.R2RMethods.Count} methods"); + SkipLine(); + } foreach (R2RMethod method in r2r.R2RMethods) { - DumpMethod(r2r, method); + DumpMethod(r2r, method, methodsNode); } } } @@ -423,17 +609,37 @@ public void Dump(R2RReader r2r) { if (_header) { - DumpHeader(r2r, false); + DumpHeader(r2r, false, rootNode); } - QuerySection(r2r, _sections); - QueryRuntimeFunction(r2r, _runtimeFunctions); - QueryMethod(r2r, "R2R Methods by Query", _queries, true); - QueryMethod(r2r, "R2R Methods by Keyword", _keywords, false); + QuerySection(r2r, _sections, rootNode); + QueryRuntimeFunction(r2r, _runtimeFunctions, rootNode); + QueryMethod(r2r, "R2R Methods by Query", _queries, true, rootNode); + QueryMethod(r2r, "R2R Methods by Keyword", _keywords, false, rootNode); + } + if (!_xml) + { + _writer.WriteLine("============================================================="); + SkipLine(); + } + } + + private void Serialize(object obj, XmlNode node) + { + using (XmlWriter xmlWriter = node.CreateNavigator().AppendChild()) + { + xmlWriter.WriteWhitespace(""); + XmlSerializer Serializer = new XmlSerializer(obj.GetType()); + Serializer.Serialize(xmlWriter, obj); } + } - _writer.WriteLine("============================================================="); - _writer.WriteLine(); + private XmlNode AddXMLNode(String name, String contents, XmlNode parentNode) + { + XmlNode node = _xmlDocument.CreateNode("element", name, ""); + parentNode.AppendChild(node); + node.InnerText = contents; + return node; } /// @@ -545,15 +751,6 @@ public RuntimeFunction FindRuntimeFunction(R2RReader r2r, int rtfQuery) private int Run(string[] args) { ArgumentSyntax syntax = ParseCommandLine(args); - - if (_help) - { - _writer.WriteLine(syntax.GetHelpText()); - return 0; - } - - if (_inputFilenames.Count == 0) - throw new ArgumentException("Input filename must be specified (--in )"); // open output stream if (_outputFilename != null) @@ -565,11 +762,25 @@ private int Run(string[] args) _writer = Console.Out; } + if (_help) + { + _writer.WriteLine(syntax.GetHelpText()); + return 0; + } + + if (_inputFilenames.Count == 0) + throw new ArgumentException("Input filename must be specified (--in )"); + try { foreach (string filename in _inputFilenames) { R2RReader r2r = new R2RReader(filename); + if (_xml) + { + _xmlDocument = new XmlDocument(); + } + if (_disasm) { _disassembler = CoreDisTools.GetDisasm(r2r.Machine); @@ -581,6 +792,11 @@ private int Run(string[] args) { CoreDisTools.FinishDisasm(_disassembler); } + + if (_xml) + { + _xmlDocument.Save(_writer); + } } } catch (Exception e) From 52132d3f837da545610b5ad125dd5a9b19e4cc33 Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Fri, 15 Jun 2018 17:09:48 -0700 Subject: [PATCH 3/8] Make unwindinfo and gcinfo xml serializable --- src/tools/r2rdump/GCInfo.cs | 52 ++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/tools/r2rdump/GCInfo.cs b/src/tools/r2rdump/GCInfo.cs index de2ce66bb169..5e44e8f542fc 100644 --- a/src/tools/r2rdump/GCInfo.cs +++ b/src/tools/r2rdump/GCInfo.cs @@ -45,9 +45,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) { @@ -104,27 +106,29 @@ 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 SafePointOffsets { get; } - public IEnumerable InterruptibleRanges { get; } - public GcSlotTable SlotTable { get; } - public int Size { get; } - public int Offset { get; } - public Dictionary 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 SafePointOffsets { get; set; } + public List InterruptibleRanges { get; set; } + public GcSlotTable SlotTable { get; set; } + public int Size { get; set; } + public int Offset { get; set; } + public Dictionary Transitions { get; set; } + + public GcInfo() { } public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion) { From 3be7f69aec7164e9d2c13a01d52abaec277aeb46 Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Tue, 19 Jun 2018 17:57:52 -0700 Subject: [PATCH 4/8] XMLSerialize gc transitions and section contents --- src/tools/r2rdump/GCInfo.cs | 4 +- src/tools/r2rdump/R2RDump.cs | 121 ++++++++++++++++++-------- src/tools/r2rdump/R2RImportSection.cs | 25 +++--- 3 files changed, 99 insertions(+), 51 deletions(-) diff --git a/src/tools/r2rdump/GCInfo.cs b/src/tools/r2rdump/GCInfo.cs index 5e44e8f542fc..cf51c8b18146 100644 --- a/src/tools/r2rdump/GCInfo.cs +++ b/src/tools/r2rdump/GCInfo.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Reflection.PortableExecutable; using System.Text; +using System.Xml.Serialization; namespace R2RDump { @@ -126,7 +127,8 @@ public string GetSlotState(GcSlotTable slotTable) public GcSlotTable SlotTable { get; set; } public int Size { get; set; } public int Offset { get; set; } - public Dictionary Transitions { get; set; } + [XmlIgnore] + public Dictionary Transitions { get; } public GcInfo() { } diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs index 6546ed6c6093..1e6ccf6b487f 100644 --- a/src/tools/r2rdump/R2RDump.cs +++ b/src/tools/r2rdump/R2RDump.cs @@ -229,6 +229,8 @@ private void DumpMethod(R2RReader r2r, R2RMethod method, XmlNode parentNode) XmlNode gcNode = _xmlDocument.CreateNode("element", "GcInfo", ""); methodNode.AppendChild(gcNode); Serialize(method.GcInfo, gcNode); + + Serialize(new List(method.GcInfo.Transitions.Values), gcNode); } else { @@ -271,7 +273,7 @@ private void DumpRuntimeFunction(R2RReader r2r, RuntimeFunction rtf, XmlNode par if (_disasm) { - string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf.StartAddress, r2r.GetOffset(rtf.StartAddress), r2r.Image, rtf.Size); + string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf, r2r.GetOffset(rtf.StartAddress), r2r.Image); if (_xml) { AddXMLNode("Disassembly", disassembly, rtfNode); @@ -363,14 +365,8 @@ public void DumpBytes(R2RReader r2r, int rva, uint size, XmlNode parentNode, boo SkipLine(); } - private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode parentNode) + private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode contentsNode) { - XmlNode contentsNode = null; - if (_xml) - { - contentsNode = _xmlDocument.CreateNode("element", "Contents", ""); - parentNode.AppendChild(contentsNode); - } switch (section.Type) { case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: @@ -382,70 +378,119 @@ private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode pare _writer.WriteLine(availableTypes.ToString()); } - foreach (string name in r2r.AvailableTypes) + if (_xml) { - if (_xml) - { - AddXMLNode("AvailableType", name, contentsNode); - } - else + Serialize(r2r.AvailableTypes, contentsNode); + } + else + { + foreach (string name in r2r.AvailableTypes) { _writer.WriteLine(name); } } break; case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: - NativeArray methodEntryPoints = new NativeArray(r2r.Image, (uint)r2r.GetOffset(section.RelativeVirtualAddress)); - _writer.Write(methodEntryPoints.ToString()); + if (!_xml) + { + NativeArray methodEntryPoints = new NativeArray(r2r.Image, (uint)r2r.GetOffset(section.RelativeVirtualAddress)); + _writer.Write(methodEntryPoints.ToString()); + } break; case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS: - uint instanceSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); - NativeParser instanceParser = new NativeParser(r2r.Image, instanceSectionOffset); - NativeHashtable instMethodEntryPoints = new NativeHashtable(r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); - _writer.Write(instMethodEntryPoints.ToString()); + if (!_xml) + { + uint instanceSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); + NativeParser instanceParser = new NativeParser(r2r.Image, instanceSectionOffset); + NativeHashtable instMethodEntryPoints = new NativeHashtable(r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); + _writer.Write(instMethodEntryPoints.ToString()); + } break; case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: - int rtfOffset = r2r.GetOffset(section.RelativeVirtualAddress); - int rtfEndOffset = rtfOffset + section.Size; - int rtfIndex = 0; - while (rtfOffset < rtfEndOffset) + if (!_xml) { - uint rva = NativeReader.ReadUInt32(r2r.Image, ref rtfOffset); - _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}"); - rtfIndex++; + int rtfOffset = r2r.GetOffset(section.RelativeVirtualAddress); + int rtfEndOffset = rtfOffset + section.Size; + int rtfIndex = 0; + while (rtfOffset < rtfEndOffset) + { + uint rva = NativeReader.ReadUInt32(r2r.Image, ref rtfOffset); + _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}"); + rtfIndex++; + } } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: - _writer.WriteLine(r2r.CompileIdentifier); + if (!_xml) + { + _writer.WriteLine(r2r.CompileIdentifier); + } break; case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: foreach (R2RImportSection importSection in r2r.ImportSections) { - _writer.Write(importSection.ToString()); + if (_xml) + { + Serialize(importSection, contentsNode); + } + else + { + _writer.Write(importSection.ToString()); + } if (_raw && importSection.Entries.Count != 0) { if (importSection.SectionRVA != 0) { - _writer.WriteLine("Section Bytes:"); - DumpBytes(r2r, importSection.SectionRVA, (uint)importSection.SectionSize); + XmlNode bytesNode = null; + if (_xml) + { + bytesNode = _xmlDocument.CreateNode("element", "SectionBytes", ""); + contentsNode.AppendChild(bytesNode); + } + else + { + _writer.WriteLine("Section Bytes:"); + } + DumpBytes(r2r, importSection.SectionRVA, (uint)importSection.SectionSize, bytesNode); } if (importSection.SignatureRVA != 0) { - _writer.WriteLine("Signature Bytes:"); - DumpBytes(r2r, importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int)); + XmlNode bytesNode = null; + if (_xml) + { + bytesNode = _xmlDocument.CreateNode("element", "SignatureBytes", ""); + contentsNode.AppendChild(bytesNode); + } + else + { + _writer.WriteLine("Signature Bytes:"); + } + DumpBytes(r2r, importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int), bytesNode); } if (importSection.AuxiliaryDataRVA != 0) { - _writer.WriteLine("AuxiliaryData Bytes:"); - DumpBytes(r2r, importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size); + XmlNode bytesNode = null; + if (_xml) + { + bytesNode = _xmlDocument.CreateNode("element", "AuxiliaryDataBytes", ""); + contentsNode.AppendChild(bytesNode); + } + else + { + _writer.WriteLine("AuxiliaryData Bytes:"); + } + DumpBytes(r2r, importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, bytesNode); } } - foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) + if (!_xml) { + foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) + { + _writer.WriteLine(); + _writer.WriteLine(entry.ToString()); + } _writer.WriteLine(); - _writer.WriteLine(entry.ToString()); } - _writer.WriteLine(); } break; } diff --git a/src/tools/r2rdump/R2RImportSection.cs b/src/tools/r2rdump/R2RImportSection.cs index e91ef3495eb7..4f591dff4d5e 100644 --- a/src/tools/r2rdump/R2RImportSection.cs +++ b/src/tools/r2rdump/R2RImportSection.cs @@ -24,6 +24,7 @@ public enum CorCompileImportType 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. @@ -31,9 +32,9 @@ public enum CorCompileImportFlags public struct ImportSectionEntry { - public long Section { get; } - public uint SignatureRVA { get; } - public uint Signature { get; } + public long Section { get; set; } + public uint SignatureRVA { get; set; } + public uint Signature { get; set; } public ImportSectionEntry(long section, uint signatureRVA, uint signature) { Section = section; @@ -54,35 +55,35 @@ public override string ToString() /// /// Section containing values to be fixed up /// - public int SectionRVA { get; } - public int SectionSize { get; } + public int SectionRVA { get; set; } + public int SectionSize { get; set; } /// /// One or more of ImportSectionFlags /// - public CorCompileImportFlags Flags { get; } + public CorCompileImportFlags Flags { get; set; } /// /// One of ImportSectionType /// - public CorCompileImportType Type { get; } + public CorCompileImportType Type { get; set; } /// /// /// - public byte EntrySize { get; } + public byte EntrySize { get; set; } /// /// RVA of optional signature descriptors /// - public int SignatureRVA { get; } - public List Entries { get; } + public int SignatureRVA { get; set; } + public List Entries { get; set; } /// /// RVA of optional auxiliary data (typically GC info) /// - public int AuxiliaryDataRVA { get; } - public GcInfo AuxiliaryData { get; } + public int AuxiliaryDataRVA { get; set; } + public GcInfo AuxiliaryData { get; set; } public R2RImportSection(byte[] image, int rva, int size, CorCompileImportFlags flags, byte type, byte entrySize, int signatureRVA, List entries, int auxDataRVA, int auxDataOffset, Machine machine, ushort majorVersion) { From 5678ab7e406ba8040aff07cb9364c70ac6042d83 Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Thu, 21 Jun 2018 18:31:22 -0700 Subject: [PATCH 5/8] Xml serialize section contents and gcinfo transitions --- src/tools/r2rdump/GCInfo.cs | 3 ++- src/tools/r2rdump/R2RDump.cs | 40 +++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/tools/r2rdump/GCInfo.cs b/src/tools/r2rdump/GCInfo.cs index cf51c8b18146..c423eabf2af2 100644 --- a/src/tools/r2rdump/GCInfo.cs +++ b/src/tools/r2rdump/GCInfo.cs @@ -127,8 +127,9 @@ public string GetSlotState(GcSlotTable slotTable) public GcSlotTable SlotTable { get; set; } public int Size { get; set; } public int Offset { get; set; } + [XmlIgnore] - public Dictionary Transitions { get; } + public Dictionary Transitions { get; set; } public GcInfo() { } diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs index 1e6ccf6b487f..6606b49d2a12 100644 --- a/src/tools/r2rdump/R2RDump.cs +++ b/src/tools/r2rdump/R2RDump.cs @@ -230,7 +230,10 @@ private void DumpMethod(R2RReader r2r, R2RMethod method, XmlNode parentNode) methodNode.AppendChild(gcNode); Serialize(method.GcInfo, gcNode); - Serialize(new List(method.GcInfo.Transitions.Values), gcNode); + foreach (KeyValuePair transition in method.GcInfo.Transitions) + { + Serialize(transition, gcNode); + } } else { @@ -407,21 +410,29 @@ private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode cont } break; case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: - if (!_xml) + int rtfOffset = r2r.GetOffset(section.RelativeVirtualAddress); + int rtfEndOffset = rtfOffset + section.Size; + int rtfIndex = 0; + while (rtfOffset < rtfEndOffset) { - int rtfOffset = r2r.GetOffset(section.RelativeVirtualAddress); - int rtfEndOffset = rtfOffset + section.Size; - int rtfIndex = 0; - while (rtfOffset < rtfEndOffset) + uint rva = NativeReader.ReadUInt32(r2r.Image, ref rtfOffset); + if (_xml) + { + AddXMLNode($"{rtfIndex}", $"0x{rva:X8}", contentsNode); + } + else { - uint rva = NativeReader.ReadUInt32(r2r.Image, ref rtfOffset); _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}"); - rtfIndex++; } + rtfIndex++; } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: - if (!_xml) + if(_xml) + { + AddXMLNode("CompileIdentifier", r2r.CompileIdentifier, contentsNode); + } + else { _writer.WriteLine(r2r.CompileIdentifier); } @@ -482,15 +493,20 @@ private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode cont DumpBytes(r2r, importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, bytesNode); } } - if (!_xml) + foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) { - foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) + if (_xml) + { + Serialize(entry, contentsNode); + } + else { _writer.WriteLine(); _writer.WriteLine(entry.ToString()); } - _writer.WriteLine(); } + if (!_xml) + _writer.WriteLine(); } break; } From f377d7b4c3771cba99189b957349001878a23840 Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Fri, 22 Jun 2018 16:17:24 -0700 Subject: [PATCH 6/8] Refactor into TextDumper and XmlDumper classes --- src/tools/r2rdump/R2RDump.cs | 582 ++++---------------------------- src/tools/r2rdump/R2RHeader.cs | 6 +- src/tools/r2rdump/R2RReader.cs | 6 +- src/tools/r2rdump/TextDumper.cs | 286 ++++++++++++++++ src/tools/r2rdump/XmlDumper.cs | 309 +++++++++++++++++ 5 files changed, 661 insertions(+), 528 deletions(-) create mode 100644 src/tools/r2rdump/TextDumper.cs create mode 100644 src/tools/r2rdump/XmlDumper.cs diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs index 6606b49d2a12..9a0062b331bb 100644 --- a/src/tools/r2rdump/R2RDump.cs +++ b/src/tools/r2rdump/R2RDump.cs @@ -12,13 +12,39 @@ namespace R2RDump { + abstract class Dumper + { + internal R2RReader _r2r; + internal bool _raw; + internal bool _header; + internal bool _disasm; + internal IntPtr _disassembler; + internal bool _unwind; + internal bool _gc; + internal bool _sectionContents; + internal TextWriter _writer; + + abstract internal void Begin(); + abstract internal void End(); + abstract internal void WriteDivider(string title); + abstract internal void WriteSubDivider(); + abstract internal void SkipLine(); + abstract internal void DumpHeader(bool dumpSections); + abstract internal void DumpSection(R2RSection section, XmlNode parentNode = null); + abstract internal void DumpAllMethods(); + abstract internal void DumpMethod(R2RMethod method, XmlNode parentNode = null); + abstract internal void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNode = null); + abstract internal void DumpBytes(int rva, uint size, XmlNode parentNode = null, bool convertToOffset = true); + abstract internal void DumpSectionContents(R2RSection section, XmlNode parentNode = null); + abstract internal XmlNode DumpQueryCount(string q, string title, int count); + } + class R2RDump { private bool _help; private IReadOnlyList _inputFilenames = Array.Empty(); private string _outputFilename = null; private bool _xml; - private XmlDocument _xmlDocument; private bool _raw; private bool _header; private bool _disasm; @@ -33,6 +59,7 @@ class R2RDump private bool _sectionContents; private TextWriter _writer; private Dictionary _selectedSections = new Dictionary(); + private Dumper _dumper; private R2RDump() { @@ -107,411 +134,6 @@ public static void WriteWarning(string warning) Console.WriteLine($"Warning: {warning}"); } - private void WriteDivider(string title) - { - if (_xml) - return; - int len = 61 - title.Length - 2; - _writer.WriteLine(new String('=', len/2) + " " + title + " " + new String('=', (int)Math.Ceiling(len/2.0))); - SkipLine(); - } - - private void WriteSubDivider() - { - if(_xml) - return; - _writer.WriteLine("_______________________________________________"); - SkipLine(); - } - - private void SkipLine() - { - if (_xml) - return; - _writer.WriteLine(); - } - - /// - /// Dumps the R2RHeader and all the sections in the header - /// - private void DumpHeader(R2RReader r2r, bool dumpSections, XmlNode parentNode) - { - XmlNode headerNode = null; - if (_xml) - { - headerNode = _xmlDocument.CreateNode("element", "Header", ""); - parentNode.AppendChild(headerNode); - Serialize(r2r.R2RHeader, headerNode); - } - else - { - _writer.WriteLine(r2r.R2RHeader.ToString()); - } - if (_raw) - { - DumpBytes(r2r, r2r.R2RHeader.RelativeVirtualAddress, (uint)r2r.R2RHeader.Size, headerNode); - } - SkipLine(); - if (dumpSections) - { - XmlNode sectionsNode = null; - if (_xml) - { - sectionsNode = _xmlDocument.CreateNode("element", "Sections", ""); - parentNode.AppendChild(sectionsNode); - AddXMLNode("Count", r2r.R2RHeader.Sections.Count.ToString(), sectionsNode); - } - else - { - WriteDivider("R2R Sections"); - _writer.WriteLine($"{r2r.R2RHeader.Sections.Count} sections"); - SkipLine(); - } - foreach (R2RSection section in r2r.R2RHeader.Sections.Values) - { - DumpSection(r2r, section, sectionsNode); - } - } - SkipLine(); - } - - /// - /// Dumps one R2RSection - /// - private void DumpSection(R2RReader r2r, R2RSection section, XmlNode parentNode) - { - XmlNode sectionNode = null; - if (_xml) - { - sectionNode = _xmlDocument.CreateNode("element", "Section", ""); - parentNode.AppendChild(sectionNode); - Serialize(section, sectionNode); - } - else - { - WriteSubDivider(); - _writer.WriteLine(section.ToString()); - } - - if (_raw) - { - DumpBytes(r2r, section.RelativeVirtualAddress, (uint)section.Size, sectionNode); - SkipLine(); - } - if (_sectionContents) - { - DumpSectionContents(r2r, section, sectionNode); - SkipLine(); - } - } - - /// - /// Dumps one R2RMethod. - /// - private void DumpMethod(R2RReader r2r, R2RMethod method, XmlNode parentNode) - { - XmlNode methodNode = null; - if (_xml) - { - methodNode = _xmlDocument.CreateNode("element", "Method", ""); - parentNode.AppendChild(methodNode); - Serialize(method, methodNode); - } - else - { - WriteSubDivider(); - _writer.WriteLine(method.ToString()); - } - if (_gc) - { - if (_xml) - { - XmlNode gcNode = _xmlDocument.CreateNode("element", "GcInfo", ""); - methodNode.AppendChild(gcNode); - Serialize(method.GcInfo, gcNode); - - foreach (KeyValuePair transition in method.GcInfo.Transitions) - { - Serialize(transition, gcNode); - } - } - else - { - _writer.WriteLine("GcInfo:"); - _writer.Write(method.GcInfo); - } - - if (_raw) - { - DumpBytes(r2r, method.GcInfo.Offset, (uint)method.GcInfo.Size, methodNode, false); - } - } - SkipLine(); - - XmlNode rtfsNode = null; - if (_xml) - { - rtfsNode = _xmlDocument.CreateNode("element", "RuntimeFunctions", ""); - methodNode.AppendChild(rtfsNode); - } - foreach (RuntimeFunction runtimeFunction in method.RuntimeFunctions) - { - DumpRuntimeFunction(r2r, runtimeFunction, rtfsNode); - } - } - - /// - /// Dumps one runtime function. - /// - private void DumpRuntimeFunction(R2RReader r2r, RuntimeFunction rtf, XmlNode parentNode) - { - XmlNode rtfNode = null; - if (_xml) - { - rtfNode = _xmlDocument.CreateNode("element", "RuntimeFunction", ""); - parentNode.AppendChild(rtfNode); - AddXMLNode("MethodRid", rtf.Method.Rid.ToString(), rtfNode); - Serialize(rtf, rtfNode); - } - - if (_disasm) - { - string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf, r2r.GetOffset(rtf.StartAddress), r2r.Image); - if (_xml) - { - AddXMLNode("Disassembly", disassembly, rtfNode); - } - else - { - _writer.WriteLine($"Id: {rtf.Id}"); - _writer.Write(disassembly); - } - } - else if (!_xml) - { - _writer.Write($"{rtf}"); - } - - if (_raw) - { - if (!_xml) - _writer.WriteLine("Raw Bytes:"); - DumpBytes(r2r, rtf.StartAddress, (uint)rtf.Size, rtfNode); - } - if (_unwind) - { - XmlNode unwindNode = null; - if (_xml) - { - unwindNode = _xmlDocument.CreateNode("element", "UnwindInfo", ""); - rtfNode.AppendChild(unwindNode); - Serialize(rtf.UnwindInfo, unwindNode); - } - else - { - _writer.WriteLine("UnwindInfo:"); - _writer.Write(rtf.UnwindInfo); - } - if (_raw) - { - DumpBytes(r2r, rtf.UnwindRVA, (uint)((Amd64.UnwindInfo)rtf.UnwindInfo).Size, unwindNode); - } - } - SkipLine(); - } - - /// - /// Prints a formatted string containing a block of bytes from the relative virtual address and size - /// - public void DumpBytes(R2RReader r2r, int rva, uint size, XmlNode parentNode, bool convertToOffset = true) - { - int start = rva; - if (convertToOffset) - start = r2r.GetOffset(rva); - if (start > r2r.Image.Length || start + size > r2r.Image.Length) - { - throw new IndexOutOfRangeException(); - } - - if (_xml && parentNode != null) - { - StringBuilder sb = new StringBuilder(); - sb.Append($"{r2r.Image[start]:X2}"); - for (uint i = 1; i < size; i++) - { - sb.Append($" {r2r.Image[start + i]:X2}"); - } - AddXMLNode("Raw", sb.ToString(), parentNode); - return; - } - - _writer.Write(" "); - if (rva % 16 != 0) - { - int floor = rva / 16 * 16; - _writer.Write($"{floor:X8}:"); - _writer.Write(new String(' ', (rva - floor) * 3)); - } - for (uint i = 0; i < size; i++) - { - if ((rva + i) % 16 == 0) - { - _writer.Write($"{rva + i:X8}:"); - } - _writer.Write($" {r2r.Image[start + i]:X2}"); - if ((rva + i) % 16 == 15 && i != size - 1) - { - SkipLine(); - _writer.Write(" "); - } - } - SkipLine(); - } - - private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode contentsNode) - { - switch (section.Type) - { - case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: - if(!_xml) - { - uint availableTypesSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); - NativeParser availableTypesParser = new NativeParser(r2r.Image, availableTypesSectionOffset); - NativeHashtable availableTypes = new NativeHashtable(r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); - _writer.WriteLine(availableTypes.ToString()); - } - - if (_xml) - { - Serialize(r2r.AvailableTypes, contentsNode); - } - else - { - foreach (string name in r2r.AvailableTypes) - { - _writer.WriteLine(name); - } - } - break; - case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: - if (!_xml) - { - NativeArray methodEntryPoints = new NativeArray(r2r.Image, (uint)r2r.GetOffset(section.RelativeVirtualAddress)); - _writer.Write(methodEntryPoints.ToString()); - } - break; - case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS: - if (!_xml) - { - uint instanceSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); - NativeParser instanceParser = new NativeParser(r2r.Image, instanceSectionOffset); - NativeHashtable instMethodEntryPoints = new NativeHashtable(r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); - _writer.Write(instMethodEntryPoints.ToString()); - } - break; - case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: - int rtfOffset = r2r.GetOffset(section.RelativeVirtualAddress); - int rtfEndOffset = rtfOffset + section.Size; - int rtfIndex = 0; - while (rtfOffset < rtfEndOffset) - { - uint rva = NativeReader.ReadUInt32(r2r.Image, ref rtfOffset); - if (_xml) - { - AddXMLNode($"{rtfIndex}", $"0x{rva:X8}", contentsNode); - } - else - { - _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}"); - } - rtfIndex++; - } - break; - case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: - if(_xml) - { - AddXMLNode("CompileIdentifier", r2r.CompileIdentifier, contentsNode); - } - else - { - _writer.WriteLine(r2r.CompileIdentifier); - } - break; - case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: - foreach (R2RImportSection importSection in r2r.ImportSections) - { - if (_xml) - { - Serialize(importSection, contentsNode); - } - else - { - _writer.Write(importSection.ToString()); - } - if (_raw && importSection.Entries.Count != 0) - { - if (importSection.SectionRVA != 0) - { - XmlNode bytesNode = null; - if (_xml) - { - bytesNode = _xmlDocument.CreateNode("element", "SectionBytes", ""); - contentsNode.AppendChild(bytesNode); - } - else - { - _writer.WriteLine("Section Bytes:"); - } - DumpBytes(r2r, importSection.SectionRVA, (uint)importSection.SectionSize, bytesNode); - } - if (importSection.SignatureRVA != 0) - { - XmlNode bytesNode = null; - if (_xml) - { - bytesNode = _xmlDocument.CreateNode("element", "SignatureBytes", ""); - contentsNode.AppendChild(bytesNode); - } - else - { - _writer.WriteLine("Signature Bytes:"); - } - DumpBytes(r2r, importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int), bytesNode); - } - if (importSection.AuxiliaryDataRVA != 0) - { - XmlNode bytesNode = null; - if (_xml) - { - bytesNode = _xmlDocument.CreateNode("element", "AuxiliaryDataBytes", ""); - contentsNode.AppendChild(bytesNode); - } - else - { - _writer.WriteLine("AuxiliaryData Bytes:"); - } - DumpBytes(r2r, importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, bytesNode); - } - } - foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) - { - if (_xml) - { - Serialize(entry, contentsNode); - } - else - { - _writer.WriteLine(); - _writer.WriteLine(entry.ToString()); - } - } - if (!_xml) - _writer.WriteLine(); - } - break; - } - } - // /// For each query in the list of queries, search for all methods matching the query by name, signature or id /// @@ -519,31 +141,19 @@ private void DumpSectionContents(R2RReader r2r, R2RSection section, XmlNode cont /// The title to print, "R2R Methods by Query" or "R2R Methods by Keyword" /// The keywords/ids to search for /// Specifies whether to look for methods with names/signatures/ids matching the method exactly or partially - private void QueryMethod(R2RReader r2r, string title, IReadOnlyList queries, bool exact, XmlNode parentNode) + private void QueryMethod(R2RReader r2r, string title, IReadOnlyList queries, bool exact) { if (queries.Count > 0) { - WriteDivider(title); + _dumper.WriteDivider(title); } foreach (string q in queries) { IList res = FindMethod(r2r, q, exact); - XmlNode queryNode = null; - if (_xml) - { - queryNode = _xmlDocument.CreateNode("element", "Methods", ""); - parentNode.AppendChild(queryNode); - AddXMLNode("Query", q, queryNode); - AddXMLNode("Count", res.Count.ToString(), queryNode); - } - else - { - _writer.WriteLine(res.Count + " result(s) for \"" + q + "\""); - SkipLine(); - } + XmlNode queryNode = _dumper.DumpQueryCount(q, "Methods", res.Count); foreach (R2RMethod method in res) { - DumpMethod(r2r, method, queryNode); + _dumper.DumpMethod(method, queryNode); } } } @@ -553,31 +163,19 @@ private void QueryMethod(R2RReader r2r, string title, IReadOnlyList quer /// /// Contains all the extracted info about the ReadyToRun image /// The names/values to search for - private void QuerySection(R2RReader r2r, IReadOnlyList queries, XmlNode parentNode) + private void QuerySection(R2RReader r2r, IReadOnlyList queries) { if (queries.Count > 0) { - WriteDivider("R2R Section"); + _dumper.WriteDivider("R2R Section"); } foreach (string q in queries) { IList res = FindSection(r2r, q); - XmlNode queryNode = null; - if (_xml) - { - queryNode = _xmlDocument.CreateNode("element", "Sections", ""); - parentNode.AppendChild(queryNode); - AddXMLNode("Query", q, queryNode); - AddXMLNode("Count", res.Count.ToString(), queryNode); - } - else - { - _writer.WriteLine(res.Count + " result(s) for \"" + q + "\""); - SkipLine(); - } + XmlNode queryNode = _dumper.DumpQueryCount(q, "Sections", res.Count); foreach (R2RSection section in res) { - DumpSection(r2r, section, queryNode); + _dumper.DumpSection(section, queryNode); } } } @@ -588,11 +186,11 @@ private void QuerySection(R2RReader r2r, IReadOnlyList queries, XmlNode /// /// Contains all the extracted info about the ReadyToRun image /// The ids to search for - private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries, XmlNode parentNode) + private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries) { if (queries.Count > 0) { - WriteDivider("Runtime Functions"); + _dumper.WriteDivider("Runtime Functions"); } foreach (int q in queries) { @@ -603,19 +201,8 @@ private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries, Xml WriteWarning("Unable to find by id " + q); continue; } - XmlNode queryNode = null; - if (_xml) - { - queryNode = _xmlDocument.CreateNode("element", "RuntimeFunctions", ""); - parentNode.AppendChild(queryNode); - AddXMLNode("Query", q.ToString(), queryNode); - AddXMLNode("Count", "1", queryNode); - } - else - { - _writer.WriteLine(rtf.Method.SignatureString); - } - DumpRuntimeFunction(r2r, rtf, queryNode); + XmlNode queryNode = _dumper.DumpQueryCount(q.ToString(), "Runtime Function", 1); + _dumper.DumpRuntimeFunction(rtf, queryNode); } } @@ -625,82 +212,33 @@ private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList queries, Xml /// The structure containing the info of the ReadyToRun image public void Dump(R2RReader r2r) { - XmlNode rootNode = null; - if (_xml) - { - rootNode = _xmlDocument.CreateNode("element", "R2RDump", ""); - _xmlDocument.AppendChild(rootNode); - Serialize(r2r, rootNode); - } - else - { - _writer.WriteLine($"Filename: {r2r.Filename}"); - _writer.WriteLine($"Machine: {r2r.Machine}"); - _writer.WriteLine($"ImageBase: 0x{r2r.ImageBase:X8}"); - SkipLine(); - } + + _dumper.Begin(); if (_queries.Count == 0 && _keywords.Count == 0 && _runtimeFunctions.Count == 0 && _sections.Count == 0) //dump all sections and methods { - WriteDivider("R2R Header"); - DumpHeader(r2r, true, rootNode); + _dumper.WriteDivider("R2R Header"); + _dumper.DumpHeader(true); if (!_header) { - XmlNode methodsNode = null; - if (_xml) - { - methodsNode = _xmlDocument.CreateNode("element", "Methods", ""); - rootNode.AppendChild(methodsNode); - AddXMLNode("Count", r2r.R2RMethods.Count.ToString(), methodsNode); - } - else - { - WriteDivider("R2R Methods"); - _writer.WriteLine($"{r2r.R2RMethods.Count} methods"); - SkipLine(); - } - foreach (R2RMethod method in r2r.R2RMethods) - { - DumpMethod(r2r, method, methodsNode); - } + _dumper.DumpAllMethods(); } } else //dump queried sections/methods/runtimeFunctions { if (_header) { - DumpHeader(r2r, false, rootNode); + _dumper.DumpHeader(false); } - QuerySection(r2r, _sections, rootNode); - QueryRuntimeFunction(r2r, _runtimeFunctions, rootNode); - QueryMethod(r2r, "R2R Methods by Query", _queries, true, rootNode); - QueryMethod(r2r, "R2R Methods by Keyword", _keywords, false, rootNode); - } - if (!_xml) - { - _writer.WriteLine("============================================================="); - SkipLine(); - } - } - - private void Serialize(object obj, XmlNode node) - { - using (XmlWriter xmlWriter = node.CreateNavigator().AppendChild()) - { - xmlWriter.WriteWhitespace(""); - XmlSerializer Serializer = new XmlSerializer(obj.GetType()); - Serializer.Serialize(xmlWriter, obj); + QuerySection(r2r, _sections); + QueryRuntimeFunction(r2r, _runtimeFunctions); + QueryMethod(r2r, "R2R Methods by Query", _queries, true); + QueryMethod(r2r, "R2R Methods by Keyword", _keywords, false); } - } - private XmlNode AddXMLNode(String name, String contents, XmlNode parentNode) - { - XmlNode node = _xmlDocument.CreateNode("element", name, ""); - parentNode.AppendChild(node); - node.InnerText = contents; - return node; + _dumper.End(); } /// @@ -837,27 +375,27 @@ private int Run(string[] args) foreach (string filename in _inputFilenames) { R2RReader r2r = new R2RReader(filename); - if (_xml) - { - _xmlDocument = new XmlDocument(); - } if (_disasm) { _disassembler = CoreDisTools.GetDisasm(r2r.Machine); } + if (_xml) + { + _dumper = new XmlDumper(r2r, _writer, _raw, _header, _disasm, _disassembler, _unwind, _gc, _sectionContents); + } + else + { + _dumper = new TextDumper(r2r, _writer, _raw, _header, _disasm, _disassembler, _unwind, _gc, _sectionContents); + } + Dump(r2r); if (_disasm) { CoreDisTools.FinishDisasm(_disassembler); } - - if (_xml) - { - _xmlDocument.Save(_writer); - } } } catch (Exception e) diff --git a/src/tools/r2rdump/R2RHeader.cs b/src/tools/r2rdump/R2RHeader.cs index cf7e65a0e968..7212d3eff70b 100644 --- a/src/tools/r2rdump/R2RHeader.cs +++ b/src/tools/r2rdump/R2RHeader.cs @@ -70,9 +70,9 @@ public R2RHeader(byte[] image, int rva, int curOffset) RelativeVirtualAddress = rva; int startOffset = curOffset; - byte[] signature = new byte[sizeof(uint)]; - Array.Copy(image, curOffset, signature, 0, sizeof(uint)); - SignatureString = Encoding.UTF8.GetString(signature).Replace("\0", string.Empty); ; + byte[] signature = new byte[sizeof(uint) - 1]; // -1 removes the null character at the end of the cstring + Array.Copy(image, curOffset, signature, 0, sizeof(uint) - 1); + SignatureString = Encoding.UTF8.GetString(signature); Signature = NativeReader.ReadUInt32(image, ref curOffset); if (Signature != READYTORUN_SIGNATURE) { diff --git a/src/tools/r2rdump/R2RReader.cs b/src/tools/r2rdump/R2RReader.cs index 56539dadbbfd..026d7cc5004a 100644 --- a/src/tools/r2rdump/R2RReader.cs +++ b/src/tools/r2rdump/R2RReader.cs @@ -312,10 +312,10 @@ private string ParseCompilerIdentifier() return ""; } R2RSection compilerIdentifierSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER]; - byte[] identifier = new byte[compilerIdentifierSection.Size]; + byte[] identifier = new byte[compilerIdentifierSection.Size - 1]; int identifierOffset = GetOffset(compilerIdentifierSection.RelativeVirtualAddress); - Array.Copy(Image, identifierOffset, identifier, 0, compilerIdentifierSection.Size); - return Encoding.UTF8.GetString(identifier).Replace("\0", string.Empty); + Array.Copy(Image, identifierOffset, identifier, 0, compilerIdentifierSection.Size - 1); + return Encoding.UTF8.GetString(identifier); } private void ParseImportSections() diff --git a/src/tools/r2rdump/TextDumper.cs b/src/tools/r2rdump/TextDumper.cs new file mode 100644 index 000000000000..f444f0d5264e --- /dev/null +++ b/src/tools/r2rdump/TextDumper.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; + +namespace R2RDump +{ + class TextDumper : Dumper + { + public TextDumper(R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, IntPtr disassembler, bool unwind, bool gc, bool sectionContents) + { + _r2r = r2r; + _writer = writer; + + _raw = raw; + _header = header; + _disasm = disasm; + _disassembler = disassembler; + _unwind = unwind; + _gc = gc; + _sectionContents = sectionContents; + } + + internal override void Begin() + { + _writer.WriteLine($"Filename: {_r2r.Filename}"); + _writer.WriteLine($"Machine: {_r2r.Machine}"); + _writer.WriteLine($"ImageBase: 0x{_r2r.ImageBase:X8}"); + SkipLine(); + } + + internal override void End() + { + _writer.WriteLine("============================================================="); + SkipLine(); + } + + internal override void WriteDivider(string title) + { + int len = 61 - title.Length - 2; + _writer.WriteLine(new String('=', len / 2) + " " + title + " " + new String('=', (int)Math.Ceiling(len / 2.0))); + SkipLine(); + } + + internal override void WriteSubDivider() + { + _writer.WriteLine("_______________________________________________"); + SkipLine(); + } + + internal override void SkipLine() + { + _writer.WriteLine(); + } + + /// + /// Dumps the R2RHeader and all the sections in the header + /// + internal override void DumpHeader(bool dumpSections) + { + _writer.WriteLine(_r2r.R2RHeader.ToString()); + + if (_raw) + { + DumpBytes(_r2r.R2RHeader.RelativeVirtualAddress, (uint)_r2r.R2RHeader.Size); + } + SkipLine(); + if (dumpSections) + { + WriteDivider("R2R Sections"); + _writer.WriteLine($"{_r2r.R2RHeader.Sections.Count} sections"); + SkipLine(); + + foreach (R2RSection section in _r2r.R2RHeader.Sections.Values) + { + DumpSection(section); + } + } + SkipLine(); + } + + /// + /// Dumps one R2RSection + /// + internal override void DumpSection(R2RSection section, XmlNode parentNode = null) + { + WriteSubDivider(); + _writer.WriteLine(section.ToString()); + + if (_raw) + { + DumpBytes(section.RelativeVirtualAddress, (uint)section.Size); + SkipLine(); + } + if (_sectionContents) + { + DumpSectionContents(section); + SkipLine(); + } + } + + internal override void DumpAllMethods() + { + WriteDivider("R2R Methods"); + _writer.WriteLine($"{_r2r.R2RMethods.Count} methods"); + SkipLine(); + foreach (R2RMethod method in _r2r.R2RMethods) + { + DumpMethod(method); + } + } + + /// + /// Dumps one R2RMethod. + /// + internal override void DumpMethod(R2RMethod method, XmlNode parentNode = null) + { + WriteSubDivider(); + _writer.WriteLine(method.ToString()); + + if (_gc) + { + _writer.WriteLine("GcInfo:"); + _writer.Write(method.GcInfo); + + if (_raw) + { + DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, null, false); + } + } + SkipLine(); + + foreach (RuntimeFunction runtimeFunction in method.RuntimeFunctions) + { + DumpRuntimeFunction(runtimeFunction); + } + } + + /// + /// Dumps one runtime function. + /// + internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNode = null) + { + _writer.WriteLine(rtf.Method.SignatureString); + _writer.Write($"{rtf}"); + + if (_disasm) + { + string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image); + _writer.Write(disassembly); + } + + if (_raw) + { + _writer.WriteLine("Raw Bytes:"); + DumpBytes(rtf.StartAddress, (uint)rtf.Size); + } + if (_unwind) + { + _writer.WriteLine("UnwindInfo:"); + _writer.Write(rtf.UnwindInfo); + if (_raw) + { + DumpBytes(rtf.UnwindRVA, (uint)((UnwindInfo)rtf.UnwindInfo).Size); + } + } + SkipLine(); + } + + /// + /// Prints a formatted string containing a block of bytes from the relative virtual address and size + /// + internal override void DumpBytes(int rva, uint size, XmlNode parentNode = null, bool convertToOffset = true) + { + int start = rva; + if (convertToOffset) + start = _r2r.GetOffset(rva); + if (start > _r2r.Image.Length || start + size > _r2r.Image.Length) + { + throw new IndexOutOfRangeException(); + } + + _writer.Write(" "); + if (rva % 16 != 0) + { + int floor = rva / 16 * 16; + _writer.Write($"{floor:X8}:"); + _writer.Write(new String(' ', (rva - floor) * 3)); + } + for (uint i = 0; i < size; i++) + { + if ((rva + i) % 16 == 0) + { + _writer.Write($"{rva + i:X8}:"); + } + _writer.Write($" {_r2r.Image[start + i]:X2}"); + if ((rva + i) % 16 == 15 && i != size - 1) + { + SkipLine(); + _writer.Write(" "); + } + } + SkipLine(); + } + + internal override void DumpSectionContents(R2RSection section, XmlNode parentNode = null) + { + switch (section.Type) + { + case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: + uint availableTypesSectionOffset = (uint)_r2r.GetOffset(section.RelativeVirtualAddress); + NativeParser availableTypesParser = new NativeParser(_r2r.Image, availableTypesSectionOffset); + NativeHashtable availableTypes = new NativeHashtable(_r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); + _writer.WriteLine(availableTypes.ToString()); + + foreach (string name in _r2r.AvailableTypes) + { + _writer.WriteLine(name); + } + break; + case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: + NativeArray methodEntryPoints = new NativeArray(_r2r.Image, (uint)_r2r.GetOffset(section.RelativeVirtualAddress)); + _writer.Write(methodEntryPoints.ToString()); + break; + case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS: + uint instanceSectionOffset = (uint)_r2r.GetOffset(section.RelativeVirtualAddress); + NativeParser instanceParser = new NativeParser(_r2r.Image, instanceSectionOffset); + NativeHashtable instMethodEntryPoints = new NativeHashtable(_r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); + _writer.Write(instMethodEntryPoints.ToString()); + break; + case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: + int rtfOffset = _r2r.GetOffset(section.RelativeVirtualAddress); + int rtfEndOffset = rtfOffset + section.Size; + int rtfIndex = 0; + while (rtfOffset < rtfEndOffset) + { + uint rva = NativeReader.ReadUInt32(_r2r.Image, ref rtfOffset); + _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}"); + rtfIndex++; + } + break; + case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: + _writer.WriteLine(_r2r.CompileIdentifier); + break; + case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: + foreach (R2RImportSection importSection in _r2r.ImportSections) + { + _writer.Write(importSection.ToString()); + if (_raw && importSection.Entries.Count != 0) + { + if (importSection.SectionRVA != 0) + { + _writer.WriteLine("Section Bytes:"); + DumpBytes(importSection.SectionRVA, (uint)importSection.SectionSize); + } + if (importSection.SignatureRVA != 0) + { + _writer.WriteLine("Signature Bytes:"); + DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int)); + } + if (importSection.AuxiliaryDataRVA != 0) + { + _writer.WriteLine("AuxiliaryData Bytes:"); + DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size); + } + } + foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) + { + _writer.WriteLine(); + _writer.WriteLine(entry.ToString()); + } + _writer.WriteLine(); + } + break; + } + } + + internal override XmlNode DumpQueryCount(string q, string title, int count) + { + _writer.WriteLine(count + " result(s) for \"" + q + "\""); + SkipLine(); + return null; + } + } +} diff --git a/src/tools/r2rdump/XmlDumper.cs b/src/tools/r2rdump/XmlDumper.cs new file mode 100644 index 000000000000..52c28f4e81db --- /dev/null +++ b/src/tools/r2rdump/XmlDumper.cs @@ -0,0 +1,309 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace R2RDump +{ + class XmlDumper : Dumper + { + private XmlDocument _xmlDocument; + private XmlNode _rootNode; + + public XmlDumper(R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, IntPtr disassembler, bool unwind, bool gc, bool sectionContents) + { + _r2r = r2r; + _writer = writer; + _xmlDocument = new XmlDocument(); + + _raw = raw; + _header = header; + _disasm = disasm; + _disassembler = disassembler; + _unwind = unwind; + _gc = gc; + _sectionContents = sectionContents; + } + + internal override void Begin() + { + _rootNode = _xmlDocument.CreateNode("element", "R2RDump", ""); + _xmlDocument.AppendChild(_rootNode); + Serialize(_r2r, _rootNode); + } + + internal override void End() { + _xmlDocument.Save(_writer); + } + + internal override void WriteDivider(string title) + { + } + + internal override void WriteSubDivider() + { + } + + internal override void SkipLine() + { + } + + /// + /// Dumps the R2RHeader and all the sections in the header + /// + internal override void DumpHeader(bool dumpSections) + { + XmlNode headerNode = _xmlDocument.CreateNode("element", "Header", ""); + _rootNode.AppendChild(headerNode); + Serialize(_r2r.R2RHeader, headerNode); + + if (_raw) + { + DumpBytes(_r2r.R2RHeader.RelativeVirtualAddress, (uint)_r2r.R2RHeader.Size, headerNode); + } + + if (dumpSections) + { + XmlNode sectionsNode = _xmlDocument.CreateNode("element", "Sections", ""); + _rootNode.AppendChild(sectionsNode); + AddXMLNode("Count", _r2r.R2RHeader.Sections.Count.ToString(), sectionsNode); + + foreach (R2RSection section in _r2r.R2RHeader.Sections.Values) + { + DumpSection(section, sectionsNode); + } + } + } + + /// + /// Dumps one R2RSection + /// + internal override void DumpSection(R2RSection section, XmlNode parentNode) + { + XmlNode sectionNode = _xmlDocument.CreateNode("element", "Section", ""); + parentNode.AppendChild(sectionNode); + Serialize(section, sectionNode); + + if (_raw) + { + DumpBytes(section.RelativeVirtualAddress, (uint)section.Size, sectionNode); + } + if (_sectionContents) + { + DumpSectionContents(section, sectionNode); + } + } + + internal override void DumpAllMethods() + { + XmlNode methodsNode = _xmlDocument.CreateNode("element", "Methods", ""); + _rootNode.AppendChild(methodsNode); + AddXMLNode("Count", _r2r.R2RMethods.Count.ToString(), methodsNode); + foreach (R2RMethod method in _r2r.R2RMethods) + { + DumpMethod(method, methodsNode); + } + } + + /// + /// Dumps one R2RMethod. + /// + internal override void DumpMethod(R2RMethod method, XmlNode parentNode) + { + XmlNode methodNode = _xmlDocument.CreateNode("element", "Method", ""); + parentNode.AppendChild(methodNode); + Serialize(method, methodNode); + + if (_gc) + { + XmlNode gcNode = _xmlDocument.CreateNode("element", "GcInfo", ""); + methodNode.AppendChild(gcNode); + Serialize(method.GcInfo, gcNode); + + foreach (KeyValuePair transition in method.GcInfo.Transitions) + { + Serialize(transition, gcNode); + } + + if (_raw) + { + DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, methodNode, false); + } + } + + XmlNode rtfsNode = null; + rtfsNode = _xmlDocument.CreateNode("element", "RuntimeFunctions", ""); + methodNode.AppendChild(rtfsNode); + + foreach (RuntimeFunction runtimeFunction in method.RuntimeFunctions) + { + DumpRuntimeFunction(runtimeFunction, rtfsNode); + } + } + + /// + /// Dumps one runtime function. + /// + internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNode) + { + XmlNode rtfNode = _xmlDocument.CreateNode("element", "RuntimeFunction", ""); + parentNode.AppendChild(rtfNode); + AddXMLNode("MethodRid", rtf.Method.Rid.ToString(), rtfNode); + Serialize(rtf, rtfNode); + + if (_disasm) + { + string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image); + AddXMLNode("Disassembly", disassembly, rtfNode); + } + + if (_raw) + { + DumpBytes(rtf.StartAddress, (uint)rtf.Size, rtfNode); + } + if (_unwind) + { + XmlNode unwindNode = null; + unwindNode = _xmlDocument.CreateNode("element", "UnwindInfo", ""); + rtfNode.AppendChild(unwindNode); + Serialize(rtf.UnwindInfo, unwindNode); + + if (_raw) + { + DumpBytes(rtf.UnwindRVA, (uint)((UnwindInfo)rtf.UnwindInfo).Size, unwindNode); + } + } + } + + /// + /// Prints a formatted string containing a block of bytes from the relative virtual address and size + /// + internal override void DumpBytes(int rva, uint size, XmlNode parentNode, bool convertToOffset = true) + { + int start = rva; + if (convertToOffset) + start = _r2r.GetOffset(rva); + if (start > _r2r.Image.Length || start + size > _r2r.Image.Length) + { + throw new IndexOutOfRangeException(); + } + + if (parentNode != null) + { + StringBuilder sb = new StringBuilder(); + sb.Append($"{_r2r.Image[start]:X2}"); + for (uint i = 1; i < size; i++) + { + sb.Append($" {_r2r.Image[start + i]:X2}"); + } + AddXMLNode("Raw", sb.ToString(), parentNode); + return; + } + + _writer.Write(" "); + if (rva % 16 != 0) + { + int floor = rva / 16 * 16; + _writer.Write($"{floor:X8}:"); + _writer.Write(new String(' ', (rva - floor) * 3)); + } + for (uint i = 0; i < size; i++) + { + if ((rva + i) % 16 == 0) + { + _writer.Write($"{rva + i:X8}:"); + } + _writer.Write($" {_r2r.Image[start + i]:X2}"); + if ((rva + i) % 16 == 15 && i != size - 1) + { + _writer.Write(" "); + } + } + } + + internal override void DumpSectionContents(R2RSection section, XmlNode parentNode) + { + XmlNode contentsNode = _xmlDocument.CreateNode("element", "Contents", ""); + parentNode.AppendChild(contentsNode); + + switch (section.Type) + { + case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: + + foreach (string name in _r2r.AvailableTypes) + { + AddXMLNode("AvailableType", name, contentsNode); + } + break; + case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: + int rtfOffset = _r2r.GetOffset(section.RelativeVirtualAddress); + int rtfEndOffset = rtfOffset + section.Size; + int rtfIndex = 0; + while (rtfOffset < rtfEndOffset) + { + uint rva = NativeReader.ReadUInt32(_r2r.Image, ref rtfOffset); + AddXMLNode($"id{rtfIndex}", $"0x{rva:X8}", contentsNode); + rtfIndex++; + } + break; + case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: + AddXMLNode("CompileIdentifier", _r2r.CompileIdentifier, contentsNode); + break; + case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: + foreach (R2RImportSection importSection in _r2r.ImportSections) + { + Serialize(importSection, contentsNode); + if (_raw && importSection.Entries.Count != 0) + { + if (importSection.SectionRVA != 0) + { + DumpBytes(importSection.SectionRVA, (uint)importSection.SectionSize, contentsNode); + } + if (importSection.SignatureRVA != 0) + { + DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int), contentsNode); + } + if (importSection.AuxiliaryDataRVA != 0) + { + DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, contentsNode); + } + } + foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) + { + Serialize(entry, contentsNode); + } + } + break; + } + } + + internal override XmlNode DumpQueryCount(string q, string title, int count) + { + XmlNode queryNode = _xmlDocument.CreateNode("element", title, ""); + _rootNode.AppendChild(queryNode); + AddXMLNode("Query", q, queryNode); + AddXMLNode("Count", count.ToString(), queryNode); + return queryNode; + } + + private void Serialize(object obj, XmlNode node) + { + using (XmlWriter xmlWriter = node.CreateNavigator().AppendChild()) + { + xmlWriter.WriteWhitespace(""); + XmlSerializer Serializer = new XmlSerializer(obj.GetType()); + Serializer.Serialize(xmlWriter, obj); + } + } + + private XmlNode AddXMLNode(String name, String contents, XmlNode parentNode) + { + XmlNode node = _xmlDocument.CreateNode("element", name, ""); + parentNode.AppendChild(node); + node.InnerText = contents; + return node; + } + } +} From cbbd3d6482231aac216500c3947267e4a89fbb8a Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Tue, 26 Jun 2018 14:11:46 -0700 Subject: [PATCH 7/8] Dump disasm line by line, changes to dumping bytes to xml, fix compilerIdentifier typo --- src/tools/r2rdump/CoreDisTools.cs | 35 ++++------------- src/tools/r2rdump/R2RDump.cs | 3 +- src/tools/r2rdump/R2RReader.cs | 6 +-- src/tools/r2rdump/TextDumper.cs | 32 +++++++++++++--- src/tools/r2rdump/XmlDumper.cs | 62 ++++++++++++++++--------------- 5 files changed, 72 insertions(+), 66 deletions(-) diff --git a/src/tools/r2rdump/CoreDisTools.cs b/src/tools/r2rdump/CoreDisTools.cs index 6070e43fd390..a84046d359de 100644 --- a/src/tools/r2rdump/CoreDisTools.cs +++ b/src/tools/r2rdump/CoreDisTools.cs @@ -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 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) diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs index 9a0062b331bb..659bc31511c3 100644 --- a/src/tools/r2rdump/R2RDump.cs +++ b/src/tools/r2rdump/R2RDump.cs @@ -34,7 +34,8 @@ abstract class Dumper abstract internal void DumpAllMethods(); abstract internal void DumpMethod(R2RMethod method, XmlNode parentNode = null); abstract internal void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNode = null); - abstract internal void DumpBytes(int rva, uint size, XmlNode parentNode = null, bool convertToOffset = true); + abstract internal unsafe void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode = null); + abstract internal void DumpBytes(int rva, uint size, XmlNode parentNode = null, string name = "Raw", bool convertToOffset = true); abstract internal void DumpSectionContents(R2RSection section, XmlNode parentNode = null); abstract internal XmlNode DumpQueryCount(string q, string title, int count); } diff --git a/src/tools/r2rdump/R2RReader.cs b/src/tools/r2rdump/R2RReader.cs index 026d7cc5004a..d365f87f3a80 100644 --- a/src/tools/r2rdump/R2RReader.cs +++ b/src/tools/r2rdump/R2RReader.cs @@ -79,9 +79,9 @@ public class R2RReader public IList AvailableTypes { get; } /// - /// The compile identifier string from READYTORUN_SECTION_COMPILER_IDENTIFIER + /// The compiler identifier string from READYTORUN_SECTION_COMPILER_IDENTIFIER /// - public string CompileIdentifier { get; } + public string CompilerIdentifier { get; } public IList ImportSections { get; } @@ -142,7 +142,7 @@ public unsafe R2RReader(string filename) AvailableTypes = new List(); ParseAvailableTypes(); - CompileIdentifier = ParseCompilerIdentifier(); + CompilerIdentifier = ParseCompilerIdentifier(); ImportSections = new List(); ParseImportSections(); diff --git a/src/tools/r2rdump/TextDumper.cs b/src/tools/r2rdump/TextDumper.cs index f444f0d5264e..7cfb98b281b0 100644 --- a/src/tools/r2rdump/TextDumper.cs +++ b/src/tools/r2rdump/TextDumper.cs @@ -126,7 +126,7 @@ internal override void DumpMethod(R2RMethod method, XmlNode parentNode = null) if (_raw) { - DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, null, false); + DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, null, "", false); } } SkipLine(); @@ -147,8 +147,7 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNo if (_disasm) { - string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image); - _writer.Write(disassembly); + DumpDisasm(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image); } if (_raw) @@ -168,10 +167,33 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNo SkipLine(); } + internal unsafe override void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode = null) + { + int rtfOffset = 0; + int codeOffset = rtf.CodeOffset; + Dictionary transitions = rtf.Method.GcInfo.Transitions; + GcSlotTable slotTable = rtf.Method.GcInfo.SlotTable; + while (rtfOffset < rtf.Size) + { + string instr; + int instrSize = CoreDisTools.GetInstruction(Disasm, rtf, imageOffset, rtfOffset, image, out instr); + + _writer.Write(instr); + if (transitions.ContainsKey(codeOffset)) + { + _writer.WriteLine($"\t\t\t\t{transitions[codeOffset].GetSlotState(slotTable)}"); + } + + CoreDisTools.ClearOutputBuffer(); + rtfOffset += instrSize; + codeOffset += instrSize; + } + } + /// /// Prints a formatted string containing a block of bytes from the relative virtual address and size /// - internal override void DumpBytes(int rva, uint size, XmlNode parentNode = null, bool convertToOffset = true) + internal override void DumpBytes(int rva, uint size, XmlNode parentNode = null, string name = "Raw", bool convertToOffset = true) { int start = rva; if (convertToOffset) @@ -241,7 +263,7 @@ internal override void DumpSectionContents(R2RSection section, XmlNode parentNod } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: - _writer.WriteLine(_r2r.CompileIdentifier); + _writer.WriteLine(_r2r.CompilerIdentifier); break; case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: foreach (R2RImportSection importSection in _r2r.ImportSections) diff --git a/src/tools/r2rdump/XmlDumper.cs b/src/tools/r2rdump/XmlDumper.cs index 52c28f4e81db..8604adb68d61 100644 --- a/src/tools/r2rdump/XmlDumper.cs +++ b/src/tools/r2rdump/XmlDumper.cs @@ -122,14 +122,14 @@ internal override void DumpMethod(R2RMethod method, XmlNode parentNode) methodNode.AppendChild(gcNode); Serialize(method.GcInfo, gcNode); - foreach (KeyValuePair transition in method.GcInfo.Transitions) + foreach (GcInfo.GcTransition transition in method.GcInfo.Transitions.Values) { Serialize(transition, gcNode); } if (_raw) { - DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, methodNode, false); + DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, gcNode, "Raw", false); } } @@ -155,8 +155,7 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNo if (_disasm) { - string disassembly = CoreDisTools.GetCodeBlock(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image); - AddXMLNode("Disassembly", disassembly, rtfNode); + DumpDisasm(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image, rtfNode); } if (_raw) @@ -177,10 +176,33 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNo } } + internal unsafe override void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode) + { + int rtfOffset = 0; + int codeOffset = rtf.CodeOffset; + Dictionary transitions = rtf.Method.GcInfo.Transitions; + GcSlotTable slotTable = rtf.Method.GcInfo.SlotTable; + while (rtfOffset < rtf.Size) + { + string instr; + int instrSize = CoreDisTools.GetInstruction(Disasm, rtf, imageOffset, rtfOffset, image, out instr); + + AddXMLNode("offset"+codeOffset, instr, parentNode); + if (transitions.ContainsKey(codeOffset)) + { + AddXMLNode("Transition", transitions[codeOffset].GetSlotState(slotTable), parentNode); + } + + CoreDisTools.ClearOutputBuffer(); + rtfOffset += instrSize; + codeOffset += instrSize; + } + } + /// /// Prints a formatted string containing a block of bytes from the relative virtual address and size /// - internal override void DumpBytes(int rva, uint size, XmlNode parentNode, bool convertToOffset = true) + internal override void DumpBytes(int rva, uint size, XmlNode parentNode, string name = "Raw", bool convertToOffset = true) { int start = rva; if (convertToOffset) @@ -198,29 +220,9 @@ internal override void DumpBytes(int rva, uint size, XmlNode parentNode, bool co { sb.Append($" {_r2r.Image[start + i]:X2}"); } - AddXMLNode("Raw", sb.ToString(), parentNode); + AddXMLNode(name, sb.ToString(), parentNode); return; } - - _writer.Write(" "); - if (rva % 16 != 0) - { - int floor = rva / 16 * 16; - _writer.Write($"{floor:X8}:"); - _writer.Write(new String(' ', (rva - floor) * 3)); - } - for (uint i = 0; i < size; i++) - { - if ((rva + i) % 16 == 0) - { - _writer.Write($"{rva + i:X8}:"); - } - _writer.Write($" {_r2r.Image[start + i]:X2}"); - if ((rva + i) % 16 == 15 && i != size - 1) - { - _writer.Write(" "); - } - } } internal override void DumpSectionContents(R2RSection section, XmlNode parentNode) @@ -249,7 +251,7 @@ internal override void DumpSectionContents(R2RSection section, XmlNode parentNod } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: - AddXMLNode("CompileIdentifier", _r2r.CompileIdentifier, contentsNode); + AddXMLNode("CompilerIdentifier", _r2r.CompilerIdentifier, contentsNode); break; case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: foreach (R2RImportSection importSection in _r2r.ImportSections) @@ -259,15 +261,15 @@ internal override void DumpSectionContents(R2RSection section, XmlNode parentNod { if (importSection.SectionRVA != 0) { - DumpBytes(importSection.SectionRVA, (uint)importSection.SectionSize, contentsNode); + DumpBytes(importSection.SectionRVA, (uint)importSection.SectionSize, contentsNode, "SectionBytes"); } if (importSection.SignatureRVA != 0) { - DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int), contentsNode); + DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int), contentsNode, "SignatureBytes"); } if (importSection.AuxiliaryDataRVA != 0) { - DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, contentsNode); + DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, contentsNode, "AuxiliaryDataBytes"); } } foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) From 6f78c938f5e84a8c302a0b791b1420b7b30608a5 Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Tue, 26 Jun 2018 15:25:02 -0700 Subject: [PATCH 8/8] Fix merge errors, replace spaces with tab, print unwind flag name --- src/tools/r2rdump/Amd64/UnwindInfo.cs | 104 ++++++++++++++++---------- src/tools/r2rdump/R2RMethod.cs | 2 +- src/tools/r2rdump/TextDumper.cs | 2 +- src/tools/r2rdump/XmlDumper.cs | 2 +- 4 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/tools/r2rdump/Amd64/UnwindInfo.cs b/src/tools/r2rdump/Amd64/UnwindInfo.cs index 1adca9a8c6ca..00c55bb79496 100644 --- a/src/tools/r2rdump/Amd64/UnwindInfo.cs +++ b/src/tools/r2rdump/Amd64/UnwindInfo.cs @@ -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) { @@ -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) { @@ -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}"); @@ -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) { @@ -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 { @@ -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"); @@ -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(); diff --git a/src/tools/r2rdump/R2RMethod.cs b/src/tools/r2rdump/R2RMethod.cs index 3851085045cf..20d48701915a 100644 --- a/src/tools/r2rdump/R2RMethod.cs +++ b/src/tools/r2rdump/R2RMethod.cs @@ -13,7 +13,7 @@ namespace R2RDump { - interface BaseUnwindInfo + public interface BaseUnwindInfo { } diff --git a/src/tools/r2rdump/TextDumper.cs b/src/tools/r2rdump/TextDumper.cs index 7cfb98b281b0..303cb904d891 100644 --- a/src/tools/r2rdump/TextDumper.cs +++ b/src/tools/r2rdump/TextDumper.cs @@ -161,7 +161,7 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNo _writer.Write(rtf.UnwindInfo); if (_raw) { - DumpBytes(rtf.UnwindRVA, (uint)((UnwindInfo)rtf.UnwindInfo).Size); + DumpBytes(rtf.UnwindRVA, (uint)((Amd64.UnwindInfo)rtf.UnwindInfo).Size); } } SkipLine(); diff --git a/src/tools/r2rdump/XmlDumper.cs b/src/tools/r2rdump/XmlDumper.cs index 8604adb68d61..c10ae7c72b1d 100644 --- a/src/tools/r2rdump/XmlDumper.cs +++ b/src/tools/r2rdump/XmlDumper.cs @@ -171,7 +171,7 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNo if (_raw) { - DumpBytes(rtf.UnwindRVA, (uint)((UnwindInfo)rtf.UnwindInfo).Size, unwindNode); + DumpBytes(rtf.UnwindRVA, (uint)((Amd64.UnwindInfo)rtf.UnwindInfo).Size, unwindNode); } } }