summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/r2rdump/R2RDump.cs96
-rw-r--r--src/tools/r2rdump/R2RMethod.cs147
-rw-r--r--src/tools/r2rdump/R2RReader.cs69
-rw-r--r--src/tools/r2rdump/R2RSignature.cs96
-rw-r--r--src/tools/r2rdump/TextDumper.cs40
-rw-r--r--src/tools/r2rdump/XmlDumper.cs46
6 files changed, 278 insertions, 216 deletions
diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs
index 34b86b75ef..0901ee672e 100644
--- a/src/tools/r2rdump/R2RDump.cs
+++ b/src/tools/r2rdump/R2RDump.cs
@@ -6,24 +6,60 @@ using System;
using System.Collections.Generic;
using System.CommandLine;
using System.IO;
+using System.Linq;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace R2RDump
{
+ public class DumpOptions
+ {
+ public bool Raw;
+ public bool Normalize;
+ public bool Header;
+ public bool Disasm;
+ public bool Unwind;
+ public bool GC;
+ public bool SectionContents;
+ }
+
public abstract class Dumper
{
- internal R2RReader _r2r;
- internal TextWriter _writer;
+ protected readonly R2RReader _r2r;
+ protected readonly TextWriter _writer;
+ protected readonly Disassembler _disassembler;
+ protected readonly DumpOptions _options;
- internal bool _raw;
- internal bool _header;
- internal bool _disasm;
- internal Disassembler _disassembler;
- internal bool _unwind;
- internal bool _gc;
- internal bool _sectionContents;
+ public Dumper(R2RReader r2r, TextWriter writer, Disassembler disassembler, DumpOptions options)
+ {
+ _r2r = r2r;
+ _writer = writer;
+ _disassembler = disassembler;
+ _options = options;
+ }
+
+ public IEnumerable<R2RSection> NormalizedSections()
+ {
+ IEnumerable<R2RSection> sections = _r2r.R2RHeader.Sections.Values;
+ if (_options.Normalize)
+ {
+ sections = sections.OrderBy((s) => s.Type);
+ }
+ return sections;
+ }
+
+ public IEnumerable<R2RMethod> NormalizedMethods()
+ {
+ IEnumerable<R2RMethod> methods = _r2r.R2RMethods;
+ if (_options.Normalize)
+ {
+ methods = methods.OrderBy((m) => m.SignatureString);
+ }
+ return methods;
+ }
/// <summary>
/// Run right before printing output
@@ -54,18 +90,13 @@ namespace R2RDump
private bool _help;
private IReadOnlyList<string> _inputFilenames = Array.Empty<string>();
private string _outputFilename = null;
- private bool _xml;
- private bool _raw;
- private bool _header;
- private bool _disasm;
+ private DumpOptions _options = new DumpOptions();
private IReadOnlyList<string> _queries = Array.Empty<string>();
private IReadOnlyList<string> _keywords = Array.Empty<string>();
private IReadOnlyList<int> _runtimeFunctions = Array.Empty<int>();
private IReadOnlyList<string> _sections = Array.Empty<string>();
private bool _diff;
- private bool _unwind;
- private bool _gc;
- private bool _sectionContents;
+ private bool _xml;
private TextWriter _writer;
private Dictionary<R2RSection.SectionType, bool> _selectedSections = new Dictionary<R2RSection.SectionType, bool>();
private Dumper _dumper;
@@ -91,16 +122,17 @@ namespace 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");
+ syntax.DefineOption("raw", ref _options.Raw, "Dump the raw bytes of each section or runtime function");
+ syntax.DefineOption("header", ref _options.Header, "Dump R2R header");
+ syntax.DefineOption("d|disasm", ref _options.Disasm, "Show disassembly of methods or runtime functions");
syntax.DefineOptionList("q|query", ref _queries, "Query method by exact name, signature, row id or token");
syntax.DefineOptionList("k|keyword", ref _keywords, "Search method by keyword");
syntax.DefineOptionList("r|runtimefunction", ref _runtimeFunctions, ArgStringToInt, "Get one runtime function by id or relative virtual address");
syntax.DefineOptionList("s|section", ref _sections, "Get section by keyword");
- syntax.DefineOption("unwind", ref _unwind, "Dump unwindInfo");
- syntax.DefineOption("gc", ref _gc, "Dump gcInfo and slot table");
- syntax.DefineOption("sc", ref _sectionContents, "Dump section contents");
+ syntax.DefineOption("unwind", ref _options.Unwind, "Dump unwindInfo");
+ syntax.DefineOption("gc", ref _options.GC, "Dump gcInfo and slot table");
+ syntax.DefineOption("sc", ref _options.SectionContents, "Dump section contents");
+ syntax.DefineOption("n|normalize", ref _options.Normalize, "Normalize dump by sorting the various tables and methods (default = unsorted i.e. file order)");
syntax.DefineOption("v|verbose", ref verbose, "Dump disassembly, unwindInfo, gcInfo and section contents");
syntax.DefineOption("diff", ref _diff, "Compare two R2R images");
syntax.DefineOption("ignoreSensitive", ref _ignoreSensitive, "Ignores sensitive properties in xml dump to avoid failing tests");
@@ -108,10 +140,10 @@ namespace R2RDump
if (verbose)
{
- _disasm = true;
- _unwind = true;
- _gc = true;
- _sectionContents = true;
+ _options.Disasm = true;
+ _options.Unwind = true;
+ _options.GC = true;
+ _options.SectionContents = true;
}
return argSyntax;
@@ -237,14 +269,14 @@ namespace R2RDump
_dumper.WriteDivider("R2R Header");
_dumper.DumpHeader(true);
- if (!_header)
+ if (!_options.Header)
{
_dumper.DumpAllMethods();
}
}
else //dump queried sections, methods and runtimeFunctions
{
- if (_header)
+ if (_options.Header)
{
_dumper.DumpHeader(false);
}
@@ -267,7 +299,7 @@ namespace R2RDump
{
int id;
bool isNum = ArgStringToInt(query, out id);
- bool idMatch = isNum && (method.Rid == id || method.Token == id);
+ bool idMatch = isNum && (method.Rid == id || MetadataTokens.GetRowNumber(method.MetadataReader, method.MethodHandle) == id);
bool sigMatch = false;
if (exact)
@@ -401,7 +433,7 @@ namespace R2RDump
// parse the ReadyToRun image
R2RReader r2r = new R2RReader(filename);
- if (_disasm)
+ if (_options.Disasm)
{
if (r2r.InputArchitectureSupported() && r2r.DisassemblerArchitectureSupported())
{
@@ -415,11 +447,11 @@ namespace R2RDump
if (_xml)
{
- _dumper = new XmlDumper(_ignoreSensitive, r2r, _writer, _raw, _header, _disasm, disassembler, _unwind, _gc, _sectionContents);
+ _dumper = new XmlDumper(_ignoreSensitive, r2r, _writer, disassembler, _options);
}
else
{
- _dumper = new TextDumper(r2r, _writer, _raw, _header, _disasm, disassembler, _unwind, _gc, _sectionContents);
+ _dumper = new TextDumper(r2r, _writer, disassembler, _options);
}
if (!_diff)
diff --git a/src/tools/r2rdump/R2RMethod.cs b/src/tools/r2rdump/R2RMethod.cs
index 1ea77ea04b..89cfd51b17 100644
--- a/src/tools/r2rdump/R2RMethod.cs
+++ b/src/tools/r2rdump/R2RMethod.cs
@@ -211,8 +211,10 @@ namespace R2RDump
{
private const int _mdtMethodDef = 0x06000000;
- MetadataReader _mdReader;
- MethodDefinition _methodDef;
+ /// <summary>
+ /// ECMA metadata reader for the method module.
+ /// </summary>
+ public MetadataReader MetadataReader { get; }
/// <summary>
/// An unique index for the method
@@ -230,8 +232,6 @@ namespace R2RDump
/// </summary>
public string SignatureString { get; set; }
- public bool IsGeneric { get; set; }
-
public MethodSignature<string> Signature { get; }
/// <summary>
@@ -240,9 +240,9 @@ namespace R2RDump
public string DeclaringType { get; set; }
/// <summary>
- /// The token of the method consisting of the table code (0x06) and row id
+ /// The method metadata handle
/// </summary>
- public uint Token { get; set; }
+ public EntityHandle MethodHandle { get; set; }
/// <summary>
/// The row id of the method
@@ -264,105 +264,96 @@ namespace R2RDump
public FixupCell[] Fixups { get; set; }
- /// <summary>
- /// Maps all the generic parameters to the type in the instance
- /// </summary>
- private Dictionary<string, string> _genericParamInstanceMap;
-
public R2RMethod() { }
/// <summary>
/// Extracts the method signature from the metadata by rid
/// </summary>
- public R2RMethod(int index, MetadataReader mdReader, uint rid, int entryPointId, CorElementType[] instanceArgs, uint[] tok, FixupCell[] fixups)
+ public R2RMethod(
+ int index,
+ MetadataReader mdReader,
+ EntityHandle methodHandle,
+ int entryPointId,
+ string owningType,
+ string constrainedType,
+ string[] instanceArgs,
+ FixupCell[] fixups)
{
Index = index;
- Token = _mdtMethodDef | rid;
- Rid = rid;
+ MethodHandle = methodHandle;
EntryPointRuntimeFunctionId = entryPointId;
- _mdReader = mdReader;
+ MetadataReader = mdReader;
RuntimeFunctions = new List<RuntimeFunction>();
- // get the method signature from the MethodDefhandle
- MethodDefinitionHandle methodDefHandle = MetadataTokens.MethodDefinitionHandle((int)rid);
- _methodDef = mdReader.GetMethodDefinition(methodDefHandle);
- Name = mdReader.GetString(_methodDef.Name);
- BlobReader signatureReader = mdReader.GetBlobReader(_methodDef.Signature);
-
- TypeDefinitionHandle declaringTypeHandle = _methodDef.GetDeclaringType();
- DeclaringType = MetadataNameFormatter.FormatHandle(mdReader, declaringTypeHandle);
-
- SignatureHeader signatureHeader = signatureReader.ReadSignatureHeader();
- IsGeneric = signatureHeader.IsGeneric;
- GenericParameterHandleCollection genericParams = _methodDef.GetGenericParameters();
- _genericParamInstanceMap = new Dictionary<string, string>();
-
- int argCount = signatureReader.ReadCompressedInteger();
- if (IsGeneric)
- {
- argCount = signatureReader.ReadCompressedInteger();
- }
+ EntityHandle owningTypeHandle;
+ GenericParameterHandleCollection genericParams = default(GenericParameterHandleCollection);
- Fixups = fixups;
+ DisassemblingGenericContext genericContext = new DisassemblingGenericContext(typeParameters: Array.Empty<string>(), methodParameters: instanceArgs);
+ DisassemblingTypeProvider typeProvider = new DisassemblingTypeProvider();
- DisassemblingTypeProvider provider = new DisassemblingTypeProvider();
- if (IsGeneric && instanceArgs != null && tok != null)
+ // get the method signature from the method handle
+ switch (MethodHandle.Kind)
{
- InitGenericInstances(genericParams, instanceArgs, tok);
- }
+ case HandleKind.MethodDefinition:
+ {
+ MethodDefinition methodDef = MetadataReader.GetMethodDefinition((MethodDefinitionHandle)MethodHandle);
+ Name = MetadataReader.GetString(methodDef.Name);
+ Signature = methodDef.DecodeSignature<string, DisassemblingGenericContext>(typeProvider, genericContext);
+ owningTypeHandle = methodDef.GetDeclaringType();
+ genericParams = methodDef.GetGenericParameters();
+ }
+ break;
- DisassemblingGenericContext genericContext = new DisassemblingGenericContext(new string[0], _genericParamInstanceMap.Values.ToArray());
- Signature = _methodDef.DecodeSignature(provider, genericContext);
+ case HandleKind.MemberReference:
+ {
+ MemberReference memberRef = MetadataReader.GetMemberReference((MemberReferenceHandle)MethodHandle);
+ Name = MetadataReader.GetString(memberRef.Name);
+ Signature = memberRef.DecodeMethodSignature<string, DisassemblingGenericContext>(typeProvider, genericContext);
+ owningTypeHandle = memberRef.Parent;
+ }
+ break;
- SignatureString = GetSignature();
- }
+ default:
+ throw new NotImplementedException();
+ }
- /// <summary>
- /// Initialize map of generic parameters names to the type in the instance
- /// </summary>
- private void InitGenericInstances(GenericParameterHandleCollection genericParams, CorElementType[] instanceArgs, uint[] tok)
- {
- if (instanceArgs.Length != genericParams.Count || tok.Length != genericParams.Count)
+ if (owningType != null)
{
- throw new BadImageFormatException("Generic param indices out of bounds");
+ DeclaringType = owningType;
}
-
- for (int i = 0; i < instanceArgs.Length; i++)
+ else
{
- string key = _mdReader.GetString(_mdReader.GetGenericParameter(genericParams.ElementAt(i)).Name); // name of the generic param, eg. "T"
- string type = instanceArgs[i].ToString(); // type of the generic param instance
- if (instanceArgs[i] == CorElementType.ELEMENT_TYPE_VALUETYPE)
- {
- var t = _mdReader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle((int)tok[i]));
- type = _mdReader.GetString(t.Name); // name of the struct
-
- }
- _genericParamInstanceMap[key] = type;
+ DeclaringType = MetadataNameFormatter.FormatHandle(MetadataReader, owningTypeHandle);
}
- }
- /// <summary>
- /// Returns a string with format DeclaringType.Name<GenericTypes,...>(ArgTypes,...)
- /// </summary>
- private string GetSignature()
- {
- StringBuilder sb = new StringBuilder();
+ Fixups = fixups;
- sb.AppendFormat($"{DeclaringType}.{Name}");
+ StringBuilder sb = new StringBuilder();
+ sb.Append(Signature.ReturnType);
+ sb.Append(" ");
+ sb.Append(DeclaringType);
+ sb.Append(".");
+ sb.Append(Name);
- if (IsGeneric)
+ if (Signature.GenericParameterCount != 0)
{
sb.Append("<");
- int i = 0;
- foreach (var instance in _genericParamInstanceMap.Values)
+ for (int i = 0; i < Signature.GenericParameterCount; i++)
{
if (i > 0)
{
sb.Append(", ");
}
- sb.AppendFormat($"{instance}");
- i++;
+ if (instanceArgs != null && instanceArgs.Length > i)
+ {
+ sb.Append(instanceArgs[i]);
+ }
+ else
+ {
+ sb.Append("!");
+ sb.Append(i);
+ }
}
sb.Append(">");
}
@@ -378,17 +369,17 @@ namespace R2RDump
}
sb.Append(")");
- return sb.ToString();
+ SignatureString = sb.ToString();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.AppendLine($"{Signature.ReturnType} {SignatureString}");
+ sb.AppendLine(SignatureString);
- sb.AppendLine($"Token: 0x{Token:X8}");
- sb.AppendLine($"Rid: {Rid}");
+ sb.AppendLine($"Handle: 0x{MetadataTokens.GetToken(MetadataReader, MethodHandle):X8}");
+ sb.AppendLine($"Rid: {MetadataTokens.GetRowNumber(MetadataReader, MethodHandle)}");
sb.AppendLine($"EntryPointRuntimeFunctionId: {EntryPointRuntimeFunctionId}");
sb.AppendLine($"Number of RuntimeFunctions: {RuntimeFunctions.Count}");
if (Fixups != null)
diff --git a/src/tools/r2rdump/R2RReader.cs b/src/tools/r2rdump/R2RReader.cs
index d67f9679d3..265000aa1b 100644
--- a/src/tools/r2rdump/R2RReader.cs
+++ b/src/tools/r2rdump/R2RReader.cs
@@ -268,10 +268,11 @@ namespace R2RDump
int offset = 0;
if (methodEntryPoints.TryGetAt(Image, rid - 1, ref offset))
{
+ EntityHandle methodHandle = MetadataTokens.MethodDefinitionHandle((int)rid);
int runtimeFunctionId;
FixupCell[] fixups;
GetRuntimeFunctionIndexFromOffset(offset, out runtimeFunctionId, out fixups);
- R2RMethod method = new R2RMethod(R2RMethods.Count, MetadataReader, rid, runtimeFunctionId, null, null, fixups);
+ R2RMethod method = new R2RMethod(R2RMethods.Count, MetadataReader, methodHandle, runtimeFunctionId, owningType: null, constrainedType: null, instanceArgs: null, fixups: fixups);
if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= isEntryPoint.Length)
{
@@ -300,33 +301,55 @@ namespace R2RDump
NativeParser curParser = allEntriesEnum.GetNext();
while (!curParser.IsNull())
{
- uint methodFlags = curParser.GetCompressedData();
- uint rid = curParser.GetCompressedData();
- if ((methodFlags & (byte)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0)
+ SignatureDecoder decoder = new SignatureDecoder(this, (int)curParser.Offset);
+
+ string owningType = null;
+
+ uint methodFlags = decoder.ReadUInt();
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0)
+ {
+ owningType = decoder.ReadTypeSignature();
+ }
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_SlotInsteadOfToken) != 0)
+ {
+ throw new NotImplementedException();
+ }
+ EntityHandle methodHandle;
+ int rid = (int)decoder.ReadUInt();
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken) != 0)
{
- uint nArgs = curParser.GetCompressedData();
- CorElementType[] args = new CorElementType[nArgs];
- uint[] tokens = new uint[nArgs];
- for (int i = 0; i < nArgs; i++)
+ methodHandle = MetadataTokens.MemberReferenceHandle(rid);
+ }
+ else
+ {
+ methodHandle = MetadataTokens.MethodDefinitionHandle(rid);
+ }
+ string[] methodTypeArgs = null;
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0)
+ {
+ uint typeArgCount = decoder.ReadUInt();
+ methodTypeArgs = new string[typeArgCount];
+ for (int typeArgIndex = 0; typeArgIndex < typeArgCount; typeArgIndex++)
{
- args[i] = (CorElementType)curParser.GetByte();
- if (args[i] == CorElementType.ELEMENT_TYPE_VALUETYPE)
- {
- tokens[i] = curParser.GetCompressedData();
- tokens[i] = (tokens[i] >> 2);
- }
+ methodTypeArgs[typeArgIndex] = decoder.ReadTypeSignature();
}
+ }
- int runtimeFunctionId;
- FixupCell[] fixups;
- GetRuntimeFunctionIndexFromOffset((int)curParser.Offset, out runtimeFunctionId, out fixups);
- R2RMethod method = new R2RMethod(R2RMethods.Count, MetadataReader, rid, runtimeFunctionId, args, tokens, fixups);
- if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < isEntryPoint.Length)
- {
- isEntryPoint[method.EntryPointRuntimeFunctionId] = true;
- }
- R2RMethods.Add(method);
+ string constrainedType = null;
+ if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_Constrained) != 0)
+ {
+ constrainedType = decoder.ReadTypeSignature();
+ }
+
+ int runtimeFunctionId;
+ FixupCell[] fixups;
+ GetRuntimeFunctionIndexFromOffset((int)decoder.Offset, out runtimeFunctionId, out fixups);
+ R2RMethod method = new R2RMethod(R2RMethods.Count, MetadataReader, methodHandle, runtimeFunctionId, owningType, constrainedType, methodTypeArgs, fixups);
+ if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < isEntryPoint.Length)
+ {
+ isEntryPoint[method.EntryPointRuntimeFunctionId] = true;
}
+ R2RMethods.Add(method);
curParser = allEntriesEnum.GetNext();
}
}
diff --git a/src/tools/r2rdump/R2RSignature.cs b/src/tools/r2rdump/R2RSignature.cs
index 2522200fd8..7cf81bdf3a 100644
--- a/src/tools/r2rdump/R2RSignature.cs
+++ b/src/tools/r2rdump/R2RSignature.cs
@@ -35,10 +35,10 @@ namespace R2RDump
/// <param name="metadataReader">Metadata reader corresponding to the handle</param>
/// <param name="handle">Metadata handle to parse</param>
/// <param name="namespaceQualified">Include namespace in type names</param>
- public static string FormatHandle(MetadataReader metadataReader, Handle handle, bool namespaceQualified = true)
+ public static string FormatHandle(MetadataReader metadataReader, Handle handle, bool namespaceQualified = true, string owningTypeOverride = null)
{
MetadataNameFormatter formatter = new MetadataNameFormatter(metadataReader);
- return formatter.EmitHandleName(handle, namespaceQualified);
+ return formatter.EmitHandleName(handle, namespaceQualified, owningTypeOverride);
}
public static string FormatSignature(R2RReader r2rReader, int imageOffset)
@@ -52,18 +52,18 @@ namespace R2RDump
/// Emit a given token to a specified string builder.
/// </summary>
/// <param name="methodToken">ECMA token to provide string representation for</param>
- private string EmitHandleName(Handle handle, bool namespaceQualified)
+ private string EmitHandleName(Handle handle, bool namespaceQualified, string owningTypeOverride)
{
switch (handle.Kind)
{
case HandleKind.MemberReference:
- return EmitMemberReferenceName((MemberReferenceHandle)handle);
+ return EmitMemberReferenceName((MemberReferenceHandle)handle, owningTypeOverride);
case HandleKind.MethodSpecification:
- return EmitMethodSpecificationName((MethodSpecificationHandle)handle);
+ return EmitMethodSpecificationName((MethodSpecificationHandle)handle, owningTypeOverride);
case HandleKind.MethodDefinition:
- return EmitMethodDefinitionName((MethodDefinitionHandle)handle);
+ return EmitMethodDefinitionName((MethodDefinitionHandle)handle, owningTypeOverride);
case HandleKind.TypeReference:
return EmitTypeReferenceName((TypeReferenceHandle)handle, namespaceQualified);
@@ -83,18 +83,19 @@ namespace R2RDump
/// Emit a method specification.
/// </summary>
/// <param name="methodSpecHandle">Method specification handle</param>
- private string EmitMethodSpecificationName(MethodSpecificationHandle methodSpecHandle)
+ private string EmitMethodSpecificationName(MethodSpecificationHandle methodSpecHandle, string owningTypeOverride)
{
MethodSpecification methodSpec = _metadataReader.GetMethodSpecification(methodSpecHandle);
DisassemblingGenericContext genericContext = new DisassemblingGenericContext(Array.Empty<string>(), Array.Empty<string>());
- return EmitHandleName(methodSpec.Method, namespaceQualified: true) + methodSpec.DecodeSignature<string, DisassemblingGenericContext>(this, genericContext);
+ return EmitHandleName(methodSpec.Method, namespaceQualified: true, owningTypeOverride: owningTypeOverride)
+ + methodSpec.DecodeSignature<string, DisassemblingGenericContext>(this, genericContext);
}
/// <summary>
/// Emit a method reference.
/// </summary>
/// <param name="memberRefHandle">Member reference handle</param>
- private string EmitMemberReferenceName(MemberReferenceHandle memberRefHandle)
+ private string EmitMemberReferenceName(MemberReferenceHandle memberRefHandle, string owningTypeOverride)
{
MemberReference methodRef = _metadataReader.GetMemberReference(memberRefHandle);
StringBuilder builder = new StringBuilder();
@@ -102,7 +103,7 @@ namespace R2RDump
MethodSignature<String> methodSig = methodRef.DecodeMethodSignature<string, DisassemblingGenericContext>(this, genericContext);
builder.Append(methodSig.ReturnType);
builder.Append(" ");
- builder.Append(EmitContainingTypeAndMethodName(methodRef));
+ builder.Append(EmitContainingTypeAndMethodName(methodRef, owningTypeOverride));
builder.Append(EmitMethodSignature(methodSig));
return builder.ToString();
}
@@ -111,7 +112,7 @@ namespace R2RDump
/// Emit a method definition.
/// </summary>
/// <param name="methodSpecHandle">Method definition handle</param>
- private string EmitMethodDefinitionName(MethodDefinitionHandle methodDefinitionHandle)
+ private string EmitMethodDefinitionName(MethodDefinitionHandle methodDefinitionHandle, string owningTypeOverride)
{
MethodDefinition methodDef = _metadataReader.GetMethodDefinition(methodDefinitionHandle);
DisassemblingGenericContext genericContext = new DisassemblingGenericContext(Array.Empty<string>(), Array.Empty<string>());
@@ -119,7 +120,11 @@ namespace R2RDump
StringBuilder builder = new StringBuilder();
builder.Append(methodSig.ReturnType);
builder.Append(" ");
- builder.Append(EmitHandleName(methodDef.GetDeclaringType(), namespaceQualified: true));
+ if (owningTypeOverride == null)
+ {
+ owningTypeOverride = EmitHandleName(methodDef.GetDeclaringType(), namespaceQualified: false, owningTypeOverride: null);
+ }
+ builder.Append(owningTypeOverride);
builder.Append(".");
builder.Append(EmitString(methodDef.Name));
builder.Append(EmitMethodSignature(methodSig));
@@ -175,9 +180,13 @@ namespace R2RDump
/// </summary>
/// <param name="methodRef">Method reference to format</param>
/// <param name="methodSignature">Output method signature</param>
- private string EmitContainingTypeAndMethodName(MemberReference methodRef)
+ private string EmitContainingTypeAndMethodName(MemberReference methodRef, string owningTypeOverride)
{
- return EmitHandleName(methodRef.Parent, namespaceQualified: true) + "." + EmitString(methodRef.Name);
+ if (owningTypeOverride == null)
+ {
+ owningTypeOverride = EmitHandleName(methodRef.Parent, namespaceQualified: true, owningTypeOverride: null);
+ }
+ return owningTypeOverride + "." + EmitString(methodRef.Name);
}
/// <summary>
@@ -193,7 +202,7 @@ namespace R2RDump
if (typeRef.ResolutionScope.Kind != HandleKind.AssemblyReference)
{
// Nested type - format enclosing type followed by the nested type
- return EmitHandleName(typeRef.ResolutionScope, namespaceQualified) + "+" + typeName;
+ return EmitHandleName(typeRef.ResolutionScope, namespaceQualified, owningTypeOverride: null) + "+" + typeName;
}
if (namespaceQualified)
{
@@ -219,7 +228,7 @@ namespace R2RDump
if (typeDef.IsNested)
{
// Nested type
- return EmitHandleName(typeDef.GetDeclaringType(), namespaceQualified) + "+" + typeName;
+ return EmitHandleName(typeDef.GetDeclaringType(), namespaceQualified, owningTypeOverride: null) + "+" + typeName;
}
string output;
@@ -294,6 +303,19 @@ namespace R2RDump
}
/// <summary>
+ /// Construct the signature decoder by storing the image byte array and offset within the array.
+ /// </summary>
+ /// <param name="metadataReader">Metadata reader for the R2R image</param>
+ /// <param name="signature">Signature to parse</param>
+ /// <param name="offset">Optional signature offset within the signature byte array, 0 by default</param>
+ public SignatureDecoder(MetadataReader metadataReader, byte[] signature, int offset = 0)
+ {
+ _image = signature;
+ _metadataReader = metadataReader;
+ _offset = offset;
+ }
+
+ /// <summary>
/// Read a single byte from the signature stream and advances the current offset.
/// </summary>
public byte ReadByte()
@@ -398,6 +420,20 @@ namespace R2RDump
return builder.ToString();
}
+ public string ReadMethodSignature()
+ {
+ StringBuilder builder = new StringBuilder();
+ ParseMethod(builder);
+ return builder.ToString();
+ }
+
+ public string ReadTypeSignature()
+ {
+ StringBuilder builder = new StringBuilder();
+ ParseType(builder);
+ return builder.ToString();
+ }
+
/// <summary>
/// Parse the signature into a given output string builder.
/// </summary>
@@ -445,12 +481,12 @@ namespace R2RDump
break;
case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_DefToken:
- ParseMethodDefToken(builder);
+ ParseMethodDefToken(builder, owningTypeOverride: null);
builder.Append(" (METHOD_ENTRY_DEF_TOKEN)");
break;
case ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry_RefToken:
- ParseMethodRefToken(builder);
+ ParseMethodRefToken(builder, owningTypeOverride: null);
builder.Append(" (METHOD_ENTRY_REF_TOKEN)");
break;
@@ -461,12 +497,12 @@ namespace R2RDump
break;
case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_DefToken:
- ParseMethodDefToken(builder);
+ ParseMethodDefToken(builder, owningTypeOverride: null);
builder.Append(" (VIRTUAL_ENTRY_DEF_TOKEN)");
break;
case ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry_RefToken:
- ParseMethodRefToken(builder);
+ ParseMethodRefToken(builder, owningTypeOverride: null);
builder.Append(" (VIRTUAL_ENTRY_REF_TOKEN)");
break;
@@ -744,7 +780,7 @@ namespace R2RDump
break;
case CorElementType.ELEMENT_TYPE_CANON_ZAPSIG:
- builder.Append("canon_zapsig");
+ builder.Append("__Canon");
break;
case CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG:
@@ -784,9 +820,12 @@ namespace R2RDump
private void ParseMethod(StringBuilder builder)
{
uint methodFlags = ReadUInt();
+ string owningTypeOverride = null;
if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0)
{
- ParseType(builder);
+ SignatureDecoder owningTypeDecoder = new SignatureDecoder(_metadataReader, _image, _offset);
+ owningTypeOverride = owningTypeDecoder.ReadTypeSignature();
+ _offset = owningTypeDecoder._offset;
}
if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_SlotInsteadOfToken) != 0)
{
@@ -794,11 +833,11 @@ namespace R2RDump
}
if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken) != 0)
{
- ParseMethodRefToken(builder);
+ ParseMethodRefToken(builder, owningTypeOverride: owningTypeOverride);
}
else
{
- ParseMethodDefToken(builder);
+ ParseMethodDefToken(builder, owningTypeOverride: owningTypeOverride);
}
if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0)
@@ -827,20 +866,21 @@ namespace R2RDump
/// Read a methodDef token from the signature and output the corresponding object to the builder.
/// </summary>
/// <param name="builder">Output string builder</param>
- private void ParseMethodDefToken(StringBuilder builder)
+ private void ParseMethodDefToken(StringBuilder builder, string owningTypeOverride)
{
uint methodDefToken = ReadUInt() | (uint)CorTokenType.mdtMethodDef;
- builder.Append(MetadataNameFormatter.FormatHandle(_metadataReader, MetadataTokens.Handle((int)methodDefToken)));
+ builder.Append(MetadataNameFormatter.FormatHandle(_metadataReader, MetadataTokens.Handle((int)methodDefToken), namespaceQualified: true, owningTypeOverride: owningTypeOverride));
}
/// <summary>
/// Read a memberRef token from the signature and output the corresponding object to the builder.
/// </summary>
/// <param name="builder">Output string builder</param>
- private void ParseMethodRefToken(StringBuilder builder)
+ /// <param name="owningTypeOverride">Explicit owning type override</param>
+ private void ParseMethodRefToken(StringBuilder builder, string owningTypeOverride)
{
uint methodRefToken = ReadUInt() | (uint)CorTokenType.mdtMemberRef;
- builder.Append(MetadataNameFormatter.FormatHandle(_metadataReader, MetadataTokens.Handle((int)methodRefToken)));
+ builder.Append(MetadataNameFormatter.FormatHandle(_metadataReader, MetadataTokens.Handle((int)methodRefToken), namespaceQualified: false, owningTypeOverride: owningTypeOverride));
}
/// <summary>
diff --git a/src/tools/r2rdump/TextDumper.cs b/src/tools/r2rdump/TextDumper.cs
index 2b95b21e67..3fa444c763 100644
--- a/src/tools/r2rdump/TextDumper.cs
+++ b/src/tools/r2rdump/TextDumper.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Xml;
@@ -9,18 +10,9 @@ namespace R2RDump
{
class TextDumper : Dumper
{
- public TextDumper(R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, Disassembler disassembler, bool unwind, bool gc, bool sectionContents)
+ public TextDumper(R2RReader r2r, TextWriter writer, Disassembler disassembler, DumpOptions options)
+ : base(r2r, writer, disassembler, options)
{
- _r2r = r2r;
- _writer = writer;
-
- _raw = raw;
- _header = header;
- _disasm = disasm;
- _disassembler = disassembler;
- _unwind = unwind;
- _gc = gc;
- _sectionContents = sectionContents;
}
internal override void Begin()
@@ -63,7 +55,7 @@ namespace R2RDump
{
_writer.WriteLine(_r2r.R2RHeader.ToString());
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(_r2r.R2RHeader.RelativeVirtualAddress, (uint)_r2r.R2RHeader.Size);
}
@@ -73,8 +65,8 @@ namespace R2RDump
WriteDivider("R2R Sections");
_writer.WriteLine($"{_r2r.R2RHeader.Sections.Count} sections");
SkipLine();
-
- foreach (R2RSection section in _r2r.R2RHeader.Sections.Values)
+
+ foreach (R2RSection section in NormalizedSections())
{
DumpSection(section);
}
@@ -90,12 +82,12 @@ namespace R2RDump
WriteSubDivider();
_writer.WriteLine(section.ToString());
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(section.RelativeVirtualAddress, (uint)section.Size);
SkipLine();
}
- if (_sectionContents)
+ if (_options.SectionContents)
{
DumpSectionContents(section);
SkipLine();
@@ -107,7 +99,7 @@ namespace R2RDump
WriteDivider("R2R Methods");
_writer.WriteLine($"{_r2r.R2RMethods.Count} methods");
SkipLine();
- foreach (R2RMethod method in _r2r.R2RMethods)
+ foreach (R2RMethod method in NormalizedMethods())
{
DumpMethod(method);
}
@@ -121,12 +113,12 @@ namespace R2RDump
WriteSubDivider();
_writer.WriteLine(method.ToString());
- if (_gc && method.GcInfo != null)
+ if (_options.GC && method.GcInfo != null)
{
_writer.WriteLine("GcInfo:");
_writer.Write(method.GcInfo);
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, null, "", false);
}
@@ -147,21 +139,21 @@ namespace R2RDump
_writer.WriteLine(rtf.Method.SignatureString);
_writer.Write($"{rtf}");
- if (_disasm)
+ if (_options.Disasm)
{
DumpDisasm(rtf, _r2r.GetOffset(rtf.StartAddress));
}
- if (_raw)
+ if (_options.Raw)
{
_writer.WriteLine("Raw Bytes:");
DumpBytes(rtf.StartAddress, (uint)rtf.Size);
}
- if (_unwind)
+ if (_options.Unwind)
{
_writer.WriteLine("UnwindInfo:");
_writer.Write(rtf.UnwindInfo);
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(rtf.UnwindRVA, (uint)rtf.UnwindInfo.Size);
}
@@ -303,7 +295,7 @@ namespace R2RDump
foreach (R2RImportSection importSection in _r2r.ImportSections)
{
_writer.Write(importSection.ToString());
- if (_raw && importSection.Entries.Count != 0)
+ if (_options.Raw && importSection.Entries.Count != 0)
{
if (importSection.SectionRVA != 0)
{
diff --git a/src/tools/r2rdump/XmlDumper.cs b/src/tools/r2rdump/XmlDumper.cs
index f260000e1f..97a90e78aa 100644
--- a/src/tools/r2rdump/XmlDumper.cs
+++ b/src/tools/r2rdump/XmlDumper.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Xml;
@@ -15,21 +16,12 @@ namespace R2RDump
private bool _ignoreSensitive;
private XmlAttributeOverrides _ignoredProperties;
- public XmlDumper(bool ignoreSensitive, R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, Disassembler disassembler, bool unwind, bool gc, bool sectionContents)
+ public XmlDumper(bool ignoreSensitive, R2RReader r2r, TextWriter writer, Disassembler disassembler, DumpOptions options)
+ : base(r2r, writer, disassembler, options)
{
_ignoreSensitive = ignoreSensitive;
- _r2r = r2r;
- _writer = writer;
XmlDocument = new XmlDocument();
- _raw = raw;
- _header = header;
- _disasm = disasm;
- _disassembler = disassembler;
- _unwind = unwind;
- _gc = gc;
- _sectionContents = sectionContents;
-
_ignoredProperties = new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
attrs.XmlIgnore = _ignoreSensitive;
@@ -48,14 +40,6 @@ namespace R2RDump
_ignoredProperties.Add(typeof(R2RSection), "Size", attrs);
}
- public XmlDocument GetXmlDocument()
- {
- Begin();
- DumpHeader(true);
- DumpAllMethods();
- return XmlDocument;
- }
-
internal override void Begin()
{
_rootNode = XmlDocument.CreateNode("element", "R2RDump", "");
@@ -91,7 +75,7 @@ namespace R2RDump
_rootNode.AppendChild(headerNode);
Serialize(_r2r.R2RHeader, headerNode);
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(_r2r.R2RHeader.RelativeVirtualAddress, (uint)_r2r.R2RHeader.Size, headerNode);
}
@@ -102,7 +86,7 @@ namespace R2RDump
_rootNode.AppendChild(sectionsNode);
AddXMLNode("Count", _r2r.R2RHeader.Sections.Count.ToString(), sectionsNode);
- foreach (R2RSection section in _r2r.R2RHeader.Sections.Values)
+ foreach (R2RSection section in NormalizedSections())
{
DumpSection(section, sectionsNode);
}
@@ -120,11 +104,11 @@ namespace R2RDump
parentNode.AppendChild(sectionNode);
Serialize(section, sectionNode);
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(section.RelativeVirtualAddress, (uint)section.Size, sectionNode);
}
- if (_sectionContents)
+ if (_options.SectionContents)
{
DumpSectionContents(section, sectionNode);
}
@@ -135,7 +119,7 @@ namespace R2RDump
XmlNode methodsNode = XmlDocument.CreateNode("element", "Methods", "");
_rootNode.AppendChild(methodsNode);
AddXMLAttribute(methodsNode, "Count", _r2r.R2RMethods.Count.ToString());
- foreach (R2RMethod method in _r2r.R2RMethods)
+ foreach (R2RMethod method in NormalizedMethods())
{
DumpMethod(method, methodsNode);
}
@@ -151,7 +135,7 @@ namespace R2RDump
parentNode.AppendChild(methodNode);
Serialize(method, methodNode);
- if (_gc && method.GcInfo != null)
+ if (_options.GC && method.GcInfo != null)
{
XmlNode gcNode = XmlDocument.CreateNode("element", "GcInfo", "");
methodNode.AppendChild(gcNode);
@@ -165,7 +149,7 @@ namespace R2RDump
}
}
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(method.GcInfo.Offset, (uint)method.GcInfo.Size, gcNode, "Raw", false);
}
@@ -192,23 +176,23 @@ namespace R2RDump
AddXMLNode("MethodRid", rtf.Method.Rid.ToString(), rtfNode);
Serialize(rtf, rtfNode);
- if (_disasm)
+ if (_options.Disasm)
{
DumpDisasm(rtf, _r2r.GetOffset(rtf.StartAddress), rtfNode);
}
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(rtf.StartAddress, (uint)rtf.Size, rtfNode);
}
- if (_unwind && rtf.UnwindInfo != null)
+ if (_options.Unwind && rtf.UnwindInfo != null)
{
XmlNode unwindNode = null;
unwindNode = XmlDocument.CreateNode("element", "UnwindInfo", "");
rtfNode.AppendChild(unwindNode);
Serialize(rtf.UnwindInfo, unwindNode);
- if (_raw)
+ if (_options.Raw)
{
DumpBytes(rtf.UnwindRVA, (uint)((Amd64.UnwindInfo)rtf.UnwindInfo).Size, unwindNode);
}
@@ -308,7 +292,7 @@ namespace R2RDump
contentsNode.AppendChild(importSectionsNode);
Serialize(importSection, importSectionsNode);
- if (_raw && importSection.Entries.Count != 0)
+ if (_options.Raw && importSection.Entries.Count != 0)
{
if (importSection.SectionRVA != 0)
{