//===-- 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/Interpreter.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/util/ArrayCache.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/Twine.h"
#include "../Expr/ArrayExprOptimizer.h"
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
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 T> 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:
class Timer {
public:
Timer();
virtual ~Timer();
/// The event callback.
virtual void run() = 0;
};
typedef std::pair<ExecutionState*,ExecutionState*> StatePair;
enum TerminateReason {
Abort,
Assert,
BadVectorAccess,
Exec,
External,
Free,
Model,
Overflow,
Ptr,
ReadOnly,
ReportError,
User,
Unhandled
};
private:
static const char *TerminateReasonNames[];
class TimerInfo;
std::unique_ptr<KModule> kmodule;
InterpreterHandler *interpreterHandler;
Searcher *searcher;
ExternalDispatcher *externalDispatcher;
TimingSolver *solver;
MemoryManager *memory;
std::set<ExecutionState*> states;
StatsTracker *statsTracker;
TreeStreamWriter *pathWriter, *symPathWriter;
SpecialFunctionHandler *specialFunctionHandler;
std::vector<TimerInfo*> timers;
PTree *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<MergeHandler *> mergeGroups;
/// ExecutionStates currently paused from scheduling because they are
/// waiting to be merged in a klee_close_merge instruction
std::set<ExecutionState *> 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<ExecutionState *> 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<ExecutionState *> removedStates;
/// Used to track states that are not terminated, but should not
/// be scheduled by the searcher.
std::vector<ExecutionState *> pausedStates;
/// States that were 'paused' from scheduling, that now may be
/// scheduled again
std::vector<ExecutionState *> 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<ExecutionState*, std::vector<SeedInfo> > seedMap;
/// Map of globals to their representative memory object.
std::map<const llvm::GlobalValue*, MemoryObject*> globalObjects;
/// Map of globals to their bound address. This also includes
/// globals that have no representative object (i.e. functions).
std::map<const llvm::GlobalValue*, ref<ConstantExpr> > globalAddresses;
/// The set of legal function addresses, used to validate function
/// pointers. We use the actual Function* address as the function address.
std::set<uint64_t> 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<bool> *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<struct KTest *> *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<llvm::raw_ostream> 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 printFileLine(ExecutionState &state, KInstruction *ki,
llvm::raw_ostream &file);
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<Expr> > &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<std::pair<const MemoryObject*, const ObjectState*>,
ExecutionState*> > ExactResolutionList;
void resolveExact(ExecutionState &state,
ref<Expr> 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.
void executeAlloc(ExecutionState &state,
ref<Expr> size,
bool isLocal,
KInstruction *target,
bool zeroMemory=false,
const ObjectState *reallocFrom=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<Expr> address,
KInstruction *target = 0);
void executeCall(ExecutionState &state,
KInstruction *ki,
llvm::Function *f,
std::vector< ref<Expr> > &arguments);
// do address resolution / object binding / out of bounds checking
// and perform the operation
void executeMemoryOperation(ExecutionState &state,
bool isWrite,
ref<Expr> address,
ref<Expr> 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<Expr> > &conditions,
std::vector<ExecutionState*> &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<Expr> 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<Expr> condition);
// Called on [for now] concrete reads, replaces constant with a symbolic
// Used for testing.
ref<Expr> replaceReadWithSymbolic(ExecutionState &state, ref<Expr> 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<Expr> value);
void bindArgument(KFunction *kf,
unsigned index,
ExecutionState &state,
ref<Expr> 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<klee::ConstantExpr> 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<klee::ConstantExpr> 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<Expr> toUnique(const ExecutionState &state, ref<Expr> &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<klee::ConstantExpr> toConstant(ExecutionState &state, ref<Expr> 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<Expr> e, KInstruction *target);
/// Get textual information regarding a memory address.
std::string getAddressInfo(ExecutionState &state, ref<Expr> 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 <typename TypeIt>
void computeOffsets(KGEPInstruction *kgepi, TypeIt ib, TypeIt ie);
/// bindInstructionConstants - Initialize any necessary per instruction
/// constant values.
void bindInstructionConstants(KInstruction *KI);
void handlePointsToObj(ExecutionState &state,
KInstruction *target,
const std::vector<ref<Expr> > &arguments);
void doImpliedValueConcretization(ExecutionState &state,
ref<Expr> e,
ref<ConstantExpr> value);
/// Add a timer to be executed periodically.
///
/// \param timer The timer object to run on firings.
/// \param rate The approximate delay (in seconds) between firings.
void addTimer(Timer *timer, time::Span rate);
void initTimers();
void processTimers(ExecutionState *current, time::Span maxInstTime);
void checkMemoryUsage();
void printDebugInstructions(ExecutionState &state);
void doDumpStates();
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<bool> *path) override {
assert(!replayKTest && "cannot replay both buffer and path");
replayPath = path;
replayPosition = 0;
}
llvm::Module *setModule(std::vector<std::unique_ptr<llvm::Module>> &modules,
const ModuleOptions &opts) override;
void useSeeds(const std::vector<struct KTest *> *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<std::pair<std::string, std::vector<unsigned char>>> &res)
override;
void getCoveredLines(const ExecutionState &state,
std::map<const std::string *, std::set<unsigned>> &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