/// <summary> /// Returns a <see cref="Call"/> instruction denoting either the beginning or end of a /// program section guarded by a monitor, depending on whether the locked attribute is /// respectively set or deleted. /// </summary> /// <param name="setLockedAttribute"></param> /// <param name="paramCount"></param> /// <param name="state"></param> /// <returns></returns> private static Call CreateLockedAttributeCall( bool setLockedAttribute, int paramCount, ProgramState state) { var returnIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var callFlags = new Call.CallFlags(isVirtual: false, noReturn: false, isObjCBlock: false); // There are up to two arguments (monitor object and a boolean indicating the result of // the attempt to acquire the lock, passed by reference), but the latter need only be // removed from the stack without being reflected in the translation. var arg = state.PopMany(paramCount).First(); var callArgs = new List <Call.CallArg> { new Call.CallArg(arg.Item1, arg.Item2) }; return(setLockedAttribute ? new Call(returnIdentifier, new Tvoid(), new ConstExpression( ProcedureName.BuiltIn__set_locked_attribute), callArgs, callFlags, state.CurrentLocation) : new Call(returnIdentifier, new Tvoid(), new ConstExpression( ProcedureName. BuiltIn__delete_locked_attribute), callArgs, callFlags, state.CurrentLocation)); }
/// <summary> /// Creates a <see cref="CfgNode"/> containing instructions for memory allocation as well /// as constructor invocation. /// </summary> /// <param name="type">The SIL type to be allocate memory for.</param> /// <param name="state">Current program state.</param> /// <returns>Node with the object allocation instructions, as well as the variable which /// represents the new object.</returns> protected static (CfgNode, VarExpression) CreateObjectAllocationNode(Tptr type, ProgramState state) { var typeName = type.StripPointer().ToString(); var newObjectIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var newObjectVariable = new VarExpression(newObjectIdentifier); var callFlags = new Call.CallFlags(isVirtual: false, noReturn: false, isObjCBlock: false); var objectAllocationCall = new Call(newObjectIdentifier, type, new ConstExpression(ProcedureName.BuiltIn__new), new List <Call.CallArg> { new Call.CallArg( new SizeofExpression( type.StripPointer(), SizeofExpression.SizeofExpressionKind.exact), type) }, callFlags, state.CurrentLocation); var objectConstructorCall = new Call(state.GetIdentifier(Identifier.IdentKind.Normal), new Tvoid(), new ConstExpression(new ProcedureName(".ctor", new List <string>(), typeName, "System.Void", false)), new List <Call.CallArg> { new Call.CallArg(newObjectVariable, type) }, callFlags, state.CurrentLocation); var node = new StatementNode(state.CurrentLocation, StatementNode.StatementNodeKind.Call, state.ProcDesc, comment: $"System.Void {typeName}::.ctor()"); node.Instructions.Add(objectAllocationCall); node.Instructions.Add(objectConstructorCall); return(node, newObjectVariable); }
/// <summary> /// Creates and returns a <see cref="Call"/> instruction indicating object memory /// allocation and the temporary identifier for the new object. Examples of CIL /// instructions for which this method is used include initobj and newobj. /// </summary> /// <param name="newObjectReference">The type to be allocated.</param> /// <param name="state">Current program state.</param> /// <returns>Instruction representing the memory allocation, as well as the identifier for /// the new object.</returns> protected static (Call, VarExpression) CreateMemoryAllocationCall( TypeReference newObjectReference, ProgramState state) { var type = Typ.FromTypeReference(newObjectReference); var newObjectIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var callFlags = new Call.CallFlags(isVirtual: false, noReturn: false, isObjCBlock: false); var args = new List <Call.CallArg> { new Call.CallArg(new SizeofExpression(type.StripPointer(), "exact"), type) }; return(new Call(newObjectIdentifier, type, new ConstExpression(ProcedureName.BuiltIn__new), args, callFlags, state.CurrentLocation), new VarExpression(newObjectIdentifier)); }
/// <summary> /// Creates a method call returned via out parameter. /// </summary> /// <param name="state">Current program state.</param> /// <param name="isVirtual">True if method call is virtual, false otherwise.</param> /// <param name="calledMethod">The method being called.</param> /// <param name="returnType">The return type of the method being called.</param> /// <param name="returnVariable">Identifies the variable returned by the method.</param> /// <param name="callArgs">The method arguments.</param> /// <param name="methodCall">The Call SIL instruction.</param> /// <param name="isConstructorCall"><c>true</c> if the call is for a constructor, /// <c>false</c> otherwise.</param> protected static void CreateMethodCall(ProgramState state, bool isVirtual, MethodReference calledMethod, out TypeReference returnType, out Identifier returnVariable, out List <Call.CallArg> callArgs, out Call methodCall, bool isConstructorCall = false) { callArgs = new List <Call.CallArg>(); returnType = calledMethod.ReturnType; var paramCount = calledMethod.Parameters.Count; if (calledMethod.HasThis) { paramCount++; } if (isConstructorCall) { // In this case, the "this" argument of the constructor is located at the top of // the stack; we remove it and place it at the front of the argument list. (var thisExpr, var thisType) = state.Pop(); callArgs.Add(new Call.CallArg(thisExpr, thisType)); paramCount--; } var funcExp = new ConstExpression(new ProcedureName(calledMethod)); callArgs.AddRange(state.PopMany(paramCount) .Select(p => new Call.CallArg(p.Item1, p.Item2)) .ToList()); var callFlags = new Call.CallFlags(isVirtual, false, false); returnVariable = state.GetIdentifier(Identifier.IdentKind.Normal); methodCall = new Call(returnId: returnVariable, returnType: Typ.FromTypeReference(returnType), functionExpression: funcExp, args: callArgs, flags: callFlags, location: state.CurrentLocation); }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { switch (instruction.OpCode.Code) { case Code.Box: (var value, var type) = state.Pop(); var boxedValueIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var boxedObjectVariable = new VarExpression(boxedValueIdentifier); var boxedObjectType = new BoxedValueType(Tptr.PtrKind.Pk_pointer, new Tstruct("System.Object"), value, type); var callFlags = new Call.CallFlags(false, false, false); // The value in question is boxed into a generic object. var objectAllocationCall = new Call(boxedValueIdentifier, boxedObjectType, new ConstExpression(ProcedureName.BuiltIn__new), new List <Call.CallArg> { new Call.CallArg( new SizeofExpression( boxedObjectType.StripPointer(), "exact"), boxedObjectType) }, callFlags, state.CurrentLocation); var objectConstructorCall = new Call(state.GetIdentifier(Identifier.IdentKind.Normal), new Tvoid(), new ConstExpression(new ProcedureName(".ctor", new List <string>(), "System.Object", "System.Void", false)), new List <Call.CallArg> { new Call.CallArg(boxedObjectVariable, boxedObjectType) }, callFlags, state.CurrentLocation); var node = new StatementNode(state.CurrentLocation, StatementNode.StatementNodeKind.Call, state.ProcDesc, comment: "System.Void System.Object::.ctor()"); node.Instructions.Add(objectAllocationCall); node.Instructions.Add(objectConstructorCall); RegisterNode(state, node); state.PushExpr(boxedObjectVariable, boxedObjectType); state.PushInstruction(instruction.Next, node); state.AppendToPreviousNode = true; return(true); default: return(false); } }