Browse Source

Allow decompiling whole assembly in IL + C# mode.

pull/923/head
Daniel Grunwald 8 years ago
parent
commit
3aca47d1f5
  1. 25
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  2. 15
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  3. 2
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  4. 65
      ILSpy/Languages/CSharpILMixedLanguage.cs
  5. 30
      ILSpy/Languages/ILLanguage.cs

25
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -63,7 +63,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -63,7 +63,7 @@ namespace ICSharpCode.Decompiler.CSharp
readonly Stack<StatePerSequencePoint> outerStates = new Stack<StatePerSequencePoint>();
// Collects information for the current sequence point.
StatePerSequencePoint current = new StatePerSequencePoint();
StatePerSequencePoint current;
void VisitAsSequencePoint(AstNode node)
{
@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp
return;
}
// Add the IL range associated with this instruction to the current sequence point.
if (!inst.ILRange.IsEmpty) {
if (!inst.ILRange.IsEmpty && current.Intervals != null) {
current.Intervals.Add(inst.ILRange);
current.Function = inst.Ancestors.OfType<ILFunction>().FirstOrDefault();
}
@ -189,13 +189,24 @@ namespace ICSharpCode.Decompiler.CSharp @@ -189,13 +189,24 @@ namespace ICSharpCode.Decompiler.CSharp
list.Add(sequencePoint);
}
foreach (var (function, list) in dict.ToList()) {
// For each function, sort sequence points
// and insert hidden sequence points in the gaps.
// For each function, sort sequence points and fix overlaps+gaps
var newList = new List<SequencePoint>();
int pos = 0;
foreach (var sequencePoint in list.OrderBy(sp => sp.Offset)) {
Debug.Assert(sequencePoint.Offset >= pos);
if (sequencePoint.Offset > pos) {
foreach (var sequencePoint in list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset)) {
if (sequencePoint.Offset < pos) {
// overlapping sequence point?
// delete previous sequence points that are after sequencePoint.Offset
while (newList.Count > 0 && newList.Last().EndOffset > pos) {
var last = newList.Last();
if (last.Offset >= sequencePoint.Offset) {
newList.RemoveAt(newList.Count - 1);
} else {
last.EndOffset = sequencePoint.Offset;
newList[newList.Count - 1] = last;
}
}
} else if (sequencePoint.Offset > pos) {
// insert hidden sequence point in the gap.
var hidden = new SequencePoint();
hidden.Offset = pos;
hidden.EndOffset = sequencePoint.Offset;

15
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs

@ -43,15 +43,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -43,15 +43,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
this.context = context;
this.usingScope = this.rootUsingScope = rootNode.Annotation<UsingScope>();
currentMember = context.DecompiledMember;
SetContext();
rootNode.AcceptVisitor(this);
}
void SetContext()
{
this.usingScope = rootUsingScope;
foreach (var name in currentMember.Namespace.Split('.'))
usingScope = new UsingScope(usingScope, name);
resolveContext = new CSharpTypeResolveContext(currentMember.ParentAssembly, usingScope.Resolve(context.TypeSystem.Compilation), currentMember.DeclaringTypeDefinition, currentMember);
string ns = currentMember?.Namespace ?? context.DecompiledTypeDefinition?.Namespace;
if (ns != null) {
foreach (var name in ns.Split('.'))
usingScope = new UsingScope(usingScope, name);
}
resolveContext = new CSharpTypeResolveContext(
context.DecompiledAssembly,
usingScope.Resolve(context.TypeSystem.Compilation),
currentMember?.DeclaringTypeDefinition ?? context.DecompiledTypeDefinition,
currentMember);
resolver = new CSharpResolver(resolveContext);
}

2
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Disassembler
this.cancellationToken = cancellationToken;
}
public void Disassemble(MethodBody body)
public virtual void Disassemble(MethodBody body)
{
// start writing IL code
MethodDefinition method = body.Method;

65
ILSpy/Languages/CSharpILMixedLanguage.cs

@ -16,68 +16,69 @@ using ICSharpCode.Decompiler.IL; @@ -16,68 +16,69 @@ using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy
{
[Export(typeof(Language))]
class CSharpILMixedLanguage : Language
class CSharpILMixedLanguage : ILLanguage
{
private readonly bool detectControlStructure = true;
public override string Name => "IL with C#";
public override string FileExtension => ".il";
protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options)
{
return new ReflectionDisassembler(output,
new MixedMethodBodyDisassembler(output, detectControlStructure, options),
options.CancellationToken);
}
CSharpDecompiler CreateDecompiler(ModuleDefinition module, DecompilationOptions options)
static CSharpDecompiler CreateDecompiler(ModuleDefinition module, DecompilationOptions options)
{
CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings);
decompiler.CancellationToken = options.CancellationToken;
return decompiler;
}
void WriteCode(TextWriter output, DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem)
static void WriteCode(TextWriter output, DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem)
{
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
TokenWriter tokenWriter = new TextWriterTokenWriter(output);
tokenWriter = TokenWriter.WrapInWriterThatSetsLocationsInAST(tokenWriter);
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, settings.CSharpFormattingOptions));
}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
//AddReferenceWarningMessage(method.Module.Assembly, output);
var csharpOutput = new StringWriter();
CSharpDecompiler decompiler = CreateDecompiler(method.Module, options);
var st = decompiler.Decompile(method);
WriteCode(csharpOutput, options.DecompilerSettings, st, decompiler.TypeSystem);
var sequencePoints = (IList<SequencePoint>)decompiler.CreateSequencePoints(st).FirstOrDefault(kvp => kvp.Key.CecilMethod == method).Value ?? EmptyList<SequencePoint>.Instance;
var codeLines = csharpOutput.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None);
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
var methodDisassembler = new MixedMethodBodyDisassembler(output, codeLines, sequencePoints, detectControlStructure, options.CancellationToken);
var dis = new ReflectionDisassembler(output, methodDisassembler, options.CancellationToken);
dis.DisassembleMethod(method);
}
class MixedMethodBodyDisassembler : MethodBodyDisassembler
{
readonly DecompilationOptions options;
// list sorted by IL offset
IList<SequencePoint> sequencePoints;
IList<Decompiler.IL.SequencePoint> sequencePoints;
// lines of raw c# source code
string[] codeLines;
public MixedMethodBodyDisassembler(ITextOutput output, string[] codeLines, IList<SequencePoint> sequencePoints, bool detectControlStructure, CancellationToken cancellationToken)
: base(output, detectControlStructure, cancellationToken)
public MixedMethodBodyDisassembler(ITextOutput output, bool detectControlStructure, DecompilationOptions options)
: base(output, detectControlStructure, options.CancellationToken)
{
if (codeLines == null)
throw new ArgumentNullException(nameof(codeLines));
if (sequencePoints == null)
throw new ArgumentNullException(nameof(sequencePoints));
this.options = options;
}
this.codeLines = codeLines;
this.sequencePoints = sequencePoints;
public override void Disassemble(MethodBody body)
{
var method = body.Method;
try {
var csharpOutput = new StringWriter();
CSharpDecompiler decompiler = CreateDecompiler(method.Module, options);
var st = decompiler.Decompile(method);
WriteCode(csharpOutput, options.DecompilerSettings, st, decompiler.TypeSystem);
this.sequencePoints = decompiler.CreateSequencePoints(st).FirstOrDefault(kvp => kvp.Key.CecilMethod == method).Value ?? (IList<Decompiler.IL.SequencePoint>)EmptyList<Decompiler.IL.SequencePoint>.Instance;
this.codeLines = csharpOutput.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None);
base.Disassemble(body);
} finally {
this.sequencePoints = null;
this.codeLines = null;
}
}
protected override void WriteInstruction(ITextOutput output, Mono.Cecil.Cil.Instruction instruction)
protected override void WriteInstruction(ITextOutput output, Instruction instruction)
{
int index = sequencePoints.BinarySearch(instruction.Offset, seq => seq.Offset);
if (index >= 0) {

30
ILSpy/Languages/ILLanguage.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.ILSpy @@ -34,7 +34,7 @@ namespace ICSharpCode.ILSpy
[Export(typeof(Language))]
public class ILLanguage : Language
{
private readonly bool detectControlStructure = true;
protected bool detectControlStructure = true;
public override string Name {
get { return "IL"; }
@ -44,21 +44,26 @@ namespace ICSharpCode.ILSpy @@ -44,21 +44,26 @@ namespace ICSharpCode.ILSpy
get { return ".il"; }
}
protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options)
{
return new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
var dis = CreateDisassembler(output, options);
dis.DisassembleMethod(method);
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
var dis = CreateDisassembler(output, options);
dis.DisassembleField(field);
}
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
ReflectionDisassembler rd = CreateDisassembler(output, options);
rd.DisassembleProperty(property);
if (property.GetMethod != null) {
output.WriteLine();
@ -76,7 +81,7 @@ namespace ICSharpCode.ILSpy @@ -76,7 +81,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
ReflectionDisassembler rd = CreateDisassembler(output, options);
rd.DisassembleEvent(ev);
if (ev.AddMethod != null) {
output.WriteLine();
@ -94,13 +99,14 @@ namespace ICSharpCode.ILSpy @@ -94,13 +99,14 @@ namespace ICSharpCode.ILSpy
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
var dis = CreateDisassembler(output, options);
dis.DisassembleType(type);
}
public override void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options)
{
new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleNamespace(nameSpace, types);
var dis = CreateDisassembler(output, options);
dis.DisassembleNamespace(nameSpace, types);
}
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
@ -108,17 +114,17 @@ namespace ICSharpCode.ILSpy @@ -108,17 +114,17 @@ namespace ICSharpCode.ILSpy
output.WriteLine("// " + assembly.FileName);
output.WriteLine();
ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
var dis = CreateDisassembler(output, options);
if (options.FullDecompilation)
rd.WriteAssemblyReferences(assembly.ModuleDefinition);
dis.WriteAssemblyReferences(assembly.ModuleDefinition);
if (assembly.AssemblyDefinition != null)
rd.WriteAssemblyHeader(assembly.AssemblyDefinition);
dis.WriteAssemblyHeader(assembly.AssemblyDefinition);
output.WriteLine();
rd.WriteModuleHeader(assembly.ModuleDefinition);
dis.WriteModuleHeader(assembly.ModuleDefinition);
if (options.FullDecompilation) {
output.WriteLine();
output.WriteLine();
rd.WriteModuleContents(assembly.ModuleDefinition);
dis.WriteModuleContents(assembly.ModuleDefinition);
}
}

Loading…
Cancel
Save