/// <summary> /// Converts the provided trilean to an I4 stack value, pushes it onto the stack and returns the success /// dispatcher result. /// </summary> /// <param name="context">The current execution context.</param> /// <param name="result">The trilean value.</param> /// <returns>The dispatch result.</returns> protected static DispatchResult ConvertToI4AndReturnSuccess(CilExecutionContext context, Trilean result) { var i4Result = new I4Value(result.ToBooleanOrFalse() ? 1 : 0, 0xFFFFFFFEu | (result.IsKnown ? 1u : 0u)); context.ProgramState.Stack.Push(i4Result); return(DispatchResult.Success()); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var stack = context.ProgramState.Stack; // Pop arguments. var valueValue = stack.Pop(); var indexValue = stack.Pop(); var arrayValue = stack.Pop(); // Check if both array and index are known. if (!arrayValue.IsKnown) { throw new DispatchException($"Destination array value for instruction at offset IL_{instruction.Offset:X4} is unknown."); } if (!indexValue.IsKnown) { throw new DispatchException($"Index for instruction at offset IL_{instruction.Offset:X4} is unknown."); } // Expect an int32 or a native int for index, and extract its value. if (indexValue.CliValueType != CliValueType.Int32 && indexValue.CliValueType != CliValueType.NativeInt) { return(DispatchResult.InvalidProgram()); } int index = indexValue.InterpretAsI4().I32; // Expect an O value with a .NET array in it. switch (arrayValue) { case OValue { IsZero: { Value : TrileanValue.True } } : // Pushed array object is null. return(new DispatchResult(new NullReferenceException()));
/// <inheritdoc /> protected override DispatchResult Execute( CilExecutionContext context, CilInstruction instruction, FValue left, FValue right) { left.F64 /= right.F64; context.ProgramState.Stack.Push(left); return(DispatchResult.Success()); }
/// <inheritdoc /> protected override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction, IntegerValue left, IntegerValue right) { var result = left.IsLessThan(right, instruction.OpCode.Code == CilCode.Clt); return(ConvertToI4AndReturnSuccess(context, result)); }
/// <inheritdoc /> public DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); // If the containing method is expected to return a value, the stack should contain exactly one value, // and no values otherwise. int popCount = environment.Architecture.GetStackPopCount(instruction); if (context.ProgramState.Stack.Size != popCount) { return(DispatchResult.InvalidProgram()); } // Pop result. if (popCount == 1) { context.Result.ReturnValue = context.ProgramState.Stack.Pop(); } return(new DispatchResult { HasTerminated = true }); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); var factory = environment.Module.CorLibTypeFactory; var stack = context.ProgramState.Stack; var valueValue = stack.Pop(); var pointerValue = (IPointerValue)stack.Pop(); var marshaller = environment.CliMarshaller; switch (instruction.OpCode.Code) { case CilCode.Stind_I: if (pointerValue.Is32Bit) { pointerValue.WriteInteger32(0, valueValue.InterpretAsI4()); } else { pointerValue.WriteInteger64(0, valueValue.InterpretAsI8()); } break; case CilCode.Stind_I1: pointerValue.WriteInteger8(0, (Integer8Value)marshaller.ToCtsValue(valueValue.InterpretAsI1(), factory.SByte)); break; case CilCode.Stind_I2: pointerValue.WriteInteger16(0, (Integer16Value)marshaller.ToCtsValue(valueValue.InterpretAsI2(), factory.Int16)); break; case CilCode.Stind_I4: pointerValue.WriteInteger32(0, (Integer32Value)marshaller.ToCtsValue(valueValue.InterpretAsI4(), factory.Int32)); break; case CilCode.Stind_I8: pointerValue.WriteInteger64(0, (Integer64Value)marshaller.ToCtsValue(valueValue.InterpretAsI8(), factory.Int64)); break; case CilCode.Stind_R4: pointerValue.WriteFloat32(0, (Float32Value)marshaller.ToCtsValue(valueValue.InterpretAsR4(), factory.Single)); break; case CilCode.Stind_R8: pointerValue.WriteFloat64(0, (Float64Value)marshaller.ToCtsValue(valueValue.InterpretAsR8(), factory.Double)); break; default: return(DispatchResult.InvalidProgram()); } return(base.Execute(context, instruction)); }
/// <inheritdoc /> public DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var result = VerifyCondition(context, instruction); int newOffset; if (result.IsKnown) { if (result) { newOffset = ((ICilLabel)instruction.Operand).Offset; } else { newOffset = instruction.Offset + instruction.Size; } } else { // TODO: dispatch event, allowing the user to handle unknown branch conditions. throw new DispatchException("Branch condition could not be evaluated."); } var stack = context.ProgramState.Stack; for (int i = 0; i < ArgumentCount; i++) { stack.Pop(); } context.ProgramState.ProgramCounter = newOffset; return(DispatchResult.Success()); }
/// <inheritdoc /> protected override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction, IntegerValue left, IntegerValue right) { left.Xor(right); context.ProgramState.Stack.Push((ICliValue)left); return(DispatchResult.Success()); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); var variables = new IVariable[1]; if (environment.Architecture.GetReadVariables(instruction, variables) != 1) { throw new DispatchException( $"Architecture returned an incorrect number of variables being read from instruction {instruction}."); } switch (variables[0]) { case CilParameter parameter: var value = environment.CliMarshaller.ToCliValue( context.ProgramState.Variables[variables[0]], parameter.Parameter.ParameterType); context.ProgramState.Stack.Push(value); return(base.Execute(context, instruction)); default: return(DispatchResult.InvalidProgram()); } }
/// <inheritdoc /> protected override ICliValue GetUnknownElementValue(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); var type = (ITypeDefOrRef)instruction.Operand; return(environment.CliMarshaller.ToCliValue(new UnknownValue(), type.ToTypeSignature())); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); var variables = new IVariable[1]; if (environment.Architecture.GetWrittenVariables(instruction, variables) != 1) { throw new DispatchException( $"Architecture returned an incorrect number of variables being written by instruction {instruction}."); } switch (variables[0]) { case CilVariable cilVariable: var value = environment.CliMarshaller.ToCtsValue( context.ProgramState.Stack.Pop(), cilVariable.Variable.VariableType); context.ProgramState.Variables[variables[0]] = value; return(base.Execute(context, instruction)); default: return(DispatchResult.InvalidProgram()); } }
/// <inheritdoc /> protected override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction, FValue left, FValue right) { bool result = left.IsGreaterThan(right, instruction.OpCode.Code == CilCode.Cgt_Un); return(ConvertToI4AndReturnSuccess(context, result)); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var stack = context.ProgramState.Stack; stack.Push((ICliValue)stack.Top.Copy()); return(base.Execute(context, instruction)); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var stack = context.ProgramState.Stack; // Pop arguments. var lengthValue = stack.Pop(); var sourceAddress = stack.Pop(); var destinationAddress = stack.Pop(); // Interpret arguments. if (!(destinationAddress is IPointerValue destinationPointer) || !(sourceAddress is IPointerValue sourcePointer)) { return(DispatchResult.InvalidProgram()); } if (!lengthValue.IsKnown) { throw new DispatchException("Number of bytes to copy is unknown."); } int length = lengthValue.InterpretAsI4().I32; // Copy data. Span <byte> data = stackalloc byte[length]; Span <byte> bitmask = stackalloc byte[length]; sourcePointer.ReadBytes(0, data, bitmask); destinationPointer.WriteBytes(0, data, bitmask); return(base.Execute(context, instruction)); }
/// <inheritdoc /> protected override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction, OValue left, OValue right) { var result = left.IsEqualTo(right); return(ConvertToI4AndReturnSuccess(context, result)); }
/// <inheritdoc /> protected override Trilean VerifyCondition(CilExecutionContext context, CilInstruction instruction, OValue left, OValue right) { return(left.IsKnown && right.IsKnown ? ReferenceEquals(left.ReferencedObject, right.ReferencedObject) : Trilean.Unknown); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var stack = context.ProgramState.Stack; // Pop arguments. var indexValue = stack.Pop(); var arrayValue = stack.Pop(); // Check if both array and index are known. if (!arrayValue.IsKnown || !indexValue.IsKnown) { stack.Push(GetUnknownElementValue(context, instruction)); return(base.Execute(context, instruction)); } // Expect an int32 or a native int for index, and extract its value. if (indexValue.CliValueType != CliValueType.Int32 && indexValue.CliValueType != CliValueType.NativeInt) { return(DispatchResult.InvalidProgram()); } int index = indexValue.InterpretAsI4().I32; // Obtain element. ICliValue elementValue; switch (arrayValue) { case OValue { IsZero: { Value : TrileanValue.True } } : // Pushed array object is null. return(new DispatchResult(new NullReferenceException()));
/// <inheritdoc /> protected override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction, IntegerValue value, int shiftCount) { value.RightShift(shiftCount, instruction.OpCode.Code == CilCode.Shr); context.ProgramState.Stack.Push((ICliValue)value); return(DispatchResult.Success()); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); var field = ((IFieldDescriptor)instruction.Operand).Resolve(); var stack = context.ProgramState.Stack; var objectValue = stack.Pop(); IConcreteValue fieldValue; if (field.IsStatic) { // Undocumented: The runtime does allow access of static fields through the ldfld opcode. // In this case, the object instance that is pushed is ignored, allowing constructs like: // // ldnull // ldfld <some_static_field> // // without the runtime throwing a NullReferenceException. var staticField = environment.StaticFieldFactory.Get(field); fieldValue = environment.CliMarshaller.ToCliValue(staticField.Value, field.Signature.FieldType); } else { // Attempt to dereference the object instance. switch (objectValue) { case { IsKnown: false } :
/// <inheritdoc /> protected override Trilean VerifyCondition(CilExecutionContext context, CilInstruction instruction, FValue left, FValue right) { // ReSharper disable once CompareOfFloatsByEqualityOperator bool equal = left.F64 == right.F64; bool lessThan = left.IsLessThan(right, IsSigned(instruction)); return(lessThan || equal); }
public static (ICliValue left, ICliValue right) PopBinaryOperationArguments(CilExecutionContext context) { var values = PeekBinaryOperationArguments(context); var stack = context.ProgramState.Stack; stack.Pop(); stack.Pop(); return(values); }
/// <inheritdoc /> protected override ICliValue GetElementValue(CilExecutionContext context, CilInstruction instruction, IDotNetArrayValue array, int index) { var environment = context.GetService <ICilRuntimeEnvironment>(); var type = (ITypeDescriptor)instruction.Operand; var typeLayout = environment.ValueFactory.GetTypeMemoryLayout(type); return(array.LoadElement(index, typeLayout, environment.CliMarshaller)); }
/// <inheritdoc /> protected override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction, FValue left, FValue right) { // ReSharper disable once CompareOfFloatsByEqualityOperator var i4Result = new I4Value(left.F64 == right.F64 ? 1 : 0); context.ProgramState.Stack.Push(i4Result); return(DispatchResult.Success()); }
private static DispatchResult ExecuteDefault(CilExecutionContext context, IntegerValue value, IntegerValue left) { if (value.IsNonZero.IsUnknown) { value.MarkFullyUnknown(); } context.ProgramState.Stack.Push((ICliValue)left); return(DispatchResult.Success()); }
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); var stack = context.ProgramState.Stack; var value = (ICliValue)stack.Pop(); bool overflowed = false; ICliValue newValue = instruction.OpCode.Code switch { CilCode.Conv_I1 => value.ConvertToI1(false, out _), CilCode.Conv_Ovf_I1 => value.ConvertToI1(false, out overflowed), CilCode.Conv_Ovf_I1_Un => value.ConvertToI1(true, out overflowed), CilCode.Conv_U1 => value.ConvertToU1(false, out _), CilCode.Conv_Ovf_U1 => value.ConvertToU1(false, out overflowed), CilCode.Conv_Ovf_U1_Un => value.ConvertToU1(true, out overflowed), CilCode.Conv_I2 => value.ConvertToI2(false, out _), CilCode.Conv_Ovf_I2 => value.ConvertToI2(false, out overflowed), CilCode.Conv_Ovf_I2_Un => value.ConvertToI2(true, out overflowed), CilCode.Conv_U2 => value.ConvertToU2(false, out _), CilCode.Conv_Ovf_U2 => value.ConvertToU2(false, out overflowed), CilCode.Conv_Ovf_U2_Un => value.ConvertToU2(true, out overflowed), CilCode.Conv_I4 => value.ConvertToI4(false, out _), CilCode.Conv_Ovf_I4 => value.ConvertToI4(false, out overflowed), CilCode.Conv_Ovf_I4_Un => value.ConvertToI4(true, out overflowed), CilCode.Conv_U4 => value.ConvertToU4(false, out _), CilCode.Conv_Ovf_U4 => value.ConvertToU4(false, out overflowed), CilCode.Conv_Ovf_U4_Un => value.ConvertToU4(true, out overflowed), CilCode.Conv_I8 => value.ConvertToI8(false, out _), CilCode.Conv_Ovf_I8 => value.ConvertToI8(false, out overflowed), CilCode.Conv_Ovf_I8_Un => value.ConvertToI8(true, out overflowed), CilCode.Conv_U8 => value.ConvertToU8(false, out _), CilCode.Conv_Ovf_U8 => value.ConvertToU8(false, out overflowed), CilCode.Conv_Ovf_U8_Un => value.ConvertToU8(true, out overflowed), CilCode.Conv_I => value.ConvertToI(environment.Is32Bit, false, out _), CilCode.Conv_Ovf_I => value.ConvertToI(environment.Is32Bit, false, out overflowed), CilCode.Conv_Ovf_I_Un => value.ConvertToI(environment.Is32Bit, true, out overflowed), CilCode.Conv_U => value.ConvertToU(environment.Is32Bit, false, out _), CilCode.Conv_Ovf_U => value.ConvertToU(environment.Is32Bit, false, out overflowed), CilCode.Conv_Ovf_U_Un => value.ConvertToU(environment.Is32Bit, true, out overflowed), CilCode.Conv_R4 => value.ConvertToR4(), CilCode.Conv_R8 => value.ConvertToR8(), CilCode.Conv_R_Un => value.ConvertToR(), _ => throw new ArgumentOutOfRangeException() }; if (overflowed) { return(new DispatchResult(new OverflowException())); } context.ProgramState.Stack.Push(newValue); return(base.Execute(context, instruction)); } }
/// <inheritdoc /> public override Trilean VerifyCondition(CilExecutionContext context, CilInstruction instruction) { var(left, right) = BinaryOperationHelper.PeekBinaryOperationArguments(context); return((left, right) switch { (IntegerValue a, IntegerValue b) => VerifyCondition(context, instruction, a, b), (FValue a, FValue b) => VerifyCondition(context, instruction, a, b), (OValue a, OValue b) => VerifyCondition(context, instruction, a, b), _ => Trilean.Unknown, });
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var type = instruction.Operand as ITypeDefOrRef; var environment = context.GetService <ICilRuntimeEnvironment>(); var allocator = environment.ValueFactory; var layout = allocator.GetTypeMemoryLayout(type); context.ProgramState.Stack.Push(new I4Value((int)layout.Size)); return(base.Execute(context, instruction)); }
/// <inheritdoc /> public DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var(left, right) = BinaryOperationHelper.PopBinaryOperationArguments(context); var result = (left, right) switch { (IntegerValue a, IntegerValue b) => Execute(context, instruction, a, b), (FValue a, FValue b) => Execute(context, instruction, a, b), (OValue a, OValue b) => Execute(context, instruction, a, b), _ => DispatchResult.InvalidProgram(), };
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var type = (ITypeDefOrRef)instruction.Operand; var memoryLayout = context.GetService <ICilRuntimeEnvironment>().ValueFactory.GetTypeMemoryLayout(type); var sourceAddress = context.ProgramState.Stack.Pop(); var destinationAddress = context.ProgramState.Stack.Pop(); switch (destinationAddress) { case { IsKnown: false } :
/// <inheritdoc /> public override DispatchResult Execute(CilExecutionContext context, CilInstruction instruction) { var environment = context.GetService <ICilRuntimeEnvironment>(); var referencedField = (IFieldDescriptor)instruction.Operand; var staticField = environment.StaticFieldFactory.Get(referencedField); var value = environment.CliMarshaller.ToCliValue(staticField.Value, referencedField.Signature.FieldType); context.ProgramState.Stack.Push(value); return(base.Execute(context, instruction)); }