diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index 7e4ea70ed..d46ff2278 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -8,14 +8,24 @@ using Cecil = Mono.Cecil; using Mono.Cecil; using Mono.Cecil.Cil; +using Decompiler.ControlFlow; + namespace Decompiler { public class AstMetodBodyBuilder { + MethodDefinition methodDef; static Dictionary localVarTypes = new Dictionary(); static Dictionary localVarDefined = new Dictionary(); public static BlockStatement CreateMetodBody(MethodDefinition methodDef) + { + AstMetodBodyBuilder builder = new AstMetodBodyBuilder(); + builder.methodDef = methodDef; + return builder.CreateMetodBody(); + } + + public BlockStatement CreateMetodBody() { Ast.BlockStatement astBlock = new Ast.BlockStatement(); @@ -25,7 +35,7 @@ namespace Decompiler StackExpressionCollection exprCollection = new StackExpressionCollection(body); exprCollection.Optimize(); - ControlFlow.MethodBodyGraph bodyGraph = new ControlFlow.MethodBodyGraph(exprCollection); + MethodBodyGraph bodyGraph = new MethodBodyGraph(exprCollection); foreach(VariableDefinition varDef in methodDef.Body.Variables) { localVarTypes[varDef.Name] = varDef.VariableType; @@ -37,50 +47,74 @@ namespace Decompiler // astBlock.Children.Add(astLocalVar); } - for(int b = 0; b < bodyGraph.Childs.Count; b++) { - ControlFlow.BasicBlock node = (ControlFlow.BasicBlock)bodyGraph.Childs[b]; - astBlock.Children.Add(MakeComment(node.ToString())); - for(int i = 0; i < node.Body.Count; i++) { - StackExpression expr = node.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; - } - } catch (NotImplementedException) { - astStatement = MakeComment(expr.LastByteCode.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.LastByteCode.OpCode.Code == Code.Ret && -// expr.LastByteCode.PopCount == 0 && -// !expr.IsBranchTarget) { -// continue; -// } - astBlock.Children.Add(astStatement); + astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs)); + + return astBlock; + } + + IEnumerable TransformNodes(IEnumerable nodes) + { + foreach(Node node in nodes) { + foreach(Ast.Statement stmt in TransformNode(node)) { + yield return stmt; } } + } + + IEnumerable TransformNode(Node node) + { + yield return MakeComment(node.ToString()); - return astBlock; + if (node is BasicBlock) { + yield return new Ast.LabelStatement(string.Format("BasicBlock_{0}", ((BasicBlock)node).Id)); + foreach(StackExpression expr in ((BasicBlock)node).Body) { + yield return TransformExpression(expr); + } + } else if (node is AcyclicGraph) { + Ast.BlockStatement blockStatement = new Ast.BlockStatement(); + blockStatement.Children.AddRange(TransformNodes(node.Childs)); + yield return blockStatement; + } else if (node is Loop) { + Ast.BlockStatement blockStatement = new Ast.BlockStatement(); + blockStatement.Children.AddRange(TransformNodes(node.Childs)); + yield return new Ast.DoLoopStatement( + new Ast.PrimitiveExpression(true, true.ToString()), + blockStatement, + ConditionType.While, + ConditionPosition.Start + ); + } else { + throw new Exception("Bad node type"); + } + } + + Ast.Statement TransformExpression(StackExpression expr) + { + 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; + } + } catch (NotImplementedException) { + astStatement = MakeComment(expr.LastByteCode.Description); + } + return astStatement; } static Ast.ExpressionStatement MakeComment(string text) diff --git a/src/ControlFlow/Node.cs b/src/ControlFlow/Node.cs index 926840b48..d7e2dbe1d 100644 --- a/src/ControlFlow/Node.cs +++ b/src/ControlFlow/Node.cs @@ -57,18 +57,15 @@ namespace Decompiler.ControlFlow public void Optimize() { - bool optimized; - do { - optimized = false; - foreach(Node child in this.Childs) { - if (child.Predecessors.Count == 1) { - Node predecessor = child.Predecessors[0]; - MergeChilds(predecessor, child); - optimized = true; - break; // Collection was modified; restart - } + for(int i = 0; i < this.Childs.Count;) { + Node child = childs[i]; + if (child.Predecessors.Count == 1) { + MergeChilds(child.Predecessors[0], child); + i = 0; // Restart + } else { + i++; // Next } - } while (optimized); + } } static void MergeChilds(Node head, Node tail) @@ -124,10 +121,11 @@ namespace Decompiler.ControlFlow Relink(head, mergedNode); Relink(tail, mergedNode); - // Remove the old nodes and add the merged node - container.Childs.Remove(head); + // Remove the old nodes and add the merged node - replace head with the merged node container.Childs.Remove(tail); - container.Childs.Add(mergedNode); + int headIndex = container.Childs.IndexOf(head); + container.Childs.Remove(head); + container.Childs.Insert(headIndex, mergedNode); } static void Relink(Node node, Node target) diff --git a/src/ControlFlow/Nodes.cs b/src/ControlFlow/Nodes.cs index 8d93c41cd..f4445d042 100644 --- a/src/ControlFlow/Nodes.cs +++ b/src/ControlFlow/Nodes.cs @@ -22,6 +22,27 @@ namespace Decompiler.ControlFlow this.Childs.Add(basicBlock); } basicBlock.Body.Add(exprs[i]); + exprs[i].BasicBlock = basicBlock; + } + + // Add fall-though links + for(int i = 0; i < exprs.Count - 1; i++) { + BasicBlock node = exprs[i].BasicBlock; + BasicBlock target = exprs[i + 1].BasicBlock; + if (node != target) { + node.Successors.Add(target); + target.Predecessors.Add(node); + } + } + + // Add branch links + for(int i = 0; i < exprs.Count; i++) { + if (exprs[i].BranchTarget != null) { + BasicBlock node = exprs[i].BasicBlock; + BasicBlock target = exprs[i].BranchTarget.BasicBlock; + node.Successors.Add(target); + target.Predecessors.Add(node); + } } this.HeadChild = this.Childs[0]; @@ -33,6 +54,11 @@ namespace Decompiler.ControlFlow public AcyclicGraph(Node parent): base(parent){ } + + public override string ToString() + { + return "AcyclicGraph"; + } } public class Loop: Node @@ -40,6 +66,11 @@ namespace Decompiler.ControlFlow public Loop(Node parent): base(parent){ } + + public override string ToString() + { + return "Loop"; + } } public class BasicBlock: Node diff --git a/src/StackExpression.cs b/src/StackExpression.cs index 857c171f1..bbecfeaf8 100644 --- a/src/StackExpression.cs +++ b/src/StackExpression.cs @@ -9,10 +9,21 @@ namespace Decompiler { public class StackExpression { + ControlFlow.BasicBlock basicBlock; StackExpressionCollection owner; ByteCode lastByteCode; List lastArguments = new List(); + public Decompiler.ControlFlow.BasicBlock BasicBlock { + get { return basicBlock; } + set { + basicBlock = value; + foreach (StackExpression lastArgument in lastArguments) { + lastArgument.BasicBlock = value; + } + } + } + public StackExpressionCollection Owner { get { return owner; } }