/*
Copyright (C) 2011-2012 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see .
*/
using System;
using System.Collections.Generic;
using dot10.DotNet;
using dot10.DotNet.Emit;
namespace de4dot.blocks.cflow {
public class InstructionEmulator {
ValueStack valueStack = new ValueStack();
Dictionary protectedStackValues = new Dictionary();
IList parameterDefs;
IList localDefs;
List args = new List();
List locals = new List();
MethodDef prev_method;
List cached_args = new List();
List cached_locals = new List();
public InstructionEmulator() {
}
public InstructionEmulator(MethodDef method) {
init(method);
}
public void init(Blocks blocks) {
init(blocks.Method);
}
public void init(MethodDef method) {
this.parameterDefs = method.Parameters;
this.localDefs = method.Body.Variables;
valueStack.init();
protectedStackValues.Clear();
if (method != prev_method) {
prev_method = method;
cached_args.Clear();
for (int i = 0; i < parameterDefs.Count; i++)
cached_args.Add(getUnknownValue(parameterDefs[i].Type));
cached_locals.Clear();
for (int i = 0; i < localDefs.Count; i++)
cached_locals.Add(getUnknownValue(localDefs[i].Type));
}
args.Clear();
args.AddRange(cached_args);
locals.Clear();
locals.AddRange(cached_locals);
}
public void setProtected(Value value) {
protectedStackValues[value] = true;
}
static Value getUnknownValue(ITypeDefOrRef type) {
return getUnknownValue(type.ToTypeSig(false));
}
static Value getUnknownValue(TypeSig type) {
if (type == null)
return new UnknownValue();
switch (type.ElementType) {
case ElementType.Boolean: return Int32Value.createUnknownBool();
case ElementType.I1: return Int32Value.createUnknown();
case ElementType.U1: return Int32Value.createUnknownUInt8();
case ElementType.I2: return Int32Value.createUnknown();
case ElementType.U2: return Int32Value.createUnknownUInt16();
case ElementType.I4: return Int32Value.createUnknown();
case ElementType.U4: return Int32Value.createUnknown();
case ElementType.I8: return Int64Value.createUnknown();
case ElementType.U8: return Int64Value.createUnknown();
}
return new UnknownValue();
}
Value truncateValue(Value value, TypeSig type) {
if (type == null)
return value;
if (protectedStackValues.ContainsKey(value))
return value;
switch (type.ElementType) {
case ElementType.Boolean:
if (value.isInt32())
return ((Int32Value)value).toBoolean();
return Int32Value.createUnknownBool();
case ElementType.I1:
if (value.isInt32())
return ((Int32Value)value).toInt8();
return Int32Value.createUnknown();
case ElementType.U1:
if (value.isInt32())
return ((Int32Value)value).toUInt8();
return Int32Value.createUnknownUInt8();
case ElementType.I2:
if (value.isInt32())
return ((Int32Value)value).toInt16();
return Int32Value.createUnknown();
case ElementType.U2:
if (value.isInt32())
return ((Int32Value)value).toUInt16();
return Int32Value.createUnknownUInt16();
case ElementType.I4:
case ElementType.U4:
if (value.isInt32())
return value;
return Int32Value.createUnknown();
case ElementType.I8:
case ElementType.U8:
if (value.isInt64())
return value;
return Int64Value.createUnknown();
case ElementType.R4:
if (value.isReal8())
return new Real8Value((float)((Real8Value)value).value);
return new UnknownValue();
case ElementType.R8:
if (value.isReal8())
return value;
return new UnknownValue();
}
return value;
}
static Value getValue(List list, int i) {
if (0 <= i && i < list.Count)
return list[i];
return new UnknownValue();
}
public Value getArg(int i) {
return getValue(args, i);
}
public Value getArg(Parameter arg) {
if (arg == null)
return new UnknownValue();
return getArg(arg.Index);
}
TypeSig getArgType(int index) {
if (0 <= index && index < parameterDefs.Count)
return parameterDefs[index].Type;
return null;
}
public void setArg(Parameter arg, Value value) {
if (arg != null)
setArg(arg.Index, value);
}
public void makeArgUnknown(Parameter arg) {
if (arg != null)
setArg(arg, getUnknownArg(arg.Index));
}
void setArg(int index, Value value) {
if (0 <= index && index < args.Count)
args[index] = truncateValue(value, getArgType(index));
}
Value getUnknownArg(int index) {
return getUnknownValue(getArgType(index));
}
public Value getLocal(int i) {
return getValue(locals, i);
}
public Value getLocal(Local local) {
if (local == null)
return new UnknownValue();
return getLocal(local.Index);
}
public void setLocal(Local local, Value value) {
if (local != null)
setLocal(local.Index, value);
}
public void makeLocalUnknown(Local local) {
if (local != null)
setLocal(local.Index, getUnknownLocal(local.Index));
}
void setLocal(int index, Value value) {
if (0 <= index && index < locals.Count)
locals[index] = truncateValue(value, localDefs[index].Type);
}
Value getUnknownLocal(int index) {
if (0 <= index && index < localDefs.Count)
return getUnknownValue(localDefs[index].Type);
return new UnknownValue();
}
public int stackSize() {
return valueStack.Size;
}
public void push(Value value) {
valueStack.push(value);
}
public Value pop() {
return valueStack.pop();
}
public Value peek() {
return valueStack.peek();
}
public void emulate(IEnumerable instructions) {
foreach (var instr in instructions)
emulate(instr.Instruction);
}
public void emulate(IList instructions, int start, int end) {
for (int i = start; i < end; i++)
emulate(instructions[i].Instruction);
}
public void emulate(Instruction instr) {
switch (instr.OpCode.Code) {
case Code.Starg:
case Code.Starg_S: emulate_Starg((Parameter)instr.Operand); break;
case Code.Stloc:
case Code.Stloc_S: emulate_Stloc((Local)instr.Operand); break;
case Code.Stloc_0: emulate_Stloc(0); break;
case Code.Stloc_1: emulate_Stloc(1); break;
case Code.Stloc_2: emulate_Stloc(2); break;
case Code.Stloc_3: emulate_Stloc(3); break;
case Code.Ldarg:
case Code.Ldarg_S: valueStack.push(getArg((Parameter)instr.Operand)); break;
case Code.Ldarg_0: valueStack.push(getArg(0)); break;
case Code.Ldarg_1: valueStack.push(getArg(1)); break;
case Code.Ldarg_2: valueStack.push(getArg(2)); break;
case Code.Ldarg_3: valueStack.push(getArg(3)); break;
case Code.Ldloc:
case Code.Ldloc_S: valueStack.push(getLocal((Local)instr.Operand)); break;
case Code.Ldloc_0: valueStack.push(getLocal(0)); break;
case Code.Ldloc_1: valueStack.push(getLocal(1)); break;
case Code.Ldloc_2: valueStack.push(getLocal(2)); break;
case Code.Ldloc_3: valueStack.push(getLocal(3)); break;
case Code.Ldarga:
case Code.Ldarga_S: emulate_Ldarga((Parameter)instr.Operand); break;
case Code.Ldloca:
case Code.Ldloca_S: emulate_Ldloca((Local)instr.Operand); break;
case Code.Dup: valueStack.copyTop(); break;
case Code.Ldc_I4: valueStack.push(new Int32Value((int)instr.Operand)); break;
case Code.Ldc_I4_S: valueStack.push(new Int32Value((sbyte)instr.Operand)); break;
case Code.Ldc_I8: valueStack.push(new Int64Value((long)instr.Operand)); break;
case Code.Ldc_R4: valueStack.push(new Real8Value((float)instr.Operand)); break;
case Code.Ldc_R8: valueStack.push(new Real8Value((double)instr.Operand)); break;
case Code.Ldc_I4_0: valueStack.push(Int32Value.zero); break;
case Code.Ldc_I4_1: valueStack.push(Int32Value.one); break;
case Code.Ldc_I4_2: valueStack.push(new Int32Value(2)); break;
case Code.Ldc_I4_3: valueStack.push(new Int32Value(3)); break;
case Code.Ldc_I4_4: valueStack.push(new Int32Value(4)); break;
case Code.Ldc_I4_5: valueStack.push(new Int32Value(5)); break;
case Code.Ldc_I4_6: valueStack.push(new Int32Value(6)); break;
case Code.Ldc_I4_7: valueStack.push(new Int32Value(7)); break;
case Code.Ldc_I4_8: valueStack.push(new Int32Value(8)); break;
case Code.Ldc_I4_M1:valueStack.push(new Int32Value(-1)); break;
case Code.Ldnull: valueStack.push(NullValue.Instance); break;
case Code.Ldstr: valueStack.push(new StringValue((string)instr.Operand)); break;
case Code.Box: valueStack.push(new BoxedValue(valueStack.pop())); break;
case Code.Conv_U1: emulate_Conv_U1(instr); break;
case Code.Conv_U2: emulate_Conv_U2(instr); break;
case Code.Conv_U4: emulate_Conv_U4(instr); break;
case Code.Conv_U8: emulate_Conv_U8(instr); break;
case Code.Conv_I1: emulate_Conv_I1(instr); break;
case Code.Conv_I2: emulate_Conv_I2(instr); break;
case Code.Conv_I4: emulate_Conv_I4(instr); break;
case Code.Conv_I8: emulate_Conv_I8(instr); break;
case Code.Add: emulate_Add(instr); break;
case Code.Sub: emulate_Sub(instr); break;
case Code.Mul: emulate_Mul(instr); break;
case Code.Div: emulate_Div(instr); break;
case Code.Div_Un: emulate_Div_Un(instr); break;
case Code.Rem: emulate_Rem(instr); break;
case Code.Rem_Un: emulate_Rem_Un(instr); break;
case Code.Neg: emulate_Neg(instr); break;
case Code.And: emulate_And(instr); break;
case Code.Or: emulate_Or(instr); break;
case Code.Xor: emulate_Xor(instr); break;
case Code.Not: emulate_Not(instr); break;
case Code.Shl: emulate_Shl(instr); break;
case Code.Shr: emulate_Shr(instr); break;
case Code.Shr_Un: emulate_Shr_Un(instr); break;
case Code.Ceq: emulate_Ceq(instr); break;
case Code.Cgt: emulate_Cgt(instr); break;
case Code.Cgt_Un: emulate_Cgt_Un(instr); break;
case Code.Clt: emulate_Clt(instr); break;
case Code.Clt_Un: emulate_Clt_Un(instr); break;
case Code.Unbox_Any:emulate_Unbox_Any(instr); break;
case Code.Call: emulate_Call(instr); break;
case Code.Callvirt: emulate_Callvirt(instr); break;
case Code.Castclass: emulate_Castclass(instr); break;
case Code.Isinst: emulate_Isinst(instr); break;
case Code.Add_Ovf: emulateIntOps2(); break;
case Code.Add_Ovf_Un: emulateIntOps2(); break;
case Code.Sub_Ovf: emulateIntOps2(); break;
case Code.Sub_Ovf_Un: emulateIntOps2(); break;
case Code.Mul_Ovf: emulateIntOps2(); break;
case Code.Mul_Ovf_Un: emulateIntOps2(); break;
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I1_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I2_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I4_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_I8_Un: valueStack.pop(); valueStack.push(Int64Value.createUnknown()); break;
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U1_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt8()); break;
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U2_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt16()); break;
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U4_Un: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_U8_Un: valueStack.pop(); valueStack.push(Int64Value.createUnknown()); break;
case Code.Ldelem_I1: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldelem_I2: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldelem_I4: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldelem_I8: valueStack.pop(2); valueStack.push(Int64Value.createUnknown()); break;
case Code.Ldelem_U1: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt8()); break;
case Code.Ldelem_U2: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt16()); break;
case Code.Ldelem_U4: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldelem: valueStack.pop(2); valueStack.push(getUnknownValue(instr.Operand as ITypeDefOrRef)); break;
case Code.Ldind_I1: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldind_I2: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldind_I4: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldind_I8: valueStack.pop(); valueStack.push(Int64Value.createUnknown()); break;
case Code.Ldind_U1: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt8()); break;
case Code.Ldind_U2: valueStack.pop(); valueStack.push(Int32Value.createUnknownUInt16()); break;
case Code.Ldind_U4: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldlen: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Sizeof: valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldfld: emulate_Ldfld(instr); break;
case Code.Ldsfld: emulate_Ldsfld(instr); break;
case Code.Ldftn: valueStack.push(new ObjectValue(instr.Operand)); break;
case Code.Ldsflda: valueStack.push(new ObjectValue(instr.Operand)); break;
case Code.Ldtoken: valueStack.push(new ObjectValue(instr.Operand)); break;
case Code.Ldvirtftn:valueStack.pop(); valueStack.push(new ObjectValue()); break;
case Code.Ldflda: valueStack.pop(); valueStack.push(new ObjectValue()); break;
case Code.Unbox:
case Code.Conv_R_Un:
case Code.Conv_R4:
case Code.Conv_R8:
case Code.Arglist:
case Code.Beq:
case Code.Beq_S:
case Code.Bge:
case Code.Bge_S:
case Code.Bge_Un:
case Code.Bge_Un_S:
case Code.Bgt:
case Code.Bgt_S:
case Code.Bgt_Un:
case Code.Bgt_Un_S:
case Code.Ble:
case Code.Ble_S:
case Code.Ble_Un:
case Code.Ble_Un_S:
case Code.Blt:
case Code.Blt_S:
case Code.Blt_Un:
case Code.Blt_Un_S:
case Code.Bne_Un:
case Code.Bne_Un_S:
case Code.Brfalse:
case Code.Brfalse_S:
case Code.Brtrue:
case Code.Brtrue_S:
case Code.Br:
case Code.Br_S:
case Code.Break:
case Code.Calli:
case Code.Ckfinite:
case Code.Constrained:
case Code.Conv_I:
case Code.Conv_Ovf_I:
case Code.Conv_Ovf_I_Un:
case Code.Conv_Ovf_U:
case Code.Conv_Ovf_U_Un:
case Code.Conv_U:
case Code.Cpblk:
case Code.Cpobj:
case Code.Endfilter:
case Code.Endfinally:
case Code.Initblk:
case Code.Initobj:
case Code.Jmp:
case Code.Ldelema:
case Code.Ldelem_I:
case Code.Ldelem_R4:
case Code.Ldelem_R8:
case Code.Ldelem_Ref:
case Code.Ldind_I:
case Code.Ldind_R4:
case Code.Ldind_R8:
case Code.Ldind_Ref:
case Code.Ldobj:
case Code.Leave:
case Code.Leave_S:
case Code.Localloc:
case Code.Mkrefany:
case Code.Newarr:
case Code.Newobj:
case Code.Nop:
case Code.Pop:
case Code.Readonly:
case Code.Refanytype:
case Code.Refanyval:
case Code.Ret:
case Code.Rethrow:
case Code.Stelem:
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.Stfld:
case Code.Stind_I:
case Code.Stind_I1:
case Code.Stind_I2:
case Code.Stind_I4:
case Code.Stind_I8:
case Code.Stind_R4:
case Code.Stind_R8:
case Code.Stind_Ref:
case Code.Stobj:
case Code.Stsfld:
case Code.Switch:
case Code.Tailcall:
case Code.Throw:
case Code.Unaligned:
case Code.Volatile:
default:
updateStack(instr);
break;
}
}
void updateStack(Instruction instr) {
int pushes, pops;
instr.CalculateStackUsage(out pushes, out pops);
if (pops == -1)
valueStack.clear();
else {
valueStack.pop(pops);
valueStack.push(pushes);
}
}
void emulate_Conv_U1(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int32Value.Conv_U1((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int32Value.Conv_U1((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int32Value.Conv_U1((Real8Value)val1)); break;
default: valueStack.push(Int32Value.createUnknownUInt8()); break;
}
}
void emulate_Conv_I1(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int32Value.Conv_I1((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int32Value.Conv_I1((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int32Value.Conv_I1((Real8Value)val1)); break;
default: valueStack.push(Int32Value.createUnknown()); break;
}
}
void emulate_Conv_U2(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int32Value.Conv_U2((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int32Value.Conv_U2((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int32Value.Conv_U2((Real8Value)val1)); break;
default: valueStack.push(Int32Value.createUnknownUInt16()); break;
}
}
void emulate_Conv_I2(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int32Value.Conv_I2((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int32Value.Conv_I2((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int32Value.Conv_I2((Real8Value)val1)); break;
default: valueStack.push(Int32Value.createUnknown()); break;
}
}
void emulate_Conv_U4(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int32Value.Conv_U4((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int32Value.Conv_U4((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int32Value.Conv_U4((Real8Value)val1)); break;
default: valueStack.push(Int32Value.createUnknown()); break;
}
}
void emulate_Conv_I4(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int32Value.Conv_I4((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int32Value.Conv_I4((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int32Value.Conv_I4((Real8Value)val1)); break;
default: valueStack.push(Int32Value.createUnknown()); break;
}
}
void emulate_Conv_U8(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int64Value.Conv_U8((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int64Value.Conv_U8((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int64Value.Conv_U8((Real8Value)val1)); break;
default: valueStack.push(Int64Value.createUnknown()); break;
}
}
void emulate_Conv_I8(Instruction instr) {
var val1 = valueStack.pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.push(Int64Value.Conv_I8((Int32Value)val1)); break;
case ValueType.Int64: valueStack.push(Int64Value.Conv_I8((Int64Value)val1)); break;
case ValueType.Real8: valueStack.push(Int64Value.Conv_I8((Real8Value)val1)); break;
default: valueStack.push(Int64Value.createUnknown()); break;
}
}
void emulate_Add(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Add((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Add((Int64Value)val1, (Int64Value)val2));
else if (val1.isReal8() && val2.isReal8())
valueStack.push(Real8Value.Add((Real8Value)val1, (Real8Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Sub(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Sub((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Sub((Int64Value)val1, (Int64Value)val2));
else if (val1.isReal8() && val2.isReal8())
valueStack.push(Real8Value.Sub((Real8Value)val1, (Real8Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Mul(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Mul((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Mul((Int64Value)val1, (Int64Value)val2));
else if (val1.isReal8() && val2.isReal8())
valueStack.push(Real8Value.Mul((Real8Value)val1, (Real8Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Div(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Div((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Div((Int64Value)val1, (Int64Value)val2));
else if (val1.isReal8() && val2.isReal8())
valueStack.push(Real8Value.Div((Real8Value)val1, (Real8Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Div_Un(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Div_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Div_Un((Int64Value)val1, (Int64Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Rem(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Rem((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Rem((Int64Value)val1, (Int64Value)val2));
else if (val1.isReal8() && val2.isReal8())
valueStack.push(Real8Value.Rem((Real8Value)val1, (Real8Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Rem_Un(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Rem_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Rem_Un((Int64Value)val1, (Int64Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Neg(Instruction instr) {
var val1 = valueStack.pop();
if (val1.isInt32())
valueStack.push(Int32Value.Neg((Int32Value)val1));
else if (val1.isInt64())
valueStack.push(Int64Value.Neg((Int64Value)val1));
else if (val1.isReal8())
valueStack.push(Real8Value.Neg((Real8Value)val1));
else
valueStack.pushUnknown();
}
void emulate_And(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.And((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.And((Int64Value)val1, (Int64Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Or(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Or((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Or((Int64Value)val1, (Int64Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Xor(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Xor((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Xor((Int64Value)val1, (Int64Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Not(Instruction instr) {
var val1 = valueStack.pop();
if (val1.isInt32())
valueStack.push(Int32Value.Not((Int32Value)val1));
else if (val1.isInt64())
valueStack.push(Int64Value.Not((Int64Value)val1));
else
valueStack.pushUnknown();
}
void emulate_Shl(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Shl((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt32())
valueStack.push(Int64Value.Shl((Int64Value)val1, (Int32Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Shr(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Shr((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt32())
valueStack.push(Int64Value.Shr((Int64Value)val1, (Int32Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Shr_Un(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Shr_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt32())
valueStack.push(Int64Value.Shr_Un((Int64Value)val1, (Int32Value)val2));
else
valueStack.pushUnknown();
}
void emulate_Ceq(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Ceq((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2));
else if (val1.isNull() && val2.isNull())
valueStack.push(Int32Value.one);
else
valueStack.push(Int32Value.createUnknownBool());
}
void emulate_Cgt(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Cgt((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Cgt((Int64Value)val1, (Int64Value)val2));
else
valueStack.push(Int32Value.createUnknownBool());
}
void emulate_Cgt_Un(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Cgt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Cgt_Un((Int64Value)val1, (Int64Value)val2));
else
valueStack.push(Int32Value.createUnknownBool());
}
void emulate_Clt(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Clt((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Clt((Int64Value)val1, (Int64Value)val2));
else
valueStack.push(Int32Value.createUnknownBool());
}
void emulate_Clt_Un(Instruction instr) {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.Clt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.Clt_Un((Int64Value)val1, (Int64Value)val2));
else
valueStack.push(Int32Value.createUnknownBool());
}
void emulate_Unbox_Any(Instruction instr) {
var val1 = valueStack.pop();
if (val1.isBoxed())
valueStack.push(((BoxedValue)val1).value);
else
valueStack.pushUnknown();
}
void emulate_Starg(Parameter arg) {
setArg(arg == null ? -1 : arg.Index, valueStack.pop());
}
void emulate_Stloc(Local local) {
emulate_Stloc(local == null ? -1 : local.Index);
}
void emulate_Stloc(int index) {
setLocal(index, valueStack.pop());
}
void emulate_Ldarga(Parameter arg) {
valueStack.pushUnknown();
makeArgUnknown(arg);
}
void emulate_Ldloca(Local local) {
emulate_Ldloca(local == null ? -1 : local.Index);
}
void emulate_Ldloca(int index) {
valueStack.pushUnknown();
setLocal(index, getUnknownLocal(index));
}
void emulate_Call(Instruction instr) {
emulate_Call(instr, (IMethod)instr.Operand);
}
void emulate_Callvirt(Instruction instr) {
emulate_Call(instr, (IMethod)instr.Operand);
}
void emulate_Call(Instruction instr, IMethod method) {
int pushes, pops;
instr.CalculateStackUsage(out pushes, out pops);
valueStack.pop(pops);
if (pushes == 1)
valueStack.push(getUnknownValue(method.MethodSig.GetRetType()));
else
valueStack.push(pushes);
}
void emulate_Castclass(Instruction instr) {
var val1 = valueStack.pop();
if (val1.isNull())
valueStack.push(val1);
else
valueStack.pushUnknown();
}
void emulate_Isinst(Instruction instr) {
var val1 = valueStack.pop();
if (val1.isNull())
valueStack.push(val1);
else
valueStack.pushUnknown();
}
void emulate_Ldfld(Instruction instr) {
var val1 = valueStack.pop();
emulateLoadField(instr.Operand as IField);
}
void emulate_Ldsfld(Instruction instr) {
emulateLoadField(instr.Operand as IField);
}
void emulateLoadField(IField field) {
if (field != null)
valueStack.push(getUnknownValue(field.FieldSig.GetFieldType()));
else
valueStack.pushUnknown();
}
void emulateIntOps2() {
var val2 = valueStack.pop();
var val1 = valueStack.pop();
if (val1.isInt32() && val2.isInt32())
valueStack.push(Int32Value.createUnknown());
else if (val1.isInt64() && val2.isInt64())
valueStack.push(Int64Value.createUnknown());
else
valueStack.pushUnknown();
}
}
}