summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmy <amycmyu@gmail.com>2018-06-01 08:05:44 -0700
committerZach Montoya <zamont@microsoft.com>2018-06-01 08:05:44 -0700
commit88c10681e2b9a8584f574df234ee2a2ff74a8ea3 (patch)
tree8a593110c50fcd9603e4e8b8aad8a887decbccf5
parentc17ca743320b8c0c54ca1b8248b4e8cbc771c241 (diff)
downloadcoreclr-88c10681e2b9a8584f574df234ee2a2ff74a8ea3.tar.gz
coreclr-88c10681e2b9a8584f574df234ee2a2ff74a8ea3.tar.bz2
coreclr-88c10681e2b9a8584f574df234ee2a2ff74a8ea3.zip
R2RDump - Commandline interface (#18136)
* Use ReadCompressedData for NativeHashTable, fix ref signature types, save array dimension, use AppendLine to avoid line-ending problems * Include System.CommandLine, arg parsing, read/write file * Add commandline options to search sections/methods/runtimeFunctions, option to dump raw data * Added comments, save cli options in global variables, renamed some functions * Add DumpByte function to R2RSection and R2RHeader, indent raw bytes * Change some cli option names, use DumpRuntimeFunction, return list of query matches, changes to ArgStringToInt * Move DumpBytes to R2RDump, print method of runtime function * Use writer object instead of Console * Use TextWriter instead of own writer class * Handle jagged arrays and other cases using MethodDefinition.DecodeSignature with a slightly modified DisassemblingTypeProvider * Close the _writer in finally block
-rw-r--r--src/tools/r2rdump/DisassemblingTypeProvider.cs226
-rw-r--r--src/tools/r2rdump/NativeHashtable.cs8
-rw-r--r--src/tools/r2rdump/NativeReader.cs24
-rw-r--r--src/tools/r2rdump/R2RDump.cs453
-rw-r--r--src/tools/r2rdump/R2RDump.csproj4
-rw-r--r--src/tools/r2rdump/R2RHeader.cs18
-rw-r--r--src/tools/r2rdump/R2RMethod.cs147
-rw-r--r--src/tools/r2rdump/R2RReader.cs54
-rw-r--r--src/tools/r2rdump/R2RSection.cs6
-rw-r--r--src/tools/r2rdump/SignatureType.cs118
10 files changed, 813 insertions, 245 deletions
diff --git a/src/tools/r2rdump/DisassemblingTypeProvider.cs b/src/tools/r2rdump/DisassemblingTypeProvider.cs
new file mode 100644
index 0000000000..c0a7e148c1
--- /dev/null
+++ b/src/tools/r2rdump/DisassemblingTypeProvider.cs
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Text;
+
+namespace R2RDump
+{
+ internal class DisassemblingGenericContext
+ {
+ public DisassemblingGenericContext(string[] typeParameters, string[] methodParameters)
+ {
+ MethodParameters = methodParameters;
+ TypeParameters = typeParameters;
+ }
+
+ public string[] MethodParameters { get; }
+ public string[] TypeParameters { get; }
+ }
+
+ // Test implementation of ISignatureTypeProvider<TType, TGenericContext> that uses strings in ilasm syntax as TType.
+ // A real provider in any sort of perf constraints would not want to allocate strings freely like this, but it keeps test code simple.
+ internal class DisassemblingTypeProvider : ISignatureTypeProvider<string, DisassemblingGenericContext>
+ {
+ public virtual string GetPrimitiveType(PrimitiveTypeCode typeCode)
+ {
+ return typeCode.ToString();
+ }
+
+ public virtual string GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind = 0)
+ {
+ TypeDefinition definition = reader.GetTypeDefinition(handle);
+
+ string name = definition.Namespace.IsNil
+ ? reader.GetString(definition.Name)
+ : reader.GetString(definition.Namespace) + "." + reader.GetString(definition.Name);
+
+ if ((definition.Attributes & TypeAttributes.NestedPublic) != 0 || (definition.Attributes & TypeAttributes.NestedFamily) != 0)
+ {
+ TypeDefinitionHandle declaringTypeHandle = definition.GetDeclaringType();
+ return GetTypeFromDefinition(reader, declaringTypeHandle, 0) + "/" + name;
+ }
+
+ return name;
+ }
+
+ public virtual string GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind = 0)
+ {
+ TypeReference reference = reader.GetTypeReference(handle);
+ Handle scope = reference.ResolutionScope;
+
+ string name = reference.Namespace.IsNil
+ ? reader.GetString(reference.Name)
+ : reader.GetString(reference.Namespace) + "." + reader.GetString(reference.Name);
+
+ switch (scope.Kind)
+ {
+ case HandleKind.ModuleReference:
+ return "[.module " + reader.GetString(reader.GetModuleReference((ModuleReferenceHandle)scope).Name) + "]" + name;
+
+ case HandleKind.AssemblyReference:
+ var assemblyReferenceHandle = (AssemblyReferenceHandle)scope;
+ var assemblyReference = reader.GetAssemblyReference(assemblyReferenceHandle);
+ return "[" + reader.GetString(assemblyReference.Name) + "]" + name;
+
+ case HandleKind.TypeReference:
+ return GetTypeFromReference(reader, (TypeReferenceHandle)scope) + "/" + name;
+
+ default:
+ return name;
+ }
+ }
+
+ public virtual string GetTypeFromSpecification(MetadataReader reader, DisassemblingGenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind = 0)
+ {
+ return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
+ }
+
+ public virtual string GetSZArrayType(string elementType)
+ {
+ return elementType + "[]";
+ }
+
+ public virtual string GetPointerType(string elementType)
+ {
+ return elementType + "*";
+ }
+
+ public virtual string GetByReferenceType(string elementType)
+ {
+ return "ref " + elementType;
+ }
+
+ public virtual string GetGenericMethodParameter(DisassemblingGenericContext genericContext, int index)
+ {
+ if (index >= genericContext.MethodParameters.Length)
+ {
+ R2RDump.WriteWarning("GenericMethodParameters index out of bounds");
+ return "";
+ }
+ return genericContext.MethodParameters[index];
+ }
+
+ public virtual string GetGenericTypeParameter(DisassemblingGenericContext genericContext, int index)
+ {
+ if (index >= genericContext.TypeParameters.Length)
+ {
+ R2RDump.WriteWarning("GenericTypeParameter index out of bounds");
+ return "";
+ }
+ return genericContext.TypeParameters[index];
+ }
+
+ public virtual string GetPinnedType(string elementType)
+ {
+ return elementType + " pinned";
+ }
+
+ public virtual string GetGenericInstantiation(string genericType, ImmutableArray<string> typeArguments)
+ {
+ return genericType + "<" + String.Join(",", typeArguments) + ">";
+ }
+
+ public virtual string GetArrayType(string elementType, ArrayShape shape)
+ {
+ var builder = new StringBuilder();
+
+ builder.Append(elementType);
+ builder.Append('[');
+
+ for (int i = 0; i < shape.Rank; i++)
+ {
+ int lowerBound = 0;
+
+ if (i < shape.LowerBounds.Length)
+ {
+ lowerBound = shape.LowerBounds[i];
+ builder.Append(lowerBound);
+ }
+
+ builder.Append("...");
+
+ if (i < shape.Sizes.Length)
+ {
+ builder.Append(lowerBound + shape.Sizes[i] - 1);
+ }
+
+ if (i < shape.Rank - 1)
+ {
+ builder.Append(',');
+ }
+ }
+
+ builder.Append(']');
+
+ return builder.ToString();
+ }
+
+ public virtual string GetTypeFromHandle(MetadataReader reader, DisassemblingGenericContext genericContext, EntityHandle handle)
+ {
+ switch (handle.Kind)
+ {
+ case HandleKind.TypeDefinition:
+ return GetTypeFromDefinition(reader, (TypeDefinitionHandle)handle);
+
+ case HandleKind.TypeReference:
+ return GetTypeFromReference(reader, (TypeReferenceHandle)handle);
+
+ case HandleKind.TypeSpecification:
+ return GetTypeFromSpecification(reader, genericContext, (TypeSpecificationHandle)handle);
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(handle));
+ }
+ }
+
+ public virtual string GetModifiedType(string modifierType, string unmodifiedType, bool isRequired)
+ {
+ return unmodifiedType + (isRequired ? " modreq(" : " modopt(") + modifierType + ")";
+ }
+
+ public virtual string GetFunctionPointerType(MethodSignature<string> signature)
+ {
+ ImmutableArray<string> parameterTypes = signature.ParameterTypes;
+
+ int requiredParameterCount = signature.RequiredParameterCount;
+
+ var builder = new StringBuilder();
+ builder.Append("method ");
+ builder.Append(signature.ReturnType);
+ builder.Append(" *(");
+
+ int i;
+ for (i = 0; i < requiredParameterCount; i++)
+ {
+ builder.Append(parameterTypes[i]);
+ if (i < parameterTypes.Length - 1)
+ {
+ builder.Append(", ");
+ }
+ }
+
+ if (i < parameterTypes.Length)
+ {
+ builder.Append("..., ");
+ for (; i < parameterTypes.Length; i++)
+ {
+ builder.Append(parameterTypes[i]);
+ if (i < parameterTypes.Length - 1)
+ {
+ builder.Append(", ");
+ }
+ }
+ }
+
+ builder.Append(')');
+ return builder.ToString();
+ }
+ }
+
+}
diff --git a/src/tools/r2rdump/NativeHashtable.cs b/src/tools/r2rdump/NativeHashtable.cs
index 902080017b..b596622b1d 100644
--- a/src/tools/r2rdump/NativeHashtable.cs
+++ b/src/tools/r2rdump/NativeHashtable.cs
@@ -47,6 +47,14 @@ namespace R2RDump
return val;
}
+ public uint GetCompressedData()
+ {
+ int off = (int)Offset;
+ uint val = NativeReader.ReadCompressedData(_image, ref off);
+ Offset += 1;
+ return val;
+ }
+
public uint GetUnsigned()
{
uint value = 0;
diff --git a/src/tools/r2rdump/NativeReader.cs b/src/tools/r2rdump/NativeReader.cs
index 13b674433f..b3359f7632 100644
--- a/src/tools/r2rdump/NativeReader.cs
+++ b/src/tools/r2rdump/NativeReader.cs
@@ -200,5 +200,29 @@ namespace R2RDump
return offset;
}
+
+ public static uint ReadCompressedData(byte[] image, ref int start)
+ {
+ int off = start;
+ uint data = ReadUInt32(image, ref off);
+ if ((data & 0x80) == 0x00)
+ {
+ start++;
+ return (byte)data;
+ }
+ if ((data & 0xC0) == 0x80) // 10?? ????
+ {
+ data = (uint)((ReadByte(image, ref start) & 0x3f) << 8);
+ data |= ReadByte(image, ref start);
+ }
+ else // 110? ????
+ {
+ data = (uint)(ReadByte(image, ref start) & 0x1f) << 24;
+ data |= (uint)ReadByte(image, ref start) << 16;
+ data |= (uint)ReadByte(image, ref start) << 8;
+ data |= ReadByte(image, ref start);
+ }
+ return data;
+ }
}
}
diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs
index 7d0bd2fd19..9aa80395f5 100644
--- a/src/tools/r2rdump/R2RDump.cs
+++ b/src/tools/r2rdump/R2RDump.cs
@@ -4,55 +4,470 @@
using System;
using System.Collections.Generic;
+using System.CommandLine;
+using System.IO;
namespace R2RDump
{
class R2RDump
{
- public static void OutputWarning(string warning)
+ private bool _help = false;
+ private IReadOnlyList<string> _inputFilenames = Array.Empty<string>();
+ private string _outputFilename = null;
+ private bool _raw = false;
+ private bool _header = false;
+ private bool _disasm = false;
+ 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 = false;
+ private TextWriter _writer;
+
+ private R2RDump()
+ {
+ }
+
+ private ArgumentSyntax ParseCommandLine(string[] args)
+ {
+ ArgumentSyntax argSyntax = ArgumentSyntax.Parse(args, syntax =>
+ {
+ syntax.ApplicationName = "R2RDump";
+ syntax.HandleHelp = false;
+ syntax.HandleErrors = true;
+
+ 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("v|verbose|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.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("diff", ref _diff, "Compare two R2R images"); // not yet implemented
+ });
+
+ return argSyntax;
+ }
+
+ private int ArgStringToInt(string arg)
+ {
+ int n;
+ if (!ArgStringToInt(arg, out n))
+ {
+ throw new ArgumentException("Can't parse argument to int");
+ }
+ return n;
+ }
+
+ /// <summary>
+ /// Converts string passed as cmd line args into int, works for hexidecimal with 0x as prefix
+ /// </summary>
+ /// <param name="arg">The argument string to convert</param>
+ /// <param name="n">The integer representation</param>
+ private bool ArgStringToInt(string arg, out int n)
+ {
+ arg = arg.Trim();
+ if (arg.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+ {
+ return int.TryParse(arg.Substring(2), System.Globalization.NumberStyles.HexNumber, null, out n);
+ }
+ return int.TryParse(arg, out n);
+ }
+
+ public static void WriteWarning(string warning)
{
Console.WriteLine($"Warning: {warning}");
}
- public static int Main(string[] args)
+ private void WriteDivider(string title)
{
- try
+ _writer.WriteLine("============== " + title + " ==============");
+ _writer.WriteLine();
+ }
+
+ private void WriteSubDivider()
+ {
+ _writer.WriteLine("------------------");
+ _writer.WriteLine();
+ }
+
+ /// <summary>
+ /// Dumps the R2RHeader and all the sections in the header
+ /// </summary>
+ private void DumpHeader(R2RReader r2r, bool dumpSections)
+ {
+ _writer.WriteLine(r2r.R2RHeader.ToString());
+ if (_raw)
+ {
+ DumpBytes(r2r, r2r.R2RHeader.RelativeVirtualAddress, (uint)r2r.R2RHeader.Size);
+ }
+ if (dumpSections)
+ {
+ WriteDivider("R2R Sections");
+ foreach (R2RSection section in r2r.R2RHeader.Sections.Values)
+ {
+ DumpSection(r2r, section);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Dumps one R2RSection
+ /// </summary>
+ private void DumpSection(R2RReader r2r, R2RSection section)
+ {
+ WriteSubDivider();
+ _writer.WriteLine(section.ToString());
+ if (_raw)
+ {
+ DumpBytes(r2r, section.RelativeVirtualAddress, (uint)section.Size);
+ }
+ }
+
+ /// <summary>
+ /// Dumps one R2RMethod.
+ /// </summary>
+ private void DumpMethod(R2RReader r2r, R2RMethod method)
+ {
+ WriteSubDivider();
+ _writer.WriteLine(method.ToString());
+
+ foreach (RuntimeFunction runtimeFunction in method.RuntimeFunctions)
+ {
+ DumpRuntimeFunction(r2r, runtimeFunction);
+ }
+ }
+
+ /// <summary>
+ /// Dumps one runtime function.
+ /// </summary>
+ private void DumpRuntimeFunction(R2RReader r2r, RuntimeFunction rtf)
+ {
+ _writer.WriteLine(rtf.ToString());
+ if (_raw)
+ {
+ DumpBytes(r2r, rtf.StartAddress, (uint)rtf.Size);
+ }
+ _writer.WriteLine();
+ }
+
+ /// <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)
+ {
+ uint start = (uint)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)
+ {
+ _writer.WriteLine();
+ _writer.Write(" ");
+ }
+ }
+ _writer.WriteLine();
+ }
+
+ // <summary>
+ /// For each query in the list of queries, search for all methods matching the query by name, signature or id
+ /// </summary>
+ /// <param name="r2r">Contains all the extracted info about the ReadyToRun image</param>
+ /// <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)
+ {
+ if (queries.Count > 0)
{
- if (args.Length < 1)
+ WriteDivider(title);
+ }
+ foreach (string q in queries)
+ {
+ IList<R2RMethod> res = FindMethod(r2r, q, exact);
+
+ _writer.WriteLine(res.Count + " result(s) for \"" + q + "\"");
+ _writer.WriteLine();
+ foreach (R2RMethod method in res)
{
- throw new System.ArgumentException("File name must be passed as argument");
+ DumpMethod(r2r, method);
}
+ }
+ }
- R2RReader r2r = new R2RReader(args[0]);
+ // <summary>
+ /// For each query in the list of queries, search for all sections by the name or value of the ReadyToRunSectionType enum
+ /// </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)
+ {
+ if (queries.Count > 0)
+ {
+ WriteDivider("R2R Section");
+ }
+ foreach (string q in queries)
+ {
+ IList<R2RSection> res = FindSection(r2r, q);
- if (r2r.IsR2R)
+ _writer.WriteLine(res.Count + " result(s) for \"" + q + "\"");
+ _writer.WriteLine();
+ foreach (R2RSection section in res)
{
- Console.WriteLine($"Filename: {r2r.Filename}");
- Console.WriteLine($"Machine: {r2r.Machine}");
- Console.WriteLine($"ImageBase: 0x{r2r.ImageBase:X8}");
+ DumpSection(r2r, section);
+ }
+ }
+ }
+
+ // <summary>
+ /// For each query in the list of queries, search for a runtime function by id.
+ /// The method containing the runtime function gets outputted, along with the single runtime function that was searched
+ /// </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)
+ {
+ if (queries.Count > 0)
+ {
+ WriteDivider("Runtime Functions");
+ }
+ foreach (int q in queries)
+ {
+ RuntimeFunction rtf = FindRuntimeFunction(r2r, q);
- Console.WriteLine("============== R2R Header ==============");
- Console.WriteLine(r2r.R2RHeader.ToString());
- foreach (KeyValuePair<R2RSection.SectionType, R2RSection> section in r2r.R2RHeader.Sections)
+ if (rtf == null)
+ {
+ WriteWarning("Unable to find by id " + q);
+ continue;
+ }
+ _writer.WriteLine(rtf.Method.SignatureString);
+ DumpRuntimeFunction(r2r, rtf);
+ }
+ }
+
+ /// <summary>
+ /// Outputs specified headers, sections, methods or runtime functions for one ReadyToRun image
+ /// </summary>
+ /// <param name="r2r">The structure containing the info of the ReadyToRun image</param>
+ public void Dump(R2RReader r2r)
+ {
+ _writer.WriteLine($"Filename: {r2r.Filename}");
+ _writer.WriteLine($"Machine: {r2r.Machine}");
+ _writer.WriteLine($"ImageBase: 0x{r2r.ImageBase:X8}");
+ _writer.WriteLine();
+
+ if (_queries.Count == 0 && _keywords.Count == 0 && _runtimeFunctions.Count == 0 && _sections.Count == 0) //dump all sections and methods
+ {
+ WriteDivider("R2R Header");
+ DumpHeader(r2r, true);
+
+ if (!_header)
+ {
+ WriteDivider("R2R Methods");
+ _writer.WriteLine();
+ foreach (R2RMethod method in r2r.R2RMethods)
{
- Console.WriteLine("------------------\n");
- Console.WriteLine(section.Value.ToString());
+ DumpMethod(r2r, method);
}
+ }
+ }
+ else //dump queried sections/methods/runtimeFunctions
+ {
+ if (_header)
+ {
+ DumpHeader(r2r, false);
+ }
- Console.WriteLine("============== Native Code ==============\n");
- foreach (R2RMethod method in r2r.R2RMethods)
+ QuerySection(r2r, _sections);
+ QueryRuntimeFunction(r2r, _runtimeFunctions);
+ QueryMethod(r2r, "R2R Methods by Query", _queries, true);
+ QueryMethod(r2r, "R2R Methods by Keyword", _keywords, false);
+ }
+
+ _writer.WriteLine("========================================================");
+ _writer.WriteLine();
+ }
+
+ /// <summary>
+ /// Returns true if the name/signature/id of <param>method</param> matches <param>query</param>
+ /// </summary>
+ /// <param name="exact">Specifies exact or partial match</param>
+ /// <remarks>Case-insensitive and ignores whitespace</remarks>
+ private bool Match(R2RMethod method, string query, bool exact)
+ {
+ int id;
+ bool isNum = ArgStringToInt(query, out id);
+ bool idMatch = isNum && (method.Rid == id || method.Token == id);
+
+ bool sigMatch = false;
+ if (exact)
+ {
+ sigMatch = method.Name.Equals(query, StringComparison.OrdinalIgnoreCase);
+ if (!sigMatch)
+ {
+ string sig = method.SignatureString.Replace(" ", "");
+ string q = query.Replace(" ", "");
+ int iMatch = sig.IndexOf(q, StringComparison.OrdinalIgnoreCase);
+ sigMatch = (iMatch == 0 || (iMatch > 0 && iMatch == (sig.Length - q.Length) && sig[iMatch - 1] == '.'));
+ }
+ }
+ else
+ {
+ string sig = method.Signature.ReturnType + method.SignatureString.Replace(" ", "");
+ sigMatch = (sig.IndexOf(query.Replace(" ", ""), StringComparison.OrdinalIgnoreCase) >= 0);
+ }
+
+ return idMatch || sigMatch;
+ }
+
+ /// <summary>
+ /// Returns true if the name or value of the ReadyToRunSectionType of <param>section</param> matches <param>query</param>
+ /// </summary>
+ /// <remarks>Case-insensitive</remarks>
+ private bool Match(R2RSection section, string query)
+ {
+ int queryInt;
+ bool isNum = ArgStringToInt(query, out queryInt);
+ string typeName = Enum.GetName(typeof(R2RSection.SectionType), section.Type);
+
+ return (isNum && (int)section.Type == queryInt) || typeName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;
+ }
+
+ /// <summary>
+ /// Finds all R2RMethods by name/signature/id matching <param>query</param>
+ /// </summary>
+ /// <param name="r2r">Contains all extracted info about the ReadyToRun image</param>
+ /// <param name="query">The name/signature/id to search for</param>
+ /// <param name="exact">Specifies exact or partial match</param>
+ /// <out name="res">List of all matching methods</out>
+ /// <remarks>Case-insensitive and ignores whitespace</remarks>
+ public IList<R2RMethod> FindMethod(R2RReader r2r, string query, bool exact)
+ {
+ List<R2RMethod> res = new List<R2RMethod>();
+ foreach (R2RMethod method in r2r.R2RMethods)
+ {
+ if (Match(method, query, exact))
+ {
+ res.Add(method);
+ }
+ }
+ return res;
+ }
+
+ /// <summary>
+ /// Finds all R2RSections by name or value of the ReadyToRunSectionType matching <param>query</param>
+ /// </summary>
+ /// <param name="r2r">Contains all extracted info about the ReadyToRun image</param>
+ /// <param name="query">The name or value to search for</param>
+ /// <out name="res">List of all matching sections</out>
+ /// <remarks>Case-insensitive</remarks>
+ public IList<R2RSection> FindSection(R2RReader r2r, string query)
+ {
+ List<R2RSection> res = new List<R2RSection>();
+ foreach (R2RSection section in r2r.R2RHeader.Sections.Values)
+ {
+ if (Match(section, query))
+ {
+ res.Add(section);
+ }
+ }
+ return res;
+ }
+
+ /// <summary>
+ /// Returns the runtime function with id matching <param>rtfQuery</param>
+ /// </summary>
+ /// <param name="r2r">Contains all extracted info about the ReadyToRun image</param>
+ /// <param name="rtfQuery">The name or value to search for</param>
+ public RuntimeFunction FindRuntimeFunction(R2RReader r2r, int rtfQuery)
+ {
+ foreach (R2RMethod m in r2r.R2RMethods)
+ {
+ foreach (RuntimeFunction rtf in m.RuntimeFunctions)
+ {
+ if (rtf.Id == rtfQuery || (rtf.StartAddress >= rtfQuery && rtf.StartAddress + rtf.Size < rtfQuery))
{
- Console.Write(method.ToString());
- Console.WriteLine("------------------\n");
+ return rtf;
}
}
}
+ return null;
+ }
+
+ 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 <file>)");
+
+ // open output stream
+ if (_outputFilename != null)
+ {
+ _writer = File.CreateText(_outputFilename);
+ }
+ else
+ {
+ _writer = Console.Out;
+ }
+
+ try
+ {
+ foreach (string filename in _inputFilenames)
+ {
+ R2RReader r2r = new R2RReader(filename);
+ Dump(r2r);
+ }
+ }
catch (Exception e)
{
Console.WriteLine("Error: " + e.ToString());
return 1;
}
+ finally
+ {
+ // close output stream
+ _writer.Close();
+ }
+
return 0;
}
+
+ public static int Main(string[] args)
+ {
+ try
+ {
+ return new R2RDump().Run(args);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Error: " + e.ToString());
+ return 1;
+ }
+ }
}
}
diff --git a/src/tools/r2rdump/R2RDump.csproj b/src/tools/r2rdump/R2RDump.csproj
index b9b5b5cd6c..cb9e76fb4d 100644
--- a/src/tools/r2rdump/R2RDump.csproj
+++ b/src/tools/r2rdump/R2RDump.csproj
@@ -9,4 +9,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="System.CommandLine" Version="0.1.0-e160119-1" />
+ </ItemGroup>
+
</Project>
diff --git a/src/tools/r2rdump/R2RHeader.cs b/src/tools/r2rdump/R2RHeader.cs
index 33ef42431a..96eacd583a 100644
--- a/src/tools/r2rdump/R2RHeader.cs
+++ b/src/tools/r2rdump/R2RHeader.cs
@@ -74,7 +74,7 @@ namespace R2RDump
Signature = NativeReader.ReadUInt32(image, ref curOffset);
if (Signature != READYTORUN_SIGNATURE)
{
- throw new System.BadImageFormatException("Incorrect R2R header signature");
+ throw new System.BadImageFormatException("Incorrect R2R header signature: " + SignatureString);
}
MajorVersion = NativeReader.ReadUInt16(image, ref curOffset);
@@ -89,7 +89,7 @@ namespace R2RDump
var sectionType = (R2RSection.SectionType)type;
if (!Enum.IsDefined(typeof(R2RSection.SectionType), type))
{
- R2RDump.OutputWarning("Invalid ReadyToRun section type");
+ R2RDump.WriteWarning("Invalid ReadyToRun section type");
}
Sections[sectionType] = new R2RSection(sectionType,
NativeReader.ReadInt32(image, ref curOffset),
@@ -102,19 +102,19 @@ namespace R2RDump
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.AppendFormat($"Signature: 0x{Signature:X8} ({SignatureString})\n");
- sb.AppendFormat($"RelativeVirtualAddress: 0x{RelativeVirtualAddress:X8}\n");
+ sb.AppendLine($"Signature: 0x{Signature:X8} ({SignatureString})");
+ sb.AppendLine($"RelativeVirtualAddress: 0x{RelativeVirtualAddress:X8}");
if (Signature == READYTORUN_SIGNATURE)
{
- sb.AppendFormat($"Size: {Size} bytes\n");
- sb.AppendFormat($"MajorVersion: 0x{MajorVersion:X4}\n");
- sb.AppendFormat($"MinorVersion: 0x{MinorVersion:X4}\n");
- sb.AppendFormat($"Flags: 0x{Flags:X8}\n");
+ sb.AppendLine($"Size: {Size} bytes");
+ sb.AppendLine($"MajorVersion: 0x{MajorVersion:X4}");
+ sb.AppendLine($"MinorVersion: 0x{MinorVersion:X4}");
+ sb.AppendLine($"Flags: 0x{Flags:X8}");
foreach (ReadyToRunFlag flag in Enum.GetValues(typeof(ReadyToRunFlag)))
{
if ((Flags & (uint)flag) != 0)
{
- sb.AppendFormat($" - {Enum.GetName(typeof(ReadyToRunFlag), flag)}\n");
+ sb.AppendLine($" - {Enum.GetName(typeof(ReadyToRunFlag), flag)}");
}
}
}
diff --git a/src/tools/r2rdump/R2RMethod.cs b/src/tools/r2rdump/R2RMethod.cs
index fd077b6b7c..1b658df40a 100644
--- a/src/tools/r2rdump/R2RMethod.cs
+++ b/src/tools/r2rdump/R2RMethod.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
@@ -11,7 +12,7 @@ using System.Text;
namespace R2RDump
{
- struct RuntimeFunction
+ class RuntimeFunction
{
/// <summary>
/// The index of the runtime function
@@ -37,7 +38,12 @@ namespace R2RDump
/// </summary>
public int UnwindRVA { get; }
- public RuntimeFunction(int id, int startRva, int endRva, int unwindRva)
+ /// <summary>
+ /// The method that this runtime function belongs to
+ /// </summary>
+ public R2RMethod Method { get; }
+
+ public RuntimeFunction(int id, int startRva, int endRva, int unwindRva, R2RMethod method)
{
Id = id;
StartAddress = startRva;
@@ -45,21 +51,22 @@ namespace R2RDump
if (endRva == -1)
Size = -1;
UnwindRVA = unwindRva;
+ Method = method;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.AppendFormat($"Id: {Id}\n");
- sb.AppendFormat($"StartAddress: 0x{StartAddress:X8}\n");
+ sb.AppendLine($"Id: {Id}");
+ sb.AppendLine($"StartAddress: 0x{StartAddress:X8}");
if (Size == -1)
{
- sb.Append("Size: Unavailable\n");
+ sb.AppendLine("Size: Unavailable");
}
else
{
- sb.AppendFormat($"Size: {Size} bytes\n");
+ sb.AppendLine($"Size: {Size} bytes");
}
return sb.ToString();
@@ -78,17 +85,24 @@ namespace R2RDump
/// </summary>
public string Name { get; }
+ /// <summary>
+ /// The signature with format: namespace.class.methodName<S, T, ...>(S, T, ...)
+ /// </summary>
+ public string SignatureString { get; }
+
public bool IsGeneric { get; }
- /// <summary>
+ /*/// <summary>
/// The return type of the method
/// </summary>
- public SignatureType ReturnType { get; }
+ public string ReturnType { get; }
/// <summary>
/// The argument types of the method
/// </summary>
- public SignatureType[] ArgTypes { get; }
+ public string[] ArgTypes { get; }*/
+
+ public MethodSignature<string> Signature { get; }
/// <summary>
/// The type that the method belongs to
@@ -101,9 +115,14 @@ namespace R2RDump
public uint Token { get; }
/// <summary>
+ /// The row id of the method
+ /// </summary>
+ public uint Rid { get; }
+
+ /// <summary>
/// All the runtime functions of this method
/// </summary>
- public List<RuntimeFunction> RuntimeFunctions { get; }
+ public IList<RuntimeFunction> RuntimeFunctions { get; }
/// <summary>
/// The id of the entrypoint runtime function
@@ -113,7 +132,7 @@ namespace R2RDump
/// <summary>
/// Maps all the generic parameters to the type in the instance
/// </summary>
- Dictionary<string, GenericInstance> _genericParamInstanceMap;
+ Dictionary<string, string> _genericParamInstanceMap;
[Flags]
public enum EncodeMethodSigFlags
@@ -156,6 +175,7 @@ namespace R2RDump
public R2RMethod(byte[] image, MetadataReader mdReader, uint rid, int entryPointId, GenericElementTypes[] instanceArgs, uint[] tok)
{
Token = _mdtMethodDef | rid;
+ Rid = rid;
EntryPointRuntimeFunctionId = entryPointId;
_mdReader = mdReader;
@@ -187,7 +207,7 @@ namespace R2RDump
SignatureHeader signatureHeader = signatureReader.ReadSignatureHeader();
IsGeneric = signatureHeader.IsGeneric;
GenericParameterHandleCollection genericParams = _methodDef.GetGenericParameters();
- _genericParamInstanceMap = new Dictionary<string, GenericInstance>();
+ _genericParamInstanceMap = new Dictionary<string, string>();
int argCount = signatureReader.ReadCompressedInteger();
if (IsGeneric)
@@ -195,17 +215,16 @@ namespace R2RDump
argCount = signatureReader.ReadCompressedInteger();
}
- ReturnType = new SignatureType(ref signatureReader, mdReader, genericParams);
- ArgTypes = new SignatureType[argCount];
- for (int i = 0; i < argCount; i++)
- {
- ArgTypes[i] = new SignatureType(ref signatureReader, mdReader, genericParams);
- }
-
+ DisassemblingTypeProvider provider = new DisassemblingTypeProvider();
if (IsGeneric && instanceArgs != null && tok != null)
{
InitGenericInstances(genericParams, instanceArgs, tok);
}
+
+ DisassemblingGenericContext genericContext = new DisassemblingGenericContext(new string[0], _genericParamInstanceMap.Values.ToArray());
+ Signature = _methodDef.DecodeSignature(provider, genericContext);
+
+ SignatureString = GetSignature();
}
private void InitGenericInstances(GenericParameterHandleCollection genericParams, GenericElementTypes[] instanceArgs, uint[] tok)
@@ -215,80 +234,66 @@ namespace R2RDump
throw new BadImageFormatException("Generic param indices out of bounds");
}
- for (int i = 0; i < genericParams.Count; i++)
+ for (int i = 0; i < instanceArgs.Length; i++)
{
- var key = _mdReader.GetString(_mdReader.GetGenericParameter(genericParams.ElementAt(i)).Name);
-
+ string key = _mdReader.GetString(_mdReader.GetGenericParameter(genericParams.ElementAt(i)).Name);
+ string name = instanceArgs[i].ToString();
if (instanceArgs[i] == GenericElementTypes.ValueType)
{
- string classname = _mdReader.GetString(_mdReader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle((int)tok[i])).Name);
- _genericParamInstanceMap[key] = new GenericInstance(instanceArgs[i], classname);
- }
- else
- {
- _genericParamInstanceMap[key] = new GenericInstance(instanceArgs[i], Enum.GetName(typeof(GenericElementTypes), instanceArgs[i]));
- }
- }
-
- if ((ReturnType.Flags & SignatureType.SignatureTypeFlags.GENERIC) != 0)
- {
- ReturnType.GenericInstance = _genericParamInstanceMap[ReturnType.TypeName];
- }
+ var t = _mdReader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle((int)tok[i]));
+ name = _mdReader.GetString(t.Name);
- for (int i = 0; i < ArgTypes.Length; i++)
- {
- if ((ArgTypes[i].Flags & SignatureType.SignatureTypeFlags.GENERIC) != 0)
- {
- ArgTypes[i].GenericInstance = _genericParamInstanceMap[ArgTypes[i].TypeName];
}
+ _genericParamInstanceMap[key] = name;
}
}
- public override string ToString()
+ private string GetSignature()
{
StringBuilder sb = new StringBuilder();
- if (Name != null)
- {
- sb.AppendFormat($"{ReturnType.ToString()} ");
- sb.AppendFormat($"{DeclaringType}{Name}");
-
- if (IsGeneric)
- {
- sb.Append("<");
- int i = 0;
- foreach (var instance in _genericParamInstanceMap.Values)
- {
- if (i > 0)
- {
- sb.Append(", ");
- }
- sb.AppendFormat($"{instance.TypeName}");
- i++;
- }
- sb.Append(">");
- }
+ sb.AppendFormat($"{DeclaringType}{Name}");
- sb.Append("(");
- for (int i = 0; i < ArgTypes.Length; i++)
+ if (IsGeneric)
+ {
+ sb.Append("<");
+ int i = 0;
+ foreach (var instance in _genericParamInstanceMap.Values)
{
if (i > 0)
{
sb.Append(", ");
}
- sb.AppendFormat($"{ArgTypes[i].ToString()}");
+ sb.AppendFormat($"{instance}");
+ i++;
}
- sb.Append(")\n");
+ sb.Append(">");
}
- sb.AppendFormat($"Token: 0x{Token:X8}\n");
- sb.AppendFormat($"EntryPointRuntimeFunctionId: {EntryPointRuntimeFunctionId}\n");
- sb.AppendFormat($"Number of RuntimeFunctions: {RuntimeFunctions.Count}\n\n");
-
- foreach (RuntimeFunction runtimeFunction in RuntimeFunctions)
+ sb.Append("(");
+ for (int i = 0; i < Signature.ParameterTypes.Length; i++)
{
- sb.AppendFormat($"{runtimeFunction}\n");
+ if (i > 0)
+ {
+ sb.Append(", ");
+ }
+ sb.AppendFormat($"{Signature.ParameterTypes[i]}");
}
+ sb.Append(")");
+
+ return sb.ToString();
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.AppendLine($"{Signature.ReturnType} {SignatureString}");
+
+ sb.AppendLine($"Token: 0x{Token:X8}");
+ sb.AppendLine($"Rid: {Rid}");
+ sb.AppendLine($"EntryPointRuntimeFunctionId: {EntryPointRuntimeFunctionId}");
+ sb.AppendLine($"Number of RuntimeFunctions: {RuntimeFunctions.Count}");
return sb.ToString();
}
diff --git a/src/tools/r2rdump/R2RReader.cs b/src/tools/r2rdump/R2RReader.cs
index 343cf27344..18969d1bb6 100644
--- a/src/tools/r2rdump/R2RReader.cs
+++ b/src/tools/r2rdump/R2RReader.cs
@@ -7,17 +7,18 @@ using System.Collections.Generic;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
+using System.Text;
namespace R2RDump
{
class R2RReader
{
+ private readonly PEReader peReader;
+
/// <summary>
/// Byte array containing the ReadyToRun image
/// </summary>
- private readonly byte[] _image;
-
- private readonly PEReader peReader;
+ public byte[] Image { get; }
/// <summary>
/// Name of the image file
@@ -49,22 +50,22 @@ namespace R2RDump
/// The runtime functions and method signatures of each method
/// TODO: generic methods
/// </summary>
- public List<R2RMethod> R2RMethods { get; }
+ public IList<R2RMethod> R2RMethods { get; }
/// <summary>
- /// Initializes the fields of the R2RHeader
+ /// Initializes the fields of the R2RHeader and R2RMethods
/// </summary>
/// <param name="filename">PE image</param>
/// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
public unsafe R2RReader(string filename)
{
Filename = filename;
- _image = File.ReadAllBytes(filename);
+ Image = File.ReadAllBytes(filename);
- fixed (byte* p = _image)
+ fixed (byte* p = Image)
{
IntPtr ptr = (IntPtr)p;
- peReader = new PEReader(p, _image.Length);
+ peReader = new PEReader(p, Image.Length);
IsR2R = (peReader.PEHeaders.CorHeader.Flags == CorFlags.ILLibrary);
if (!IsR2R)
@@ -78,7 +79,7 @@ namespace R2RDump
// initialize R2RHeader
DirectoryEntry r2rHeaderDirectory = peReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory;
int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress);
- R2RHeader = new R2RHeader(_image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset);
+ R2RHeader = new R2RHeader(Image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset);
if (r2rHeaderDirectory.Size != R2RHeader.Size)
{
throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory");
@@ -107,15 +108,15 @@ namespace R2RDump
// initialize R2RMethods with method signatures from MethodDefHandle, and runtime function indices from MethodDefEntryPoints
int methodDefEntryPointsRVA = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS].RelativeVirtualAddress;
int methodDefEntryPointsOffset = GetOffset(methodDefEntryPointsRVA);
- NativeArray methodEntryPoints = new NativeArray(_image, (uint)methodDefEntryPointsOffset);
+ NativeArray methodEntryPoints = new NativeArray(Image, (uint)methodDefEntryPointsOffset);
uint nMethodEntryPoints = methodEntryPoints.GetCount();
R2RMethods = new List<R2RMethod>();
for (uint rid = 1; rid <= nMethodEntryPoints; rid++)
{
int offset = 0;
- if (methodEntryPoints.TryGetAt(_image, rid - 1, ref offset))
+ if (methodEntryPoints.TryGetAt(Image, rid - 1, ref offset))
{
- R2RMethod method = new R2RMethod(_image, mdReader, rid, GetEntryPointIdFromOffset(offset), null, null);
+ R2RMethod method = new R2RMethod(Image, mdReader, rid, GetEntryPointIdFromOffset(offset), null, null);
if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= nRuntimeFunctions)
{
@@ -129,17 +130,17 @@ namespace R2RDump
// instance method table
R2RSection instMethodEntryPointSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS];
int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress);
- NativeParser parser = new NativeParser(_image, (uint)instMethodEntryPointsOffset);
- NativeHashtable instMethodEntryPoints = new NativeHashtable(_image, parser);
+ NativeParser parser = new NativeParser(Image, (uint)instMethodEntryPointsOffset);
+ NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser);
NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries();
NativeParser curParser = allEntriesEnum.GetNext();
while (!curParser.IsNull())
{
- byte methodFlags = curParser.GetByte();
- byte rid = curParser.GetByte();
+ uint methodFlags = curParser.GetCompressedData();
+ uint rid = curParser.GetCompressedData();
if ((methodFlags & (byte)R2RMethod.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation) != 0)
{
- byte nArgs = curParser.GetByte();
+ uint nArgs = curParser.GetCompressedData();
R2RMethod.GenericElementTypes[] args = new R2RMethod.GenericElementTypes[nArgs];
uint[] tokens = new uint[nArgs];
for (int i = 0; i < nArgs; i++)
@@ -147,14 +148,14 @@ namespace R2RDump
args[i] = (R2RMethod.GenericElementTypes)curParser.GetByte();
if (args[i] == R2RMethod.GenericElementTypes.ValueType)
{
- tokens[i] = curParser.GetByte();
+ tokens[i] = curParser.GetCompressedData();
tokens[i] = (tokens[i] >> 2);
}
}
uint id = curParser.GetUnsigned();
id = id >> 1;
- R2RMethod method = new R2RMethod(_image, mdReader, rid, (int)id, args, tokens);
+ R2RMethod method = new R2RMethod(Image, mdReader, rid, (int)id, args, tokens);
if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < nRuntimeFunctions)
{
isEntryPoint[method.EntryPointRuntimeFunctionId] = true;
@@ -174,15 +175,15 @@ namespace R2RDump
curOffset = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize;
do
{
- int startRva = NativeReader.ReadInt32(_image, ref curOffset);
+ int startRva = NativeReader.ReadInt32(Image, ref curOffset);
int endRva = -1;
if (Machine == Machine.Amd64)
{
- endRva = NativeReader.ReadInt32(_image, ref curOffset);
+ endRva = NativeReader.ReadInt32(Image, ref curOffset);
}
- int unwindRva = NativeReader.ReadInt32(_image, ref curOffset);
+ int unwindRva = NativeReader.ReadInt32(Image, ref curOffset);
- method.RuntimeFunctions.Add(new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva));
+ method.RuntimeFunctions.Add(new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva, method));
runtimeFunctionId++;
}
while (runtimeFunctionId < nRuntimeFunctions && !isEntryPoint[runtimeFunctionId]);
@@ -202,17 +203,20 @@ namespace R2RDump
return rva - containingSection.VirtualAddress + containingSection.PointerToRawData;
}
+ /// <summary>
+ /// Reads the method entrypoint from the offset. Used for non-generic methods
+ /// </summary>
private int GetEntryPointIdFromOffset(int offset)
{
// get the id of the entry point runtime function from the MethodEntryPoints NativeArray
uint id = 0; // the RUNTIME_FUNCTIONS index
- offset = (int)NativeReader.DecodeUnsigned(_image, (uint)offset, ref id);
+ offset = (int)NativeReader.DecodeUnsigned(Image, (uint)offset, ref id);
if ((id & 1) != 0)
{
if ((id & 2) != 0)
{
uint val = 0;
- NativeReader.DecodeUnsigned(_image, (uint)offset, ref val);
+ NativeReader.DecodeUnsigned(Image, (uint)offset, ref val);
offset -= (int)val;
}
// TODO: Dump fixups
diff --git a/src/tools/r2rdump/R2RSection.cs b/src/tools/r2rdump/R2RSection.cs
index 0d44b7aa0d..aef32d24ba 100644
--- a/src/tools/r2rdump/R2RSection.cs
+++ b/src/tools/r2rdump/R2RSection.cs
@@ -46,9 +46,9 @@ namespace R2RDump
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.AppendFormat($"Type: {Enum.GetName(typeof(SectionType), Type)} ({Type:D})\n");
- sb.AppendFormat($"RelativeVirtualAddress: 0x{RelativeVirtualAddress:X8}\n");
- sb.AppendFormat($"Size: {Size} bytes\n");
+ sb.AppendLine($"Type: {Enum.GetName(typeof(SectionType), Type)} ({Type:D})");
+ sb.AppendLine($"RelativeVirtualAddress: 0x{RelativeVirtualAddress:X8}");
+ sb.AppendLine($"Size: {Size} bytes");
return sb.ToString();
}
}
diff --git a/src/tools/r2rdump/SignatureType.cs b/src/tools/r2rdump/SignatureType.cs
deleted file mode 100644
index e5efcfb115..0000000000
--- a/src/tools/r2rdump/SignatureType.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Reflection.Metadata;
-using System.Text;
-
-namespace R2RDump
-{
- class SignatureType
- {
- /// <summary>
- /// Indicates if the type is an array, reference, or generic
- /// </summary>
- public SignatureTypeFlags Flags { get; }
-
- /// <summary>
- /// Name of the object or primitive type, the placeholder type for generic methods
- /// </summary>
- public string TypeName { get; }
-
- /// <summary>
- /// The type that the generic method was instantiated to
- /// </summary>
- public GenericInstance GenericInstance { get; set; }
-
- [Flags]
- public enum SignatureTypeFlags
- {
- NONE = 0x00,
- ARRAY = 0x01,
- REFERENCE = 0x02,
- GENERIC = 0x04,
- };
-
- public SignatureType(ref BlobReader signatureReader, MetadataReader mdReader, GenericParameterHandleCollection genericParams)
- {
- SignatureTypeCode signatureTypeCode = signatureReader.ReadSignatureTypeCode();
- Flags = 0;
- if (signatureTypeCode == SignatureTypeCode.SZArray)
- {
- Flags |= SignatureTypeFlags.ARRAY;
- signatureTypeCode = signatureReader.ReadSignatureTypeCode();
- }
-
- TypeName = signatureTypeCode.ToString();
- if (signatureTypeCode == SignatureTypeCode.TypeHandle || signatureTypeCode == SignatureTypeCode.ByReference)
- {
- if (signatureTypeCode == SignatureTypeCode.ByReference)
- {
- Flags |= SignatureTypeFlags.REFERENCE;
- }
-
- EntityHandle handle = signatureReader.ReadTypeHandle();
- if (handle.Kind == HandleKind.TypeDefinition)
- {
- TypeDefinition typeDef = mdReader.GetTypeDefinition((TypeDefinitionHandle)handle);
- TypeName = mdReader.GetString(typeDef.Name);
- }
- else if (handle.Kind == HandleKind.TypeReference)
- {
- TypeReference typeRef = mdReader.GetTypeReference((TypeReferenceHandle)handle);
- TypeName = mdReader.GetString(typeRef.Name);
- }
- }
- else if (signatureTypeCode == SignatureTypeCode.GenericMethodParameter)
- {
- int index = signatureReader.ReadCompressedInteger();
- GenericParameter generic = mdReader.GetGenericParameter(genericParams[index]);
- TypeName = mdReader.GetString(generic.Name);
- Flags |= SignatureTypeFlags.GENERIC;
- }
- }
-
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder();
- if ((Flags & SignatureTypeFlags.REFERENCE) != 0)
- {
- sb.Append("ref ");
- }
-
- if ((Flags & SignatureTypeFlags.GENERIC) != 0)
- {
- sb.AppendFormat($"{GenericInstance.TypeName}");
- }
- else
- {
- sb.AppendFormat($"{TypeName}");
- }
- if ((Flags & SignatureTypeFlags.ARRAY) != 0)
- {
- sb.Append("[]");
- }
- return sb.ToString();
- }
- }
-
- struct GenericInstance
- {
- /// <summary>
- /// The type of the instance for generic a type
- /// </summary>
- public R2RMethod.GenericElementTypes Instance { get; }
-
- /// <summary>
- /// The type name of the instance for generic a type. Different from GenericInstance.Instance for structs (ValueType)
- /// </summary>
- public string TypeName { get; }
-
- public GenericInstance(R2RMethod.GenericElementTypes instance, string name)
- {
- Instance = instance;
- TypeName = name;
- }
- }
-}