Browse Source

Convert ByteCodeCollection to new data representation: StackExpressionCollection;

Modify the generating code to use this data representation
pull/1/head^2
David Srbecký 18 years ago
parent
commit
37d40932d9
  1. 2
      Decompiler.csproj
  2. 69
      src/AstMetodBodyBuilder.cs
  3. 48
      src/ByteCode.StackBehaviour.cs
  4. 43
      src/ByteCode.cs
  5. 5
      src/CilStack.cs
  6. 86
      src/StackExpression.cs
  7. 24
      src/StackExpressionCollection.cs

2
Decompiler.csproj

@ -48,6 +48,8 @@
<Compile Include="src\MainForm.Designer.cs" /> <Compile Include="src\MainForm.Designer.cs" />
<Compile Include="src\Program.cs" /> <Compile Include="src\Program.cs" />
<Compile Include="src\ByteCode.StackAnalysis.cs" /> <Compile Include="src\ByteCode.StackAnalysis.cs" />
<Compile Include="src\StackExpression.cs" />
<Compile Include="src\StackExpressionCollection.cs" />
<Compile Include="src\Util.cs" /> <Compile Include="src\Util.cs" />
<EmbeddedResource Include="src\MainForm.resx"> <EmbeddedResource Include="src\MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>

69
src/AstMetodBodyBuilder.cs

@ -19,6 +19,7 @@ namespace Decompiler
methodDef.Body.Simplify(); methodDef.Body.Simplify();
ByteCodeCollection body = new ByteCodeCollection(methodDef); ByteCodeCollection body = new ByteCodeCollection(methodDef);
StackExpressionCollection exprCol = new StackExpressionCollection(body);
foreach(VariableDefinition varDef in methodDef.Body.Variables) { foreach(VariableDefinition varDef in methodDef.Body.Variables) {
Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name); Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name);
@ -27,34 +28,19 @@ namespace Decompiler
astBlock.Children.Add(astLocalVar); astBlock.Children.Add(astLocalVar);
} }
foreach(ByteCode byteCode in body) { foreach(StackExpression expr in exprCol) {
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);
Ast.Statement astStatement = null; Ast.Statement astStatement = null;
try { try {
int argCount = byteCode.PopCount; List<Ast.Expression> args = new List<Ast.Expression>();
Ast.Expression[] args = new Ast.Expression[argCount]; foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) {
for(int i = 0; i < argCount; i++) { string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset);
ByteCode allocBy = byteCode.StackBefore.Peek(argCount - i).AllocadedBy; args.Add(new Ast.IdentifierExpression(name));
string name = string.Format("expr{0:X2}", allocBy.Offset);
args[i] = new Ast.IdentifierExpression(name);
} }
object codeExpr = MakeCodeDomExpression( object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray());
methodDef,
byteCode,
args);
if (codeExpr is Ast.Expression) { if (codeExpr is Ast.Expression) {
if (byteCode.PushCount == 1) { if (expr.PushCount == 1) {
string type = byteCode.Type.FullName; string type = expr.ExpressionByteCode.Type.FullName;
string name = string.Format("expr{0:X2}", byteCode.Offset); string name = string.Format("expr{0:X2}", expr.ExpressionByteCode.Offset);
Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString()));
astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr));
astStatement = astLocal; astStatement = astLocal;
@ -65,14 +51,12 @@ namespace Decompiler
astStatement = (Ast.Statement)codeExpr; astStatement = (Ast.Statement)codeExpr;
} }
} catch (NotImplementedException) { } catch (NotImplementedException) {
astStatement = MakeComment(description); astStatement = MakeComment(expr.ExpressionByteCode.Description);
} }
//astBlock.Children.Add(MakeComment(description)); if (expr.FirstByteCode.BranchesHere.Count > 0) {
if (byteCode.BranchesHere.Count > 0) { astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", expr.FirstByteCode.Offset)));
astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", byteCode.Offset)));
} }
astBlock.Children.Add(astStatement); astBlock.Children.Add(astStatement);
//astBlock.Children.Add(MakeComment(" " + stackAnalysis.StackAfter[instr].ToString()));
} }
return astBlock; return astBlock;
@ -84,27 +68,16 @@ namespace Decompiler
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); 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) { List<Ast.Expression> allArgs = new List<Ast.Expression>();
return string.Empty; // Add args from stack
} else if (operand is ByteCode) { allArgs.AddRange(args);
return string.Format("IL_{0:X2}", ((ByteCode)operand).Offset); // Args generated by nested expressions
} else if (operand is MethodReference) { foreach(StackExpression nestedExpr in expr.LastArguments) {
return ((MethodReference)operand).Name + "()"; allArgs.Add(new Ast.ParenthesizedExpression((Ast.Expression)MakeCodeDomExpression(methodDef, nestedExpr)));
} 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() + ")";
} }
return MakeCodeDomExpression(methodDef, expr.ExpressionByteCode, args);
} }
static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args) static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args)

48
src/ByteCode.StackBehaviour.cs

@ -11,43 +11,19 @@ namespace Decompiler
{ {
public int PopCount { public int PopCount {
get { get {
int popCount; return GetPopCount();
int pushCount;
SimulateStackSize(out popCount, out pushCount);
return popCount;
} }
} }
public int PushCount { public int PushCount {
get { get {
int popCount; return GetPushCount();
int pushCount;
SimulateStackSize(out popCount, out pushCount);
return pushCount;
} }
} }
void SimulateStackSize(out int popCount, out int pushCount) int GetPopCount()
{ {
int stackSize = 0; switch(this.OpCode.StackBehaviourPop) {
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) {
case StackBehaviour.Pop0: return 0; case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1; case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1; case StackBehaviour.Popi: return 1;
@ -68,9 +44,9 @@ namespace Decompiler
case StackBehaviour.Popref_popi_popref: return 3; case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: throw new Exception("PopAll"); case StackBehaviour.PopAll: throw new Exception("PopAll");
case StackBehaviour.Varpop: case StackBehaviour.Varpop:
switch(byteCode.OpCode.Code) { switch(this.OpCode.Code) {
case Code.Call: case Code.Call:
Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand); Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand);
if (cecilMethod.HasThis) { if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */; return cecilMethod.Parameters.Count + 1 /* this */;
} else { } else {
@ -87,13 +63,13 @@ namespace Decompiler
case Code.Newobj: throw new NotImplementedException(); case Code.Newobj: throw new NotImplementedException();
default: throw new Exception("Unknown Varpop opcode"); 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.Push0: return 0;
case StackBehaviour.Push1: return 1; case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2; case StackBehaviour.Push1_push1: return 2;
@ -103,9 +79,9 @@ namespace Decompiler
case StackBehaviour.Pushr8: return 1; case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1; case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls case StackBehaviour.Varpush: // Happens only for calls
switch(byteCode.OpCode.Code) { switch(this.OpCode.Code) {
case Code.Call: case Code.Call:
Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand); Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand);
if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) { if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) {
return 0; return 0;
} else { } else {
@ -115,7 +91,7 @@ namespace Decompiler
case Code.Callvirt: throw new NotImplementedException(); case Code.Callvirt: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode"); 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);
} }
} }
} }

43
src/ByteCode.cs

@ -12,8 +12,6 @@ namespace Decompiler
ByteCode previous; ByteCode previous;
ByteCode next; ByteCode next;
List<ByteCode> nestedByteCodes = new List<ByteCode>();
MethodDefinition methodDef; MethodDefinition methodDef;
int offset; int offset;
OpCode opCode; OpCode opCode;
@ -29,10 +27,6 @@ namespace Decompiler
set { next = value; } set { next = value; }
} }
public List<ByteCode> NestedByteCodes {
get { return nestedByteCodes; }
}
public int Offset { public int Offset {
get { return offset; } get { return offset; }
set { offset = value; } set { offset = value; }
@ -68,5 +62,42 @@ namespace Decompiler
this.opCode = inst.OpCode; this.opCode = inst.OpCode;
this.operand = inst.Operand; 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() + ")";
}
}
} }
} }

5
src/CilStack.cs

@ -75,6 +75,11 @@ namespace Decompiler
this.Add(slot); this.Add(slot);
} }
public CilStackSlot[] PeekCount(int count)
{
return this.GetRange(this.Count - count, count).ToArray();
}
public CilStackSlot Peek(int depth) public CilStackSlot Peek(int depth)
{ {
return this[this.Count - depth]; return this[this.Count - depth];

86
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<StackExpression> lastArguments = new List<StackExpression>();
public ByteCode ExpressionByteCode {
get { return expressionByteCode; }
}
public List<StackExpression> 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;
}
}
}

24
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<StackExpression>
{
public StackExpressionCollection(ByteCodeCollection byteCodeCol)
{
foreach(ByteCode bc in byteCodeCol) {
this.Add(new StackExpression(bc));
}
}
public void Optimize()
{
}
}
}
Loading…
Cancel
Save