//===-- Searcher.h ----------------------------------------------*- C++ -*-===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef KLEE_SEARCHER_H #define KLEE_SEARCHER_H #include #include #include #include // FIXME: Move out of header, use llvm streams. #include namespace llvm { class BasicBlock; class Function; class Instruction; } namespace klee { template class DiscretePDF; class ExecutionState; class Executor; class Searcher { public: virtual ~Searcher(); virtual ExecutionState &selectState() = 0; virtual void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates) = 0; virtual bool empty() = 0; // prints name of searcher as a klee_message() // TODO: could probably make prettier or more flexible virtual void printName(std::ostream &os) { os << "\n"; } // pgbovine - to be called when a searcher gets activated and // deactivated, say, by a higher-level searcher; most searchers // don't need this functionality, so don't have to override. virtual void activate() {} virtual void deactivate() {} // utility functions void addState(ExecutionState *es, ExecutionState *current = 0) { std::set tmp; tmp.insert(es); update(current, tmp, std::set()); } void removeState(ExecutionState *es, ExecutionState *current = 0) { std::set tmp; tmp.insert(es); update(current, std::set(), tmp); } enum CoreSearchType { DFS, RandomState, RandomPath, NURS_CovNew, NURS_MD2U, NURS_Depth, NURS_ICnt, NURS_CPICnt, NURS_QC }; }; class DFSSearcher : public Searcher { std::vector states; public: ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty() { return states.empty(); } void printName(std::ostream &os) { os << "DFSSearcher\n"; } }; class RandomSearcher : public Searcher { std::vector states; public: ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty() { return states.empty(); } void printName(std::ostream &os) { os << "RandomSearcher\n"; } }; class WeightedRandomSearcher : public Searcher { public: enum WeightType { Depth, QueryCost, InstCount, CPInstCount, MinDistToUncovered, CoveringNew }; private: Executor &executor; DiscretePDF *states; WeightType type; bool updateWeights; double getWeight(ExecutionState*); public: WeightedRandomSearcher(Executor &executor, WeightType type); ~WeightedRandomSearcher(); ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty(); void printName(std::ostream &os) { os << "WeightedRandomSearcher::"; switch(type) { case Depth : os << "Depth\n"; return; case QueryCost : os << "QueryCost\n"; return; case InstCount : os << "InstCount\n"; return; case CPInstCount : os << "CPInstCount\n"; return; case MinDistToUncovered : os << "MinDistToUncovered\n"; return; case CoveringNew : os << "CoveringNew\n"; return; default : os << "\n"; return; } } }; class RandomPathSearcher : public Searcher { Executor &executor; public: RandomPathSearcher(Executor &_executor); ~RandomPathSearcher(); ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty(); void printName(std::ostream &os) { os << "RandomPathSearcher\n"; } }; class MergingSearcher : public Searcher { Executor &executor; std::set statesAtMerge; Searcher *baseSearcher; llvm::Function *mergeFunction; private: llvm::Instruction *getMergePoint(ExecutionState &es); public: MergingSearcher(Executor &executor, Searcher *baseSearcher); ~MergingSearcher(); ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty() { return baseSearcher->empty() && statesAtMerge.empty(); } void printName(std::ostream &os) { os << "MergingSearcher\n"; } }; class BumpMergingSearcher : public Searcher { Executor &executor; std::map statesAtMerge; Searcher *baseSearcher; llvm::Function *mergeFunction; private: llvm::Instruction *getMergePoint(ExecutionState &es); public: BumpMergingSearcher(Executor &executor, Searcher *baseSearcher); ~BumpMergingSearcher(); ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty() { return baseSearcher->empty() && statesAtMerge.empty(); } void printName(std::ostream &os) { os << "BumpMergingSearcher\n"; } }; class BatchingSearcher : public Searcher { Searcher *baseSearcher; double timeBudget; unsigned instructionBudget; ExecutionState *lastState; double lastStartTime; unsigned lastStartInstructions; public: BatchingSearcher(Searcher *baseSearcher, double _timeBudget, unsigned _instructionBudget); ~BatchingSearcher(); ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty() { return baseSearcher->empty(); } void printName(std::ostream &os) { os << " timeBudget: " << timeBudget << ", instructionBudget: " << instructionBudget << ", baseSearcher:\n"; baseSearcher->printName(os); os << "\n"; } }; class IterativeDeepeningTimeSearcher : public Searcher { Searcher *baseSearcher; double time, startTime; std::set pausedStates; public: IterativeDeepeningTimeSearcher(Searcher *baseSearcher); ~IterativeDeepeningTimeSearcher(); ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty() { return baseSearcher->empty() && pausedStates.empty(); } void printName(std::ostream &os) { os << "IterativeDeepeningTimeSearcher\n"; } }; class InterleavedSearcher : public Searcher { typedef std::vector searchers_ty; searchers_ty searchers; unsigned index; public: explicit InterleavedSearcher(const searchers_ty &_searchers); ~InterleavedSearcher(); ExecutionState &selectState(); void update(ExecutionState *current, const std::set &addedStates, const std::set &removedStates); bool empty() { return searchers[0]->empty(); } void printName(std::ostream &os) { os << " containing " << searchers.size() << " searchers:\n"; for (searchers_ty::iterator it = searchers.begin(), ie = searchers.end(); it != ie; ++it) (*it)->printName(os); os << "\n"; } }; } #endif