about summary refs log tree commit diff homepage
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/klee/main.cpp309
1 files changed, 144 insertions, 165 deletions
diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp
index 1178c9cf..b81131d9 100644
--- a/tools/klee/main.cpp
+++ b/tools/klee/main.cpp
@@ -120,20 +120,18 @@ namespace {
   OptExitOnError("exit-on-error",
               cl::desc("Exit if errors occur"));
 
-
-  enum LibcType {
-    NoLibc, KleeLibc, UcLibc
-  };
-
-  cl::opt<LibcType>
-  Libc("libc",
-       cl::desc("Choose libc version (none by default)."),
-       cl::values(clEnumValN(NoLibc, "none", "Don't link in a libc"),
-                  clEnumValN(KleeLibc, "klee", "Link in klee libc"),
-		  clEnumValN(UcLibc, "uclibc", "Link in uclibc (adapted for klee)")
-		  KLEE_LLVM_CL_VAL_END),
-       cl::init(NoLibc));
-
+  enum class LibcType { FreeStandingLibc, KleeLibc, UcLibc };
+
+  cl::opt<LibcType> Libc(
+      "libc", cl::desc("Choose libc version (none by default)."),
+      cl::values(
+          clEnumValN(
+              LibcType::FreeStandingLibc, "none",
+              "Don't link in a libc (only provide freestanding environment)"),
+          clEnumValN(LibcType::KleeLibc, "klee", "Link in klee libc"),
+          clEnumValN(LibcType::UcLibc, "uclibc",
+                     "Link in uclibc (adapted for klee)") KLEE_LLVM_CL_VAL_END),
+      cl::init(LibcType::FreeStandingLibc));
 
   cl::opt<bool>
   WithPOSIXRuntime("posix-runtime",
@@ -622,7 +620,7 @@ static void parseArguments(int argc, char **argv) {
   cl::ParseCommandLineOptions(argc, argv, " klee\n");
 }
 
-static int initEnv(Module *mainModule) {
+static void initEnv(Module *mainModule) {
 
   /*
     nArgcP = alloc oldArgc->getType()
@@ -637,13 +635,11 @@ static int initEnv(Module *mainModule) {
   */
 
   Function *mainFn = mainModule->getFunction(EntryPoint);
-  if (!mainFn) {
+  if (!mainFn)
     klee_error("'%s' function not found in module.", EntryPoint.c_str());
-  }
 
-  if (mainFn->arg_size() < 2) {
+  if (mainFn->arg_size() < 2)
     klee_error("Cannot handle ""--posix-runtime"" when main() has less than two arguments.\n");
-  }
 
   Instruction *firstInst = &*(mainFn->begin()->begin());
 
@@ -680,8 +676,6 @@ static int initEnv(Module *mainModule) {
 
   new StoreInst(oldArgc, argcPtr, initEnvCall);
   new StoreInst(oldArgv, argvPtr, initEnvCall);
-
-  return 0;
 }
 
 
@@ -828,7 +822,7 @@ static const char *unsafeExternals[] = {
   "kill", // mmmhmmm
 };
 #define NELEMS(array) (sizeof(array)/sizeof(array[0]))
-void externalsAndGlobalsCheck(const Module *m) {
+void externalsAndGlobalsCheck(const llvm::Module *m) {
   std::map<std::string, bool> externals;
   std::set<std::string> modelled(modelledExternals,
                                  modelledExternals+NELEMS(modelledExternals));
@@ -838,14 +832,14 @@ void externalsAndGlobalsCheck(const Module *m) {
                                unsafeExternals+NELEMS(unsafeExternals));
 
   switch (Libc) {
-  case KleeLibc:
+  case LibcType::KleeLibc:
     dontCare.insert(dontCareKlee, dontCareKlee+NELEMS(dontCareKlee));
     break;
-  case UcLibc:
+  case LibcType::UcLibc:
     dontCare.insert(dontCareUclibc,
                     dontCareUclibc+NELEMS(dontCareUclibc));
     break;
-  case NoLibc: /* silence compiler warning */
+  case LibcType::FreeStandingLibc: /* silence compiler warning */
     break;
   }
 
@@ -976,148 +970,113 @@ static char *format_tdiff(char *buf, long seconds)
 }
 
 #ifndef SUPPORT_KLEE_UCLIBC
-static llvm::Module *linkWithUclibc(llvm::Module *mainModule, StringRef libDir) {
+static void
+linkWithUclibc(StringRef libDir,
+               std::vector<std::unique_ptr<llvm::Module>> &modules) {
   klee_error("invalid libc, no uclibc support!\n");
 }
 #else
 static void replaceOrRenameFunction(llvm::Module *module,
 		const char *old_name, const char *new_name)
 {
-  Function *f, *f2;
-  f = module->getFunction(new_name);
-  f2 = module->getFunction(old_name);
-  if (f2) {
-    if (f) {
-      f2->replaceAllUsesWith(f);
-      f2->eraseFromParent();
+  Function *new_function, *old_function;
+  new_function = module->getFunction(new_name);
+  old_function = module->getFunction(old_name);
+  if (old_function) {
+    if (new_function) {
+      old_function->replaceAllUsesWith(new_function);
+      old_function->eraseFromParent();
     } else {
-      f2->setName(new_name);
-      assert(f2->getName() == new_name);
+      old_function->setName(new_name);
+      assert(old_function->getName() == new_name);
     }
   }
 }
-static llvm::Module *linkWithUclibc(llvm::Module *mainModule, StringRef libDir) {
-  LLVMContext &ctx = mainModule->getContext();
-  // Ensure that klee-uclibc exists
-  SmallString<128> uclibcBCA(libDir);
-  llvm::sys::path::append(uclibcBCA, KLEE_UCLIBC_BCA_NAME);
-
-#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6)
-  Twine uclibcBCA_twine(uclibcBCA.c_str());
-  if (!llvm::sys::fs::exists(uclibcBCA_twine))
-#else
-  bool uclibcExists=false;
-  llvm::sys::fs::exists(uclibcBCA.c_str(), uclibcExists);
-  if (!uclibcExists)
-#endif
-    klee_error("Cannot find klee-uclibc : %s", uclibcBCA.c_str());
-
-  Function *f;
-  // force import of __uClibc_main
-  mainModule->getOrInsertFunction(
-      "__uClibc_main",
-      FunctionType::get(Type::getVoidTy(ctx), std::vector<Type *>(), true));
-
-  // force various imports
-  if (WithPOSIXRuntime) {
-    llvm::Type *i8Ty = Type::getInt8Ty(ctx);
-    mainModule->getOrInsertFunction("realpath",
-                                    PointerType::getUnqual(i8Ty),
-                                    PointerType::getUnqual(i8Ty),
-                                    PointerType::getUnqual(i8Ty),
-                                    NULL);
-    mainModule->getOrInsertFunction("getutent",
-                                    PointerType::getUnqual(i8Ty),
-                                    NULL);
-    mainModule->getOrInsertFunction("__fgetc_unlocked",
-                                    Type::getInt32Ty(ctx),
-                                    PointerType::getUnqual(i8Ty),
-                                    NULL);
-    mainModule->getOrInsertFunction("__fputc_unlocked",
-                                    Type::getInt32Ty(ctx),
-                                    Type::getInt32Ty(ctx),
-                                    PointerType::getUnqual(i8Ty),
-                                    NULL);
-  }
-
-  f = mainModule->getFunction("__ctype_get_mb_cur_max");
-  if (f) f->setName("_stdlib_mb_cur_max");
-
-  // Strip of asm prefixes for 64 bit versions because they are not
-  // present in uclibc and we want to make sure stuff will get
-  // linked. In the off chance that both prefixed and unprefixed
-  // versions are present in the module, make sure we don't create a
-  // naming conflict.
-  for (Module::iterator fi = mainModule->begin(), fe = mainModule->end();
-       fi != fe; ++fi) {
-    Function *f = &*fi;
-    const std::string &name = f->getName();
-    if (name[0]=='\01') {
-      unsigned size = name.size();
-      if (name[size-2]=='6' && name[size-1]=='4') {
-        std::string unprefixed = name.substr(1);
-
-        // See if the unprefixed version exists.
-        if (Function *f2 = mainModule->getFunction(unprefixed)) {
-          f->replaceAllUsesWith(f2);
-          f->eraseFromParent();
-        } else {
-          f->setName(unprefixed);
-        }
-      }
-    }
-  }
-
-  mainModule = klee::linkWithLibrary(mainModule, uclibcBCA.c_str());
-  assert(mainModule && "unable to link with uclibc");
-
-
-  replaceOrRenameFunction(mainModule, "__libc_open", "open");
-  replaceOrRenameFunction(mainModule, "__libc_fcntl", "fcntl");
 
+static void
+createLibCWrapper(std::vector<std::unique_ptr<llvm::Module>> &modules,
+                  llvm::StringRef intendedFunction,
+                  llvm::StringRef libcMainFunction) {
   // XXX we need to rearchitect so this can also be used with
-  // programs externally linked with uclibc.
+  // programs externally linked with libc implementation.
 
-  // We now need to swap things so that __uClibc_main is the entry
+  // We now need to swap things so that libcMainFunction is the entry
   // point, in such a way that the arguments are passed to
-  // __uClibc_main correctly. We do this by renaming the user main
-  // and generating a stub function to call __uClibc_main. There is
+  // libcMainFunction correctly. We do this by renaming the user main
+  // and generating a stub function to call intendedFunction. There is
   // also an implicit cooperation in that runFunctionAsMain sets up
-  // the environment arguments to what uclibc expects (following
+  // the environment arguments to what a libc expects (following
   // argv), since it does not explicitly take an envp argument.
-  Function *userMainFn = mainModule->getFunction(EntryPoint);
+  auto &ctx = modules[0]->getContext();
+  Function *userMainFn = modules[0]->getFunction(intendedFunction);
   assert(userMainFn && "unable to get user main");
-  Function *uclibcMainFn = mainModule->getFunction("__uClibc_main");
-  assert(uclibcMainFn && "unable to get uclibc main");
-  userMainFn->setName("__user_main");
+  // Rename entry point using a prefix
+  userMainFn->setName("__user_" + intendedFunction);
+
+  // force import of libcMainFunction
+  llvm::Function *libcMainFn = nullptr;
+  for (auto &module : modules) {
+    if ((libcMainFn = module->getFunction(libcMainFunction)))
+      break;
+  }
+  if (!libcMainFn)
+    klee_error("Could not add %s wrapper", libcMainFunction.str().c_str());
+
+  auto inModuleRefernce = libcMainFn->getParent()->getOrInsertFunction(
+      userMainFn->getName(), userMainFn->getFunctionType());
 
-  const FunctionType *ft = uclibcMainFn->getFunctionType();
-  assert(ft->getNumParams() == 7);
+  const auto ft = libcMainFn->getFunctionType();
+
+  if (ft->getNumParams() != 7)
+    klee_error("Imported %s wrapper does not have the correct "
+               "number of arguments",
+               libcMainFunction.str().c_str());
 
   std::vector<Type *> fArgs;
   fArgs.push_back(ft->getParamType(1)); // argc
   fArgs.push_back(ft->getParamType(2)); // argv
-  Function *stub = Function::Create(FunctionType::get(Type::getInt32Ty(ctx), fArgs, false),
-                                    GlobalVariable::ExternalLinkage,
-                                    EntryPoint,
-                                    mainModule);
+  Function *stub =
+      Function::Create(FunctionType::get(Type::getInt32Ty(ctx), fArgs, false),
+                       GlobalVariable::ExternalLinkage, intendedFunction,
+                       libcMainFn->getParent());
   BasicBlock *bb = BasicBlock::Create(ctx, "entry", stub);
 
   std::vector<llvm::Value*> args;
-  args.push_back(llvm::ConstantExpr::getBitCast(userMainFn,
-                                                ft->getParamType(0)));
+  args.push_back(
+      llvm::ConstantExpr::getBitCast(inModuleRefernce, ft->getParamType(0)));
   args.push_back(&*(stub->arg_begin())); // argc
   args.push_back(&*(++stub->arg_begin())); // argv
   args.push_back(Constant::getNullValue(ft->getParamType(3))); // app_init
   args.push_back(Constant::getNullValue(ft->getParamType(4))); // app_fini
   args.push_back(Constant::getNullValue(ft->getParamType(5))); // rtld_fini
   args.push_back(Constant::getNullValue(ft->getParamType(6))); // stack_end
-  CallInst::Create(uclibcMainFn, args, "", bb);
+  CallInst::Create(libcMainFn, args, "", bb);
 
   new UnreachableInst(ctx, bb);
+}
 
+static void
+linkWithUclibc(StringRef libDir,
+               std::vector<std::unique_ptr<llvm::Module>> &modules) {
+  LLVMContext &ctx = modules[0]->getContext();
+
+  size_t newModules = modules.size();
+
+  // Ensure that klee-uclibc exists
+  SmallString<128> uclibcBCA(libDir);
+  std::string errorMsg;
+  llvm::sys::path::append(uclibcBCA, KLEE_UCLIBC_BCA_NAME);
+  if (!klee::loadFile(uclibcBCA.c_str(), ctx, modules, errorMsg))
+    klee_error("Cannot find klee-uclibc '%s': %s", uclibcBCA.c_str(),
+               errorMsg.c_str());
+
+  for (auto i = newModules, j = modules.size(); i < j; ++i) {
+    replaceOrRenameFunction(modules[i].get(), "__libc_open", "open");
+    replaceOrRenameFunction(modules[i].get(), "__libc_fcntl", "fcntl");
+  }
+
+  createLibCWrapper(modules, EntryPoint, "__uClibc_main");
   klee_message("NOTE: Using klee-uclibc : %s", uclibcBCA.c_str());
-  return mainModule;
 }
 #endif
 
@@ -1200,16 +1159,27 @@ int main(int argc, char **argv, char **envp) {
   // Load the bytecode...
   std::string errorMsg;
   LLVMContext ctx;
-  Module *mainModule = klee::loadModule(ctx, InputFile, errorMsg);
-  if (!mainModule) {
+  std::vector<std::unique_ptr<llvm::Module>> loadedModules;
+  if (!klee::loadFile(InputFile, ctx, loadedModules, errorMsg)) {
+    klee_error("error loading program '%s': %s", InputFile.c_str(),
+               errorMsg.c_str());
+  }
+  // Load and link the whole files content. The assumption is that this is the
+  // application under test.
+  // Nothing gets removed in the first place.
+  std::unique_ptr<llvm::Module> M(klee::linkModules(
+      loadedModules, "" /* link all modules together */, errorMsg));
+  if (!M) {
     klee_error("error loading program '%s': %s", InputFile.c_str(),
                errorMsg.c_str());
   }
 
+  llvm::Module *mainModule = M.get();
+  // Push the module as the first entry
+  loadedModules.emplace_back(std::move(M));
+
   if (WithPOSIXRuntime) {
-    int r = initEnv(mainModule);
-    if (r != 0)
-      return r;
+    initEnv(mainModule);
   }
 
   std::string LibraryDir = KleeHandler::getRunTimeLibraryPath(argv[0]);
@@ -1219,44 +1189,45 @@ int main(int argc, char **argv, char **envp) {
                                   /*CheckOvershift=*/CheckOvershift);
 
   switch (Libc) {
-  case NoLibc: /* silence compiler warning */
-    break;
-
-  case KleeLibc: {
+  case LibcType::KleeLibc: {
     // FIXME: Find a reasonable solution for this.
     SmallString<128> Path(Opts.LibraryDir);
-    llvm::sys::path::append(Path, "klee-libc.bc");
-    mainModule = klee::linkWithLibrary(mainModule, Path.c_str());
-    assert(mainModule && "unable to link with klee-libc");
+    llvm::sys::path::append(Path, "libklee-libc.bca");
+    if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules,
+                        errorMsg))
+      klee_error("error loading klee libc '%s': %s", Path.c_str(),
+                 errorMsg.c_str());
+  }
+  /* Falls through. */
+  case LibcType::FreeStandingLibc: {
+    SmallString<128> Path(Opts.LibraryDir);
+    llvm::sys::path::append(Path, "libkleeRuntimeFreeStanding.bca");
+    if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules,
+                        errorMsg))
+      klee_error("error loading free standing support '%s': %s", Path.c_str(),
+                 errorMsg.c_str());
     break;
   }
-
-  case UcLibc:
-    mainModule = linkWithUclibc(mainModule, LibraryDir);
+  case LibcType::UcLibc:
+    linkWithUclibc(LibraryDir, loadedModules);
     break;
   }
 
   if (WithPOSIXRuntime) {
     SmallString<128> Path(Opts.LibraryDir);
     llvm::sys::path::append(Path, "libkleeRuntimePOSIX.bca");
-    klee_message("NOTE: Using model: %s", Path.c_str());
-    mainModule = klee::linkWithLibrary(mainModule, Path.c_str());
-    assert(mainModule && "unable to link with simple model");
+    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::vector<std::string>::iterator libs_it;
-  std::vector<std::string>::iterator libs_ie;
-  for (libs_it = LinkLibraries.begin(), libs_ie = LinkLibraries.end();
-          libs_it != libs_ie; ++libs_it) {
-    const char * libFilename = libs_it->c_str();
-    klee_message("Linking in library: %s.\n", libFilename);
-    mainModule = klee::linkWithLibrary(mainModule, libFilename);
-  }
-  // Get the desired main function.  klee_main initializes uClibc
-  // locale and other data and then calls main.
-  Function *mainFn = mainModule->getFunction(EntryPoint);
-  if (!mainFn) {
-    klee_error("'%s' function not found in module.", EntryPoint.c_str());
+  for (const auto &library : LinkLibraries) {
+    if (!klee::loadFile(library, mainModule->getContext(), loadedModules,
+                        errorMsg))
+      klee_error("error loading free standing support '%s': %s",
+                 library.c_str(), errorMsg.c_str());
   }
 
   // FIXME: Change me to std types.
@@ -1309,6 +1280,7 @@ int main(int argc, char **argv, char **envp) {
   KleeHandler *handler = new KleeHandler(pArgc, pArgv);
   Interpreter *interpreter =
     theInterpreter = Interpreter::create(ctx, IOpts, handler);
+  assert(interpreter);
   handler->setInterpreter(interpreter);
 
   for (int i=0; i<argc; i++) {
@@ -1316,8 +1288,15 @@ int main(int argc, char **argv, char **envp) {
   }
   handler->getInfoStream() << "PID: " << getpid() << "\n";
 
-  const Module *finalModule =
-    interpreter->setModule(mainModule, Opts);
+  // Get the desired main function.  klee_main initializes uClibc
+  // locale and other data and then calls main.
+
+  auto finalModule = interpreter->setModule(loadedModules, Opts);
+  Function *mainFn = finalModule->getFunction(EntryPoint);
+  if (!mainFn) {
+    klee_error("'%s' function not found in module.", EntryPoint.c_str());
+  }
+
   externalsAndGlobalsCheck(finalModule);
 
   if (ReplayPathFile != "") {