mirror of https://github.com/icsharpcode/ILSpy.git
31 changed files with 765 additions and 1203 deletions
@ -1,83 +0,0 @@
@@ -1,83 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public partial class ByteCode |
||||
{ |
||||
CilStack stackBefore; |
||||
CilStack stackAfter; |
||||
List<ByteCode> branchesHere = new List<ByteCode>(); |
||||
|
||||
public CilStack StackBefore { |
||||
get { return stackBefore; } |
||||
} |
||||
|
||||
public CilStack StackAfter { |
||||
get { return stackAfter; } |
||||
} |
||||
|
||||
public List<ByteCode> BranchesHere { |
||||
get { return branchesHere; } |
||||
} |
||||
|
||||
public void MergeStackBeforeWith(CilStack stack) |
||||
{ |
||||
CilStack mergedStack; |
||||
if (CilStack.Merge(this.stackBefore, stack, out mergedStack)) { |
||||
// Stacks are identical
|
||||
return; |
||||
} |
||||
this.stackBefore = mergedStack; |
||||
|
||||
stackAfter = SimulateEffectOnStack(this.StackBefore); |
||||
|
||||
if (this.OpCode.Code == Code.Endfinally) { |
||||
return; // TODO
|
||||
} |
||||
|
||||
if (this.OpCode.Code == Code.Switch) { |
||||
this.Next.MergeStackBeforeWith(this.StackAfter); |
||||
foreach(ByteCode target in (ByteCode[])this.Operand) { |
||||
target.MergeStackBeforeWith(this.StackAfter); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
switch(this.OpCode.FlowControl) { |
||||
case FlowControl.Branch: |
||||
this.BranchTarget.MergeStackBeforeWith(this.StackAfter); |
||||
break; |
||||
case FlowControl.Cond_Branch: |
||||
this.Next.MergeStackBeforeWith(this.StackAfter); |
||||
this.BranchTarget.MergeStackBeforeWith(this.StackAfter); |
||||
break; |
||||
case FlowControl.Next: |
||||
case FlowControl.Call: |
||||
this.Next.MergeStackBeforeWith(this.StackAfter); |
||||
break; |
||||
case FlowControl.Return: |
||||
if (this.StackAfter.Count > 0) throw new Exception("Non-empty stack at return instruction"); |
||||
break; |
||||
default: throw new NotImplementedException(); |
||||
} |
||||
} |
||||
|
||||
public CilStack SimulateEffectOnStack(CilStack oldStack) |
||||
{ |
||||
CilStack newStack = oldStack.Clone(); |
||||
List<Cecil.TypeReference> typeArgs = new List<Cecil.TypeReference>(); |
||||
foreach(CilStackSlot slot in newStack.PopCount(this.PopCount)) { |
||||
typeArgs.Add(slot.Type); |
||||
} |
||||
for (int i = 0; i < this.PushCount; i++) { |
||||
newStack.Push(new CilStackSlot(this, this.GetType(typeArgs.ToArray()))); |
||||
} |
||||
return newStack; |
||||
} |
||||
} |
||||
} |
@ -1,100 +0,0 @@
@@ -1,100 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public partial class ByteCode |
||||
{ |
||||
public int PopCount { |
||||
get { |
||||
return GetPopCount(); |
||||
} |
||||
} |
||||
|
||||
public int PushCount { |
||||
get { |
||||
return GetPushCount(); |
||||
} |
||||
} |
||||
|
||||
int GetPopCount() |
||||
{ |
||||
switch(this.OpCode.StackBehaviourPop) { |
||||
case StackBehaviour.Pop0: return 0; |
||||
case StackBehaviour.Pop1: return 1; |
||||
case StackBehaviour.Popi: return 1; |
||||
case StackBehaviour.Popref: return 1; |
||||
case StackBehaviour.Pop1_pop1: return 2; |
||||
case StackBehaviour.Popi_pop1: return 2; |
||||
case StackBehaviour.Popi_popi: return 2; |
||||
case StackBehaviour.Popi_popi8: return 2; |
||||
case StackBehaviour.Popi_popr4: return 2; |
||||
case StackBehaviour.Popi_popr8: return 2; |
||||
case StackBehaviour.Popref_pop1: return 2; |
||||
case StackBehaviour.Popref_popi: return 2; |
||||
case StackBehaviour.Popi_popi_popi: return 3; |
||||
case StackBehaviour.Popref_popi_popi: return 3; |
||||
case StackBehaviour.Popref_popi_popi8: return 3; |
||||
case StackBehaviour.Popref_popi_popr4: return 3; |
||||
case StackBehaviour.Popref_popi_popr8: return 3; |
||||
case StackBehaviour.Popref_popi_popref: return 3; |
||||
case StackBehaviour.PopAll: return this.StackBefore.Count; |
||||
case StackBehaviour.Varpop: |
||||
switch(this.OpCode.Code) { |
||||
case Code.Call: |
||||
case Code.Callvirt: |
||||
Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand); |
||||
if (cecilMethod.HasThis) { |
||||
return cecilMethod.Parameters.Count + 1 /* this */; |
||||
} else { |
||||
return cecilMethod.Parameters.Count; |
||||
} |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
case Code.Ret: |
||||
if (methodDef.ReturnType.FullName == Constants.Void) { |
||||
return 0; |
||||
} else { |
||||
return 1; |
||||
} |
||||
case Code.Newobj: |
||||
Cecil.MethodReference ctorMethod = ((MethodReference)this.Operand); |
||||
return ctorMethod.Parameters.Count; |
||||
default: throw new Exception("Unknown Varpop opcode"); |
||||
} |
||||
default: throw new Exception("Unknown pop behaviour: " + this.OpCode.StackBehaviourPop); |
||||
} |
||||
} |
||||
|
||||
int GetPushCount() |
||||
{ |
||||
switch(this.OpCode.StackBehaviourPush) { |
||||
case StackBehaviour.Push0: return 0; |
||||
case StackBehaviour.Push1: return 1; |
||||
case StackBehaviour.Push1_push1: return 2; |
||||
case StackBehaviour.Pushi: return 1; |
||||
case StackBehaviour.Pushi8: return 1; |
||||
case StackBehaviour.Pushr4: return 1; |
||||
case StackBehaviour.Pushr8: return 1; |
||||
case StackBehaviour.Pushref: return 1; |
||||
case StackBehaviour.Varpush: // Happens only for calls
|
||||
switch(this.OpCode.Code) { |
||||
case Code.Call: |
||||
case Code.Callvirt: |
||||
Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand); |
||||
if (cecilMethod.ReturnType.FullName == Constants.Void) { |
||||
return 0; |
||||
} else { |
||||
return 1; |
||||
} |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
default: throw new Exception("Unknown Varpush opcode"); |
||||
} |
||||
default: throw new Exception("Unknown push behaviour: " + this.OpCode.StackBehaviourPush); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,116 +0,0 @@
@@ -1,116 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public partial class ByteCode |
||||
{ |
||||
ByteCode previous; |
||||
ByteCode next; |
||||
|
||||
MethodDefinition methodDef; |
||||
int offset; |
||||
OpCode opCode; |
||||
object operand; |
||||
|
||||
public ByteCode Previous { |
||||
get { return previous; } |
||||
set { previous = value; } |
||||
} |
||||
|
||||
public ByteCode Next { |
||||
get { return next; } |
||||
set { next = value; } |
||||
} |
||||
|
||||
public int Offset { |
||||
get { return offset; } |
||||
set { offset = value; } |
||||
} |
||||
|
||||
public OpCode OpCode { |
||||
get { return opCode; } |
||||
set { opCode = value; } |
||||
} |
||||
|
||||
public object Operand { |
||||
get { return operand; } |
||||
set { operand = value; } |
||||
} |
||||
|
||||
public ByteCode BranchTarget { |
||||
get { |
||||
return operand as ByteCode; |
||||
} |
||||
} |
||||
|
||||
public bool CanBranch { |
||||
get { |
||||
return OpCode.FlowControl == FlowControl.Branch || |
||||
OpCode.FlowControl == FlowControl.Cond_Branch; |
||||
} |
||||
} |
||||
|
||||
public ByteCode(MethodDefinition methodDef, Instruction inst) |
||||
{ |
||||
this.methodDef = methodDef; |
||||
this.offset = inst.Offset; |
||||
this.opCode = inst.OpCode; |
||||
this.operand = inst.Operand; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return this.OpCode + " " + FormatByteCodeOperand(this.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 |
||||
); |
||||
} |
||||
} |
||||
|
||||
public string FormatedOperand { |
||||
get { |
||||
return FormatByteCodeOperand(this.Operand); |
||||
} |
||||
} |
||||
|
||||
public static string 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 FieldReference) { |
||||
return ((FieldReference)operand).Name; |
||||
} else if (operand is string) { |
||||
return "\"" + operand + "\""; |
||||
} else if (operand is int) { |
||||
return operand.ToString(); |
||||
} else { |
||||
return operand.ToString(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,100 +0,0 @@
@@ -1,100 +0,0 @@
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public class ByteCodeCollection: IEnumerable<ByteCode> |
||||
{ |
||||
List<ByteCode> list = new List<ByteCode>(); |
||||
|
||||
public IEnumerator<ByteCode> GetEnumerator() |
||||
{ |
||||
return list.GetEnumerator(); |
||||
} |
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() |
||||
{ |
||||
return list.GetEnumerator(); |
||||
} |
||||
|
||||
public int Count { |
||||
get { |
||||
return list.Count; |
||||
} |
||||
} |
||||
|
||||
public ByteCode this[int index] { |
||||
get { |
||||
return list[index]; |
||||
} |
||||
} |
||||
|
||||
public ByteCode GetByOffset(int offset) |
||||
{ |
||||
foreach(ByteCode byteCode in this) { |
||||
if (byteCode.Offset == offset) { |
||||
return byteCode; |
||||
} |
||||
} |
||||
throw new Exception("Not found"); |
||||
} |
||||
|
||||
public int IndexOf(ByteCode byteCode) |
||||
{ |
||||
return list.IndexOf(byteCode); |
||||
} |
||||
|
||||
public ByteCodeCollection(MethodDefinition methodDef) |
||||
{ |
||||
foreach(Instruction inst in methodDef.Body.Instructions) { |
||||
list.Add(new ByteCode(methodDef, inst)); |
||||
} |
||||
foreach(ByteCode byteCode in this) { |
||||
if (byteCode.CanBranch) { |
||||
if (byteCode.Operand is Instruction[]) { |
||||
List<ByteCode> operands = new List<ByteCode>(); |
||||
foreach(Instruction inst in (Instruction[])byteCode.Operand) { |
||||
ByteCode target = GetByOffset(inst.Offset); |
||||
operands.Add(target); |
||||
target.BranchesHere.Add(byteCode); |
||||
} |
||||
byteCode.Operand = operands.ToArray(); |
||||
} else { |
||||
ByteCode target = GetByOffset(((Instruction)byteCode.Operand).Offset); |
||||
byteCode.Operand = target; |
||||
target.BranchesHere.Add(byteCode); |
||||
} |
||||
} |
||||
} |
||||
UpdateNextPrevious(); |
||||
UpdateStackAnalysis(methodDef); |
||||
} |
||||
|
||||
void UpdateNextPrevious() |
||||
{ |
||||
for(int i = 0; i < list.Count - 1; i++) { |
||||
this[i].Next = this[i + 1]; |
||||
this[i + 1].Previous = this[i]; |
||||
} |
||||
} |
||||
|
||||
void UpdateStackAnalysis(MethodDefinition methodDef) |
||||
{ |
||||
if (this.Count > 0) { |
||||
this[0].MergeStackBeforeWith(CilStack.Empty); |
||||
} |
||||
foreach(ExceptionHandler handler in methodDef.Body.ExceptionHandlers) { |
||||
ByteCode byteCode = this.GetByOffset(handler.HandlerStart.Offset); |
||||
CilStack expetionStack = new CilStack(); |
||||
// TODO: Allocated by what?
|
||||
expetionStack.Add(new CilStackSlot(byteCode, ByteCode.TypeException)); |
||||
byteCode.MergeStackBeforeWith(expetionStack); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,137 +0,0 @@
@@ -1,137 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public class ByteCodeExpression |
||||
{ |
||||
ControlFlow.BasicBlock basicBlock; |
||||
|
||||
OpCode opCode; |
||||
object operand; |
||||
List<ByteCodeExpression> arguments = new List<ByteCodeExpression>(); |
||||
bool returnsValue; |
||||
Cecil.TypeReference type; |
||||
|
||||
ByteCodeExpression branchTarget; |
||||
List<ByteCodeExpression> branchesHere = new List<ByteCodeExpression>(); |
||||
|
||||
bool isSSASR = false; |
||||
|
||||
public Decompiler.ControlFlow.BasicBlock BasicBlock { |
||||
get { return basicBlock; } |
||||
set { |
||||
basicBlock = value; |
||||
foreach (ByteCodeExpression argument in arguments) { |
||||
argument.BasicBlock = value; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public OpCode OpCode { |
||||
get { return opCode; } |
||||
set { opCode = value; } |
||||
} |
||||
|
||||
public object Operand { |
||||
get { return operand; } |
||||
set { operand = value; } |
||||
} |
||||
|
||||
public List<ByteCodeExpression> Arguments { |
||||
get { return arguments; } |
||||
} |
||||
|
||||
public bool ReturnsValue { |
||||
get { return returnsValue; } |
||||
set { returnsValue = value; } |
||||
} |
||||
|
||||
public TypeReference Type { |
||||
get { return type; } |
||||
set { type = value; } |
||||
} |
||||
|
||||
/// <summary> Single static assignment; single read </summary>
|
||||
public bool IsSSASR { |
||||
get { return isSSASR; } |
||||
set { isSSASR = value; } |
||||
} |
||||
|
||||
public ByteCodeExpression BranchTarget { |
||||
get { return branchTarget; } |
||||
set { branchTarget = value; } |
||||
} |
||||
|
||||
public List<ByteCodeExpression> BranchesHere { |
||||
get { return branchesHere; } |
||||
} |
||||
|
||||
public bool IsBranchTarget { |
||||
get { return BranchesHere.Count > 0; } |
||||
} |
||||
|
||||
public static ByteCodeExpression Ldloc(string name) |
||||
{ |
||||
return new ByteCodeExpression(OpCodes.Ldloc, new VariableDefinition(name, null), true); |
||||
} |
||||
|
||||
public static ByteCodeExpression Stloc(string name) |
||||
{ |
||||
return new ByteCodeExpression(OpCodes.Stloc, new VariableDefinition(name, null), false); |
||||
} |
||||
|
||||
public ByteCodeExpression(OpCode opCode, object operand, bool returnsValue) |
||||
{ |
||||
this.opCode = opCode; |
||||
this.operand = operand; |
||||
this.returnsValue = returnsValue; |
||||
} |
||||
|
||||
public ByteCodeExpression(ByteCode byteCode) |
||||
{ |
||||
this.OpCode = byteCode.OpCode; |
||||
this.Operand = byteCode.Operand; |
||||
foreach(CilStackSlot arg in byteCode.StackBefore.PeekCount(byteCode.PopCount)) { |
||||
string name = string.Format("expr{0:X2}", arg.AllocadedBy.Offset); |
||||
this.Arguments.Add(Ldloc(name)); |
||||
} |
||||
this.ReturnsValue = byteCode.PushCount > 0; |
||||
this.Type = byteCode.Type; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[ByteCodeExpression OpCode={0}]", this.opCode); |
||||
} |
||||
|
||||
public ByteCodeExpression Clone() |
||||
{ |
||||
ByteCodeExpression clone = (ByteCodeExpression)this.MemberwiseClone(); |
||||
clone.branchTarget = null; |
||||
clone.branchesHere = new List<ByteCodeExpression>(); |
||||
return clone; |
||||
} |
||||
|
||||
public bool IsConstant() |
||||
{ |
||||
if (!IsOpCodeConstant()) return false; |
||||
foreach(ByteCodeExpression arg in this.Arguments) { |
||||
if (!arg.IsConstant()) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool IsOpCodeConstant() |
||||
{ |
||||
switch(this.OpCode.Code) { |
||||
case Code.Ldarg: return true; |
||||
default: return false; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,108 +0,0 @@
@@ -1,108 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public class ByteCodeExpressionCollection: List<ByteCodeExpression> |
||||
{ |
||||
public ByteCodeExpressionCollection(ByteCodeCollection byteCodeCol) |
||||
{ |
||||
Dictionary<ByteCode, ByteCodeExpression> exprForByteCode = new Dictionary<ByteCode, ByteCodeExpression>(); |
||||
|
||||
foreach(ByteCode byteCode in byteCodeCol) { |
||||
ByteCodeExpression newExpr = new ByteCodeExpression(byteCode); |
||||
|
||||
// If the bytecode pushes anything encapsulate it with stloc
|
||||
if (byteCode.PushCount > 0) { |
||||
string name = string.Format("expr{0:X2}", byteCode.Offset); |
||||
ByteCodeExpression stExpr = ByteCodeExpression.Stloc(name); |
||||
stExpr.Arguments.Add(newExpr); |
||||
stExpr.IsSSASR = byteCode.PushCount == 1; |
||||
newExpr = stExpr; |
||||
} |
||||
|
||||
exprForByteCode[byteCode] = newExpr; |
||||
this.Add(newExpr); |
||||
} |
||||
|
||||
// Branching links
|
||||
foreach(ByteCodeExpression expr in this) { |
||||
if (expr.Operand is ByteCode) { |
||||
expr.BranchTarget = exprForByteCode[(ByteCode)expr.Operand]; |
||||
expr.BranchTarget.BranchesHere.Add(expr); |
||||
} |
||||
} |
||||
} |
||||
|
||||
Dictionary<ByteCodeExpression, object> alreadyDuplicated = new Dictionary<ByteCodeExpression, object>(); |
||||
|
||||
public void Optimize() |
||||
{ |
||||
for(int i = 0; i < this.Count - 1; i++) { |
||||
if (i < 0) continue; |
||||
|
||||
ByteCodeExpression expr = this[i]; |
||||
ByteCodeExpression nextExpr = this[i + 1]; |
||||
|
||||
// Duplicate 'dup' expressions
|
||||
|
||||
if (expr.OpCode.Code == Code.Stloc && |
||||
expr.Arguments[0].OpCode.Code == Code.Dup && |
||||
expr.Arguments[0].Arguments[0].IsConstant() && |
||||
!alreadyDuplicated.ContainsKey(expr)) |
||||
{ |
||||
Options.NotifyCollapsingExpression(); |
||||
this.Insert(i + 1, expr.Clone()); |
||||
this[i].IsSSASR = true; |
||||
this[i + 1].IsSSASR = true; |
||||
alreadyDuplicated.Add(this[i], null); |
||||
alreadyDuplicated.Add(this[i + 1], null); |
||||
continue; |
||||
} |
||||
|
||||
// Try to in-line stloc into following expression
|
||||
|
||||
if (expr.OpCode.Code == Code.Stloc && |
||||
expr.IsSSASR && |
||||
!nextExpr.IsBranchTarget) { |
||||
|
||||
// If the next expression is stloc, look inside
|
||||
if (nextExpr.OpCode.Code == Code.Stloc && |
||||
nextExpr.Arguments[0].OpCode.Code != Code.Ldloc) { |
||||
nextExpr = nextExpr.Arguments[0]; |
||||
} |
||||
|
||||
// Find the use of the 'expr'
|
||||
for(int j = 0; j < nextExpr.Arguments.Count; j++) { |
||||
ByteCodeExpression arg = nextExpr.Arguments[j]; |
||||
|
||||
if (arg.OpCode.Code == Code.Ldloc && |
||||
((VariableDefinition)arg.Operand).Name == ((VariableDefinition)expr.Operand).Name) { |
||||
// Found
|
||||
Options.NotifyCollapsingExpression(); |
||||
this.RemoveAt(i); i--; // Remove the stloc
|
||||
nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body
|
||||
// Move branch links
|
||||
foreach(ByteCodeExpression predExpr in expr.BranchesHere) { |
||||
predExpr.BranchTarget = this[i + 1]; |
||||
predExpr.BranchTarget.BranchesHere.Add(predExpr); |
||||
} |
||||
|
||||
i--; // Try the same index again
|
||||
break; |
||||
} |
||||
if (arg.OpCode.Code != Code.Ldloc) { |
||||
// This argument might have side effects so we can not
|
||||
// move the 'expr' after it. Terminate
|
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,144 +0,0 @@
@@ -1,144 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Ast = ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
// Imutable
|
||||
public struct CilStackSlot { |
||||
ByteCode allocadedBy; |
||||
Cecil.TypeReference type; |
||||
|
||||
public ByteCode AllocadedBy { |
||||
get { return allocadedBy; } |
||||
} |
||||
|
||||
public Cecil.TypeReference Type { |
||||
get { return type; } |
||||
} |
||||
|
||||
public CilStackSlot(ByteCode allocadedBy, Cecil.TypeReference type) |
||||
{ |
||||
if (allocadedBy == null) throw new ArgumentNullException(); |
||||
if (type == null) throw new ArgumentNullException(); |
||||
|
||||
this.allocadedBy = allocadedBy; |
||||
this.type = type; |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
int hashCode = 0; |
||||
if (allocadedBy != null) hashCode ^= allocadedBy.GetHashCode(); |
||||
if (type != null) hashCode ^= type.GetHashCode(); |
||||
return hashCode; |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
if (!(obj is CilStackSlot)) return false; |
||||
CilStackSlot myCilStackSlot = (CilStackSlot)obj; |
||||
return object.Equals(this.allocadedBy, myCilStackSlot.allocadedBy) && object.Equals(this.type, myCilStackSlot.type); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
if (allocadedBy == null) { |
||||
return "<??>"; |
||||
} else { |
||||
return string.Format("expr{0:X2}", this.allocadedBy.Offset); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <remarks> The tail of the list is the top of the stack </remarks>
|
||||
public class CilStack: List<CilStackSlot> { |
||||
public static CilStack Empty = new CilStack(); |
||||
|
||||
public CilStack Clone() |
||||
{ |
||||
return new CilStack(this); |
||||
} |
||||
|
||||
public CilStackSlot[] PopCount(int count) |
||||
{ |
||||
CilStackSlot[] poped = this.GetRange(this.Count - count, count).ToArray(); |
||||
this.RemoveRange(this.Count - count, count); |
||||
return poped; |
||||
} |
||||
|
||||
public void Push(CilStackSlot slot) |
||||
{ |
||||
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]; |
||||
} |
||||
|
||||
public CilStack(): base() |
||||
{ |
||||
|
||||
} |
||||
|
||||
public CilStack(IEnumerable<CilStackSlot> slotEnum): base(slotEnum) |
||||
{ |
||||
|
||||
} |
||||
|
||||
// Return true if stacks are same
|
||||
public static bool Merge(CilStack stack1, CilStack stack2, out CilStack merged) |
||||
{ |
||||
// Both null
|
||||
if (stack1 == null && stack2 == null) { |
||||
throw new Exception("Both stacks are null"); |
||||
} |
||||
// One of stacks null, one is not
|
||||
if (stack1 == null || stack2 == null) { |
||||
merged = stack1 ?? stack2; |
||||
return false; |
||||
} |
||||
// Both are non-null
|
||||
if (stack1.Count != stack2.Count) { |
||||
throw new Exception("Stack merge error: different sizes"); |
||||
} |
||||
|
||||
bool same = true; |
||||
int count = stack1.Count; |
||||
merged = stack1.Clone(); |
||||
for (int i = 0; i < count; i++) { |
||||
if (!stack1[i].Equals(stack2[i])) { |
||||
// TODO: Do the merge
|
||||
// merged[i] = new CilStackSlot(null, null); // Merge slots
|
||||
same = false; |
||||
} |
||||
} |
||||
return same; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
string ret = "Stack: {"; |
||||
bool first = true; |
||||
foreach(CilStackSlot slot in this) { |
||||
if (!first) ret += ", "; |
||||
ret += slot.ToString(); |
||||
first = false; |
||||
} |
||||
ret += "}"; |
||||
return ret; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,246 @@
@@ -0,0 +1,246 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Text; |
||||
|
||||
using Decompiler.Mono.Cecil.Rocks; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
using Cecil = Mono.Cecil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public class ILAstBuilder |
||||
{ |
||||
class ByteCode |
||||
{ |
||||
public Instruction Instruction; |
||||
public ILStack StackBefore; |
||||
|
||||
public string TmpVarName { get { return "expr" + this.Instruction.Offset; } } |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[{0}, [{1}]]", Instruction, StackBefore); |
||||
} |
||||
} |
||||
|
||||
class ILStack |
||||
{ |
||||
public class Slot |
||||
{ |
||||
public ByteCode PushedBy; |
||||
public TypeReference Type; |
||||
|
||||
public Slot(ByteCode byteCode, TypeReference type) |
||||
{ |
||||
this.PushedBy = byteCode; |
||||
this.Type = type; |
||||
} |
||||
} |
||||
|
||||
public List<Slot> Items = new List<Slot>(); |
||||
|
||||
public ILStack Clone() |
||||
{ |
||||
ILStack clone = new ILStack(); |
||||
foreach(Slot s in this.Items) { |
||||
clone.Items.Add(new Slot(s.PushedBy, s.Type)); |
||||
} |
||||
return clone; |
||||
} |
||||
|
||||
public void MergeInto(ref ILStack other, out bool changed) |
||||
{ |
||||
if (other == null) { |
||||
other = this; |
||||
changed = true; |
||||
} else { |
||||
changed = false; |
||||
} |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
StringBuilder sb = new StringBuilder(); |
||||
bool first = true; |
||||
foreach (Slot s in this.Items) { |
||||
if (!first) sb.Append(", "); |
||||
sb.Append(s.PushedBy.Instruction.Offset.ToString("X")); |
||||
first = false; |
||||
} |
||||
return sb.ToString(); |
||||
} |
||||
} |
||||
|
||||
public static List<ILExpression> Build(MethodDefinition methodDef) |
||||
{ |
||||
List<ByteCode> body = new List<ByteCode>(); |
||||
|
||||
Dictionary<Instruction, ByteCode> instToByteCode = new Dictionary<Instruction, ByteCode>(); |
||||
|
||||
// Create the IL body for analisys
|
||||
foreach(Instruction inst in methodDef.Body.Instructions) { |
||||
ByteCode byteCode = new ByteCode(); |
||||
byteCode.Instruction = inst; |
||||
body.Add(byteCode); |
||||
instToByteCode.Add(inst, byteCode); |
||||
} |
||||
|
||||
// Stack analisys
|
||||
if (body.Count > 0) { |
||||
Queue<ByteCode> agenda = new Queue<ByteCode>(); |
||||
|
||||
// Add known states
|
||||
body[0].StackBefore = new ILStack(); |
||||
agenda.Enqueue(body[0]); |
||||
|
||||
if(methodDef.Body.HasExceptionHandlers) { |
||||
foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { |
||||
ByteCode tryStart = instToByteCode[ex.TryStart]; |
||||
tryStart.StackBefore = new ILStack(); |
||||
agenda.Enqueue(tryStart); |
||||
|
||||
ByteCode handlerStart = instToByteCode[ex.HandlerStart]; |
||||
handlerStart.StackBefore = new ILStack(); |
||||
handlerStart.StackBefore.Items.Add(new ILStack.Slot(null, MyRocks.TypeException)); |
||||
agenda.Enqueue(handlerStart); |
||||
} |
||||
} |
||||
|
||||
// Process agenda
|
||||
while(agenda.Count > 0) { |
||||
ByteCode byteCode = agenda.Dequeue(); |
||||
|
||||
// What is the effect of the instruction on the stack?
|
||||
ILStack newStack = byteCode.StackBefore.Clone(); |
||||
int popCount = byteCode.Instruction.GetPopCount(methodDef, byteCode.StackBefore.Items.Count); |
||||
List<TypeReference> typeArgs = new List<TypeReference>(); |
||||
for (int i = newStack.Items.Count - popCount; i < newStack.Items.Count; i++) { |
||||
typeArgs.Add(newStack.Items[i].Type); |
||||
} |
||||
TypeReference type; |
||||
try { |
||||
type = byteCode.Instruction.GetTypeInternal(methodDef, typeArgs); |
||||
} catch { |
||||
type = MyRocks.TypeObject; |
||||
} |
||||
if (popCount > 0) { |
||||
newStack.Items.RemoveRange(newStack.Items.Count - popCount, popCount); |
||||
} |
||||
int pushCount = byteCode.Instruction.GetPushCount(); |
||||
for (int i = 0; i < pushCount; i++) { |
||||
newStack.Items.Add(new ILStack.Slot(byteCode, type)); |
||||
} |
||||
|
||||
// Apply the state to any successors
|
||||
if (byteCode.Instruction.OpCode.CanFallThough()) { |
||||
ByteCode next = instToByteCode[byteCode.Instruction.Next]; |
||||
bool changed; |
||||
newStack.MergeInto(ref next.StackBefore, out changed); |
||||
if (changed) agenda.Enqueue(next); |
||||
} |
||||
if (byteCode.Instruction.OpCode.IsBranch()) { |
||||
object operand = byteCode.Instruction.Operand; |
||||
if (operand is Instruction) { |
||||
ByteCode next = instToByteCode[(Instruction)operand]; |
||||
bool changed; |
||||
newStack.MergeInto(ref next.StackBefore, out changed); |
||||
if (changed) agenda.Enqueue(next); |
||||
} else { |
||||
foreach(Instruction inst in (Instruction[])operand) { |
||||
ByteCode next = instToByteCode[inst]; |
||||
bool changed; |
||||
newStack.MergeInto(ref next.StackBefore, out changed); |
||||
if (changed) agenda.Enqueue(next); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
List<ILExpression> ast = new List<ILExpression>(); |
||||
Dictionary<ByteCode, ILExpression> byteCodeToExpr = new Dictionary<ByteCode, ILExpression>(); |
||||
|
||||
// Convert stack-based IL code to ILAst tree
|
||||
foreach(ByteCode byteCode in body) { |
||||
ILExpression expr = new ILExpression(byteCode.Instruction.OpCode, byteCode.Instruction.Operand); |
||||
|
||||
byteCodeToExpr[byteCode] = expr; |
||||
|
||||
// Reference arguments using temporary variables
|
||||
ILStack stack = byteCode.StackBefore; |
||||
for (int i = stack.Items.Count - byteCode.Instruction.GetPopCount(methodDef, byteCode.StackBefore.Items.Count); i < stack.Items.Count; i++) { |
||||
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new VariableDefinition(stack.Items[i].PushedBy.TmpVarName, null)); |
||||
ldExpr.IsTempLdloc = true; |
||||
expr.Arguments.Add(ldExpr); |
||||
} |
||||
|
||||
// If the bytecode pushes anything store the result in temporary variable
|
||||
int pushCount = byteCode.Instruction.GetPushCount(); |
||||
if (pushCount > 0) { |
||||
ILExpression stExpr = new ILExpression(OpCodes.Stloc, new VariableDefinition(byteCode.TmpVarName, null)); |
||||
stExpr.Arguments.Add(expr); |
||||
stExpr.IsTempStloc = true; |
||||
stExpr.RefCount = pushCount; |
||||
expr.Partent = stExpr; |
||||
expr = stExpr; |
||||
} |
||||
|
||||
ast.Add(expr); |
||||
} |
||||
|
||||
// Convert branch operands
|
||||
foreach(ILExpression expr in ast) { |
||||
if (expr.Operand is Instruction) { |
||||
ILExpression brTarget = byteCodeToExpr[instToByteCode[(Instruction)expr.Operand]]; |
||||
expr.Operand = brTarget; |
||||
brTarget.IsBranchTarget = true; |
||||
if (brTarget.Partent != null) { |
||||
brTarget.Partent.IsBranchTarget = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Try to in-line stloc / ldloc pairs
|
||||
for(int i = 0; i < ast.Count - 1; i++) { |
||||
ILExpression expr = ast[i]; |
||||
ILExpression nextExpr = ast[i + 1]; |
||||
|
||||
if (expr.IsTempStloc && !nextExpr.IsBranchTarget) { |
||||
|
||||
// If the next expression is stloc, look inside
|
||||
if (nextExpr.IsTempStloc) { |
||||
nextExpr = nextExpr.Arguments[0]; |
||||
} |
||||
|
||||
// Find the use of the 'expr'
|
||||
for(int j = 0; j < nextExpr.Arguments.Count; j++) { |
||||
ILExpression arg = nextExpr.Arguments[j]; |
||||
|
||||
if (!arg.IsTempLdloc) { |
||||
break; // This argument might have side effects so we can not move the 'expr' after it.
|
||||
} else { |
||||
if (((VariableDefinition)arg.Operand).Name == ((VariableDefinition)expr.Operand).Name) { |
||||
expr.RefCount--; |
||||
if (expr.RefCount <= 0) { |
||||
ast.RemoveAt(i); |
||||
} |
||||
nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body
|
||||
if (expr.IsBranchTarget) { |
||||
nextExpr.IsBranchTarget = true; |
||||
if (nextExpr.Partent != null) { |
||||
nextExpr.Partent.IsBranchTarget = true; |
||||
} |
||||
} |
||||
i = Math.Max(0, i - 2); // Try the same index again
|
||||
break; // Found
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return ast; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Text; |
||||
|
||||
using Decompiler.ControlFlow; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
using Cecil = Mono.Cecil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public class ILExpression |
||||
{ |
||||
public OpCode OpCode { get; set; } |
||||
public object Operand { get; set; } |
||||
public List<ILExpression> Arguments { get; set; } |
||||
public bool IsTempStloc { get; set; } |
||||
public bool IsTempLdloc { get; set; } |
||||
public int RefCount { get; set; } |
||||
public bool IsBranchTarget { get; set; } |
||||
public BasicBlock BasicBlock { get; set; } |
||||
|
||||
// HACK: Do preoperly
|
||||
public ILExpression Partent { get; set; } |
||||
|
||||
public ILExpression(OpCode opCode, object operand, params ILExpression[] args) |
||||
{ |
||||
this.OpCode = opCode; |
||||
this.Operand = operand; |
||||
this.Arguments = new List<ILExpression>(args); |
||||
} |
||||
|
||||
public void SetBasicBlock(BasicBlock bb) |
||||
{ |
||||
this.BasicBlock = bb; |
||||
foreach(ILExpression arg in Arguments) { |
||||
arg.SetBasicBlock(bb); |
||||
} |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
StringBuilder sb = new StringBuilder(); |
||||
sb.Append(OpCode.Name); |
||||
sb.Append('('); |
||||
bool first = true; |
||||
if (Operand != null) { |
||||
sb.Append(Operand.ToString()); |
||||
first = false; |
||||
} |
||||
foreach (ILExpression arg in this.Arguments) { |
||||
if (!first) sb.Append(","); |
||||
sb.Append(arg.ToString()); |
||||
first = false; |
||||
} |
||||
sb.Append(')'); |
||||
return sb.ToString(); |
||||
} |
||||
} |
||||
} |
@ -1,275 +1,353 @@
@@ -1,275 +1,353 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Ast = ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public partial class ByteCode |
||||
{ |
||||
static public Cecil.TypeReference TypeVoid = GetCecilType(typeof(void)); |
||||
static public Cecil.TypeReference TypeObject = GetCecilType(typeof(Object)); |
||||
static public Cecil.TypeReference TypeException = GetCecilType(typeof(Exception)); |
||||
static public Cecil.TypeReference TypeBool = GetCecilType(typeof(bool)); |
||||
static public Cecil.TypeReference TypeInt32 = GetCecilType(typeof(Int32)); |
||||
static public Cecil.TypeReference TypeString = GetCecilType(typeof(string)); |
||||
static public Cecil.TypeReference TypeZero = GetCecilType(typeof(Int32)); |
||||
static public Cecil.TypeReference TypeOne = GetCecilType(typeof(Int32)); |
||||
|
||||
static public Cecil.TypeReference GetCecilType(Type type) |
||||
{ |
||||
return new Cecil.TypeReference(type.Name, type.Namespace, null, type.IsValueType); |
||||
} |
||||
|
||||
public Cecil.TypeReference Type { |
||||
get { |
||||
if (this.PushCount == 0) { |
||||
return TypeVoid; |
||||
} else { |
||||
return this.StackAfter.Peek(1).Type; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public Cecil.TypeReference GetType(params Cecil.TypeReference[] args) |
||||
{ |
||||
try { |
||||
return(GetTypeInternal(args)); |
||||
} catch (NotImplementedException) { |
||||
return TypeObject; |
||||
} |
||||
} |
||||
|
||||
public Cecil.TypeReference GetTypeInternal(params Cecil.TypeReference[] args) |
||||
{ |
||||
OpCode opCode = this.OpCode; |
||||
object operand = this.Operand; |
||||
Cecil.TypeReference operandAsTypeRef = operand as Cecil.TypeReference; |
||||
ByteCode operandAsByteCode = operand as ByteCode; |
||||
string operandAsByteCodeLabel = operand is ByteCode ? String.Format("IL_{0:X2}", ((ByteCode)operand).Offset) : null; |
||||
Cecil.TypeReference arg1 = args.Length >= 1 ? args[0] : null; |
||||
Cecil.TypeReference arg2 = args.Length >= 2 ? args[1] : null; |
||||
Cecil.TypeReference arg3 = args.Length >= 3 ? args[2] : null; |
||||
|
||||
switch(opCode.Code) { |
||||
#region Arithmetic
|
||||
case Code.Add: |
||||
case Code.Add_Ovf: |
||||
case Code.Add_Ovf_Un: |
||||
case Code.Div: |
||||
case Code.Div_Un: |
||||
case Code.Mul: |
||||
case Code.Mul_Ovf: |
||||
case Code.Mul_Ovf_Un: |
||||
case Code.Rem: |
||||
case Code.Rem_Un: |
||||
case Code.Sub: |
||||
case Code.Sub_Ovf: |
||||
case Code.Sub_Ovf_Un: |
||||
case Code.And: |
||||
case Code.Xor: |
||||
case Code.Shl: |
||||
case Code.Shr: |
||||
case Code.Shr_Un: return TypeInt32; |
||||
|
||||
case Code.Neg: return TypeInt32; |
||||
case Code.Not: return TypeInt32; |
||||
#endregion
|
||||
#region Arrays
|
||||
case Code.Newarr: |
||||
return new Cecil.ArrayType(operandAsTypeRef); |
||||
|
||||
case Code.Ldlen: return TypeInt32; |
||||
|
||||
case Code.Ldelem_I: |
||||
case Code.Ldelem_I1: |
||||
case Code.Ldelem_I2: |
||||
case Code.Ldelem_I4: |
||||
case Code.Ldelem_I8: return TypeInt32; |
||||
case Code.Ldelem_U1: |
||||
case Code.Ldelem_U2: |
||||
case Code.Ldelem_U4: |
||||
case Code.Ldelem_R4: |
||||
case Code.Ldelem_R8: throw new NotImplementedException(); |
||||
case Code.Ldelem_Ref: |
||||
if (arg1 is ArrayType) { |
||||
return ((ArrayType)arg1).ElementType; |
||||
} else { |
||||
throw new NotImplementedException(); |
||||
} |
||||
case Code.Ldelem_Any: |
||||
case Code.Ldelema: throw new NotImplementedException(); |
||||
|
||||
case Code.Stelem_I: |
||||
case Code.Stelem_I1: |
||||
case Code.Stelem_I2: |
||||
case Code.Stelem_I4: |
||||
case Code.Stelem_I8: |
||||
case Code.Stelem_R4: |
||||
case Code.Stelem_R8: |
||||
case Code.Stelem_Ref: |
||||
case Code.Stelem_Any: return TypeVoid; |
||||
#endregion
|
||||
#region Branching
|
||||
case Code.Br: |
||||
case Code.Brfalse: |
||||
case Code.Brtrue: |
||||
case Code.Beq: |
||||
case Code.Bge: |
||||
case Code.Bge_Un: |
||||
case Code.Bgt: |
||||
case Code.Bgt_Un: |
||||
case Code.Ble: |
||||
case Code.Ble_Un: |
||||
case Code.Blt: |
||||
case Code.Blt_Un: |
||||
case Code.Bne_Un: return TypeVoid; |
||||
#endregion
|
||||
#region Comparison
|
||||
case Code.Ceq: |
||||
case Code.Cgt: |
||||
case Code.Cgt_Un: |
||||
case Code.Clt: |
||||
case Code.Clt_Un: return TypeBool; |
||||
#endregion
|
||||
#region Conversions
|
||||
case Code.Conv_I: |
||||
case Code.Conv_I1: |
||||
case Code.Conv_I2: |
||||
case Code.Conv_I4: |
||||
case Code.Conv_I8: |
||||
case Code.Conv_U: |
||||
case Code.Conv_U1: |
||||
case Code.Conv_U2: |
||||
case Code.Conv_U4: |
||||
case Code.Conv_U8: |
||||
case Code.Conv_R4: |
||||
case Code.Conv_R8: |
||||
case Code.Conv_R_Un: |
||||
|
||||
case Code.Conv_Ovf_I: |
||||
case Code.Conv_Ovf_I1: |
||||
case Code.Conv_Ovf_I2: |
||||
case Code.Conv_Ovf_I4: |
||||
case Code.Conv_Ovf_I8: |
||||
case Code.Conv_Ovf_U: |
||||
case Code.Conv_Ovf_U1: |
||||
case Code.Conv_Ovf_U2: |
||||
case Code.Conv_Ovf_U4: |
||||
case Code.Conv_Ovf_U8: |
||||
|
||||
case Code.Conv_Ovf_I_Un: |
||||
case Code.Conv_Ovf_I1_Un: |
||||
case Code.Conv_Ovf_I2_Un: |
||||
case Code.Conv_Ovf_I4_Un: |
||||
case Code.Conv_Ovf_I8_Un: |
||||
case Code.Conv_Ovf_U_Un: |
||||
case Code.Conv_Ovf_U1_Un: |
||||
case Code.Conv_Ovf_U2_Un: |
||||
case Code.Conv_Ovf_U4_Un: |
||||
case Code.Conv_Ovf_U8_Un: return TypeInt32; |
||||
#endregion
|
||||
#region Indirect
|
||||
case Code.Ldind_I: throw new NotImplementedException(); |
||||
case Code.Ldind_I1: throw new NotImplementedException(); |
||||
case Code.Ldind_I2: throw new NotImplementedException(); |
||||
case Code.Ldind_I4: throw new NotImplementedException(); |
||||
case Code.Ldind_I8: throw new NotImplementedException(); |
||||
case Code.Ldind_U1: throw new NotImplementedException(); |
||||
case Code.Ldind_U2: throw new NotImplementedException(); |
||||
case Code.Ldind_U4: throw new NotImplementedException(); |
||||
case Code.Ldind_R4: throw new NotImplementedException(); |
||||
case Code.Ldind_R8: throw new NotImplementedException(); |
||||
case Code.Ldind_Ref: throw new NotImplementedException(); |
||||
|
||||
case Code.Stind_I: throw new NotImplementedException(); |
||||
case Code.Stind_I1: throw new NotImplementedException(); |
||||
case Code.Stind_I2: throw new NotImplementedException(); |
||||
case Code.Stind_I4: throw new NotImplementedException(); |
||||
case Code.Stind_I8: throw new NotImplementedException(); |
||||
case Code.Stind_R4: throw new NotImplementedException(); |
||||
case Code.Stind_R8: throw new NotImplementedException(); |
||||
case Code.Stind_Ref: throw new NotImplementedException(); |
||||
#endregion
|
||||
case Code.Arglist: throw new NotImplementedException(); |
||||
case Code.Box: throw new NotImplementedException(); |
||||
case Code.Break: throw new NotImplementedException(); |
||||
case Code.Call: return ((MethodReference)operand).ReturnType; |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
case Code.Callvirt: return ((MethodReference)operand).ReturnType; |
||||
case Code.Castclass: throw new NotImplementedException(); |
||||
case Code.Ckfinite: throw new NotImplementedException(); |
||||
case Code.Constrained: throw new NotImplementedException(); |
||||
case Code.Cpblk: throw new NotImplementedException(); |
||||
case Code.Cpobj: throw new NotImplementedException(); |
||||
case Code.Dup: throw new NotImplementedException(); |
||||
case Code.Endfilter: throw new NotImplementedException(); |
||||
case Code.Endfinally: throw new NotImplementedException(); |
||||
case Code.Initblk: throw new NotImplementedException(); |
||||
case Code.Initobj: throw new NotImplementedException(); |
||||
case Code.Isinst: throw new NotImplementedException(); |
||||
case Code.Jmp: throw new NotImplementedException(); |
||||
case Code.Ldarg: |
||||
Cecil.TypeReference typeRef = ((ParameterDefinition)operand).ParameterType; |
||||
// 'this' returns null; TODO: Return proper type of this
|
||||
return typeRef ?? TypeObject; |
||||
case Code.Ldarga: throw new NotImplementedException(); |
||||
case Code.Ldc_I4: |
||||
if ((int)operand == 0) { |
||||
return TypeZero; |
||||
} else if ((int)operand == 1) { |
||||
return TypeOne; |
||||
} else { |
||||
return TypeInt32; |
||||
} |
||||
case Code.Ldc_I8: throw new NotImplementedException(); |
||||
case Code.Ldc_R4: throw new NotImplementedException(); |
||||
case Code.Ldc_R8: throw new NotImplementedException(); |
||||
case Code.Ldfld: return ((FieldDefinition)operand).FieldType; |
||||
case Code.Ldflda: throw new NotImplementedException(); |
||||
case Code.Ldftn: throw new NotImplementedException(); |
||||
case Code.Ldloc: return ((VariableDefinition)operand).VariableType; |
||||
case Code.Ldloca: throw new NotImplementedException(); |
||||
case Code.Ldnull: throw new NotImplementedException(); |
||||
case Code.Ldobj: throw new NotImplementedException(); |
||||
case Code.Ldsfld: throw new NotImplementedException(); |
||||
case Code.Ldsflda: throw new NotImplementedException(); |
||||
case Code.Ldstr: return TypeString; |
||||
case Code.Ldtoken: throw new NotImplementedException(); |
||||
case Code.Ldvirtftn: throw new NotImplementedException(); |
||||
case Code.Leave: throw new NotImplementedException(); |
||||
case Code.Localloc: throw new NotImplementedException(); |
||||
case Code.Mkrefany: throw new NotImplementedException(); |
||||
case Code.Newobj: throw new NotImplementedException(); |
||||
case Code.No: throw new NotImplementedException(); |
||||
case Code.Nop: return TypeVoid; |
||||
case Code.Or: throw new NotImplementedException(); |
||||
case Code.Pop: throw new NotImplementedException(); |
||||
case Code.Readonly: throw new NotImplementedException(); |
||||
case Code.Refanytype: throw new NotImplementedException(); |
||||
case Code.Refanyval: throw new NotImplementedException(); |
||||
case Code.Ret: return TypeVoid; |
||||
case Code.Rethrow: throw new NotImplementedException(); |
||||
case Code.Sizeof: throw new NotImplementedException(); |
||||
case Code.Starg: throw new NotImplementedException(); |
||||
case Code.Stfld: throw new NotImplementedException(); |
||||
case Code.Stloc: return TypeVoid; |
||||
case Code.Stobj: throw new NotImplementedException(); |
||||
case Code.Stsfld: throw new NotImplementedException(); |
||||
case Code.Switch: throw new NotImplementedException(); |
||||
case Code.Tail: throw new NotImplementedException(); |
||||
case Code.Throw: throw new NotImplementedException(); |
||||
case Code.Unaligned: throw new NotImplementedException(); |
||||
case Code.Unbox: throw new NotImplementedException(); |
||||
case Code.Unbox_Any: throw new NotImplementedException(); |
||||
case Code.Volatile: throw new NotImplementedException(); |
||||
default: throw new Exception("Unknown OpCode: " + opCode); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
/* |
||||
* Created by SharpDevelop. |
||||
* User: User |
||||
* Date: 05/02/2011 |
||||
* Time: 10:10 |
||||
* |
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||
*/ |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler.Mono.Cecil.Rocks |
||||
{ |
||||
static class MyRocks |
||||
{ |
||||
static public TypeReference TypeVoid = GetCecilType(typeof(void)); |
||||
static public TypeReference TypeObject = GetCecilType(typeof(Object)); |
||||
static public TypeReference TypeException = GetCecilType(typeof(Exception)); |
||||
static public TypeReference TypeBool = GetCecilType(typeof(bool)); |
||||
static public TypeReference TypeInt32 = GetCecilType(typeof(Int32)); |
||||
static public TypeReference TypeString = GetCecilType(typeof(string)); |
||||
static public TypeReference TypeZero = GetCecilType(typeof(Int32)); |
||||
static public TypeReference TypeOne = GetCecilType(typeof(Int32)); |
||||
|
||||
public static bool CanFallThough(this OpCode opCode) |
||||
{ |
||||
switch(opCode.FlowControl) { |
||||
case FlowControl.Branch: return false; |
||||
case FlowControl.Cond_Branch: return true; |
||||
case FlowControl.Next: return true; |
||||
case FlowControl.Call: return true; |
||||
case FlowControl.Return: return false; |
||||
case FlowControl.Throw: return false; |
||||
default: throw new NotImplementedException(); |
||||
} |
||||
} |
||||
|
||||
public static bool IsBranch(this OpCode opCode) |
||||
{ |
||||
return opCode.FlowControl == FlowControl.Branch || opCode.FlowControl == FlowControl.Cond_Branch; |
||||
} |
||||
|
||||
public static int GetPopCount(this Instruction inst, MethodDefinition methodDef, int stackLength) |
||||
{ |
||||
switch(inst.OpCode.StackBehaviourPop) { |
||||
case StackBehaviour.Pop0: return 0; |
||||
case StackBehaviour.Pop1: return 1; |
||||
case StackBehaviour.Popi: return 1; |
||||
case StackBehaviour.Popref: return 1; |
||||
case StackBehaviour.Pop1_pop1: return 2; |
||||
case StackBehaviour.Popi_pop1: return 2; |
||||
case StackBehaviour.Popi_popi: return 2; |
||||
case StackBehaviour.Popi_popi8: return 2; |
||||
case StackBehaviour.Popi_popr4: return 2; |
||||
case StackBehaviour.Popi_popr8: return 2; |
||||
case StackBehaviour.Popref_pop1: return 2; |
||||
case StackBehaviour.Popref_popi: return 2; |
||||
case StackBehaviour.Popi_popi_popi: return 3; |
||||
case StackBehaviour.Popref_popi_popi: return 3; |
||||
case StackBehaviour.Popref_popi_popi8: return 3; |
||||
case StackBehaviour.Popref_popi_popr4: return 3; |
||||
case StackBehaviour.Popref_popi_popr8: return 3; |
||||
case StackBehaviour.Popref_popi_popref: return 3; |
||||
case StackBehaviour.PopAll: return stackLength; |
||||
case StackBehaviour.Varpop: |
||||
switch(inst.OpCode.Code) { |
||||
case Code.Call: |
||||
case Code.Callvirt: |
||||
MethodReference cecilMethod = ((MethodReference)inst.Operand); |
||||
if (cecilMethod.HasThis) { |
||||
return cecilMethod.Parameters.Count + 1 /* this */; |
||||
} else { |
||||
return cecilMethod.Parameters.Count; |
||||
} |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
case Code.Ret: |
||||
if (methodDef.ReturnType.FullName == Constants.Void) { |
||||
return 0; |
||||
} else { |
||||
return 1; |
||||
} |
||||
case Code.Newobj: |
||||
MethodReference ctorMethod = ((MethodReference)inst.Operand); |
||||
return ctorMethod.Parameters.Count; |
||||
default: throw new Exception("Unknown Varpop opcode"); |
||||
} |
||||
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop); |
||||
} |
||||
} |
||||
|
||||
public static int GetPushCount(this Instruction inst) |
||||
{ |
||||
switch(inst.OpCode.StackBehaviourPush) { |
||||
case StackBehaviour.Push0: return 0; |
||||
case StackBehaviour.Push1: return 1; |
||||
case StackBehaviour.Push1_push1: return 2; |
||||
case StackBehaviour.Pushi: return 1; |
||||
case StackBehaviour.Pushi8: return 1; |
||||
case StackBehaviour.Pushr4: return 1; |
||||
case StackBehaviour.Pushr8: return 1; |
||||
case StackBehaviour.Pushref: return 1; |
||||
case StackBehaviour.Varpush: // Happens only for calls
|
||||
switch(inst.OpCode.Code) { |
||||
case Code.Call: |
||||
case Code.Callvirt: |
||||
MethodReference cecilMethod = ((MethodReference)inst.Operand); |
||||
if (cecilMethod.ReturnType.FullName == Constants.Void) { |
||||
return 0; |
||||
} else { |
||||
return 1; |
||||
} |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
default: throw new Exception("Unknown Varpush opcode"); |
||||
} |
||||
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush); |
||||
} |
||||
} |
||||
|
||||
static public TypeReference GetCecilType(Type type) |
||||
{ |
||||
return new TypeReference(type.Name, type.Namespace, null, type.IsValueType); |
||||
} |
||||
|
||||
static public TypeReference GetTypeInternal(this Instruction inst, MethodDefinition methodDef, List<TypeReference> args) |
||||
{ |
||||
OpCode opCode = inst.OpCode; |
||||
object operand = inst.Operand; |
||||
TypeReference operandAsTypeRef = operand as TypeReference; |
||||
//ByteCode operandAsByteCode = operand as ByteCode;
|
||||
//string operandAsByteCodeLabel = operand is ByteCode ? String.Format("IL_{0:X2}", ((ByteCode)operand).Offset) : null;
|
||||
TypeReference arg1 = args.Count >= 1 ? args[0] : null; |
||||
TypeReference arg2 = args.Count >= 2 ? args[1] : null; |
||||
TypeReference arg3 = args.Count >= 3 ? args[2] : null; |
||||
|
||||
switch(opCode.Code) { |
||||
#region Arithmetic
|
||||
case Code.Add: |
||||
case Code.Add_Ovf: |
||||
case Code.Add_Ovf_Un: |
||||
case Code.Div: |
||||
case Code.Div_Un: |
||||
case Code.Mul: |
||||
case Code.Mul_Ovf: |
||||
case Code.Mul_Ovf_Un: |
||||
case Code.Rem: |
||||
case Code.Rem_Un: |
||||
case Code.Sub: |
||||
case Code.Sub_Ovf: |
||||
case Code.Sub_Ovf_Un: |
||||
case Code.And: |
||||
case Code.Xor: |
||||
case Code.Shl: |
||||
case Code.Shr: |
||||
case Code.Shr_Un: return TypeInt32; |
||||
|
||||
case Code.Neg: return TypeInt32; |
||||
case Code.Not: return TypeInt32; |
||||
#endregion
|
||||
#region Arrays
|
||||
case Code.Newarr: |
||||
return new ArrayType(operandAsTypeRef); |
||||
|
||||
case Code.Ldlen: return TypeInt32; |
||||
|
||||
case Code.Ldelem_I: |
||||
case Code.Ldelem_I1: |
||||
case Code.Ldelem_I2: |
||||
case Code.Ldelem_I4: |
||||
case Code.Ldelem_I8: return TypeInt32; |
||||
case Code.Ldelem_U1: |
||||
case Code.Ldelem_U2: |
||||
case Code.Ldelem_U4: |
||||
case Code.Ldelem_R4: |
||||
case Code.Ldelem_R8: throw new NotImplementedException(); |
||||
case Code.Ldelem_Ref: |
||||
if (arg1 is ArrayType) { |
||||
return ((ArrayType)arg1).ElementType; |
||||
} else { |
||||
throw new NotImplementedException(); |
||||
} |
||||
case Code.Ldelem_Any: |
||||
case Code.Ldelema: throw new NotImplementedException(); |
||||
|
||||
case Code.Stelem_I: |
||||
case Code.Stelem_I1: |
||||
case Code.Stelem_I2: |
||||
case Code.Stelem_I4: |
||||
case Code.Stelem_I8: |
||||
case Code.Stelem_R4: |
||||
case Code.Stelem_R8: |
||||
case Code.Stelem_Ref: |
||||
case Code.Stelem_Any: return TypeVoid; |
||||
#endregion
|
||||
#region Branching
|
||||
case Code.Br: |
||||
case Code.Brfalse: |
||||
case Code.Brtrue: |
||||
case Code.Beq: |
||||
case Code.Bge: |
||||
case Code.Bge_Un: |
||||
case Code.Bgt: |
||||
case Code.Bgt_Un: |
||||
case Code.Ble: |
||||
case Code.Ble_Un: |
||||
case Code.Blt: |
||||
case Code.Blt_Un: |
||||
case Code.Bne_Un: return TypeVoid; |
||||
#endregion
|
||||
#region Comparison
|
||||
case Code.Ceq: |
||||
case Code.Cgt: |
||||
case Code.Cgt_Un: |
||||
case Code.Clt: |
||||
case Code.Clt_Un: return TypeBool; |
||||
#endregion
|
||||
#region Conversions
|
||||
case Code.Conv_I: |
||||
case Code.Conv_I1: |
||||
case Code.Conv_I2: |
||||
case Code.Conv_I4: |
||||
case Code.Conv_I8: |
||||
case Code.Conv_U: |
||||
case Code.Conv_U1: |
||||
case Code.Conv_U2: |
||||
case Code.Conv_U4: |
||||
case Code.Conv_U8: |
||||
case Code.Conv_R4: |
||||
case Code.Conv_R8: |
||||
case Code.Conv_R_Un: |
||||
|
||||
case Code.Conv_Ovf_I: |
||||
case Code.Conv_Ovf_I1: |
||||
case Code.Conv_Ovf_I2: |
||||
case Code.Conv_Ovf_I4: |
||||
case Code.Conv_Ovf_I8: |
||||
case Code.Conv_Ovf_U: |
||||
case Code.Conv_Ovf_U1: |
||||
case Code.Conv_Ovf_U2: |
||||
case Code.Conv_Ovf_U4: |
||||
case Code.Conv_Ovf_U8: |
||||
|
||||
case Code.Conv_Ovf_I_Un: |
||||
case Code.Conv_Ovf_I1_Un: |
||||
case Code.Conv_Ovf_I2_Un: |
||||
case Code.Conv_Ovf_I4_Un: |
||||
case Code.Conv_Ovf_I8_Un: |
||||
case Code.Conv_Ovf_U_Un: |
||||
case Code.Conv_Ovf_U1_Un: |
||||
case Code.Conv_Ovf_U2_Un: |
||||
case Code.Conv_Ovf_U4_Un: |
||||
case Code.Conv_Ovf_U8_Un: return TypeInt32; |
||||
#endregion
|
||||
#region Indirect
|
||||
case Code.Ldind_I: throw new NotImplementedException(); |
||||
case Code.Ldind_I1: throw new NotImplementedException(); |
||||
case Code.Ldind_I2: throw new NotImplementedException(); |
||||
case Code.Ldind_I4: throw new NotImplementedException(); |
||||
case Code.Ldind_I8: throw new NotImplementedException(); |
||||
case Code.Ldind_U1: throw new NotImplementedException(); |
||||
case Code.Ldind_U2: throw new NotImplementedException(); |
||||
case Code.Ldind_U4: throw new NotImplementedException(); |
||||
case Code.Ldind_R4: throw new NotImplementedException(); |
||||
case Code.Ldind_R8: throw new NotImplementedException(); |
||||
case Code.Ldind_Ref: throw new NotImplementedException(); |
||||
|
||||
case Code.Stind_I: throw new NotImplementedException(); |
||||
case Code.Stind_I1: throw new NotImplementedException(); |
||||
case Code.Stind_I2: throw new NotImplementedException(); |
||||
case Code.Stind_I4: throw new NotImplementedException(); |
||||
case Code.Stind_I8: throw new NotImplementedException(); |
||||
case Code.Stind_R4: throw new NotImplementedException(); |
||||
case Code.Stind_R8: throw new NotImplementedException(); |
||||
case Code.Stind_Ref: throw new NotImplementedException(); |
||||
#endregion
|
||||
case Code.Arglist: throw new NotImplementedException(); |
||||
case Code.Box: throw new NotImplementedException(); |
||||
case Code.Break: throw new NotImplementedException(); |
||||
case Code.Call: return ((MethodReference)operand).ReturnType; |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
case Code.Callvirt: return ((MethodReference)operand).ReturnType; |
||||
case Code.Castclass: throw new NotImplementedException(); |
||||
case Code.Ckfinite: throw new NotImplementedException(); |
||||
case Code.Constrained: throw new NotImplementedException(); |
||||
case Code.Cpblk: throw new NotImplementedException(); |
||||
case Code.Cpobj: throw new NotImplementedException(); |
||||
case Code.Dup: throw new NotImplementedException(); |
||||
case Code.Endfilter: throw new NotImplementedException(); |
||||
case Code.Endfinally: throw new NotImplementedException(); |
||||
case Code.Initblk: throw new NotImplementedException(); |
||||
case Code.Initobj: throw new NotImplementedException(); |
||||
case Code.Isinst: throw new NotImplementedException(); |
||||
case Code.Jmp: throw new NotImplementedException(); |
||||
case Code.Ldarg: |
||||
TypeReference typeRef = ((ParameterDefinition)operand).ParameterType; |
||||
// 'this' returns null; TODO: Return proper type of this
|
||||
return typeRef ?? TypeObject; |
||||
case Code.Ldarga: throw new NotImplementedException(); |
||||
case Code.Ldc_I4: |
||||
if ((int)operand == 0) { |
||||
return TypeZero; |
||||
} else if ((int)operand == 1) { |
||||
return TypeOne; |
||||
} else { |
||||
return TypeInt32; |
||||
} |
||||
case Code.Ldc_I8: throw new NotImplementedException(); |
||||
case Code.Ldc_R4: throw new NotImplementedException(); |
||||
case Code.Ldc_R8: throw new NotImplementedException(); |
||||
case Code.Ldfld: return ((FieldDefinition)operand).FieldType; |
||||
case Code.Ldflda: throw new NotImplementedException(); |
||||
case Code.Ldftn: throw new NotImplementedException(); |
||||
case Code.Ldloc: return ((VariableDefinition)operand).VariableType; |
||||
case Code.Ldloca: throw new NotImplementedException(); |
||||
case Code.Ldnull: throw new NotImplementedException(); |
||||
case Code.Ldobj: throw new NotImplementedException(); |
||||
case Code.Ldsfld: throw new NotImplementedException(); |
||||
case Code.Ldsflda: throw new NotImplementedException(); |
||||
case Code.Ldstr: return TypeString; |
||||
case Code.Ldtoken: throw new NotImplementedException(); |
||||
case Code.Ldvirtftn: throw new NotImplementedException(); |
||||
case Code.Leave: throw new NotImplementedException(); |
||||
case Code.Localloc: throw new NotImplementedException(); |
||||
case Code.Mkrefany: throw new NotImplementedException(); |
||||
case Code.Newobj: throw new NotImplementedException(); |
||||
case Code.No: throw new NotImplementedException(); |
||||
case Code.Nop: return TypeVoid; |
||||
case Code.Or: throw new NotImplementedException(); |
||||
case Code.Pop: throw new NotImplementedException(); |
||||
case Code.Readonly: throw new NotImplementedException(); |
||||
case Code.Refanytype: throw new NotImplementedException(); |
||||
case Code.Refanyval: throw new NotImplementedException(); |
||||
case Code.Ret: return TypeVoid; |
||||
case Code.Rethrow: throw new NotImplementedException(); |
||||
case Code.Sizeof: throw new NotImplementedException(); |
||||
case Code.Starg: throw new NotImplementedException(); |
||||
case Code.Stfld: throw new NotImplementedException(); |
||||
case Code.Stloc: return TypeVoid; |
||||
case Code.Stobj: throw new NotImplementedException(); |
||||
case Code.Stsfld: throw new NotImplementedException(); |
||||
case Code.Switch: throw new NotImplementedException(); |
||||
case Code.Tail: throw new NotImplementedException(); |
||||
case Code.Throw: throw new NotImplementedException(); |
||||
case Code.Unaligned: throw new NotImplementedException(); |
||||
case Code.Unbox: throw new NotImplementedException(); |
||||
case Code.Unbox_Any: throw new NotImplementedException(); |
||||
case Code.Volatile: throw new NotImplementedException(); |
||||
default: throw new Exception("Unknown OpCode: " + opCode); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,16 +0,0 @@
@@ -1,16 +0,0 @@
|
||||
using System; |
||||
|
||||
using Ast = ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public static class Util |
||||
{ |
||||
|
||||
} |
||||
} |
Binary file not shown.
Loading…
Reference in new issue