diff --git a/Decompiler.csproj b/Decompiler.csproj index 9a315da95..83db650ab 100644 --- a/Decompiler.csproj +++ b/Decompiler.csproj @@ -50,6 +50,7 @@ + MainForm.cs diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index b95868e66..d539825c8 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -22,8 +22,10 @@ namespace Decompiler methodDef.Body.Simplify(); ByteCodeCollection body = new ByteCodeCollection(methodDef); - StackExpressionCollection exprCol = new StackExpressionCollection(body); - exprCol.Optimize(); + StackExpressionCollection exprCollection = new StackExpressionCollection(body); + exprCollection.Optimize(); + + BasicBlockSet basicBlockSet = new BasicBlockSet(exprCollection); foreach(VariableDefinition varDef in methodDef.Body.Variables) { localVarTypes[varDef.Name] = varDef.VariableType; @@ -35,43 +37,47 @@ namespace Decompiler // astBlock.Children.Add(astLocalVar); } - for(int i = 0; i < exprCol.Count; i++) { - StackExpression expr = exprCol[i]; - Ast.Statement astStatement = null; - try { - List args = new List(); - foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) { - string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset); - args.Add(new Ast.IdentifierExpression(name)); - } - object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray()); - if (codeExpr is Ast.Expression) { - if (expr.PushCount == 1) { - string type = expr.ExpressionByteCode.Type.FullName; - string name = string.Format("expr{0:X2}", expr.ExpressionByteCode.Offset); - Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); - astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); - astStatement = astLocal; - } else { - astStatement = new ExpressionStatement((Ast.Expression)codeExpr); + for(int b = 0; b < basicBlockSet.Elements.Count; b++) { + BasicBlock basicBlock = (BasicBlock)basicBlockSet.Elements[b]; + astBlock.Children.Add(MakeComment(basicBlock.ToString())); + for(int i = 0; i < basicBlock.Body.Count; i++) { + StackExpression expr = basicBlock.Body[i]; + Ast.Statement astStatement = null; + try { + List args = new List(); + foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) { + string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset); + args.Add(new Ast.IdentifierExpression(name)); + } + object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray()); + if (codeExpr is Ast.Expression) { + if (expr.PushCount == 1) { + string type = expr.LastByteCode.Type.FullName; + string name = string.Format("expr{0:X2}", expr.LastByteCode.Offset); + Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); + astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); + astStatement = astLocal; + } else { + astStatement = new ExpressionStatement((Ast.Expression)codeExpr); + } + } else if (codeExpr is Ast.Statement) { + astStatement = (Ast.Statement)codeExpr; } - } else if (codeExpr is Ast.Statement) { - astStatement = (Ast.Statement)codeExpr; + } catch (NotImplementedException) { + astStatement = MakeComment(expr.LastByteCode.Description); } - } catch (NotImplementedException) { - astStatement = MakeComment(expr.ExpressionByteCode.Description); - } - if (expr.IsBranchTarget) { - astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", expr.FirstByteCode.Offset))); - } - // Skip last return statement - if (i == exprCol.Count - 1 && - expr.ExpressionByteCode.OpCode.Code == Code.Ret && - expr.ExpressionByteCode.PopCount == 0 && - !expr.IsBranchTarget) { - continue; + if (expr.IsBranchTarget) { + astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", expr.FirstByteCode.Offset))); + } + // Skip last return statement +// if (i == exprCol.Count - 1 && +// expr.LastByteCode.OpCode.Code == Code.Ret && +// expr.LastByteCode.PopCount == 0 && +// !expr.IsBranchTarget) { +// continue; +// } + astBlock.Children.Add(astStatement); } - astBlock.Children.Add(astStatement); } return astBlock; @@ -79,7 +85,7 @@ namespace Decompiler static Ast.ExpressionStatement MakeComment(string text) { - text = "/*" + text + "*/"; + text = "/* " + text + "*/"; return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); } @@ -97,7 +103,7 @@ namespace Decompiler allArgs.Add(astExpr); } } - return MakeCodeDomExpression(methodDef, expr.ExpressionByteCode, allArgs.ToArray()); + return MakeCodeDomExpression(methodDef, expr.LastByteCode, allArgs.ToArray()); } static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args) diff --git a/src/ByteCode.cs b/src/ByteCode.cs index 470305ffe..c73e7908a 100644 --- a/src/ByteCode.cs +++ b/src/ByteCode.cs @@ -9,6 +9,7 @@ namespace Decompiler { public partial class ByteCode { + StackExpression owner; ByteCode previous; ByteCode next; @@ -17,6 +18,11 @@ namespace Decompiler OpCode opCode; object operand; + public StackExpression Owner { + get { return owner; } + set { owner = value; } + } + public ByteCode Previous { get { return previous; } set { previous = value; } @@ -44,7 +50,7 @@ namespace Decompiler public ByteCode BranchTarget { get { - return (ByteCode)operand; + return operand as ByteCode; } } @@ -66,7 +72,7 @@ namespace Decompiler public string Description { get { return string.Format( - " {1, -22} # {2}->{3} {4} {5}", + "{1, -22} # {2}->{3} {4} {5}", this.Offset, this.OpCode + " " + FormatByteCodeOperand(this.Operand), this.OpCode.StackBehaviourPop, diff --git a/src/ControlFlow.cs b/src/ControlFlow.cs new file mode 100644 index 000000000..291399b82 --- /dev/null +++ b/src/ControlFlow.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Decompiler +{ + public class Set: List + { + + } + + + public class BasicBlock + { + int id; + BasicBlockSet owner; + Set predecessors; + public Set successors; + BasicBlock fallThroughSuccessor; + BasicBlock branchSuccessor; + List body = new List(); + + #region Peoperties + + public int Id { + get { return id; } + set { id = value; } + } + + public BasicBlockSet Owner { + get { return owner; } + set { owner = value; } + } + + public Set Predecessors { + get { return predecessors; } + set { predecessors = value; } + } + + public Set Successors { + get { return successors; } + set { successors = value; } + } + + public BasicBlock FallThroughSuccessor { + get { return fallThroughSuccessor; } + set { fallThroughSuccessor = value; } + } + + public BasicBlock BranchSuccessor { + get { return branchSuccessor; } + set { branchSuccessor = value; } + } + + public List Body { + get { return body; } + set { body = value; } + } + + #endregion + + public override string ToString() + { + //return string.Format("BackBlock {0} ({1} expressions)", id, body.Count); + return string.Format("BackBlock {0}", id, body.Count); + } + } + + public enum BasicBlockSetType { + MethodBody, + Acyclic, + Loop, + } + + public class BasicBlockSet + { + BasicBlockSet owner; + BasicBlockSetType type; + + object head; + Set elements = new Set(); + + Set BasicBlockSuccessors; + + BasicBlock headBasicBlock { + get { + return null; + } + } + + public BasicBlockSet Owner { + get { return owner; } + } + + public BasicBlockSetType Type { + get { return type; } + } + + public object Head { + get { return head; } + } + + public Set Elements { + get { return elements; } + } + + + BasicBlockSet() + { + + } + + public BasicBlockSet(object head, object tail) + { + if (head == null) throw new ArgumentNullException("head"); + if (tail == null) throw new ArgumentNullException("tail"); + + BasicBlockSet headAsSet = head as BasicBlockSet; + BasicBlockSet tailAsSet = tail as BasicBlockSet; + + // Add head + if (head is BasicBlock) { + this.head = head; + this.elements.Add(head); + } else if (headAsSet != null && headAsSet.type == BasicBlockSetType.Acyclic) { + this.head = headAsSet.head; + this.elements.AddRange(headAsSet.elements); + } else if (headAsSet != null && headAsSet.type == BasicBlockSetType.Loop) { + this.head = headAsSet; + this.elements.Add(headAsSet); + } else { + throw new Exception("Invalid head"); + } + + // Add tail + if (tail is BasicBlock) { + this.elements.Add(tail); + } else if (tailAsSet != null && tailAsSet.type == BasicBlockSetType.Acyclic) { + this.elements.AddRange(tailAsSet.elements); + } else if (tailAsSet != null && tailAsSet.type == BasicBlockSetType.Loop) { + this.elements.Add(tailAsSet); + } else { + throw new Exception("Invalid tail"); + } + + // Get type + if (tail is BasicBlock) { + if (((BasicBlock)tail).successors.Contains(this.headBasicBlock)) { + this.type = BasicBlockSetType.Loop; + } else { + this.type = BasicBlockSetType.Acyclic; + } + } else if (tailAsSet != null) { + if (tailAsSet.BasicBlockSuccessors.Contains(this.headBasicBlock)) { + + } + } else { + throw new Exception("Invalid tail"); + } + } + + public BasicBlockSet(StackExpressionCollection exprs) + { + if (exprs.Count == 0) throw new ArgumentException("Count == 0", "exprs"); + + this.owner = null; + this.type = BasicBlockSetType.MethodBody; + + BasicBlock basicBlock = null; + int basicBlockId = 1; + for(int i = 0; i < exprs.Count; i++) { + // Start new basic block if + // - this is first expression + // - last expression was branch + // - this expression is branch target + if (i == 0 || exprs[i - 1].BranchTarget != null || exprs[i].BranchesHere.Count > 0){ + basicBlock = new BasicBlock(); + this.elements.Add(basicBlock); + basicBlock.Id = basicBlockId++; + } + basicBlock.Body.Add(exprs[i]); + } + + this.head = this.elements[0]; + } + } +} diff --git a/src/StackExpression.cs b/src/StackExpression.cs index 23f3ac1bc..857c171f1 100644 --- a/src/StackExpression.cs +++ b/src/StackExpression.cs @@ -9,11 +9,16 @@ namespace Decompiler { public class StackExpression { - ByteCode expressionByteCode; + StackExpressionCollection owner; + ByteCode lastByteCode; List lastArguments = new List(); - public ByteCode ExpressionByteCode { - get { return expressionByteCode; } + public StackExpressionCollection Owner { + get { return owner; } + } + + public ByteCode LastByteCode { + get { return lastByteCode; } } // A list of closed expression for last arguments @@ -29,7 +34,7 @@ namespace Decompiler public CilStack StackAfter { get { - return this.ExpressionByteCode.StackAfter; + return this.LastByteCode.StackAfter; } } @@ -43,6 +48,26 @@ namespace Decompiler } } + public List BranchesHere { + get { + List branchesHere = new List(); + foreach(ByteCode byteCode in this.FirstByteCode.BranchesHere) { + branchesHere.Add(byteCode.Owner); + } + return branchesHere; + } + } + + public StackExpression BranchTarget { + get { + if (this.lastByteCode.BranchTarget == null) { + return null; + } else { + return this.lastByteCode.BranchTarget.Owner; + } + } + } + public bool IsBranchTarget { get { return this.FirstByteCode.BranchesHere.Count > 0; @@ -77,9 +102,9 @@ namespace Decompiler stackSize += expr.PushCount; } { - stackSize -= expressionByteCode.PopCount; + stackSize -= lastByteCode.PopCount; minStackSize = Math.Min(minStackSize, stackSize); - stackSize += expressionByteCode.PushCount; + stackSize += lastByteCode.PushCount; } popCount = -minStackSize; pushCount = stackSize - minStackSize; @@ -90,19 +115,21 @@ namespace Decompiler if (lastArguments.Count > 0) { return lastArguments[0].FirstByteCode; } else { - return this.ExpressionByteCode; + return this.LastByteCode; } } } - public StackExpression(ByteCode expressionByteCode) + public StackExpression(StackExpressionCollection owner, ByteCode lastByteCode) { - this.expressionByteCode = expressionByteCode; + this.owner = owner; + this.lastByteCode = lastByteCode; + this.lastByteCode.Owner = this; } public bool MustBeParenthesized { get { - switch(this.ExpressionByteCode.OpCode.Code) { + switch(this.LastByteCode.OpCode.Code) { #region Arithmetic case Code.Neg: case Code.Not: diff --git a/src/StackExpressionCollection.cs b/src/StackExpressionCollection.cs index ff85fe156..434c12bb5 100644 --- a/src/StackExpressionCollection.cs +++ b/src/StackExpressionCollection.cs @@ -12,7 +12,7 @@ namespace Decompiler public StackExpressionCollection(ByteCodeCollection byteCodeCol) { foreach(ByteCode bc in byteCodeCol) { - this.Add(new StackExpression(bc)); + this.Add(new StackExpression(this, bc)); } }