Beispiel #1
0
        /// <summary>
        /// Creates a variable that corresponds to the input call instruction.
        /// </summary>
        ///
        /// <param name="operand">Operand whose definition needs to be traced.</param>
        /// <param name="callInstruction">Call instruction.</param>
        /// <param name="varOperand">Current variable operand whose definition
        /// is being traced, which may be different from "operand".</param>
        /// <param name="path">Path along which to trace the definition.</param>
        ///
        /// <returns>Variable Expression corresponding to the call instruction provided.</returns>
        public static Expression MakeCallVariableExpression(Operand operand,
                                                            Instruction callInstruction, Operand varOperand, Path path)
        {
            string funcName   = PhoenixHelper.GetOperandName(callInstruction.SourceOperand1);
            string lineNumber = callInstruction.GetLineNumber().ToString();

            return(PhoenixHelper.MakeVariableExpression(operand,
                                                        (path.Config.IDENT_EFC + funcName + "@" + lineNumber), path));
        }
Beispiel #2
0
        /// <summary>
        /// Traces the definition of the operands occurring in the input special instruction
        /// backward and returns the source-level symbolic Expression that corresponds
        /// to the instruction.
        /// </summary>
        ///
        /// <param name="operand">Operand whose definition needs to be traced.</param>
        /// <param name="specialInstruction">Special instruction.</param>
        /// <param name="varOperand">Current variable operand whose definition
        /// is being traced.</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 ExecuteSpecialInstructionBackward(Operand operand,
                                                                   Instruction specialInstruction, Operand varOperand, Path path)
        {
            Expression result = null;

            switch (specialInstruction.Opcode.Id)
            {
            case Phx.Common.Opcode.Index.EnterFunction:
            case Phx.Common.Opcode.Index.Start:
                result = PhoenixHelper.MakeVariableExpression(operand,
                                                              PhoenixHelper.GetOperandName(operand), path);
                break;

            case Phx.Common.Opcode.Index.Phi:
                BasicBlock nearestBlock = path.SourceBlock;
                foreach (Operand sourceOperand in specialInstruction.SourceOperands)
                {
                    if (sourceOperand.DefinitionInstruction != null)
                    {
                        BasicBlock defBlock = sourceOperand.DefinitionInstruction.BasicBlock;
                        if (path.Blocks.Contains(defBlock) &&
                            path.IsLocatedAfter(defBlock, nearestBlock))
                        {
                            nearestBlock = defBlock;

                            Operand actualVarOperand =
                                operand.IsTemporary ? varOperand : operand;
                            actualVarOperand =
                                sourceOperand.IsTemporary ? actualVarOperand : sourceOperand;

                            result = TraceOperandBackward(sourceOperand,
                                                          actualVarOperand, path);
                        }
                    }
                }
                break;

            case Phx.Common.Opcode.Index.Label:
                break;

            default:
                throw new NotImplementedException("ExecuteSpecialInstructionBackward: " +
                                                  "Special Instruction Opcode not implemented in symbolic tracer: " +
                                                  specialInstruction.OpcodeToString());
            }

            return(result);
        }
Beispiel #3
0
        /// <summary>
        /// Traces the definition of the input operand and returns its symbolic
        /// Expression at the source level.
        /// </summary>
        ///
        /// <param name="operand">Operand whose definition needs to be traced.</param>
        /// <param name="varOperand">Current variable operand whose definition is being traced,
        /// which may be different from <paramref name="operand"/>.</param>
        /// <param name="path">Path along which to trace the definition.</param>
        ///
        /// <returns>Symbolic Expression that corresponds to the input operand.</returns>
        /// <remarks>Precondition: <paramref name="operand"/> and <paramref name="varOperand"/>
        /// are not null.</remarks>
        /// <remarks>Postcondition: The resulting Expression is not null.</remarks>
        public static Expression TraceOperandBackward(Operand operand,
                                                      Operand varOperand, Path path)
        {
            Trace.Assert(operand != null, "PHOENIX: operand cannot be null.");
            Trace.Assert(varOperand != null, "PHOENIX: varOperand cannot be null.");

            if (path.ProjectConfig.debugConfig.DUMP_INSTRUCTION_TRACE)
            {
                Console.Out.WriteLine();
                Console.Out.WriteLine(operand.Instruction.ToString());
                Console.Out.WriteLine("{ Exploring " + operand +
                                      " while converting " + varOperand);
            }

            Expression result = null;

            if (path.OperandExpressions.ContainsKey(operand))
            {
                result = path.OperandExpressions[operand].Clone();
                if (path.ProjectConfig.debugConfig.DUMP_INSTRUCTION_TRACE)
                {
                    Console.Out.WriteLine("  Memoization provides the result.");
                    Console.Out.WriteLine("  Result is " + result + " }");
                }
                return(result);
            }

            Instruction defInstruction = operand.DefinitionInstruction;

            if (operand.IsImmediateOperand)
            {
                string opValue = "";

                ImmediateOperand immOperand = operand.AsImmediateOperand;
                if (immOperand.Value.IsIntValue)
                {
                    opValue = immOperand.IntValue.ToString();
                }
                else if (immOperand.Value.IsFloatValue)
                {
                    double floatValue = immOperand.FloatValue64;
                    long   longValue  = Convert.ToInt64(floatValue);
                    Console.Out.WriteLine("PHOENIX: WARNING: Floating point constant " +
                                          "discovered during backward symbolic execution: " + floatValue + ". " +
                                          "It will be cast to the integer " + longValue + ".");
                    opValue = longValue.ToString();
                }
                else
                {
                    throw new NotSupportedException("PHOENIX: " +
                                                    "Support for this type of immediate operand not implemented.");
                }

                result      = new Constant(opValue, operand.BitSize);
                result.Type = operand.Type;
            }
            else if (operand.IsMemoryOperand)
            {
                /* This case implies a source-level dereference. */
                result = TraceMemoryOperandBackward(operand, varOperand, path);
            }
            else if ((defInstruction != null) &&
                     (defInstruction.Opcode.Id == Phx.Common.Opcode.Index.Chi) &&
                     (defInstruction.SourceOperand1.DefinitionInstruction.Opcode.Id ==
                      Phx.Common.Opcode.Index.Start))
            {
                result = PhoenixHelper.MakeVariableExpression(operand,
                                                              PhoenixHelper.GetOperandName(operand), path);
            }
            else if (defInstruction == null)
            {
                /* We are tracing a global operand. */
                result = PhoenixHelper.MakeVariableExpression(operand,
                                                              PhoenixHelper.GetOperandName(operand), path);
            }
            else if (!path.Blocks.Contains(defInstruction.BasicBlock))
            {
                result = PhoenixHelper.MakeVariableExpression(operand,
                                                              PhoenixHelper.GetOperandName(operand), path);
            }
            else
            {
                switch (defInstruction.InstructionKind)
                {
                case InstructionKind.ValueInstruction:
                    ValueInstruction valueInstruction = defInstruction.AsValueInstruction;
                    result =
                        ExecuteValueInstructionBackward(valueInstruction,
                                                        varOperand, false, path);
                    break;

                case InstructionKind.CallInstruction:
                    result =
                        PhoenixHelper.MakeCallVariableExpression(operand, defInstruction,
                                                                 varOperand, path);
                    break;

                case InstructionKind.CompareInstruction:
                    CompareInstruction compareInstruction =
                        defInstruction.AsCompareInstruction;
                    result =
                        ExecuteComparisonInstructionBackward(compareInstruction,
                                                             varOperand, path);
                    break;

                default:
                    result =
                        ExecuteSpecialInstructionBackward(operand, defInstruction,
                                                          varOperand, path);
                    break;
                }
            }

            Trace.Assert(result != null, "PHOENIX: Result Expression should not be null.");
            Trace.Assert(result.Type != null, "PHOENIX: Result Expression should have a type.");

            if (path.ProjectConfig.debugConfig.DUMP_INSTRUCTION_TRACE)
            {
                Console.Out.WriteLine("  Result is " + result + " }");
            }

            /* Remember the result for later, in case it is ever needed. */
            path.OperandExpressions[operand] = result;
            return(result);
        }
Beispiel #4
0
        /// <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);
        }