Browse Source

Add feature to the MethodBodyDisassembler that shows sequence points from PDB in disassembled IL.

pull/923/head
Daniel Grunwald 8 years ago
parent
commit
462d0da7b6
  1. 3
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 42
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  3. 14
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  4. 3
      ICSharpCode.Decompiler/IL/ILReader.cs
  5. 11
      ILSpy/Languages/CSharpILMixedLanguage.cs
  6. 2
      ILSpy/Languages/ILAstLanguage.cs
  7. 5
      ILSpy/Languages/ILLanguage.cs

3
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -111,7 +111,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -111,7 +111,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
using (var writer = new StreamWriter(outputFile)) {
module.Name = Path.GetFileNameWithoutExtension(outputFile);
var output = new PlainTextOutput(writer);
ReflectionDisassembler rd = new ReflectionDisassembler(output, false, CancellationToken.None);
ReflectionDisassembler rd = new ReflectionDisassembler(output, CancellationToken.None);
rd.DetectControlStructure = false;
rd.WriteAssemblyReferences(module);
if (module.Assembly != null)
rd.WriteAssemblyHeader(module.Assembly);

42
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Threading;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
namespace ICSharpCode.Decompiler.Disassembler
{
@ -30,15 +31,24 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -30,15 +31,24 @@ namespace ICSharpCode.Decompiler.Disassembler
public class MethodBodyDisassembler
{
readonly ITextOutput output;
readonly bool detectControlStructure;
readonly CancellationToken cancellationToken;
public MethodBodyDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken)
/// <summary>
/// Show .try/finally as blocks in IL code; indent loops.
/// </summary>
public bool DetectControlStructure { get; set; } = true;
/// <summary>
/// Show sequence points if debug information is loaded in Cecil.
/// </summary>
public bool ShowSequencePoints { get; set; }
Collection<SequencePoint> sequencePoints;
int nextSequencePointIndex;
public MethodBodyDisassembler(ITextOutput output, CancellationToken cancellationToken)
{
if (output == null)
throw new ArgumentNullException(nameof(output));
this.output = output;
this.detectControlStructure = detectControlStructure;
this.output = output ?? throw new ArgumentNullException(nameof(output));
this.cancellationToken = cancellationToken;
}
@ -55,7 +65,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -55,7 +65,9 @@ namespace ICSharpCode.Decompiler.Disassembler
DisassembleLocalsBlock(body);
output.WriteLine();
if (detectControlStructure && body.Instructions.Count > 0) {
sequencePoints = method.DebugInformation?.SequencePoints;
nextSequencePointIndex = 0;
if (DetectControlStructure && body.Instructions.Count > 0) {
Instruction inst = body.Instructions[0];
HashSet<int> branchTargets = GetBranchTargets(body.Instructions);
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, method.Body.CodeSize);
@ -66,6 +78,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -66,6 +78,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
WriteExceptionHandlers(body);
}
sequencePoints = null;
}
private void DisassembleLocalsBlock(MethodBody body)
@ -215,6 +228,21 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -215,6 +228,21 @@ namespace ICSharpCode.Decompiler.Disassembler
protected virtual void WriteInstruction(ITextOutput output, Instruction instruction)
{
if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) {
SequencePoint sp = sequencePoints[nextSequencePointIndex];
if (sp.Offset <= instruction.Offset) {
output.Write("// sequence point: ");
if (sp.Offset != instruction.Offset) {
output.Write("!! at " + DisassemblerHelpers.OffsetToString(sp.Offset) + " !!");
}
if (sp.IsHidden) {
output.WriteLine("hidden");
} else {
output.WriteLine($"(line {sp.StartLine}, col {sp.StartColumn}) to (line {sp.EndLine}, col {sp.EndColumn}) in {sp.Document?.Url}");
}
nextSequencePointIndex++;
}
}
instruction.WriteTo(output);
}
}

14
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -35,8 +35,18 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -35,8 +35,18 @@ namespace ICSharpCode.Decompiler.Disassembler
MethodBodyDisassembler methodBodyDisassembler;
MemberReference currentMember;
public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken)
: this(output, new MethodBodyDisassembler(output, detectControlStructure, cancellationToken), cancellationToken)
public bool DetectControlStructure {
get => methodBodyDisassembler.DetectControlStructure;
set => methodBodyDisassembler.DetectControlStructure = value;
}
public bool ShowSequencePoints {
get => methodBodyDisassembler.ShowSequencePoints;
set => methodBodyDisassembler.ShowSequencePoints = value;
}
public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken)
: this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken)
{
}

3
ICSharpCode.Decompiler/IL/ILReader.cs

@ -304,7 +304,8 @@ namespace ICSharpCode.Decompiler.IL @@ -304,7 +304,8 @@ namespace ICSharpCode.Decompiler.IL
inst.WriteTo(output, new ILAstWritingOptions());
output.WriteLine();
}
new Disassembler.MethodBodyDisassembler(output, false, cancellationToken).WriteExceptionHandlers(body);
new Disassembler.MethodBodyDisassembler(output, cancellationToken) { DetectControlStructure = false }
.WriteExceptionHandlers(body);
}
/// <summary>

11
ILSpy/Languages/CSharpILMixedLanguage.cs

@ -28,7 +28,10 @@ namespace ICSharpCode.ILSpy @@ -28,7 +28,10 @@ namespace ICSharpCode.ILSpy
protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options)
{
return new ReflectionDisassembler(output,
new MixedMethodBodyDisassembler(output, detectControlStructure, options),
new MixedMethodBodyDisassembler(output, options) {
DetectControlStructure = detectControlStructure,
ShowSequencePoints = true
},
options.CancellationToken);
}
@ -55,8 +58,8 @@ namespace ICSharpCode.ILSpy @@ -55,8 +58,8 @@ namespace ICSharpCode.ILSpy
// lines of raw c# source code
string[] codeLines;
public MixedMethodBodyDisassembler(ITextOutput output, bool detectControlStructure, DecompilationOptions options)
: base(output, detectControlStructure, options.CancellationToken)
public MixedMethodBodyDisassembler(ITextOutput output, DecompilationOptions options)
: base(output, options.CancellationToken)
{
this.options = options;
}
@ -102,7 +105,7 @@ namespace ICSharpCode.ILSpy @@ -102,7 +105,7 @@ namespace ICSharpCode.ILSpy
} else {
output.Write("// ");
highlightingOutput?.BeginSpan(gray);
output.WriteLine("(hidden sequence point)");
output.WriteLine("(no C# code)");
highlightingOutput?.EndSpan();
}
}

2
ILSpy/Languages/ILAstLanguage.cs

@ -77,7 +77,7 @@ namespace ICSharpCode.ILSpy @@ -77,7 +77,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
base.DecompileMethod(method, output, options);
new ReflectionDisassembler(output, false, options.CancellationToken).DisassembleMethodHeader(method);
new ReflectionDisassembler(output, options.CancellationToken).DisassembleMethodHeader(method);
output.WriteLine();
output.WriteLine();
}

5
ILSpy/Languages/ILLanguage.cs

@ -46,7 +46,10 @@ namespace ICSharpCode.ILSpy @@ -46,7 +46,10 @@ namespace ICSharpCode.ILSpy
protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options)
{
return new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
return new ReflectionDisassembler(output, options.CancellationToken) {
DetectControlStructure = detectControlStructure,
ShowSequencePoints = true
};
}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)

Loading…
Cancel
Save