/// <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 <ReadyToRunMethod> FindMethod(ReadyToRunReader r2r, string query, bool exact) { List <ReadyToRunMethod> res = new List <ReadyToRunMethod>(); foreach (ReadyToRunMethod method in r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods)) { 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 <ReadyToRunSection> FindSection(ReadyToRunReader r2r, string query) { List <ReadyToRunSection> res = new List <ReadyToRunSection>(); foreach (ReadyToRunSection section in r2r.ReadyToRunHeader.Sections.Values) { if (Match(section, query)) { res.Add(section); } } return(res); }
IEnumerable <MethodInfo> ProducePdbWriterMethods(ReadyToRunReader r2r) { foreach (var method in _dumper.NormalizedMethods()) { MethodInfo mi = new MethodInfo(); mi.Name = method.SignatureString; mi.HotRVA = (uint)method.RuntimeFunctions[0].StartAddress; mi.MethodToken = (uint)MetadataTokens.GetToken(method.MetadataReader, method.MethodHandle); mi.AssemblyName = method.MetadataReader.GetString(method.MetadataReader.GetAssemblyDefinition().Name); mi.ColdRVA = 0; yield return(mi); } }
/// <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(ReadyToRunReader r2r, int rtfQuery) { foreach (ReadyToRunMethod m in r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods)) { foreach (RuntimeFunction rtf in m.RuntimeFunctions) { if (rtf.Id == rtfQuery || (rtf.StartAddress >= rtfQuery && rtf.StartAddress + rtf.Size < rtfQuery)) { return(rtf); } } } return(null); }
/// <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(ReadyToRunReader r2r, int rtfQuery) { foreach (ReadyToRunMethod m in r2r.Methods) { foreach (RuntimeFunction rtf in m.RuntimeFunctions) { if (rtf.Id == rtfQuery || (rtf.StartAddress >= rtfQuery && rtf.StartAddress + rtf.Size < rtfQuery)) { return rtf; } } } return null; }
IEnumerable <AssemblyInfo> ProduceDebugInfoAssemblies(ReadyToRunReader r2r) { if (r2r.Composite) { foreach (KeyValuePair <string, int> kvpRefAssembly in r2r.ManifestReferenceAssemblies.OrderBy(kvp => kvp.Key, StringComparer.OrdinalIgnoreCase)) { yield return(new AssemblyInfo(kvpRefAssembly.Key, r2r.GetAssemblyMvid(kvpRefAssembly.Value))); } } else { yield return(new AssemblyInfo(r2r.GetGlobalAssemblyName(), r2r.GetAssemblyMvid(0))); } }
public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { PEFile module = method.ParentModule.PEFile; ReadyToRunReaderCacheEntry cacheEntry = GetReader(module.GetLoadedAssembly(), module); if (cacheEntry.readyToRunReader == null) { WriteCommentLine(output, cacheEntry.failureReason); } else { ReadyToRunReader reader = cacheEntry.readyToRunReader; int bitness = -1; if (reader.Machine == Machine.Amd64) { bitness = 64; } else { Debug.Assert(reader.Machine == Machine.I386); bitness = 32; } if (cacheEntry.methodMap == null) { cacheEntry.methodMap = reader.Methods.ToList() .GroupBy(m => m.MethodHandle) .ToDictionary(g => g.Key, g => g.ToArray()); } bool showMetadataTokens = ILSpy.Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens; bool showMetadataTokensInBase10 = ILSpy.Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokensInBase10; #if STRESS output = new DummyOutput(); { foreach (var readyToRunMethod in reader.Methods) { #else if (cacheEntry.methodMap.TryGetValue(method.MetadataToken, out var methods)) { foreach (var readyToRunMethod in methods) { #endif foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions) { new ReadyToRunDisassembler(output, reader, runtimeFunction).Disassemble(method.ParentModule.PEFile, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10); } } } } }
private bool TryGetMethods(ReadyToRunReader reader, ReadyToRunSection section, out IReadOnlyList <ReadyToRunMethod> methods) { int assemblyIndex = reader.GetAssemblyIndex(section); if (assemblyIndex == -1) { methods = null; return(false); } else { methods = reader.ReadyToRunAssemblies[assemblyIndex].Methods; return(true); } }
/// <summary> /// Read the R2R method map for a given R2R image. /// </summary> /// <param name="reader">R2R image to scan</param> /// <returns></returns> private Dictionary <string, int> GetR2RMethodMap(ReadyToRunReader reader, ReadyToRunSection section) { Dictionary <string, int> methodMap = new Dictionary <string, int>(); if (TryGetMethods(reader, section, out IReadOnlyList <ReadyToRunMethod> sectionMethods)) { foreach (ReadyToRunMethod method in sectionMethods) { int size = method.RuntimeFunctions.Sum(rf => rf.Size); methodMap.Add(method.SignatureString, size); } } return(methodMap); }
// <summary> /// For each query in the list of queries, dump 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(ReadyToRunReader r2r, IReadOnlyList <string> queries) { if (queries.Count > 0) { _dumper.WriteDivider("R2R Section"); } foreach (string q in queries) { IList <ReadyToRunSection> res = FindSection(r2r, q); _dumper.DumpQueryCount(q, "Sections", res.Count); foreach (ReadyToRunSection section in res) { _dumper.DumpSection(section); } } }
// <summary> /// For each query in the list of queries, dump 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(ReadyToRunReader r2r, string title, IReadOnlyList <string> queries, bool exact) { if (queries.Count > 0) { _dumper.WriteDivider(title); } foreach (string q in queries) { IList <ReadyToRunMethod> res = FindMethod(r2r, q, exact); _dumper.DumpQueryCount(q, "Methods", res.Count); foreach (ReadyToRunMethod method in res) { _dumper.DumpMethod(method); } } }
// <summary> /// For each query in the list of queries, dump 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(ReadyToRunReader r2r, IEnumerable <string> queries) { if (queries.Any()) { _dumper.WriteDivider("Runtime Functions"); } foreach (string q in queries) { RuntimeFunction rtf = FindRuntimeFunction(r2r, ArgStringToInt(q)); if (rtf == null) { WriteWarning("Unable to find by id " + q); continue; } _dumper.DumpQueryCount(q.ToString(), "Runtime Function", 1); _dumper.DumpRuntimeFunction(rtf); } }
public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { PEFile module = method.ParentModule.PEFile; ReadyToRunReaderCacheEntry cacheEntry = GetReader(module.GetLoadedAssembly(), module); if (cacheEntry.readyToRunReader == null) { WriteCommentLine(output, cacheEntry.failureReason); } else { ReadyToRunReader reader = cacheEntry.readyToRunReader; int bitness = -1; if (reader.Machine == Machine.Amd64) { bitness = 64; } else { Debug.Assert(reader.Machine == Machine.I386); bitness = 32; } foreach (ReadyToRunMethod readyToRunMethod in reader.Methods) { if (readyToRunMethod.MethodHandle == method.MetadataToken) { // TODO: Indexing foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions) { WriteCommentLine(output, readyToRunMethod.SignatureString); byte[] code = new byte[runtimeFunction.Size]; for (int i = 0; i < runtimeFunction.Size; i++) { code[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i]; } Disassemble(output, code, bitness, (ulong)runtimeFunction.StartAddress); output.WriteLine(); } } } } }
public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) { PEFile module = assembly.GetPEFileAsync().GetAwaiter().GetResult(); ReadyToRunReaderCacheEntry cacheEntry = GetReader(assembly, module); if (cacheEntry.readyToRunReader == null) { WriteCommentLine(output, cacheEntry.failureReason); } else { ReadyToRunReader reader = cacheEntry.readyToRunReader; WriteCommentLine(output, reader.Machine.ToString()); WriteCommentLine(output, reader.OperatingSystem.ToString()); WriteCommentLine(output, reader.CompilerIdentifier); WriteCommentLine(output, "TODO - display more header information"); } return(base.DecompileAssembly(assembly, output, options)); }
public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { PEFile module = method.ParentModule.PEFile; ReadyToRunReaderCacheEntry cacheEntry = GetReader(module.GetLoadedAssembly(), module); if (cacheEntry.readyToRunReader == null) { WriteCommentLine(output, cacheEntry.failureReason); } else { ReadyToRunReader reader = cacheEntry.readyToRunReader; int bitness = -1; if (reader.Machine == Machine.Amd64) { bitness = 64; } else { Debug.Assert(reader.Machine == Machine.I386); bitness = 32; } if (cacheEntry.methodMap == null) { cacheEntry.methodMap = reader.Methods.Values .SelectMany(m => m) .GroupBy(m => m.MethodHandle) .ToDictionary(g => g.Key, g => g.ToArray()); } if (cacheEntry.methodMap.TryGetValue(method.MetadataToken, out var methods)) { foreach (var readyToRunMethod in methods) { foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions) { Disassemble(output, reader, readyToRunMethod, runtimeFunction, bitness, (ulong)runtimeFunction.StartAddress); } } } } }
private IEnumerable <ReadyToRunMethod> TryGetMethods(ReadyToRunReader reader, int moduleIndex) { List <ReadyToRunMethod> methods = new List <ReadyToRunMethod>(); switch (moduleIndex) { case InvalidModule: break; case AllModules: methods.AddRange(reader.InstanceMethods.Select(im => im.Method)); foreach (ReadyToRunAssembly assembly in reader.ReadyToRunAssemblies) { methods.AddRange(assembly.Methods); } break; default: methods.AddRange(reader.ReadyToRunAssemblies[moduleIndex].Methods); break; } return(methods); }
/// <summary> /// Store the left and right file and output writer. /// </summary> /// <param name="leftFile">Left R2R file</param> /// <param name="rightFile">Right R2R file</param> /// <param name="writer">Output writer to receive the diff</param> public R2RDiff(ReadyToRunReader leftFile, ReadyToRunReader rightFile, TextWriter writer) { _leftFile = leftFile; _rightFile = rightFile; _writer = writer; }
/// <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(ReadyToRunReader r2r) { _dumper.Begin(); bool standardDump = !(_options.EntryPoints || _options.CreatePDB); if (_options.Header && standardDump) { _dumper.WriteDivider("R2R Header"); _dumper.DumpHeader(true); } bool haveQuery = false; if (_options.Section != null) { haveQuery = true; QuerySection(r2r, _options.Section); } if (_options.RuntimeFunction != null) { haveQuery = true; QueryRuntimeFunction(r2r, _options.RuntimeFunction); } if (_options.Query != null) { haveQuery = true; QueryMethod(r2r, "R2R Methods by Query", _options.Query, true); } if (_options.Keyword != null) { haveQuery = true; QueryMethod(r2r, "R2R Methods by Keyword", _options.Keyword, false); } if (!haveQuery) { // Dump all sections and methods if no queries specified if (_options.EntryPoints) { _dumper.DumpEntryPoints(); } if (_options.CreatePDB) { string pdbPath = _options.PdbPath; if (String.IsNullOrEmpty(pdbPath)) { pdbPath = Path.GetDirectoryName(r2r.Filename); } var pdbWriter = new PdbWriter(pdbPath, PDBExtraData.None); pdbWriter.WritePDBData(r2r.Filename, ProducePdbWriterMethods(r2r)); } if (!_options.Header && standardDump) { _dumper.DumpAllMethods(); } } _dumper.End(); }
private void Disassemble(PEFile currentFile, ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10) { // TODO: Decorate the disassembly with GCInfo WriteCommentLine(output, readyToRunMethod.SignatureString); Dictionary <ulong, UnwindCode> unwindInfo = null; if (ReadyToRunOptions.GetIsShowUnwindInfo(null) && bitness == 64) { unwindInfo = WriteUnwindInfo(runtimeFunction, output); } bool isShowDebugInfo = ReadyToRunOptions.GetIsShowDebugInfo(null); Dictionary <VarLocType, HashSet <ValueTuple <DebugInfo, NativeVarInfo> > > debugInfo = null; if (isShowDebugInfo) { debugInfo = WriteDebugInfo(readyToRunMethod, output); } byte[] codeBytes = new byte[runtimeFunction.Size]; for (int i = 0; i < runtimeFunction.Size; i++) { codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i]; } var codeReader = new ByteArrayCodeReader(codeBytes); var decoder = Decoder.Create(bitness, codeReader); decoder.IP = address; ulong endRip = decoder.IP + (uint)codeBytes.Length; var instructions = new InstructionList(); while (decoder.IP < endRip) { decoder.Decode(out instructions.AllocUninitializedElement()); } string disassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(null); Formatter formatter = null; if (disassemblyFormat.Equals(ReadyToRunOptions.intel)) { formatter = new NasmFormatter(); } else { Debug.Assert(disassemblyFormat.Equals(ReadyToRunOptions.gas)); formatter = new GasFormatter(); } formatter.Options.DigitSeparator = "`"; formatter.Options.FirstOperandCharIndex = 10; var tempOutput = new StringOutput(); ulong baseInstrIP = instructions[0].IP; foreach (var instr in instructions) { int byteBaseIndex = (int)(instr.IP - address); if (isShowDebugInfo && runtimeFunction.DebugInfo != null) { foreach (var bound in runtimeFunction.DebugInfo.BoundsList) { if (bound.NativeOffset == byteBaseIndex) { if (bound.ILOffset == (uint)DebugInfoBoundsType.Prolog) { WriteCommentLine(output, "Prolog"); } else if (bound.ILOffset == (uint)DebugInfoBoundsType.Epilog) { WriteCommentLine(output, "Epilog"); } else { WriteCommentLine(output, $"IL_{bound.ILOffset:x4}"); } } } } formatter.Format(instr, tempOutput); output.Write(instr.IP.ToString("X16")); output.Write(" "); int instrLen = instr.Length; for (int i = 0; i < instrLen; i++) { output.Write(codeBytes[byteBaseIndex + i].ToString("X2")); } int missingBytes = 10 - instrLen; for (int i = 0; i < missingBytes; i++) { output.Write(" "); } output.Write(" "); output.Write(tempOutput.ToStringAndReset()); DecorateUnwindInfo(output, unwindInfo, baseInstrIP, instr); DecorateDebugInfo(output, instr, debugInfo, baseInstrIP); DecorateCallSite(currentFile, output, reader, showMetadataTokens, showMetadataTokensInBase10, instr); } output.WriteLine(); }
public ReadyToRunDisassembler(ITextOutput output, ReadyToRunReader reader, RuntimeFunction runtimeFunction) { this.output = output; this.reader = reader; this.runtimeFunction = runtimeFunction; }
/// <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(ReadyToRunReader r2r) { _dumper.Begin(); bool standardDump = !(_options.EntryPoints || _options.CreatePDB || _options.CreatePerfmap); if (_options.Header && standardDump) { _dumper.WriteDivider("R2R Header"); _dumper.DumpHeader(true); } bool haveQuery = false; if (_options.Section != null) { haveQuery = true; QuerySection(r2r, _options.Section); } if (_options.RuntimeFunction != null) { haveQuery = true; QueryRuntimeFunction(r2r, _options.RuntimeFunction); } if (_options.Query != null) { haveQuery = true; QueryMethod(r2r, "R2R Methods by Query", _options.Query, true); } if (_options.Keyword != null) { haveQuery = true; QueryMethod(r2r, "R2R Methods by Keyword", _options.Keyword, false); } if (!haveQuery) { // Dump all sections and methods if no queries specified if (_options.EntryPoints) { _dumper.DumpEntryPoints(); } TargetArchitecture architecture = r2r.Machine switch { Machine.I386 => TargetArchitecture.X86, Machine.Amd64 => TargetArchitecture.X64, Machine.ArmThumb2 => TargetArchitecture.ARM, Machine.Arm64 => TargetArchitecture.ARM64, _ => throw new NotImplementedException(r2r.Machine.ToString()), }; TargetOS os = r2r.OperatingSystem switch { OperatingSystem.Windows => TargetOS.Windows, OperatingSystem.Linux => TargetOS.Linux, OperatingSystem.Apple => TargetOS.OSX, OperatingSystem.FreeBSD => TargetOS.FreeBSD, OperatingSystem.NetBSD => TargetOS.FreeBSD, _ => throw new NotImplementedException(r2r.OperatingSystem.ToString()), }; TargetDetails details = new TargetDetails(architecture, os, TargetAbi.CoreRT); if (_options.CreatePDB) { string pdbPath = _options.PdbPath; if (String.IsNullOrEmpty(pdbPath)) { pdbPath = Path.GetDirectoryName(r2r.Filename); } var pdbWriter = new PdbWriter(pdbPath, PDBExtraData.None, details); pdbWriter.WritePDBData(r2r.Filename, ProduceDebugInfoMethods(r2r)); } if (_options.CreatePerfmap) { string perfmapPath = _options.PerfmapPath; if (string.IsNullOrEmpty(perfmapPath)) { perfmapPath = Path.ChangeExtension(r2r.Filename, ".r2rmap"); } PerfMapWriter.Write(perfmapPath, _options.PerfmapFormatVersion, ProduceDebugInfoMethods(r2r), ProduceDebugInfoAssemblies(r2r), details); } if (standardDump) { _dumper.DumpAllMethods(); _dumper.DumpFixupStats(); } } _dumper.End(); }
private void Disassemble(ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address) { WriteCommentLine(output, readyToRunMethod.SignatureString); byte[] codeBytes = new byte[runtimeFunction.Size]; for (int i = 0; i < runtimeFunction.Size; i++) { codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i]; } // TODO: Decorate the disassembly with Unwind, GC and debug info var codeReader = new ByteArrayCodeReader(codeBytes); var decoder = Decoder.Create(bitness, codeReader); decoder.IP = address; ulong endRip = decoder.IP + (uint)codeBytes.Length; var instructions = new InstructionList(); while (decoder.IP < endRip) { decoder.Decode(out instructions.AllocUninitializedElement()); } string disassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(null); Formatter formatter = null; if (disassemblyFormat.Equals(ReadyToRunOptions.intel)) { formatter = new NasmFormatter(); } else { Debug.Assert(disassemblyFormat.Equals(ReadyToRunOptions.gas)); formatter = new GasFormatter(); } formatter.Options.DigitSeparator = "`"; formatter.Options.FirstOperandCharIndex = 10; var tempOutput = new StringOutput(); foreach (var instr in instructions) { int byteBaseIndex = (int)(instr.IP - address); foreach (var bound in runtimeFunction.DebugInfo.BoundsList) { if (bound.NativeOffset == byteBaseIndex) { if (bound.ILOffset == (uint)DebugInfoBoundsType.Prolog) { WriteCommentLine(output, "Prolog"); } else if (bound.ILOffset == (uint)DebugInfoBoundsType.Epilog) { WriteCommentLine(output, "Epilog"); } else { WriteCommentLine(output, $"IL_{bound.ILOffset:x4}"); } } } formatter.Format(instr, tempOutput); output.Write(instr.IP.ToString("X16")); output.Write(" "); int instrLen = instr.Length; for (int i = 0; i < instrLen; i++) { output.Write(codeBytes[byteBaseIndex + i].ToString("X2")); } int missingBytes = 10 - instrLen; for (int i = 0; i < missingBytes; i++) { output.Write(" "); } output.Write(" "); output.WriteLine(tempOutput.ToStringAndReset()); } output.WriteLine(); }
private int Run() { Disassembler disassembler = null; try { if (_options.In == null || _options.In.Length == 0) { throw new ArgumentException("Input filename must be specified (--in <file>)"); } if (_options.Diff && _options.In.Length < 2) { throw new ArgumentException("Need at least 2 input files in diff mode"); } if (_options.Naked && _options.Raw) { throw new ArgumentException("The option '--naked' is incompatible with '--raw'"); } Dumper previousDumper = null; foreach (FileInfo filename in _options.In) { // parse the ReadyToRun image ReadyToRunReader r2r = new ReadyToRunReader(_options, filename.FullName); if (_options.Disasm) { if (r2r.InputArchitectureSupported() && r2r.DisassemblerArchitectureSupported()) { disassembler = new Disassembler(r2r, _options); } else { throw new ArgumentException($"The architecture of input file {filename} ({r2r.Machine.ToString()}) or the architecture of the disassembler tools ({System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString()}) is not supported."); } } if (!_options.Diff) { // output the ReadyToRun info _dumper = new TextDumper(r2r, _writer, disassembler, _options); Dump(r2r); } else { string perFileOutput = filename.FullName + ".common-methods.r2r"; _dumper = new TextDumper(r2r, new StreamWriter(perFileOutput, append: false, _encoding), disassembler, _options); if (previousDumper != null) { new R2RDiff(previousDumper, _dumper, _writer).Run(); } previousDumper?.Writer?.Flush(); previousDumper = _dumper; } } } catch (Exception e) { Console.WriteLine("Error: " + e.ToString()); if (e is ArgumentException) { Console.WriteLine(); } return(1); } finally { if (disassembler != null) { disassembler.Dispose(); } // flush output stream _dumper?.Writer?.Flush(); _writer?.Flush(); } return(0); }
/// <summary> /// Store the R2R reader and construct the disassembler for the appropriate architecture. /// </summary> /// <param name="reader"></param> public Disassembler(ReadyToRunReader reader, DumpOptions options) { _reader = reader; _options = options; _disasm = CoreDisTools.GetDisasm(_reader.Machine); }
public TextDumper(ReadyToRunReader r2r, TextWriter writer, Disassembler disassembler, DumpOptions options) : base(r2r, writer, disassembler, options) { }
/// <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(ReadyToRunReader r2r) { _dumper.Begin(); bool standardDump = !(_options.EntryPoints || _options.CreatePDB || _options.CreatePerfmap); if (_options.Header && standardDump) { _dumper.WriteDivider("R2R Header"); _dumper.DumpHeader(true); } bool haveQuery = false; if (_options.Section != null) { haveQuery = true; QuerySection(r2r, _options.Section); } if (_options.RuntimeFunction != null) { haveQuery = true; QueryRuntimeFunction(r2r, _options.RuntimeFunction); } if (_options.Query != null) { haveQuery = true; QueryMethod(r2r, "R2R Methods by Query", _options.Query, true); } if (_options.Keyword != null) { haveQuery = true; QueryMethod(r2r, "R2R Methods by Keyword", _options.Keyword, false); } if (!haveQuery) { // Dump all sections and methods if no queries specified if (_options.EntryPoints) { _dumper.DumpEntryPoints(); } if (_options.CreatePDB) { string pdbPath = _options.PdbPath; if (String.IsNullOrEmpty(pdbPath)) { pdbPath = Path.GetDirectoryName(r2r.Filename); } var pdbWriter = new PdbWriter(pdbPath, PDBExtraData.None); pdbWriter.WritePDBData(r2r.Filename, ProduceDebugInfoMethods(r2r)); } if (_options.CreatePerfmap) { string perfmapPath = _options.PerfmapPath; if (string.IsNullOrEmpty(perfmapPath)) { perfmapPath = Path.ChangeExtension(r2r.Filename, ".r2rmap"); } // TODO: can't seem to find any place that surfaces the ABI. This is for debugging purposes, so may not be as relevant to be correct. TargetDetails details = new TargetDetails(r2r.TargetArchitecture, r2r.TargetOperatingSystem, TargetAbi.CoreRT); PerfMapWriter.Write(perfmapPath, _options.PerfmapFormatVersion, ProduceDebugInfoMethods(r2r), ProduceDebugInfoAssemblies(r2r), details); } if (standardDump) { _dumper.DumpAllMethods(); _dumper.DumpFixupStats(); } } _dumper.End(); }
private static Dictionary <string, ReadyToRunImportSection.ImportSectionEntry> GetImports(ReadyToRunReader reader) { var result = new Dictionary <string, ReadyToRunImportSection.ImportSectionEntry>(); var signatureOptions = new SignatureFormattingOptions() { Naked = true }; foreach (ReadyToRunImportSection section in reader.ImportSections) { foreach (ReadyToRunImportSection.ImportSectionEntry entry in section.Entries) { result[entry.Signature.ToString(signatureOptions)] = entry; } } return(result); }
private void Disassemble(PEFile currentFile, ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10) { WriteCommentLine(output, readyToRunMethod.SignatureString); byte[] codeBytes = new byte[runtimeFunction.Size]; for (int i = 0; i < runtimeFunction.Size; i++) { codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i]; } // TODO: Decorate the disassembly with Unwind, GC and debug info var codeReader = new ByteArrayCodeReader(codeBytes); var decoder = Decoder.Create(bitness, codeReader); decoder.IP = address; ulong endRip = decoder.IP + (uint)codeBytes.Length; var instructions = new InstructionList(); while (decoder.IP < endRip) { decoder.Decode(out instructions.AllocUninitializedElement()); } string disassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(null); Formatter formatter = null; if (disassemblyFormat.Equals(ReadyToRunOptions.intel)) { formatter = new NasmFormatter(); } else { Debug.Assert(disassemblyFormat.Equals(ReadyToRunOptions.gas)); formatter = new GasFormatter(); } formatter.Options.DigitSeparator = "`"; formatter.Options.FirstOperandCharIndex = 10; var tempOutput = new StringOutput(); foreach (var instr in instructions) { int byteBaseIndex = (int)(instr.IP - address); if (runtimeFunction.DebugInfo != null) { foreach (var bound in runtimeFunction.DebugInfo.BoundsList) { if (bound.NativeOffset == byteBaseIndex) { if (bound.ILOffset == (uint)DebugInfoBoundsType.Prolog) { WriteCommentLine(output, "Prolog"); } else if (bound.ILOffset == (uint)DebugInfoBoundsType.Epilog) { WriteCommentLine(output, "Epilog"); } else { WriteCommentLine(output, $"IL_{bound.ILOffset:x4}"); } } } } formatter.Format(instr, tempOutput); output.Write(instr.IP.ToString("X16")); output.Write(" "); int instrLen = instr.Length; for (int i = 0; i < instrLen; i++) { output.Write(codeBytes[byteBaseIndex + i].ToString("X2")); } int missingBytes = 10 - instrLen; for (int i = 0; i < missingBytes; i++) { output.Write(" "); } output.Write(" "); output.Write(tempOutput.ToStringAndReset()); int importCellAddress = (int)instr.IPRelativeMemoryAddress; if (instr.IsCallNearIndirect && reader.ImportCellNames.ContainsKey(importCellAddress)) { output.Write(" ; "); ReadyToRunSignature signature = reader.ImportSignatures[(int)instr.IPRelativeMemoryAddress]; switch (signature) { case MethodDefEntrySignature methodDefSignature: var methodDefToken = MetadataTokens.EntityHandle(unchecked ((int)methodDefSignature.MethodDefToken)); if (showMetadataTokens) { if (showMetadataTokensInBase10) { output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken)}) ", "metadata"); } else { output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken):X8}) ", "metadata"); } } methodDefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty); break; case MethodRefEntrySignature methodRefSignature: var methodRefToken = MetadataTokens.EntityHandle(unchecked ((int)methodRefSignature.MethodRefToken)); if (showMetadataTokens) { if (showMetadataTokensInBase10) { output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken)}) ", "metadata"); } else { output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken):X8}) ", "metadata"); } } methodRefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty); break; default: output.WriteLine(reader.ImportCellNames[importCellAddress]); break; } output.WriteLine(); } else { output.WriteLine(); } } output.WriteLine(); }