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)