summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAmy Yu <amycmyu@gmail.com>2018-06-22 16:17:24 -0700
committerAmy Yu <amycmyu@gmail.com>2018-06-26 15:05:06 -0700
commitf377d7b4c3771cba99189b957349001878a23840 (patch)
treebb87cea8a0f75e76a42a0065ce6ec3763a4791e0 /src
parent5678ab7e406ba8040aff07cb9364c70ac6042d83 (diff)
downloadcoreclr-f377d7b4c3771cba99189b957349001878a23840.tar.gz
coreclr-f377d7b4c3771cba99189b957349001878a23840.tar.bz2
coreclr-f377d7b4c3771cba99189b957349001878a23840.zip
Refactor into TextDumper and XmlDumper classes
Diffstat (limited to 'src')
-rw-r--r--src/tools/r2rdump/R2RDump.cs582
-rw-r--r--src/tools/r2rdump/R2RHeader.cs6
-rw-r--r--src/tools/r2rdump/R2RReader.cs6
-rw-r--r--src/tools/r2rdump/TextDumper.cs286
-rw-r--r--src/tools/r2rdump/XmlDumper.cs309
5 files changed, 661 insertions, 528 deletions
diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs
index 6606b49d2a..9a0062b331 100644
--- a/src/tools/r2rdump/R2RDump.cs
+++ b/src/tools/r2rdump/R2RDump.cs
@@ -12,13 +12,39 @@ using System.Xml.Serialization;
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<string> _inputFilenames = Array.Empty<string>();
private string _outputFilename = null;
private bool _xml;
- private XmlDocument _xmlDocument;
private bool _raw;
private bool _header;
private bool _disasm;
@@ -33,6 +59,7 @@ namespace R2RDump
private bool _sectionContents;
private TextWriter _writer;
private Dictionary<R2RSection.SectionType, bool> _selectedSections = new Dictionary<R2RSection.SectionType, bool>();
+ private Dumper _dumper;
private R2RDump()
{
@@ -107,411 +134,6 @@ namespace R2RDump
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();
- }
-
- /// <summary>
- /// Dumps the R2RHeader and all the sections in the header
- /// </summary>
- 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();
- }
-
- /// <summary>
- /// Dumps one R2RSection
- /// </summary>
- 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();
- }
- }
-
- /// <summary>
- /// Dumps one R2RMethod.
- /// </summary>
- 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<int, GcInfo.GcTransition> 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);
- }
- }
-
- /// <summary>
- /// Dumps one runtime function.
- /// </summary>
- 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();
- }
-
- /// <summary>
- /// Prints a formatted string containing a block of bytes from the relative virtual address and size
- /// </summary>
- 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;
- }
- }
-
// <summary>
/// For each query in the list of queries, search for all methods matching the query by name, signature or id
/// </summary>
@@ -519,31 +141,19 @@ namespace R2RDump
/// <param name="title">The title to print, "R2R Methods by Query" or "R2R Methods by Keyword"</param>
/// <param name="queries">The keywords/ids to search for</param>
/// <param name="exact">Specifies whether to look for methods with names/signatures/ids matching the method exactly or partially</param>
- private void QueryMethod(R2RReader r2r, string title, IReadOnlyList<string> queries, bool exact, XmlNode parentNode)
+ private void QueryMethod(R2RReader r2r, string title, IReadOnlyList<string> queries, bool exact)
{
if (queries.Count > 0)
{
- WriteDivider(title);
+ _dumper.WriteDivider(title);
}
foreach (string q in queries)
{
IList<R2RMethod> 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 @@ namespace R2RDump
/// </summary>
/// <param name="r2r">Contains all the extracted info about the ReadyToRun image</param>
/// <param name="queries">The names/values to search for</param>
- private void QuerySection(R2RReader r2r, IReadOnlyList<string> queries, XmlNode parentNode)
+ private void QuerySection(R2RReader r2r, IReadOnlyList<string> queries)
{
if (queries.Count > 0)
{
- WriteDivider("R2R Section");
+ _dumper.WriteDivider("R2R Section");
}
foreach (string q in queries)
{
IList<R2RSection> 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 @@ namespace R2RDump
/// </summary>
/// <param name="r2r">Contains all the extracted info about the ReadyToRun image</param>
/// <param name="queries">The ids to search for</param>
- private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList<int> queries, XmlNode parentNode)
+ private void QueryRuntimeFunction(R2RReader r2r, IReadOnlyList<int> queries)
{
if (queries.Count > 0)
{
- WriteDivider("Runtime Functions");
+ _dumper.WriteDivider("Runtime Functions");
}
foreach (int q in queries)
{
@@ -603,19 +201,8 @@ namespace R2RDump
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 @@ namespace R2RDump
/// <param name="r2r">The structure containing the info of the ReadyToRun image</param>
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();
}
/// <summary>
@@ -837,27 +375,27 @@ namespace R2RDump
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 cf7e65a0e9..7212d3eff7 100644
--- a/src/tools/r2rdump/R2RHeader.cs
+++ b/src/tools/r2rdump/R2RHeader.cs
@@ -70,9 +70,9 @@ namespace R2RDump
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 56539dadbb..026d7cc500 100644
--- a/src/tools/r2rdump/R2RReader.cs
+++ b/src/tools/r2rdump/R2RReader.cs
@@ -312,10 +312,10 @@ namespace R2RDump
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 0000000000..f444f0d526
--- /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();
+ }
+
+ /// <summary>
+ /// Dumps the R2RHeader and all the sections in the header
+ /// </summary>
+ 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();
+ }
+
+ /// <summary>
+ /// Dumps one R2RSection
+ /// </summary>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Dumps one R2RMethod.
+ /// </summary>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Dumps one runtime function.
+ /// </summary>
+ 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();
+ }
+
+ /// <summary>
+ /// Prints a formatted string containing a block of bytes from the relative virtual address and size
+ /// </summary>
+ 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 0000000000..52c28f4e81
--- /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()
+ {
+ }
+
+ /// <summary>
+ /// Dumps the R2RHeader and all the sections in the header
+ /// </summary>
+ 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);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Dumps one R2RSection
+ /// </summary>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Dumps one R2RMethod.
+ /// </summary>
+ 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<int, GcInfo.GcTransition> 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);
+ }
+ }
+
+ /// <summary>
+ /// Dumps one runtime function.
+ /// </summary>
+ 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);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Prints a formatted string containing a block of bytes from the relative virtual address and size
+ /// </summary>
+ 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;
+ }
+ }
+}