ExternalDispatcher.cpp

Go to the documentation of this file.
00001 //===-- ExternalDispatcher.cpp --------------------------------------------===//
00002 //
00003 //                     The KLEE Symbolic Virtual Machine
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "ExternalDispatcher.h"
00011 
00012 #include "llvm/Module.h"
00013 #include "llvm/Constants.h"
00014 #include "llvm/DerivedTypes.h"
00015 #include "llvm/Instructions.h"
00016 #include "llvm/ModuleProvider.h"
00017 #include "llvm/ExecutionEngine/JIT.h"
00018 #include "llvm/ExecutionEngine/GenericValue.h"
00019 #include "llvm/Support/CallSite.h"
00020 #include "llvm/System/DynamicLibrary.h"
00021 #include "llvm/Support/Streams.h"
00022 #include "llvm/Support/raw_ostream.h"
00023 #include <setjmp.h>
00024 #include <signal.h>
00025 
00026 using namespace llvm;
00027 using namespace klee;
00028 
00029 /***/
00030 
00031 static jmp_buf escapeCallJmpBuf;
00032 
00033 extern "C" {
00034 
00035 static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
00036   longjmp(escapeCallJmpBuf, 1);
00037 }
00038 
00039 }
00040 
00041 void *ExternalDispatcher::resolveSymbol(const std::string &name) {
00042   assert(executionEngine);
00043   
00044   const char *str = name.c_str();
00045 
00046   // We use this to validate that function names can be resolved so we
00047   // need to match how the JIT does it. Unfortunately we can't
00048   // directly access the JIT resolution function
00049   // JIT::getPointerToNamedFunction so we emulate the important points.
00050 
00051   if (str[0] == 1) // asm specifier, skipped
00052     ++str;
00053 
00054   void *addr = dl_symbols.SearchForAddressOfSymbol(str);
00055   if (addr)
00056     return addr;
00057   
00058   // If it has an asm specifier and starts with an underscore we retry
00059   // without the underscore. I (DWD) don't know why.
00060   if (name[0] == 1 && str[0]=='_') { 
00061     ++str;
00062     addr = dl_symbols.SearchForAddressOfSymbol(str);
00063   }
00064 
00065   return addr;
00066 }
00067 
00068 ExternalDispatcher::ExternalDispatcher() {
00069   dispatchModule = new Module("ExternalDispatcher");
00070   ExistingModuleProvider* MP = new ExistingModuleProvider(dispatchModule);
00071   
00072   std::string error;
00073   executionEngine = ExecutionEngine::createJIT(MP, &error);
00074   if (!executionEngine) {
00075     llvm::cerr << "unable to make jit: " << error << "\n";
00076     abort();
00077   }
00078 
00079   // from ExecutionEngine::create
00080   if (executionEngine) {
00081     // Make sure we can resolve symbols in the program as well. The zero arg
00082     // to the function tells DynamicLibrary to load the program, not a library.
00083     dl_symbols.LoadLibraryPermanently(0);
00084   }
00085 
00086 #ifdef WINDOWS
00087   preboundFunctions["getpid"] = (void*) (long) getpid;
00088   preboundFunctions["putchar"] = (void*) (long) putchar;
00089   preboundFunctions["printf"] = (void*) (long) printf;
00090   preboundFunctions["fprintf"] = (void*) (long) fprintf;
00091   preboundFunctions["sprintf"] = (void*) (long) sprintf;
00092 #endif
00093 }
00094 
00095 ExternalDispatcher::~ExternalDispatcher() {
00096   delete executionEngine;
00097 }
00098 
00099 bool ExternalDispatcher::executeCall(Function *f, Instruction *i, uint64_t *args) {
00100   dispatchers_ty::iterator it = dispatchers.find(i);
00101   Function *dispatcher;
00102 
00103   if (it == dispatchers.end()) {
00104 #ifdef WINDOWS
00105     std::map<std::string, void*>::iterator it2 = 
00106       preboundFunctions.find(f->getName()));
00107 
00108     if (it2 != preboundFunctions.end()) {
00109       // only bind once
00110       if (it2->second) {
00111         executionEngine->addGlobalMapping(f, it2->second);
00112         it2->second = 0;
00113       }
00114     }
00115 #endif
00116 
00117     dispatcher = createDispatcher(f,i);
00118 
00119     dispatchers.insert(std::make_pair(i, dispatcher));
00120 
00121     if (dispatcher) {
00122       // force the JIT execution engine to go ahead and build the
00123       // function. this ensures that any errors or assertions in the
00124       // compilation process will trigger crashes instead of being
00125       // caught as aborts in the external function.
00126       executionEngine->recompileAndRelinkFunction(dispatcher);
00127     }
00128   } else {
00129     dispatcher = it->second;
00130   }
00131 
00132   return runProtectedCall(dispatcher, args);
00133 }
00134 
00135 // XXX not reentrant
00136 static uint64_t *gTheArgsP;
00137 
00138 bool ExternalDispatcher::runProtectedCall(Function *f, uint64_t *args) {
00139   struct sigaction segvAction, segvActionOld;
00140   bool res;
00141   
00142   if (!f)
00143     return false;
00144 
00145   std::vector<GenericValue> gvArgs;
00146   gTheArgsP = args;
00147 
00148   segvAction.sa_handler = 0;
00149   memset(&segvAction.sa_mask, 0, sizeof(segvAction.sa_mask));
00150   segvAction.sa_flags = SA_SIGINFO;
00151   segvAction.sa_sigaction = ::sigsegv_handler;
00152   sigaction(SIGSEGV, &segvAction, &segvActionOld);
00153 
00154   if (setjmp(escapeCallJmpBuf)) {
00155     res = false;
00156   } else {
00157     executionEngine->runFunction(f, gvArgs);
00158     res = true;
00159   }
00160 
00161   sigaction(SIGSEGV, &segvActionOld, 0);
00162   return res;
00163 }
00164 
00165 // for performance purposes we construct the stub in such a way that
00166 // the arguments pointer is passed through the static global variable
00167 // gTheArgsP in this file. This is done so that the stub function
00168 // prototype trivially matches the special cases that the JIT knows
00169 // how to directly call. If this is not done, then the jit will end up
00170 // generating a nullary stub just to call our stub, for every single
00171 // function call.
00172 Function *ExternalDispatcher::createDispatcher(Function *target, Instruction *inst) {
00173   if (!resolveSymbol(target->getName()))
00174     return 0;
00175 
00176   CallSite cs;
00177   if (inst->getOpcode()==Instruction::Call) {
00178     cs = CallSite(cast<CallInst>(inst));
00179   } else {
00180     cs = CallSite(cast<InvokeInst>(inst));
00181   }
00182 
00183   Value **args = new Value*[cs.arg_size()];
00184 
00185   std::vector<const Type*> nullary;
00186   
00187   Function *dispatcher = Function::Create(FunctionType::get(Type::VoidTy, 
00188                                                             nullary, false),
00189                                           GlobalVariable::ExternalLinkage, 
00190                                           "",
00191                                           dispatchModule);
00192 
00193 
00194   BasicBlock *dBB = BasicBlock::Create("entry", dispatcher);
00195 
00196   Instruction *argI64sp = new IntToPtrInst(ConstantInt::get(Type::Int64Ty, (long) (void*) &gTheArgsP),
00197                                            PointerType::getUnqual(PointerType::getUnqual(Type::Int64Ty)),
00198                                            "argsp",
00199                                            dBB);
00200   Instruction *argI64s = new LoadInst(argI64sp, "args", dBB); 
00201 
00202   unsigned i = 0;
00203   for (CallSite::arg_iterator ai = cs.arg_begin(), ae = cs.arg_end();
00204        ai!=ae; ++ai, ++i) {
00205     Value *index = ConstantInt::get(Type::Int32Ty, i+1);
00206 
00207     Instruction *argI64p = GetElementPtrInst::Create(argI64s, index, "", dBB);
00208     Instruction *argp = new BitCastInst(argI64p, 
00209                                         PointerType::getUnqual((*ai)->getType()), "", dBB);
00210     args[i] = new LoadInst(argp, "", dBB);
00211   }
00212 
00213   Instruction *result = CallInst::Create(target, args, args+i, "", dBB);
00214 
00215   if (result->getType() != Type::VoidTy) {
00216     Instruction *resp = new BitCastInst(argI64s, 
00217                                         PointerType::getUnqual(result->getType()), "", dBB);
00218     new StoreInst(result, resp, dBB);
00219   }
00220 
00221   ReturnInst::Create(dBB);
00222 
00223   delete[] args;
00224 
00225   return dispatcher;
00226 }

Generated on Fri Jun 5 03:31:31 2009 for klee by  doxygen 1.5.8