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

69
src/AstMetodBodyBuilder.cs

@ -19,6 +19,7 @@ namespace Decompiler @@ -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 @@ -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<Ast.Expression> args = new List<Ast.Expression>();
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 @@ -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 @@ -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<Ast.Expression> allArgs = new List<Ast.Expression>();
// 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)

48
src/ByteCode.StackBehaviour.cs

@ -11,43 +11,19 @@ namespace Decompiler @@ -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 @@ -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 @@ -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 @@ -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 @@ -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);
}
}
}

43
src/ByteCode.cs

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

5
src/CilStack.cs

@ -75,6 +75,11 @@ namespace Decompiler @@ -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];

86
src/StackExpression.cs

@ -0,0 +1,86 @@ @@ -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 @@ @@ -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