//===-- Executor.h ----------------------------------------------*- C++ -*-===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Class to perform actual execution, hides implementation details from external // interpreter. // //===----------------------------------------------------------------------===// #ifndef KLEE_EXECUTOR_H #define KLEE_EXECUTOR_H #include "klee/ExecutionState.h" #include "klee/Expr/ArrayCache.h" #include "klee/Internal/Module/Cell.h" #include "klee/Internal/Module/KInstruction.h" #include "klee/Internal/Module/KModule.h" #include "klee/Internal/System/Time.h" #include "klee/Interpreter.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" #include "../Expr/ArrayExprOptimizer.h" #include #include #include #include #include struct KTest; namespace llvm { class BasicBlock; class BranchInst; class CallInst; class Constant; class ConstantExpr; class Function; class GlobalValue; class Instruction; class LLVMContext; class DataLayout; class Twine; class Value; } namespace klee { class Array; struct Cell; class ExecutionState; class ExternalDispatcher; class Expr; class InstructionInfoTable; struct KFunction; struct KInstruction; class KInstIterator; class KModule; class MemoryManager; class MemoryObject; class ObjectState; class PTree; class Searcher; class SeedInfo; class SpecialFunctionHandler; struct StackFrame; class StatsTracker; class TimingSolver; class TreeStreamWriter; class MergeHandler; template class ref; /// \todo Add a context object to keep track of data only live /// during an instruction step. Should contain addedStates, /// removedStates, and haltExecution, among others. class Executor : public Interpreter { friend class RandomPathSearcher; friend class OwningSearcher; friend class WeightedRandomSearcher; friend class SpecialFunctionHandler; friend class StatsTracker; friend class MergeHandler; friend class MergingSearcher; public: typedef std::pair StatePair; enum TerminateReason { Abort, Assert, BadVectorAccess, Exec, External, Free, Model, Overflow, Ptr, ReadOnly, ReportError, User, Unhandled }; private: static const char *TerminateReasonNames[]; std::unique_ptr kmodule; InterpreterHandler *interpreterHandler; Searcher *searcher; ExternalDispatcher *externalDispatcher; TimingSolver *solver; MemoryManager *memory; std::set states; StatsTracker *statsTracker; TreeStreamWriter *pathWriter, *symPathWriter; SpecialFunctionHandler *specialFunctionHandler; TimerGroup timers; std::unique_ptr processTree; /// Keeps track of all currently ongoing merges. /// An ongoing merge is a set of states which branched from a single state /// which ran into a klee_open_merge(), and not all states in the set have /// reached the corresponding klee_close_merge() yet. std::vector mergeGroups; /// ExecutionStates currently paused from scheduling because they are /// waiting to be merged in a klee_close_merge instruction std::set inCloseMerge; /// Used to track states that have been added during the current /// instructions step. /// \invariant \ref addedStates is a subset of \ref states. /// \invariant \ref addedStates and \ref removedStates are disjoint. std::vector addedStates; /// Used to track states that have been removed during the current /// instructions step. /// \invariant \ref removedStates is a subset of \ref states. /// \invariant \ref addedStates and \ref removedStates are disjoint. std::vector removedStates; /// Used to track states that are not terminated, but should not /// be scheduled by the searcher. std::vector pausedStates; /// States that were 'paused' from scheduling, that now may be /// scheduled again std::vector continuedStates; /// When non-empty the Executor is running in "seed" mode. The /// states in this map will be executed in an arbitrary order /// (outside the normal search interface) until they terminate. When /// the states reach a symbolic branch then either direction that /// satisfies one or more seeds will be added to this map. What /// happens with other states (that don't satisfy the seeds) depends /// on as-yet-to-be-determined flags. std::map > seedMap; /// Map of globals to their representative memory object. std::map globalObjects; /// Map of globals to their bound address. This also includes /// globals that have no representative object (i.e. functions). std::map > globalAddresses; /// The set of legal function addresses, used to validate function /// pointers. We use the actual Function* address as the function address. std::set legalFunctions; /// When non-null the bindings that will be used for calls to /// klee_make_symbolic in order replay. const struct KTest *replayKTest; /// When non-null a list of branch decisions to be used for replay. const std::vector *replayPath; /// The index into the current \ref replayKTest or \ref replayPath /// object. unsigned replayPosition; /// When non-null a list of "seed" inputs which will be used to /// drive execution. const std::vector *usingSeeds; /// Disables forking, instead a random path is chosen. Enabled as /// needed to control memory usage. \see fork() bool atMemoryLimit; /// Disables forking, set by client. \see setInhibitForking() bool inhibitForking; /// Signals the executor to halt execution at the next instruction /// step. bool haltExecution; /// Whether implied-value concretization is enabled. Currently /// false, it is buggy (it needs to validate its writes). bool ivcEnabled; /// The maximum time to allow for a single core solver query. /// (e.g. for a single STP query) time::Span coreSolverTimeout; /// Maximum time to allow for a single instruction. time::Span maxInstructionTime; /// Assumes ownership of the created array objects ArrayCache arrayCache; /// File to print executed instructions to std::unique_ptr debugInstFile; // @brief Buffer used by logBuffer std::string debugBufferString; // @brief buffer to store logs before flushing to file llvm::raw_string_ostream debugLogBuffer; /// Optimizes expressions ExprOptimizer optimizer; llvm::Function* getTargetFunction(llvm::Value *calledVal, ExecutionState &state); void executeInstruction(ExecutionState &state, KInstruction *ki); void run(ExecutionState &initialState); // Given a concrete object in our [klee's] address space, add it to // objects checked code can reference. MemoryObject *addExternalObject(ExecutionState &state, void *addr, unsigned size, bool isReadOnly); void initializeGlobalObject(ExecutionState &state, ObjectState *os, const llvm::Constant *c, unsigned offset); void initializeGlobals(ExecutionState &state); void stepInstruction(ExecutionState &state); void updateStates(ExecutionState *current); void transferToBasicBlock(llvm::BasicBlock *dst, llvm::BasicBlock *src, ExecutionState &state); void callExternalFunction(ExecutionState &state, KInstruction *target, llvm::Function *function, std::vector< ref > &arguments); ObjectState *bindObjectInState(ExecutionState &state, const MemoryObject *mo, bool isLocal, const Array *array = 0); /// Resolve a pointer to the memory objects it could point to the /// start of, forking execution when necessary and generating errors /// for pointers to invalid locations (either out of bounds or /// address inside the middle of objects). /// /// \param results[out] A list of ((MemoryObject,ObjectState), /// state) pairs for each object the given address can point to the /// beginning of. typedef std::vector< std::pair, ExecutionState*> > ExactResolutionList; void resolveExact(ExecutionState &state, ref p, ExactResolutionList &results, const std::string &name); /// Allocate and bind a new object in a particular state. NOTE: This /// function may fork. /// /// \param isLocal Flag to indicate if the object should be /// automatically deallocated on function return (this also makes it /// illegal to free directly). /// /// \param target Value at which to bind the base address of the new /// object. /// /// \param reallocFrom If non-zero and the allocation succeeds, /// initialize the new object from the given one and unbind it when /// done (realloc semantics). The initialized bytes will be the /// minimum of the size of the old and new objects, with remaining /// bytes initialized as specified by zeroMemory. /// /// \param allocationAlignment If non-zero, the given alignment is /// used. Otherwise, the alignment is deduced via /// Executor::getAllocationAlignment void executeAlloc(ExecutionState &state, ref size, bool isLocal, KInstruction *target, bool zeroMemory=false, const ObjectState *reallocFrom=0, size_t allocationAlignment=0); /// Free the given address with checking for errors. If target is /// given it will be bound to 0 in the resulting states (this is a /// convenience for realloc). Note that this function can cause the /// state to fork and that \ref state cannot be safely accessed /// afterwards. void executeFree(ExecutionState &state, ref address, KInstruction *target = 0); void executeCall(ExecutionState &state, KInstruction *ki, llvm::Function *f, std::vector< ref > &arguments); // do address resolution / object binding / out of bounds checking // and perform the operation void executeMemoryOperation(ExecutionState &state, bool isWrite, ref address, ref value /* undef if read */, KInstruction *target /* undef if write */); void executeMakeSymbolic(ExecutionState &state, const MemoryObject *mo, const std::string &name); /// Create a new state where each input condition has been added as /// a constraint and return the results. The input state is included /// as one of the results. Note that the output vector may included /// NULL pointers for states which were unable to be created. void branch(ExecutionState &state, const std::vector< ref > &conditions, std::vector &result); // Fork current and return states in which condition holds / does // not hold, respectively. One of the states is necessarily the // current state, and one of the states may be null. StatePair fork(ExecutionState ¤t, ref condition, bool isInternal); /// Add the given (boolean) condition as a constraint on state. This /// function is a wrapper around the state's addConstraint function /// which also manages propagation of implied values, /// validity checks, and seed patching. void addConstraint(ExecutionState &state, ref condition); // Called on [for now] concrete reads, replaces constant with a symbolic // Used for testing. ref replaceReadWithSymbolic(ExecutionState &state, ref e); const Cell& eval(KInstruction *ki, unsigned index, ExecutionState &state) const; Cell& getArgumentCell(ExecutionState &state, KFunction *kf, unsigned index) { return state.stack.back().locals[kf->getArgRegister(index)]; } Cell& getDestCell(ExecutionState &state, KInstruction *target) { return state.stack.back().locals[target->dest]; } void bindLocal(KInstruction *target, ExecutionState &state, ref value); void bindArgument(KFunction *kf, unsigned index, ExecutionState &state, ref value); /// Evaluates an LLVM constant expression. The optional argument ki /// is the instruction where this constant was encountered, or NULL /// if not applicable/unavailable. ref evalConstantExpr(const llvm::ConstantExpr *c, const KInstruction *ki = NULL); /// Evaluates an LLVM constant. The optional argument ki is the /// instruction where this constant was encountered, or NULL if /// not applicable/unavailable. ref evalConstant(const llvm::Constant *c, const KInstruction *ki = NULL); /// Return a unique constant value for the given expression in the /// given state, if it has one (i.e. it provably only has a single /// value). Otherwise return the original expression. ref toUnique(const ExecutionState &state, ref &e); /// Return a constant value for the given expression, forcing it to /// be constant in the given state by adding a constraint if /// necessary. Note that this function breaks completeness and /// should generally be avoided. /// /// \param purpose An identify string to printed in case of concretization. ref toConstant(ExecutionState &state, ref e, const char *purpose); /// Bind a constant value for e to the given target. NOTE: This /// function may fork state if the state has multiple seeds. void executeGetValue(ExecutionState &state, ref e, KInstruction *target); /// Get textual information regarding a memory address. std::string getAddressInfo(ExecutionState &state, ref address) const; // Determines the \param lastInstruction of the \param state which is not KLEE // internal and returns its InstructionInfo const InstructionInfo & getLastNonKleeInternalInstruction(const ExecutionState &state, llvm::Instruction** lastInstruction); bool shouldExitOn(enum TerminateReason termReason); // remove state from searcher only void pauseState(ExecutionState& state); // add state to searcher only void continueState(ExecutionState& state); // remove state from queue and delete void terminateState(ExecutionState &state); // call exit handler and terminate state void terminateStateEarly(ExecutionState &state, const llvm::Twine &message); // call exit handler and terminate state void terminateStateOnExit(ExecutionState &state); // call error handler and terminate state void terminateStateOnError(ExecutionState &state, const llvm::Twine &message, enum TerminateReason termReason, const char *suffix = NULL, const llvm::Twine &longMessage = ""); // call error handler and terminate state, for execution errors // (things that should not be possible, like illegal instruction or // unlowered instrinsic, or are unsupported, like inline assembly) void terminateStateOnExecError(ExecutionState &state, const llvm::Twine &message, const llvm::Twine &info="") { terminateStateOnError(state, message, Exec, NULL, info); } /// bindModuleConstants - Initialize the module constant table. void bindModuleConstants(); template void computeOffsets(KGEPInstruction *kgepi, TypeIt ib, TypeIt ie); /// bindInstructionConstants - Initialize any necessary per instruction /// constant values. void bindInstructionConstants(KInstruction *KI); void doImpliedValueConcretization(ExecutionState &state, ref e, ref value); void checkMemoryUsage(); void printDebugInstructions(ExecutionState &state); void doDumpStates(); /// Only for debug purposes; enable via debugger or klee-control void dumpStates(); void dumpPTree(); public: Executor(llvm::LLVMContext &ctx, const InterpreterOptions &opts, InterpreterHandler *ie); virtual ~Executor(); const InterpreterHandler& getHandler() { return *interpreterHandler; } void setPathWriter(TreeStreamWriter *tsw) override { pathWriter = tsw; } void setSymbolicPathWriter(TreeStreamWriter *tsw) override { symPathWriter = tsw; } void setReplayKTest(const struct KTest *out) override { assert(!replayPath && "cannot replay both buffer and path"); replayKTest = out; replayPosition = 0; } void setReplayPath(const std::vector *path) override { assert(!replayKTest && "cannot replay both buffer and path"); replayPath = path; replayPosition = 0; } llvm::Module *setModule(std::vector> &modules, const ModuleOptions &opts) override; void useSeeds(const std::vector *seeds) override { usingSeeds = seeds; } void runFunctionAsMain(llvm::Function *f, int argc, char **argv, char **envp) override; /*** Runtime options ***/ void setHaltExecution(bool value) override { haltExecution = value; } void setInhibitForking(bool value) override { inhibitForking = value; } void prepareForEarlyExit() override; /*** State accessor methods ***/ unsigned getPathStreamID(const ExecutionState &state) override; unsigned getSymbolicPathStreamID(const ExecutionState &state) override; void getConstraintLog(const ExecutionState &state, std::string &res, Interpreter::LogType logFormat = Interpreter::STP) override; bool getSymbolicSolution( const ExecutionState &state, std::vector>> &res) override; void getCoveredLines(const ExecutionState &state, std::map> &res) override; Expr::Width getWidthForLLVMType(llvm::Type *type) const; size_t getAllocationAlignment(const llvm::Value *allocSite) const; /// Returns the errno location in memory of the state int *getErrnoLocation(const ExecutionState &state) const; }; } // End klee namespace #endif /* KLEE_EXECUTOR_H */