about summary refs log tree commit diff homepage
path: root/lib/Core/ExternalDispatcher.cpp
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-05-21 04:36:41 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-05-21 04:36:41 +0000
commit6f290d8f9e9d7faac295cb51fc96884a18f4ded4 (patch)
tree46e7d426abc0c9f06ac472ac6f7f9e661b5d78cb /lib/Core/ExternalDispatcher.cpp
parenta55960edd4dcd7535526de8d2277642522aa0209 (diff)
downloadklee-6f290d8f9e9d7faac295cb51fc96884a18f4ded4.tar.gz
Initial KLEE checkin.
 - Lots more tweaks, documentation, and web page content is needed,
   but this should compile & work on OS X & Linux.


git-svn-id: https://llvm.org/svn/llvm-project/klee/trunk@72205 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Core/ExternalDispatcher.cpp')
-rw-r--r--lib/Core/ExternalDispatcher.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/lib/Core/ExternalDispatcher.cpp b/lib/Core/ExternalDispatcher.cpp
new file mode 100644
index 00000000..9e3b0a49
--- /dev/null
+++ b/lib/Core/ExternalDispatcher.cpp
@@ -0,0 +1,230 @@
+//===-- ExternalDispatcher.cpp --------------------------------------------===//
+//
+//                     The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExternalDispatcher.h"
+
+#include "llvm/Module.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Instructions.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/System/DynamicLibrary.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include <setjmp.h>
+#include <signal.h>
+
+using namespace llvm;
+using namespace klee;
+
+/***/
+
+static jmp_buf escapeCallJmpBuf;
+
+extern "C" {
+
+static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
+  longjmp(escapeCallJmpBuf, 1);
+}
+
+}
+
+void *ExternalDispatcher::resolveSymbol(const std::string &name) {
+  assert(executionEngine);
+  
+  const char *str = name.c_str();
+
+  // We use this to validate that function names can be resolved so we
+  // need to match how the JIT does it. Unfortunately we can't
+  // directly access the JIT resolution function
+  // JIT::getPointerToNamedFunction so we emulate the important points.
+
+  if (str[0] == 1) // asm specifier, skipped
+    ++str;
+
+  void *addr = dl_symbols.SearchForAddressOfSymbol(str);
+  if (addr)
+    return addr;
+  
+  // If it has an asm specifier and starts with an underscore we retry
+  // without the underscore. I (DWD) don't know why.
+  if (name[0] == 1 && str[0]=='_') { 
+    ++str;
+    addr = dl_symbols.SearchForAddressOfSymbol(str);
+  }
+
+  return addr;
+}
+
+ExternalDispatcher::ExternalDispatcher() {
+  dispatchModule = new Module("ExternalDispatcher");
+  ExistingModuleProvider* MP = new ExistingModuleProvider(dispatchModule);
+  
+  std::string error;
+  executionEngine = ExecutionEngine::createJIT(MP, &error);
+  if (!executionEngine) {
+    llvm::cerr << "unable to make jit: " << error << "\n";
+    abort();
+  }
+
+  // from ExecutionEngine::create
+  if (executionEngine) {
+    // Make sure we can resolve symbols in the program as well. The zero arg
+    // to the function tells DynamicLibrary to load the program, not a library.
+    try {
+      dl_symbols.LoadLibraryPermanently(0);
+    } catch (...) {
+      assert(0 && "Exception in LoadLibraryPermantently.\n");
+    }
+  }
+
+#ifdef WINDOWS
+  preboundFunctions["getpid"] = (void*) (long) getpid;
+  preboundFunctions["putchar"] = (void*) (long) putchar;
+  preboundFunctions["printf"] = (void*) (long) printf;
+  preboundFunctions["fprintf"] = (void*) (long) fprintf;
+  preboundFunctions["sprintf"] = (void*) (long) sprintf;
+#endif
+}
+
+ExternalDispatcher::~ExternalDispatcher() {
+  delete executionEngine;
+}
+
+bool ExternalDispatcher::executeCall(Function *f, Instruction *i, uint64_t *args) {
+  dispatchers_ty::iterator it = dispatchers.find(i);
+  Function *dispatcher;
+
+  if (it == dispatchers.end()) {
+#ifdef WINDOWS
+    std::map<std::string, void*>::iterator it2 = 
+      preboundFunctions.find(f->getName()));
+
+    if (it2 != preboundFunctions.end()) {
+      // only bind once
+      if (it2->second) {
+        executionEngine->addGlobalMapping(f, it2->second);
+        it2->second = 0;
+      }
+    }
+#endif
+
+    dispatcher = createDispatcher(f,i);
+
+    dispatchers.insert(std::make_pair(i, dispatcher));
+
+    if (dispatcher) {
+      // force the JIT execution engine to go ahead and build the
+      // function. this ensures that any errors or assertions in the
+      // compilation process will trigger crashes instead of being
+      // caught as aborts in the external function.
+      executionEngine->recompileAndRelinkFunction(dispatcher);
+    }
+  } else {
+    dispatcher = it->second;
+  }
+
+  return runProtectedCall(dispatcher, args);
+}
+
+// XXX not reentrant
+static uint64_t *gTheArgsP;
+
+bool ExternalDispatcher::runProtectedCall(Function *f, uint64_t *args) {
+  struct sigaction segvAction, segvActionOld;
+  bool res;
+  
+  if (!f)
+    return false;
+
+  std::vector<GenericValue> gvArgs;
+  gTheArgsP = args;
+
+  segvAction.sa_handler = 0;
+  memset(&segvAction.sa_mask, 0, sizeof(segvAction.sa_mask));
+  segvAction.sa_flags = SA_SIGINFO;
+  segvAction.sa_sigaction = ::sigsegv_handler;
+  sigaction(SIGSEGV, &segvAction, &segvActionOld);
+
+  if (setjmp(escapeCallJmpBuf)) {
+    res = false;
+  } else {
+    executionEngine->runFunction(f, gvArgs);
+    res = true;
+  }
+
+  sigaction(SIGSEGV, &segvActionOld, 0);
+  return res;
+}
+
+// for performance purposes we construct the stub in such a way that
+// the arguments pointer is passed through the static global variable
+// gTheArgsP in this file. This is done so that the stub function
+// prototype trivially matches the special cases that the JIT knows
+// how to directly call. If this is not done, then the jit will end up
+// generating a nullary stub just to call our stub, for every single
+// function call.
+Function *ExternalDispatcher::createDispatcher(Function *target, Instruction *inst) {
+  if (!resolveSymbol(target->getName()))
+    return 0;
+
+  CallSite cs;
+  if (inst->getOpcode()==Instruction::Call) {
+    cs = CallSite(cast<CallInst>(inst));
+  } else {
+    cs = CallSite(cast<InvokeInst>(inst));
+  }
+
+  Value **args = new Value*[cs.arg_size()];
+
+  std::vector<const Type*> nullary;
+  
+  Function *dispatcher = Function::Create(FunctionType::get(Type::VoidTy, 
+							    nullary, false),
+					  GlobalVariable::ExternalLinkage, 
+					  "",
+					  dispatchModule);
+
+
+  BasicBlock *dBB = BasicBlock::Create("entry", dispatcher);
+
+  Instruction *argI64sp = new IntToPtrInst(ConstantInt::get(Type::Int64Ty, (long) (void*) &gTheArgsP),
+					   PointerType::getUnqual(PointerType::getUnqual(Type::Int64Ty)),
+					   "argsp",
+					   dBB);
+  Instruction *argI64s = new LoadInst(argI64sp, "args", dBB); 
+
+  unsigned i = 0;
+  for (CallSite::arg_iterator ai = cs.arg_begin(), ae = cs.arg_end();
+       ai!=ae; ++ai, ++i) {
+    Value *index = ConstantInt::get(Type::Int32Ty, i+1);
+
+    Instruction *argI64p = GetElementPtrInst::Create(argI64s, index, "", dBB);
+    Instruction *argp = new BitCastInst(argI64p, 
+                                        PointerType::getUnqual((*ai)->getType()), "", dBB);
+    args[i] = new LoadInst(argp, "", dBB);
+  }
+
+  Instruction *result = CallInst::Create(target, args, args+i, "", dBB);
+
+  if (result->getType() != Type::VoidTy) {
+    Instruction *resp = new BitCastInst(argI64s, 
+                                        PointerType::getUnqual(result->getType()), "", dBB);
+    new StoreInst(result, resp, dBB);
+  }
+
+  ReturnInst::Create(dBB);
+
+  delete[] args;
+
+  return dispatcher;
+}