diff --git a/Decompiler.csproj b/Decompiler.csproj index b3be72fb4..9a315da95 100644 --- a/Decompiler.csproj +++ b/Decompiler.csproj @@ -48,6 +48,8 @@ + + MainForm.cs diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index 9202147a8..7bda9a6e3 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -19,6 +19,7 @@ namespace Decompiler methodDef.Body.Simplify(); ByteCodeCollection body = new ByteCodeCollection(methodDef); + StackExpressionCollection exprCol = new StackExpressionCollection(body); foreach(VariableDefinition varDef in methodDef.Body.Variables) { Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name); @@ -27,34 +28,19 @@ namespace Decompiler astBlock.Children.Add(astLocalVar); } - foreach(ByteCode byteCode in body) { - OpCode opCode = byteCode.OpCode; - string description = - string.Format(" {1, -22} # {2}->{3} {4} {5}", - byteCode.Offset, - opCode + " " + FormatByteCodeOperand(byteCode.Operand), - opCode.StackBehaviourPop, - opCode.StackBehaviourPush, - opCode.FlowControl == FlowControl.Next ? string.Empty : "Flow=" + opCode.FlowControl, - opCode.OpCodeType == OpCodeType.Macro ? "(macro)" : string.Empty); - + foreach(StackExpression expr in exprCol) { Ast.Statement astStatement = null; try { - int argCount = byteCode.PopCount; - Ast.Expression[] args = new Ast.Expression[argCount]; - for(int i = 0; i < argCount; i++) { - ByteCode allocBy = byteCode.StackBefore.Peek(argCount - i).AllocadedBy; - string name = string.Format("expr{0:X2}", allocBy.Offset); - args[i] = new Ast.IdentifierExpression(name); + 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, - byteCode, - args); + object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray()); if (codeExpr is Ast.Expression) { - if (byteCode.PushCount == 1) { - string type = byteCode.Type.FullName; - string name = string.Format("expr{0:X2}", byteCode.Offset); + 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; @@ -65,14 +51,12 @@ namespace Decompiler astStatement = (Ast.Statement)codeExpr; } } catch (NotImplementedException) { - astStatement = MakeComment(description); + astStatement = MakeComment(expr.ExpressionByteCode.Description); } - //astBlock.Children.Add(MakeComment(description)); - if (byteCode.BranchesHere.Count > 0) { - astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", byteCode.Offset))); + if (expr.FirstByteCode.BranchesHere.Count > 0) { + astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", expr.FirstByteCode.Offset))); } astBlock.Children.Add(astStatement); - //astBlock.Children.Add(MakeComment(" " + stackAnalysis.StackAfter[instr].ToString())); } return astBlock; @@ -84,27 +68,16 @@ namespace Decompiler return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); } - static object FormatByteCodeOperand(object operand) + static object MakeCodeDomExpression(MethodDefinition methodDef, StackExpression expr, params Ast.Expression[] args) { - if (operand == null) { - return string.Empty; - } else if (operand is ByteCode) { - return string.Format("IL_{0:X2}", ((ByteCode)operand).Offset); - } else if (operand is MethodReference) { - return ((MethodReference)operand).Name + "()"; - } else if (operand is Cecil.TypeReference) { - return ((Cecil.TypeReference)operand).FullName; - } else if (operand is VariableDefinition) { - return ((VariableDefinition)operand).Name; - } else if (operand is ParameterDefinition) { - return ((ParameterDefinition)operand).Name; - } else if (operand is string) { - return "\"" + operand + "\""; - } else if (operand is int) { - return operand.ToString(); - } else { - return "(" + operand.GetType() + ")"; + List allArgs = new List(); + // Add args from stack + allArgs.AddRange(args); + // Args generated by nested expressions + foreach(StackExpression nestedExpr in expr.LastArguments) { + allArgs.Add(new Ast.ParenthesizedExpression((Ast.Expression)MakeCodeDomExpression(methodDef, nestedExpr))); } + return MakeCodeDomExpression(methodDef, expr.ExpressionByteCode, args); } static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args) diff --git a/src/ByteCode.StackBehaviour.cs b/src/ByteCode.StackBehaviour.cs index 2a910ac9a..f4d462c94 100644 --- a/src/ByteCode.StackBehaviour.cs +++ b/src/ByteCode.StackBehaviour.cs @@ -11,43 +11,19 @@ namespace Decompiler { public int PopCount { get { - int popCount; - int pushCount; - SimulateStackSize(out popCount, out pushCount); - return popCount; + return GetPopCount(); } } public int PushCount { get { - int popCount; - int pushCount; - SimulateStackSize(out popCount, out pushCount); - return pushCount; + return GetPushCount(); } } - void SimulateStackSize(out int popCount, out int pushCount) + int GetPopCount() { - int stackSize = 0; - int minStackSize = 0; - foreach(ByteCode bc in nestedByteCodes) { - stackSize -= bc.PopCount; - minStackSize = Math.Min(minStackSize, stackSize); - stackSize += bc.PushCount; - } - { - stackSize -= GetPopCount(methodDef, this); - minStackSize = Math.Min(minStackSize, stackSize); - stackSize += GetPushCount(methodDef, this); - } - popCount = -minStackSize; - pushCount = stackSize - minStackSize; - } - - static int GetPopCount(MethodDefinition methodDef, ByteCode byteCode) - { - switch(byteCode.OpCode.StackBehaviourPop) { + switch(this.OpCode.StackBehaviourPop) { case StackBehaviour.Pop0: return 0; case StackBehaviour.Pop1: return 1; case StackBehaviour.Popi: return 1; @@ -68,9 +44,9 @@ namespace Decompiler case StackBehaviour.Popref_popi_popref: return 3; case StackBehaviour.PopAll: throw new Exception("PopAll"); case StackBehaviour.Varpop: - switch(byteCode.OpCode.Code) { + switch(this.OpCode.Code) { case Code.Call: - Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand); + Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand); if (cecilMethod.HasThis) { return cecilMethod.Parameters.Count + 1 /* this */; } else { @@ -87,13 +63,13 @@ namespace Decompiler case Code.Newobj: throw new NotImplementedException(); default: throw new Exception("Unknown Varpop opcode"); } - default: throw new Exception("Unknown pop behaviour: " + byteCode.OpCode.StackBehaviourPop); + default: throw new Exception("Unknown pop behaviour: " + this.OpCode.StackBehaviourPop); } } - static int GetPushCount(MethodDefinition methodDef, ByteCode byteCode) + int GetPushCount() { - switch(byteCode.OpCode.StackBehaviourPush) { + switch(this.OpCode.StackBehaviourPush) { case StackBehaviour.Push0: return 0; case StackBehaviour.Push1: return 1; case StackBehaviour.Push1_push1: return 2; @@ -103,9 +79,9 @@ namespace Decompiler case StackBehaviour.Pushr8: return 1; case StackBehaviour.Pushref: return 1; case StackBehaviour.Varpush: // Happens only for calls - switch(byteCode.OpCode.Code) { + switch(this.OpCode.Code) { case Code.Call: - Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand); + Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand); if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) { return 0; } else { @@ -115,7 +91,7 @@ namespace Decompiler case Code.Callvirt: throw new NotImplementedException(); default: throw new Exception("Unknown Varpush opcode"); } - default: throw new Exception("Unknown push behaviour: " + byteCode.OpCode.StackBehaviourPush); + default: throw new Exception("Unknown push behaviour: " + this.OpCode.StackBehaviourPush); } } } diff --git a/src/ByteCode.cs b/src/ByteCode.cs index a4b8206e3..470305ffe 100644 --- a/src/ByteCode.cs +++ b/src/ByteCode.cs @@ -12,8 +12,6 @@ namespace Decompiler ByteCode previous; ByteCode next; - List nestedByteCodes = new List(); - MethodDefinition methodDef; int offset; OpCode opCode; @@ -29,10 +27,6 @@ namespace Decompiler set { next = value; } } - public List NestedByteCodes { - get { return nestedByteCodes; } - } - public int Offset { get { return offset; } set { offset = value; } @@ -68,5 +62,42 @@ namespace Decompiler this.opCode = inst.OpCode; this.operand = inst.Operand; } + + public string Description { + get { + return string.Format( + " {1, -22} # {2}->{3} {4} {5}", + this.Offset, + this.OpCode + " " + FormatByteCodeOperand(this.Operand), + this.OpCode.StackBehaviourPop, + this.OpCode.StackBehaviourPush, + this.OpCode.FlowControl == FlowControl.Next ? string.Empty : "Flow=" + opCode.FlowControl, + this.OpCode.OpCodeType == OpCodeType.Macro ? "(macro)" : string.Empty + ); + } + } + + static object FormatByteCodeOperand(object operand) + { + if (operand == null) { + return string.Empty; + } else if (operand is ByteCode) { + return string.Format("IL_{0:X2}", ((ByteCode)operand).Offset); + } else if (operand is MethodReference) { + return ((MethodReference)operand).Name + "()"; + } else if (operand is Cecil.TypeReference) { + return ((Cecil.TypeReference)operand).FullName; + } else if (operand is VariableDefinition) { + return ((VariableDefinition)operand).Name; + } else if (operand is ParameterDefinition) { + return ((ParameterDefinition)operand).Name; + } else if (operand is string) { + return "\"" + operand + "\""; + } else if (operand is int) { + return operand.ToString(); + } else { + return "(" + operand.GetType() + ")"; + } + } } } diff --git a/src/CilStack.cs b/src/CilStack.cs index 56ae91286..f4d066e97 100644 --- a/src/CilStack.cs +++ b/src/CilStack.cs @@ -75,6 +75,11 @@ namespace Decompiler this.Add(slot); } + public CilStackSlot[] PeekCount(int count) + { + return this.GetRange(this.Count - count, count).ToArray(); + } + public CilStackSlot Peek(int depth) { return this[this.Count - depth]; diff --git a/src/StackExpression.cs b/src/StackExpression.cs new file mode 100644 index 000000000..59714bfdf --- /dev/null +++ b/src/StackExpression.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; + +using Cecil = Mono.Cecil; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Decompiler +{ + public class StackExpression + { + ByteCode expressionByteCode; + List lastArguments = new List(); + + public ByteCode ExpressionByteCode { + get { return expressionByteCode; } + } + + public List LastArguments { + get { return lastArguments; } + } + + public CilStack StackBefore { + get { + return this.FirstByteCode.StackBefore; + } + } + + public CilStack StackAfter { + get { + return this.ExpressionByteCode.StackAfter; + } + } + + public int PopCount { + get { + int popCount; + int pushCount; + SimulateStackSize(out popCount, out pushCount); + return popCount; + } + } + + public int PushCount { + get { + int popCount; + int pushCount; + SimulateStackSize(out popCount, out pushCount); + return pushCount; + } + } + + void SimulateStackSize(out int popCount, out int pushCount) + { + int stackSize = 0; + int minStackSize = 0; + foreach(StackExpression expr in lastArguments) { + stackSize -= expr.PopCount; + minStackSize = Math.Min(minStackSize, stackSize); + stackSize += expr.PushCount; + } + { + stackSize -= expressionByteCode.PopCount; + minStackSize = Math.Min(minStackSize, stackSize); + stackSize += expressionByteCode.PushCount; + } + popCount = -minStackSize; + pushCount = stackSize - minStackSize; + } + + public ByteCode FirstByteCode { + get { + if (lastArguments.Count > 0) { + return lastArguments[0].FirstByteCode; + } else { + return this.ExpressionByteCode; + } + } + } + + public StackExpression(ByteCode expressionByteCode) + { + this.expressionByteCode = expressionByteCode; + } + } +} diff --git a/src/StackExpressionCollection.cs b/src/StackExpressionCollection.cs new file mode 100644 index 000000000..81beb2a81 --- /dev/null +++ b/src/StackExpressionCollection.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +using Cecil = Mono.Cecil; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Decompiler +{ + public class StackExpressionCollection: List + { + public StackExpressionCollection(ByteCodeCollection byteCodeCol) + { + foreach(ByteCode bc in byteCodeCol) { + this.Add(new StackExpression(bc)); + } + } + + public void Optimize() + { + + } + } +}