diff --git a/src/coreclr/src/tools/r2rdump/R2RDiff.cs b/src/coreclr/src/tools/r2rdump/R2RDiff.cs index 8f0e871103449..60b9c0e6e1f28 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDiff.cs +++ b/src/coreclr/src/tools/r2rdump/R2RDiff.cs @@ -18,30 +18,30 @@ namespace R2RDump class R2RDiff { /// - /// Left R2R image for the diff. + /// Left dumper to use for the diff /// - private readonly ReadyToRunReader _leftFile; + private readonly Dumper _leftDumper; /// - /// Right R2R image for the diff. + /// Right dumper to use for the diff /// - private readonly ReadyToRunReader _rightFile; + private readonly Dumper _rightDumper; /// - /// Text writer to receive diff output. + /// Text writer to use for common output /// private readonly TextWriter _writer; /// /// Store the left and right file and output writer. /// - /// Left R2R file - /// Right R2R file - /// Output writer to receive the diff - public R2RDiff(ReadyToRunReader leftFile, ReadyToRunReader rightFile, TextWriter writer) + /// Dumper to use for the left diff output + /// Dumper to use for the right diff output + /// Writer to use for output common to left / right side + public R2RDiff(Dumper leftDumper, Dumper rightDumper, TextWriter writer) { - _leftFile = leftFile; - _rightFile = rightFile; + _leftDumper = leftDumper; + _rightDumper = rightDumper; _writer = writer; } @@ -54,6 +54,11 @@ public void Run() DiffPESections(); DiffR2RSections(); DiffR2RMethods(); + + HashSet commonMethods = new HashSet(_leftDumper.Reader.Methods.Select(method => method.SignatureString) + .Intersect(_rightDumper.Reader.Methods.Select(method => method.SignatureString))); + DumpCommonMethods(_leftDumper, commonMethods); + DumpCommonMethods(_rightDumper, commonMethods); } /// @@ -61,8 +66,8 @@ public void Run() /// private void DiffTitle() { - _writer.WriteLine($@"Left file: {_leftFile.Filename} ({_leftFile.Image.Length} B)"); - _writer.WriteLine($@"Right file: {_rightFile.Filename} ({_rightFile.Image.Length} B)"); + _writer.WriteLine($@"Left file: {_leftDumper.Reader.Filename} ({_leftDumper.Reader.Image.Length} B)"); + _writer.WriteLine($@"Right file: {_rightDumper.Reader.Filename} ({_rightDumper.Reader.Image.Length} B)"); _writer.WriteLine(); } @@ -71,7 +76,7 @@ private void DiffTitle() /// private void DiffPESections() { - ShowDiff(GetPESectionMap(_leftFile), GetPESectionMap(_rightFile), "PE sections"); + ShowDiff(GetPESectionMap(_leftDumper.Reader), GetPESectionMap(_rightDumper.Reader), "PE sections"); } /// @@ -79,7 +84,7 @@ private void DiffPESections() /// private void DiffR2RSections() { - ShowDiff(GetR2RSectionMap(_leftFile), GetR2RSectionMap(_rightFile), "R2R sections"); + ShowDiff(GetR2RSectionMap(_leftDumper.Reader), GetR2RSectionMap(_rightDumper.Reader), "R2R sections"); } /// @@ -87,7 +92,7 @@ private void DiffR2RSections() /// private void DiffR2RMethods() { - ShowDiff(GetR2RMethodMap(_leftFile), GetR2RMethodMap(_rightFile), "R2R methods"); + ShowDiff(GetR2RMethodMap(_leftDumper.Reader), GetR2RMethodMap(_rightDumper.Reader), "R2R methods"); } /// @@ -204,5 +209,24 @@ private Dictionary GetR2RMethodMap(ReadyToRunReader reader) return methodMap; } + + /// + /// Dump the subset of methods common to both sides of the diff to the given dumper. + /// + /// Output dumper to use + /// Set of common signatures of methods to dump + private void DumpCommonMethods(Dumper dumper, HashSet signatureFilter) + { + IEnumerable filteredMethods = dumper + .Reader + .Methods + .Where(method => signatureFilter.Contains(method.SignatureString)) + .OrderBy(method => method.SignatureString); + + foreach (ReadyToRunMethod method in filteredMethods) + { + dumper.DumpMethod(method); + } + } } } diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.cs b/src/coreclr/src/tools/r2rdump/R2RDump.cs index 5c52b52651a0d..dc9e910d74a23 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDump.cs +++ b/src/coreclr/src/tools/r2rdump/R2RDump.cs @@ -161,13 +161,19 @@ public IEnumerable NormalizedMethods() abstract internal void DumpBytes(int rva, uint size, string name = "Raw", bool convertToOffset = true); abstract internal void DumpSectionContents(ReadyToRunSection section); abstract internal void DumpQueryCount(string q, string title, int count); + + public TextWriter Writer => _writer; + + public DumpOptions Options => _options; + + public ReadyToRunReader Reader => _r2r; } class R2RDump { private readonly DumpOptions _options; - private readonly TextWriter _writer; private readonly Dictionary _selectedSections = new Dictionary(); + private TextWriter _writer; private Dumper _dumper; private R2RDump(DumpOptions options) @@ -181,16 +187,6 @@ private R2RDump(DumpOptions options) _options.GC = true; _options.SectionContents = true; } - - // open output stream - if (_options.Out != null) - { - _writer = new StreamWriter(_options.Out.FullName, append: false, encoding: Encoding.ASCII); - } - else - { - _writer = Console.Out; - } } private static int ArgStringToInt(string arg) @@ -478,7 +474,12 @@ private int Run() throw new ArgumentException("The option '--naked' is incompatible with '--raw'"); } - ReadyToRunReader previousReader = null; + Dumper previousDumper = null; + TextWriter globalWriter = null; + if (_options.Out != null) + { + globalWriter = new StreamWriter(_options.Out.FullName); + } foreach (FileInfo filename in _options.In) { @@ -497,6 +498,15 @@ private int Run() } } + if (!_options.Diff && globalWriter != null) + { + _writer = globalWriter; + } + else + { + string outFile = r2r.Filename + ".r2rdump"; + _writer = new StreamWriter(outFile, append: false, encoding: Encoding.ASCII); + } _dumper = new TextDumper(r2r, _writer, disassembler, _options); if (!_options.Diff) @@ -504,12 +514,12 @@ private int Run() // output the ReadyToRun info Dump(r2r); } - else if (previousReader != null) + else if (previousDumper != null) { - new R2RDiff(previousReader, r2r, _writer).Run(); + new R2RDiff(previousDumper, _dumper, globalWriter).Run(); } - previousReader = r2r; + previousDumper = _dumper; } } catch (Exception e)