diff options
author | Martin Nowack <martin.nowack@gmail.com> | 2018-05-15 15:12:12 +0100 |
---|---|---|
committer | Cristian Cadar <c.cadar@imperial.ac.uk> | 2018-07-04 15:13:02 +0100 |
commit | ef90f1e219fec27a3d594158ae5f380a9e9a2f37 (patch) | |
tree | 0a02b5da762b4bc59f7f6bd2453a2a6591f00062 /lib/Core/Executor.cpp | |
parent | 6803c37be83f0c97c95870a18cb230e135a131c9 (diff) | |
download | klee-ef90f1e219fec27a3d594158ae5f380a9e9a2f37.tar.gz |
Reorder linking and optimizations
Link intrinsic library before executing optimizations. This makes sure that any optimization run by KLEE on the module is executed for the intrinsic library as well. Support .ll files as input for KLEE as well.
Diffstat (limited to 'lib/Core/Executor.cpp')
-rw-r--r-- | lib/Core/Executor.cpp | 90 |
1 files changed, 61 insertions, 29 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 24fcea88..3d7eb21d 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -49,22 +49,22 @@ #include "klee/Internal/System/MemoryUsage.h" #include "klee/SolverStats.h" -#include "llvm/IR/Function.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/IR/DataLayout.h" #include "llvm/IR/TypeBuilder.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" @@ -324,8 +324,8 @@ const char *Executor::TerminateReasonNames[] = { }; Executor::Executor(LLVMContext &ctx, const InterpreterOptions &opts, - InterpreterHandler *ih) - : Interpreter(opts), kmodule(0), interpreterHandler(ih), searcher(0), + InterpreterHandler *ih) + : Interpreter(opts), interpreterHandler(ih), searcher(0), externalDispatcher(new ExternalDispatcher(ctx)), statsTracker(0), pathWriter(0), symPathWriter(0), specialFunctionHandler(0), processTree(0), replayKTest(0), replayPath(0), usingSeeds(0), @@ -393,22 +393,51 @@ Executor::Executor(LLVMContext &ctx, const InterpreterOptions &opts, } } +llvm::Module * +Executor::setModule(std::vector<std::unique_ptr<llvm::Module>> &modules, + const ModuleOptions &opts) { + assert(!kmodule && !modules.empty() && + "can only register one module"); // XXX gross -const Module *Executor::setModule(llvm::Module *module, - const ModuleOptions &opts) { - assert(!kmodule && module && "can only register one module"); // XXX gross - - kmodule = new KModule(module); + kmodule = std::unique_ptr<KModule>(new KModule()); - // Initialize the context. - DataLayout *TD = kmodule->targetData; - Context::initialize(TD->isLittleEndian(), - (Expr::Width) TD->getPointerSizeInBits()); + // Preparing the final module happens in multiple stages + + // Link with KLEE intrinsics library before running any optimizations + SmallString<128> LibPath(opts.LibraryDir); + llvm::sys::path::append(LibPath, "libkleeRuntimeIntrinsic.bca"); + std::string error; + if (!klee::loadFile(LibPath.str(), modules[0]->getContext(), modules, + error)) { + klee_error("Could not load KLEE intrinsic file %s", LibPath.c_str()); + } + // 1.) Link the modules together + while (kmodule->link(modules, opts.EntryPoint)) { + // 2.) Apply different instrumentation + kmodule->instrument(opts); + } + + // 3.) Optimise and prepare for KLEE + + // Create a list of functions that should be preserved if used + std::vector<const char *> preservedFunctions; specialFunctionHandler = new SpecialFunctionHandler(*this); + specialFunctionHandler->prepare(preservedFunctions); + + preservedFunctions.push_back(opts.EntryPoint.c_str()); + + // Preserve the free-standing library calls + preservedFunctions.push_back("memset"); + preservedFunctions.push_back("memcpy"); + preservedFunctions.push_back("memcmp"); + preservedFunctions.push_back("memmove"); + + kmodule->optimiseAndPrepare(opts, preservedFunctions); + + // 4.) Manifest the module + kmodule->manifest(interpreterHandler, StatsTracker::useStatistics()); - specialFunctionHandler->prepare(); - kmodule->prepare(opts, interpreterHandler); specialFunctionHandler->bind(); if (StatsTracker::useStatistics() || userSearcherRequiresMD2U()) { @@ -417,8 +446,13 @@ const Module *Executor::setModule(llvm::Module *module, interpreterHandler->getOutputFilename("assembly.ll"), userSearcherRequiresMD2U()); } - - return module; + + // Initialize the context. + DataLayout *TD = kmodule->targetData.get(); + Context::initialize(TD->isLittleEndian(), + (Expr::Width)TD->getPointerSizeInBits()); + + return kmodule->module.get(); } Executor::~Executor() { @@ -428,7 +462,6 @@ Executor::~Executor() { delete specialFunctionHandler; delete statsTracker; delete solver; - delete kmodule; while(!timers.empty()) { delete timers.back(); timers.pop_back(); @@ -441,7 +474,7 @@ Executor::~Executor() { void Executor::initializeGlobalObject(ExecutionState &state, ObjectState *os, const Constant *c, unsigned offset) { - DataLayout *targetData = kmodule->targetData; + const auto targetData = kmodule->targetData.get(); if (const ConstantVector *cp = dyn_cast<ConstantVector>(c)) { unsigned elementSize = targetData->getTypeStoreSize(cp->getType()->getElementType()); @@ -501,7 +534,7 @@ MemoryObject * Executor::addExternalObject(ExecutionState &state, extern void *__dso_handle __attribute__ ((__weak__)); void Executor::initializeGlobals(ExecutionState &state) { - Module *m = kmodule->module; + Module *m = kmodule->module.get(); if (m->getModuleInlineAsm() != "") klee_warning("executable has module level assembly (ignoring)"); @@ -1400,9 +1433,8 @@ Function* Executor::getTargetFunction(Value *calledVal, ExecutionState &state) { #endif std::string alias = state.getFnAlias(gv->getName()); if (alias != "") { - llvm::Module* currModule = kmodule->module; GlobalValue *old_gv = gv; - gv = currModule->getNamedValue(alias); + gv = kmodule->module->getNamedValue(alias); if (!gv) { klee_error("Function %s(), alias for %s not found!\n", alias.c_str(), old_gv->getName().str().c_str()); @@ -1738,7 +1770,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { Function *f = getTargetFunction(fp, state); // Skip debug intrinsics, we can't evaluate their metadata arguments. - if (f && isDebugIntrinsic(f, kmodule)) + if (f && isDebugIntrinsic(f, kmodule.get())) break; if (isa<InlineAsm>(fp)) { @@ -2595,14 +2627,14 @@ void Executor::bindInstructionConstants(KInstruction *KI) { } void Executor::bindModuleConstants() { - for (std::vector<KFunction*>::iterator it = kmodule->functions.begin(), - ie = kmodule->functions.end(); it != ie; ++it) { - KFunction *kf = *it; + for (auto &kfp : kmodule->functions) { + KFunction *kf = kfp.get(); for (unsigned i=0; i<kf->numInstructions; ++i) bindInstructionConstants(kf->instructions[i]); } - kmodule->constantTable = new Cell[kmodule->constants.size()]; + kmodule->constantTable = + std::unique_ptr<Cell[]>(new Cell[kmodule->constants.size()]); for (unsigned i=0; i<kmodule->constants.size(); ++i) { Cell &c = kmodule->constantTable[i]; c.value = evalConstant(kmodule->constants[i]); |