zcov: / lib/Core/ExternalDispatcher.cpp


Files: 1 Branches Taken: 67.4% 31 / 46
Generated: 2009-05-17 22:47 Branches Executed: 82.6% 38 / 46
Line Coverage: 89.2% 66 / 74


Programs: 1 Runs 371


       1                 : /* -*- mode: c++; c-basic-offset: 2; -*- */
       2                 : 
       3                 : #include "ExternalDispatcher.h"
       4                 : 
       5                 : #include "llvm/Module.h"
       6                 : #include "llvm/Constants.h"
       7                 : #include "llvm/DerivedTypes.h"
       8                 : #include "llvm/Instructions.h"
       9                 : #include "llvm/ModuleProvider.h"
      10                 : #include "llvm/ExecutionEngine/JIT.h"
      11                 : #include "llvm/ExecutionEngine/GenericValue.h"
      12                 : #include "llvm/Support/CallSite.h"
      13                 : #include "llvm/System/DynamicLibrary.h"
      14                 : #include "llvm/Support/Streams.h"
      15                 : #include "llvm/Support/raw_ostream.h"
      16                 : #include <setjmp.h>
      17                 : #include <signal.h>
      18                 : 
      19                 : using namespace llvm;
      20                 : using namespace klee;
      21                 : 
      22                 : /***/
      23                 : 
      24                 : static jmp_buf escapeCallJmpBuf;
      25                 : 
      26                 : extern "C" {
      27                 : 
      28                0: static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
      29                0:   longjmp(escapeCallJmpBuf, 1);
      30                 : }
      31                 : 
      32                 : }
      33                 : 
      34               94: void *ExternalDispatcher::resolveSymbol(const std::string &name) {
                        0: branch 0 not taken
                       94: branch 1 taken
      35               94:   assert(executionEngine);
      36                 :   
      37               94:   const char *str = name.c_str();
      38                 : 
      39                 :   // We use this to validate that function names can be resolved so we
      40                 :   // need to match how the JIT does it. Unfortunately we can't
      41                 :   // directly access the JIT resolution function
      42                 :   // JIT::getPointerToNamedFunction so we emulate the important points.
      43                 : 
                        0: branch 0 not taken
                       94: branch 1 taken
      44               94:   if (str[0] == 1) // asm specifier, skipped
      45                0:     ++str;
      46                 : 
      47               94:   void *addr = dl_symbols.SearchForAddressOfSymbol(str);
                       92: branch 0 taken
                        2: branch 1 taken
      48               94:   if (addr)
      49               92:     return addr;
      50                 :   
      51                 :   // If it has an asm specifier and starts with an underscore we retry
      52                 :   // without the underscore. I (DWD) don't know why.
                        0: branch 0 not taken
                        2: branch 1 taken
                        2: branch 2 taken
                        2: branch 3 taken
                        0: branch 4 not taken
                        2: branch 5 taken
      53                2:   if (name[0] == 1 && str[0]=='_') { 
      54                0:     ++str;
      55                0:     addr = dl_symbols.SearchForAddressOfSymbol(str);
      56                 :   }
      57                 : 
      58                2:   return addr;
      59                 : }
      60                 : 
      61              206: ExternalDispatcher::ExternalDispatcher() {
      62              103:   dispatchModule = new Module("ExternalDispatcher");
      63              206:   ExistingModuleProvider* MP = new ExistingModuleProvider(dispatchModule);
      64                 :   
      65                 :   std::string error;
      66              103:   executionEngine = ExecutionEngine::createJIT(MP, &error);
                        0: branch 0 not taken
                      103: branch 1 taken
                      103: branch 2 taken
                      103: branch 3 taken
      67              103:   if (!executionEngine) {
      68                 :     llvm::cerr << "unable to make jit: " << error << "\n";
      69                0:     abort();
      70                 :   }
      71                 : 
      72                 :   // from ExecutionEngine::create
                      103: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                        0: branch 3 not taken
      73              103:   if (executionEngine) {
      74                 :     // Make sure we can resolve symbols in the program as well. The zero arg
      75                 :     // to the function tells DynamicLibrary to load the program, not a library.
      76                 :     try {
      77              103:       dl_symbols.LoadLibraryPermanently(0);
      78                 :     } catch (...) {
      79                 :       assert(0 && "Exception in LoadLibraryPermantently.\n");
      80                 :     }
      81              103:   }
      82                 : 
      83                 : #ifdef WINDOWS
      84                 :   preboundFunctions["getpid"] = (void*) (long) getpid;
      85                 :   preboundFunctions["putchar"] = (void*) (long) putchar;
      86                 :   preboundFunctions["printf"] = (void*) (long) printf;
      87                 :   preboundFunctions["fprintf"] = (void*) (long) fprintf;
      88                 :   preboundFunctions["sprintf"] = (void*) (long) sprintf;
      89                 : #endif
      90              103: }
      91                 : 
      92              103: ExternalDispatcher::~ExternalDispatcher() {
                      103: branch 0 taken
                        0: branch 1 not taken
                      103: branch 3 taken
                      103: branch 4 taken
      93              103:   delete executionEngine;
      94              309: }
      95                 : 
      96              288: bool ExternalDispatcher::executeCall(Function *f, Instruction *i, uint64_t *args) {
      97              288:   dispatchers_ty::iterator it = dispatchers.find(i);
      98                 :   Function *dispatcher;
      99                 : 
                       84: branch 0 taken
                      204: branch 1 taken
     100              576:   if (it == dispatchers.end()) {
     101                 : #ifdef WINDOWS
     102                 :     let(it2, preboundFunctions.find(f->getName()));
     103                 : 
     104                 :     if (it2 != preboundFunctions.end()) {
     105                 :       // only bind once
     106                 :       if (it2->second) {
     107                 :         executionEngine->addGlobalMapping(f, it2->second);
     108                 :         it2->second = 0;
     109                 :       }
     110                 :     }
     111                 : #endif
     112                 : 
     113               84:     dispatcher = createDispatcher(f,i);
     114                 : 
     115              168:     dispatchers.insert(std::make_pair(i, dispatcher));
     116                 : 
                       83: branch 0 taken
                        1: branch 1 taken
     117               84:     if (dispatcher) {
     118                 :       // force the JIT execution engine to go ahead and build the
     119                 :       // function. this ensures that any errors or assertions in the
     120                 :       // compilation process will trigger crashes instead of being
     121                 :       // caught as aborts in the external function.
     122               83:       executionEngine->recompileAndRelinkFunction(dispatcher);
     123                 :     }
     124                 :   } else {
     125              204:     dispatcher = it->second;
     126                 :   }
     127                 : 
     128              288:   return runProtectedCall(dispatcher, args);
     129                 : }
     130                 : 
     131                 : // XXX not reentrant
     132                 : static uint64_t *gTheArgsP;
     133                 : 
     134              288: bool ExternalDispatcher::runProtectedCall(Function *f, uint64_t *args) {
     135                 :   struct sigaction segvAction, segvActionOld;
     136                 :   bool res;
     137                 :   
                        1: branch 0 taken
                      287: branch 1 taken
     138              288:   if (!f)
     139                1:     return false;
     140                 : 
     141                 :   std::vector<GenericValue> gvArgs;
     142              287:   gTheArgsP = args;
     143                 : 
     144              287:   segvAction.sa_handler = 0;
     145                 :   memset(&segvAction.sa_mask, 0, sizeof(segvAction.sa_mask));
     146              287:   segvAction.sa_flags = SA_SIGINFO;
     147              287:   segvAction.sa_sigaction = ::sigsegv_handler;
     148              287:   sigaction(SIGSEGV, &segvAction, &segvActionOld);
     149                 : 
                        0: branch 1 not taken
                      287: branch 2 taken
     150              287:   if (setjmp(escapeCallJmpBuf)) {
     151                0:     res = false;
     152                 :   } else {
     153              287:     executionEngine->runFunction(f, gvArgs);
     154              287:     res = true;
     155                 :   }
     156                 : 
     157              287:   sigaction(SIGSEGV, &segvActionOld, 0);
     158              287:   return res;
     159                 : }
     160                 : 
     161                 : // for performance purposes we construct the stub in such a way that
     162                 : // the arguments pointer is passed through the static global variable
     163                 : // gTheArgsP in this file. This is done so that the stub function
     164                 : // prototype trivially matches the special cases that the JIT knows
     165                 : // how to directly call. If this is not done, then the jit will end up
     166                 : // generating a nullary stub just to call our stub, for every single
     167                 : // function call.
     168               84: Function *ExternalDispatcher::createDispatcher(Function *target, Instruction *inst) {
                        1: branch 2 taken
                       83: branch 3 taken
     169              168:   if (!resolveSymbol(target->getName()))
     170                1:     return 0;
     171                 : 
     172                 :   CallSite cs;
                       83: branch 0 taken
                        0: branch 1 not taken
     173              166:   if (inst->getOpcode()==Instruction::Call) {
     174               83:     cs = CallSite(cast<CallInst>(inst));
     175                 :   } else {
     176                0:     cs = CallSite(cast<InvokeInst>(inst));
     177                 :   }
     178                 : 
     179               83:   Value **args = new Value*[cs.arg_size()];
     180                 : 
     181                 :   std::vector<const Type*> nullary;
     182                 :   
     183                 :   Function *dispatcher = Function::Create(FunctionType::get(Type::VoidTy, 
     184                 : 							    nullary, false),
     185                 : 					  GlobalVariable::ExternalLinkage, 
     186                 : 					  "",
     187              249: 					  dispatchModule);
     188                 : 
     189                 : 
     190              166:   BasicBlock *dBB = BasicBlock::Create("entry", dispatcher);
     191                 : 
     192                 :   Instruction *argI64sp = new IntToPtrInst(ConstantInt::get(Type::Int64Ty, (long) (void*) &gTheArgsP),
     193                 : 					   PointerType::getUnqual(PointerType::getUnqual(Type::Int64Ty)),
     194                 : 					   "argsp",
     195              415: 					   dBB);
     196               83:   Instruction *argI64s = new LoadInst(argI64sp, "args", dBB); 
     197                 : 
     198               83:   unsigned i = 0;
                      138: branch 1 taken
                       83: branch 2 taken
     199              304:   for (CallSite::arg_iterator ai = cs.arg_begin(), ae = cs.arg_end();
     200                 :        ai!=ae; ++ai, ++i) {
     201              138:     Value *index = ConstantInt::get(Type::Int32Ty, i+1);
     202                 : 
     203              276:     Instruction *argI64p = GetElementPtrInst::Create(argI64s, index, "", dBB);
     204                 :     Instruction *argp = new BitCastInst(argI64p, 
     205              414:                                         PointerType::getUnqual((*ai)->getType()), "", dBB);
     206              276:     args[i] = new LoadInst(argp, "", dBB);
     207                 :   }
     208                 : 
     209              166:   Instruction *result = CallInst::Create(target, args, args+i, "", dBB);
     210                 : 
                       83: branch 0 taken
                        0: branch 1 not taken
     211              166:   if (result->getType() != Type::VoidTy) {
     212                 :     Instruction *resp = new BitCastInst(argI64s, 
     213              332:                                         PointerType::getUnqual(result->getType()), "", dBB);
     214               83:     new StoreInst(result, resp, dBB);
     215                 :   }
     216                 : 
     217                 :   ReturnInst::Create(dBB);
     218                 : 
                       83: branch 0 taken
                        0: branch 1 not taken
     219               83:   delete[] args;
     220                 : 
     221               83:   return dispatcher;
                      103: branch 0 taken
                        0: branch 1 not taken
                      103: branch 2 taken
                        0: branch 3 not taken
     222              206: }

Generated: 2009-05-17 22:47 by zcov