diff options
author | Martin Nowack <m.nowack@imperial.ac.uk> | 2018-07-22 23:12:49 +0100 |
---|---|---|
committer | Cristian Cadar <c.cadar@imperial.ac.uk> | 2018-09-10 15:24:17 +0100 |
commit | 3d373d8b5c101e0798ea8a5e8015aa03537d02d8 (patch) | |
tree | dbf0f42bd7707b4c2d2505be803c770c70f6dceb | |
parent | 0f1b68e093dfe0357adf400ea7b4746f09fb4cba (diff) | |
download | klee-3d373d8b5c101e0798ea8a5e8015aa03537d02d8.tar.gz |
POSIX: Add invocation of klee_init_env into wrapper before calling main
To enable the POSIX support, the former implementation instrumented the main function and inserted a call to `klee_init_env` at the beginning. This has multiple disadvantages: * debugging information was not correctly propagated leaving the call to `klee_init_env` without debug information * the main function always required `int arg, char**` as part of the function definition of `main` Based on the new linking infrastructure, we can now add an additional wrapper `__klee_posix_wraper(int, char**)` that gets always called when POSIX support is enabled. It executes `klee_init_env` and after that calls the `main` function. Enabling POSIX support only requires the renaming of the user provided `main` into `__klee_posix_wrapped_main` in addition to linking.
-rw-r--r-- | runtime/POSIX/klee_init_env.c | 9 | ||||
-rw-r--r-- | tools/klee-replay/klee_init_env.c | 2 | ||||
-rw-r--r-- | tools/klee/main.cpp | 112 |
3 files changed, 56 insertions, 67 deletions
diff --git a/runtime/POSIX/klee_init_env.c b/runtime/POSIX/klee_init_env.c index 1fa6adea..265c3bfd 100644 --- a/runtime/POSIX/klee_init_env.c +++ b/runtime/POSIX/klee_init_env.c @@ -209,3 +209,12 @@ usage: (klee_init_env) [options] [program arguments]\n\ save_all_writes_flag, fd_fail); } +/* The following function represents the main function of the user application + * and is renamed during POSIX setup */ +int __klee_posix_wrapped_main(int argc, char **argv); + +/* This wrapper gets called instead of main if POSIX setup is used */ +int __klee_posix_wrapper(int argcPtr, char **argvPtr) { + klee_init_env(&argcPtr, &argvPtr); + return __klee_posix_wrapped_main(argcPtr, argvPtr); +} diff --git a/tools/klee-replay/klee_init_env.c b/tools/klee-replay/klee_init_env.c index 229fe43d..5e9dd06c 100644 --- a/tools/klee-replay/klee_init_env.c +++ b/tools/klee-replay/klee_init_env.c @@ -1 +1,3 @@ #include "../../runtime/POSIX/klee_init_env.c" + +int __klee_posix_wrapped_main(int argc, char **argv) { return 0; } diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp index c655aa56..0b22f5c1 100644 --- a/tools/klee/main.cpp +++ b/tools/klee/main.cpp @@ -626,62 +626,41 @@ static void parseArguments(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, " klee\n"); } -static void initEnv(Module *mainModule) { - - /* - nArgcP = alloc oldArgc->getType() - nArgvV = alloc oldArgv->getType() - store oldArgc nArgcP - store oldArgv nArgvP - klee_init_environment(nArgcP, nArgvP) - nArgc = load nArgcP - nArgv = load nArgvP - oldArgc->replaceAllUsesWith(nArgc) - oldArgv->replaceAllUsesWith(nArgv) - */ - - Function *mainFn = mainModule->getFunction(EntryPoint); +static void +preparePOSIX(std::vector<std::unique_ptr<llvm::Module>> &loadedModules, + llvm::StringRef libCPrefix) { + // Get the main function from the main module and rename it such that it can + // be called after the POSIX setup + Function *mainFn = nullptr; + for (auto &module : loadedModules) { + mainFn = module->getFunction(EntryPoint); + if (mainFn) + break; + } + if (!mainFn) klee_error("'%s' function not found in module.", EntryPoint.c_str()); + mainFn->setName("__klee_posix_wrapped_main"); + + // Add a definition of the entry function if needed. This is the case if we + // link against a libc implementation. Preparing for libc linking (i.e. + // linking with uClibc will expect a main function and rename it to + // _user_main. We just provide the definition here. + if (!libCPrefix.empty()) + mainFn->getParent()->getOrInsertFunction(EntryPoint, + mainFn->getFunctionType()); + + llvm::Function *wrapper = nullptr; + for (auto &module : loadedModules) { + wrapper = module->getFunction("__klee_posix_wrapper"); + if (wrapper) + break; + } + assert(wrapper && "klee_posix_wrapper not found"); - if (mainFn->arg_size() < 2) - klee_error("Cannot handle ""--posix-runtime"" when main() has less than two arguments.\n"); - - Instruction *firstInst = &*(mainFn->begin()->begin()); - - Value *oldArgc = &*(mainFn->arg_begin()); - Value *oldArgv = &*(++mainFn->arg_begin()); - - AllocaInst* argcPtr = - new AllocaInst(oldArgc->getType(), "argcPtr", firstInst); - AllocaInst* argvPtr = - new AllocaInst(oldArgv->getType(), "argvPtr", firstInst); - - /* Insert void klee_init_env(int* argc, char*** argv) */ - std::vector<const Type*> params; - LLVMContext &ctx = mainModule->getContext(); - params.push_back(Type::getInt32Ty(ctx)); - params.push_back(Type::getInt32Ty(ctx)); - Function* initEnvFn = - cast<Function>(mainModule->getOrInsertFunction("klee_init_env", - Type::getVoidTy(ctx), - argcPtr->getType(), - argvPtr->getType(), - NULL)); - assert(initEnvFn); - std::vector<Value*> args; - args.push_back(argcPtr); - args.push_back(argvPtr); - Instruction* initEnvCall = CallInst::Create(initEnvFn, args, - "", firstInst); - Value *argc = new LoadInst(argcPtr, "newArgc", firstInst); - Value *argv = new LoadInst(argvPtr, "newArgv", firstInst); - - oldArgc->replaceAllUsesWith(argc); - oldArgv->replaceAllUsesWith(argv); - - new StoreInst(oldArgc, argcPtr, initEnvCall); - new StoreInst(oldArgv, argvPtr, initEnvCall); + // Rename the POSIX wrapper to prefixed entrypoint, e.g. _user_main as uClibc + // would expect it or main otherwise + wrapper->setName(libCPrefix + EntryPoint); } @@ -1184,16 +1163,25 @@ int main(int argc, char **argv, char **envp) { // Push the module as the first entry loadedModules.emplace_back(std::move(M)); - if (WithPOSIXRuntime) { - initEnv(mainModule); - } - std::string LibraryDir = KleeHandler::getRunTimeLibraryPath(argv[0]); Interpreter::ModuleOptions Opts(LibraryDir.c_str(), EntryPoint, /*Optimize=*/OptimizeModule, /*CheckDivZero=*/CheckDivZero, /*CheckOvershift=*/CheckOvershift); + if (WithPOSIXRuntime) { + SmallString<128> Path(Opts.LibraryDir); + llvm::sys::path::append(Path, "libkleeRuntimePOSIX.bca"); + klee_message("NOTE: Using POSIX model: %s", Path.c_str()); + if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules, + errorMsg)) + klee_error("error loading POSIX support '%s': %s", Path.c_str(), + errorMsg.c_str()); + + std::string libcPrefix = (Libc == LibcType::UcLibc ? "__user_" : ""); + preparePOSIX(loadedModules, libcPrefix); + } + switch (Libc) { case LibcType::KleeLibc: { // FIXME: Find a reasonable solution for this. @@ -1219,16 +1207,6 @@ int main(int argc, char **argv, char **envp) { break; } - if (WithPOSIXRuntime) { - SmallString<128> Path(Opts.LibraryDir); - llvm::sys::path::append(Path, "libkleeRuntimePOSIX.bca"); - klee_message("NOTE: Using POSIX model: %s", Path.c_str()); - if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules, - errorMsg)) - klee_error("error loading POSIX support '%s': %s", Path.c_str(), - errorMsg.c_str()); - } - for (const auto &library : LinkLibraries) { if (!klee::loadFile(library, mainModule->getContext(), loadedModules, errorMsg)) |