/// <summary> /// Returns a variable Expression with the input value, which represents the variable /// corresponding to the input operand. /// </summary> /// /// <param name="operand">Operand for the variable Expression.</param> /// <param name="value">Value of the variable Expression.</param> /// <param name="path">Path that contains the operand.</param> /// <returns>Variable Expression with value <paramref name="value"/>, /// which represents the operand <paramref name="operand"/>.</returns> public static Expression MakeVariableExpression(Phx.IR.Operand operand, string value, Path path) { uint nativeWordBitSize = path.Config.WORD_BITSIZE; Expression result = null; /* Find the type of this variable, if the operand is not an address, or * the type of the variable the operand refers to, otherwise. */ Phx.Types.Type variableType = operand.IsAddress ? operand.Type.AsPointerType.ReferentType : operand.Type; /* Add an identifier to the names of aggregate objects. */ value = variableType.IsAggregateType ? path.Config.IDENT_AGGREGATE + value : value; result = ExpressionHelper.IsPointerExpressionType(variableType) ? new Expression(OperatorStore.ArrayVariableOp, value, nativeWordBitSize) : new Expression(OperatorStore.VariableOp, value, operand.IsAggregate ? nativeWordBitSize : operand.BitSize); result.Type = variableType; /* Replace a pointer Expression with the corresponding "dereferencing function". */ result = ExpressionHelper.IsPointerExpression(result) ? ExpressionHelper.MakeDereferencingFunction(result, path) : result; /* If the operand uses the address of an existing variable, determine if there * is already a temporary pointer that points to this "address-taken" variable. * If not, make a new temporary pointer that points to this variable. */ if (operand.IsAddress) { if (path.AddressTaken.ContainsKey(result)) { result = path.AddressTaken[result].Clone(); } else { Phx.Types.Type referentType = ExpressionHelper.GetPointerReferentType(operand.Type); /* Determine the basic block that contains the operand and the associated * information. */ BasicBlock operandBasicBlock = operand.Instruction.BasicBlock; BasicBlockAddendum operandBasicBlockAddendum = operandBasicBlock.FindExtensionObject(typeof(BasicBlockAddendum)) as BasicBlockAddendum; /* Generate a new temporary pointer and log the relationship between * the temporary pointer and the "address-taken" variable. */ Expression newTempPtr = path.GetNewTemporaryPointer(operand.Type); path.AddressTaken[result] = newTempPtr; /* Generate and log the assignment between the dereferenced temporary pointer * and the "address-taken" variable. This way, the generated SMT queries will * never have to use the Address-Of operator. */ Expression dereferencedNewTempPtr = ExpressionHelper.DereferencePointer(newTempPtr, operand.Type, false, path); List <Expression> assignExprs = path.GenerateAndLogAssignment(dereferencedNewTempPtr, result, operandBasicBlock); /* Add the conditional Expressions that correspond to this new assignment. */ foreach (Expression assignExpr in assignExprs) { path.AddCondition(assignExpr, operandBasicBlock.Id); } result = newTempPtr; } } /* If the variable is an "address-taken" variable, which means that its address * has been taken before, then we replace the variable with a dereference of * the temporary pointer that refers to the variable. */ if (path.AddressTaken.ContainsKey(result)) { result = ExpressionHelper.DereferencePointer(path.AddressTaken[result], operand.Type, false, path); } path.AddVariable(result); return(result); }
/// <summary> /// Traces the definition of the operands occurring in the input value instruction /// backward and returns the source-level symbolic Expression that corresponds /// to the instruction. /// </summary> /// /// <param name="valueInstruction">Value instruction.</param> /// <param name="varOperand">Current variable operand whose definition /// is being traced.</param> /// <param name="completeTrace">True, if non-temporary variables should be traced /// all the way back; false, otherwise. This flag is set to false when generating /// conditions, but true when collecting assignments; in the former, we only need /// the variable names being assigned to, whereas in the latter, we need the actual /// assignment on the right-hand side traced back completely.</param> /// <param name="path">Path along which to trace the definition.</param> /// <returns>Symbolic Expression that corresponds to the input instruction.</returns> public static Expression ExecuteValueInstructionBackward(ValueInstruction valueInstruction, Operand varOperand, bool completeTrace, Path path) { Expression result = null; Operand destOperand = valueInstruction.DestinationOperand; /* IR instructions that assign to temporary variables should be completely executed * backward. Other assignments are actual assignments in the source code. */ if (!completeTrace && !destOperand.IsTemporary) { return((destOperand.IsMemoryOperand) ? TraceMemoryOperandBackward(destOperand, varOperand, path) : PhoenixHelper.MakeVariableExpression(destOperand, PhoenixHelper.GetOperandName(destOperand), path)); } /* We will be using the first and second operands considerably. We determine what * they are before entering the switch-case statement, to keep the code efficient * and clean. */ List <Operand> srcOperands = new List <Operand>(); List <Expression> srcExprs = new List <Expression>(); foreach (Operand srcOperand in valueInstruction.SourceOperands) { srcOperands.Add(srcOperand); srcExprs.Add(TraceOperandBackward(srcOperand, varOperand, path)); } switch (valueInstruction.Opcode.Id) { case Phx.Common.Opcode.Index.Parenthesis: result = srcExprs[0]; break; case Phx.Common.Opcode.Index.Add: result = new Expression(OperatorStore.AddOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.Subtract: result = new Expression(OperatorStore.SubOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.Multiply: result = new Expression(OperatorStore.MultOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.Divide: /* Perform signed division only if the two operands are signed integers. */ Operator divOpToUse = (srcExprs[0].Type.IsSignedInt && srcExprs[1].Type.IsSignedInt) ? OperatorStore.SDivOp : OperatorStore.UDivOp; result = new Expression(divOpToUse, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.Remainder: result = new Expression(OperatorStore.RemOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.Assign: result = srcExprs[0]; break; case Phx.Common.Opcode.Index.Convert: /* This case implies a source-level cast. */ if (destOperand.IsPointer && srcOperands[0].IsPointer) { /* If a pointer to one type is cast to a pointer of another type, the size * of the pointer does not change. In this case, do not change the size * or the type of the source operand. */ result = srcExprs[0]; /* Return the result now so that its type does not get modified later in * this function to be that of the destination operand. */ return(result); } else { result = ExpressionHelper.AdjustBitSize(srcExprs[0], destOperand.BitSize, srcOperands[0].IsUnsignedInt, path); } break; case Phx.Common.Opcode.Index.Subscript: /* Dereference the first source Expression, which is a pointer Expression * that refers to the array whose element is being accessed. */ Expression arrayExpr = ExpressionHelper.DereferencePointer(srcExprs[0], ExpressionHelper.GetPointerReferentType(srcExprs[0]), true, path); /* Check if the dereferenced source Expression aliases another Expression. */ arrayExpr = path.FindAliasedExpression(arrayExpr); /* Determine the indices that are needed to access the array element * that the subscription Expression represents. */ List <Expression> accessIndexExprs = ExpressionHelper.GetArrayAccessIndices(arrayExpr, srcExprs.GetRange(1, srcExprs.Count - 1), path); /* Construct an Expression that refers to the array element that is * being accessed. This Expression will be dereferenced later. */ result = ExpressionHelper.GetArrayElementReference(arrayExpr, accessIndexExprs, path); /* Add conditions that enforce lower and upper bounds on the indices. */ List <int> upperBounds = ExpressionHelper.GetArrayIndicesUpperBounds(arrayExpr.Type, path); int currentBoundIndex = 0; foreach (Expression accessIndexExpr in accessIndexExprs) { Expression boundCondition = ExpressionHelper.AddBoundsOnIndex(accessIndexExpr, upperBounds[currentBoundIndex], path); path.AddCondition(boundCondition, valueInstruction.BasicBlock.Id); currentBoundIndex++; } break; case Phx.Common.Opcode.Index.ShiftLeft: result = new Expression(OperatorStore.ShiftLeftOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.ShiftRight: /* (From K&R): If the first Expression is an unsigned * integer, a logical right-shift is performed; * otherwise, an arithmetic right-shift is performed. */ Operator srOpToUse = srcExprs[0].Type.IsUnsignedInt ? OperatorStore.LShiftRightOp : OperatorStore.AShiftRightOp; result = new Expression(srOpToUse, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.BitAnd: result = new Expression(OperatorStore.BitAndOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.BitOr: result = new Expression(OperatorStore.BitOrOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.BitXor: result = new Expression(OperatorStore.BitXorOp, srcExprs[0], srcExprs[1], destOperand.BitSize); break; case Phx.Common.Opcode.Index.BitComplement: result = new Expression(OperatorStore.BitComplementOp, srcExprs[0], destOperand.BitSize); break; case Phx.Common.Opcode.Index.Not: List <Expression> paramList = new List <Expression>(); uint destBitSize = destOperand.BitSize; paramList.Add(new Expression(OperatorStore.EqualOp, srcExprs[0], new Constant(0, srcExprs[0].BitSize), path.Config.WORD_BITSIZE)); paramList.Add(new Constant(1, destBitSize)); paramList.Add(new Constant(0, destBitSize)); result = new Expression(OperatorStore.IteOp, paramList, destBitSize); break; case Phx.Common.Opcode.Index.Negate: result = new Expression(OperatorStore.NegateOp, srcExprs[0], destOperand.BitSize); break; case Phx.Common.Opcode.Index.Acquire: // TODO: We have not implemented complete support for this type of instruction. result = new Expression(OperatorStore.AcquireOp); break; case Phx.Common.Opcode.Index.Release: result = srcExprs[0]; break; case Phx.Common.Opcode.Index.Chi: default: throw new NotImplementedException("PHOENIX: " + "Value Instruction Opcode not implemented in symbolic tracer: " + valueInstruction.OpcodeToString()); } if (destOperand.IsPointer) { /* The operand that is being traced is a pointer. This implies that the result * is at least a pointer Expression (or equivalently, a "dereferencing function" * Expression), perhaps offset by a byte offset Expression. Add this offset to * the pointer Expression. */ Pair <Expression, Expression> baseAndOffset = ExpressionHelper.GetAugendAndAddend(result, path); Expression baseExpr = baseAndOffset.First, offsetExpr = baseAndOffset.Second; if (!srcOperands[0].IsTemporary) { /* Check if the base Expression is an alias for another Expression, but only * if the base Expression results from tracing back a non-temporary operand. * We do not need to check if an Expression that results from tracing * a temporary operand back is an alias: this check would have already * happened, since the process of tracing back a temporary operand should * eventually find (and trace back) a non-temporary operand. * * Also, checking if an Expression is an alias for another Expression * is not an idempotent operation, so it should be done sparingly. */ baseExpr = path.FindAliasedExpression(baseExpr); } Phx.Types.Type referentType = ExpressionHelper.GetPointerReferentType(destOperand.Type); if (referentType.IsUnmanagedArrayType) { Expression modifiedOffsetExpr = new Expression(OperatorStore.MultOp, offsetExpr, new Constant(referentType.BitSize, offsetExpr.BitSize), offsetExpr.BitSize); modifiedOffsetExpr.Type = offsetExpr.Type; offsetExpr = ExpressionHelper.SimplifyExpression(modifiedOffsetExpr, path); } Expression offsetBitsExpr = ExpressionHelper.ConvertToBits(offsetExpr, path); result = ExpressionHelper.AddOffsetToPointer(baseExpr, offsetBitsExpr, path); } result.Type = destOperand.Type; return(result); }