klee
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ExternalDispatcher.cpp
Go to the documentation of this file.
1 //===-- ExternalDispatcher.cpp --------------------------------------------===//
2 //
3 // The KLEE Symbolic Virtual Machine
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "ExternalDispatcher.h"
11 #include "klee/Config/Version.h"
12 
13 // Ugh.
14 #undef PACKAGE_BUGREPORT
15 #undef PACKAGE_NAME
16 #undef PACKAGE_STRING
17 #undef PACKAGE_TARNAME
18 #undef PACKAGE_VERSION
19 
20 #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3)
21 #include "llvm/IR/Module.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/DerivedTypes.h"
24 #include "llvm/IR/Instructions.h"
25 #include "llvm/IR/LLVMContext.h"
26 #else
27 #include "llvm/Module.h"
28 #include "llvm/Constants.h"
29 #include "llvm/DerivedTypes.h"
30 #include "llvm/Instructions.h"
31 #include "llvm/LLVMContext.h"
32 #endif
33 #include "llvm/ExecutionEngine/JIT.h"
34 #include "llvm/ExecutionEngine/GenericValue.h"
35 #include "llvm/Support/CallSite.h"
36 #include "llvm/Support/DynamicLibrary.h"
37 #include "llvm/Support/raw_ostream.h"
38 #if LLVM_VERSION_CODE < LLVM_VERSION(3, 0)
39 #include "llvm/Target/TargetSelect.h"
40 #else
41 #include "llvm/Support/TargetSelect.h"
42 #endif
43 #include <setjmp.h>
44 #include <signal.h>
45 
46 using namespace llvm;
47 using namespace klee;
48 
49 /***/
50 
51 static jmp_buf escapeCallJmpBuf;
52 
53 extern "C" {
54 
55 static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
56  longjmp(escapeCallJmpBuf, 1);
57 }
58 
59 }
60 
61 void *ExternalDispatcher::resolveSymbol(const std::string &name) {
62  assert(executionEngine);
63 
64  const char *str = name.c_str();
65 
66  // We use this to validate that function names can be resolved so we
67  // need to match how the JIT does it. Unfortunately we can't
68  // directly access the JIT resolution function
69  // JIT::getPointerToNamedFunction so we emulate the important points.
70 
71  if (str[0] == 1) // asm specifier, skipped
72  ++str;
73 
74  void *addr = sys::DynamicLibrary::SearchForAddressOfSymbol(str);
75  if (addr)
76  return addr;
77 
78  // If it has an asm specifier and starts with an underscore we retry
79  // without the underscore. I (DWD) don't know why.
80  if (name[0] == 1 && str[0]=='_') {
81  ++str;
82  addr = sys::DynamicLibrary::SearchForAddressOfSymbol(str);
83  }
84 
85  return addr;
86 }
87 
88 ExternalDispatcher::ExternalDispatcher() {
89  dispatchModule = new Module("ExternalDispatcher", getGlobalContext());
90 
91  std::string error;
92  executionEngine = ExecutionEngine::createJIT(dispatchModule, &error);
93  if (!executionEngine) {
94  llvm::errs() << "unable to make jit: " << error << "\n";
95  abort();
96  }
97 
98  // If we have a native target, initialize it to ensure it is linked in and
99  // usable by the JIT.
100  llvm::InitializeNativeTarget();
101 
102  // from ExecutionEngine::create
103  if (executionEngine) {
104  // Make sure we can resolve symbols in the program as well. The zero arg
105  // to the function tells DynamicLibrary to load the program, not a library.
106  sys::DynamicLibrary::LoadLibraryPermanently(0);
107  }
108 
109 #ifdef WINDOWS
110  preboundFunctions["getpid"] = (void*) (long) getpid;
111  preboundFunctions["putchar"] = (void*) (long) putchar;
112  preboundFunctions["printf"] = (void*) (long) printf;
113  preboundFunctions["fprintf"] = (void*) (long) fprintf;
114  preboundFunctions["sprintf"] = (void*) (long) sprintf;
115 #endif
116 }
117 
118 ExternalDispatcher::~ExternalDispatcher() {
119  delete executionEngine;
120 }
121 
122 bool ExternalDispatcher::executeCall(Function *f, Instruction *i, uint64_t *args) {
123  dispatchers_ty::iterator it = dispatchers.find(i);
124  Function *dispatcher;
125 
126  if (it == dispatchers.end()) {
127 #ifdef WINDOWS
128  std::map<std::string, void*>::iterator it2 =
129  preboundFunctions.find(f->getName()));
130 
131  if (it2 != preboundFunctions.end()) {
132  // only bind once
133  if (it2->second) {
134  executionEngine->addGlobalMapping(f, it2->second);
135  it2->second = 0;
136  }
137  }
138 #endif
139 
140  dispatcher = createDispatcher(f,i);
141 
142  dispatchers.insert(std::make_pair(i, dispatcher));
143 
144  if (dispatcher) {
145  // Force the JIT execution engine to go ahead and build the function. This
146  // ensures that any errors or assertions in the compilation process will
147  // trigger crashes instead of being caught as aborts in the external
148  // function.
149  executionEngine->recompileAndRelinkFunction(dispatcher);
150  }
151  } else {
152  dispatcher = it->second;
153  }
154 
155  return runProtectedCall(dispatcher, args);
156 }
157 
158 // FIXME: This is not reentrant.
159 static uint64_t *gTheArgsP;
160 
161 bool ExternalDispatcher::runProtectedCall(Function *f, uint64_t *args) {
162  struct sigaction segvAction, segvActionOld;
163  bool res;
164 
165  if (!f)
166  return false;
167 
168  std::vector<GenericValue> gvArgs;
169  gTheArgsP = args;
170 
171  segvAction.sa_handler = 0;
172  memset(&segvAction.sa_mask, 0, sizeof(segvAction.sa_mask));
173  segvAction.sa_flags = SA_SIGINFO;
174  segvAction.sa_sigaction = ::sigsegv_handler;
175  sigaction(SIGSEGV, &segvAction, &segvActionOld);
176 
177  if (setjmp(escapeCallJmpBuf)) {
178  res = false;
179  } else {
180  executionEngine->runFunction(f, gvArgs);
181  res = true;
182  }
183 
184  sigaction(SIGSEGV, &segvActionOld, 0);
185  return res;
186 }
187 
188 // For performance purposes we construct the stub in such a way that the
189 // arguments pointer is passed through the static global variable gTheArgsP in
190 // this file. This is done so that the stub function prototype trivially matches
191 // the special cases that the JIT knows how to directly call. If this is not
192 // done, then the jit will end up generating a nullary stub just to call our
193 // stub, for every single function call.
194 Function *ExternalDispatcher::createDispatcher(Function *target, Instruction *inst) {
195  if (!resolveSymbol(target->getName()))
196  return 0;
197 
198  CallSite cs;
199  if (inst->getOpcode()==Instruction::Call) {
200  cs = CallSite(cast<CallInst>(inst));
201  } else {
202  cs = CallSite(cast<InvokeInst>(inst));
203  }
204 
205  Value **args = new Value*[cs.arg_size()];
206 
207  std::vector<LLVM_TYPE_Q Type*> nullary;
208 
209  Function *dispatcher = Function::Create(FunctionType::get(Type::getVoidTy(getGlobalContext()),
210  nullary, false),
211  GlobalVariable::ExternalLinkage,
212  "",
213  dispatchModule);
214 
215 
216  BasicBlock *dBB = BasicBlock::Create(getGlobalContext(), "entry", dispatcher);
217 
218  // Get a Value* for &gTheArgsP, as an i64**.
219  Instruction *argI64sp =
220  new IntToPtrInst(ConstantInt::get(Type::getInt64Ty(getGlobalContext()),
221  (uintptr_t) (void*) &gTheArgsP),
222  PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(getGlobalContext()))),
223  "argsp", dBB);
224  Instruction *argI64s = new LoadInst(argI64sp, "args", dBB);
225 
226  // Get the target function type.
227  LLVM_TYPE_Q FunctionType *FTy =
228  cast<FunctionType>(cast<PointerType>(target->getType())->getElementType());
229 
230  // Each argument will be passed by writing it into gTheArgsP[i].
231  unsigned i = 0, idx = 2;
232  for (CallSite::arg_iterator ai = cs.arg_begin(), ae = cs.arg_end();
233  ai!=ae; ++ai, ++i) {
234  // Determine the type the argument will be passed as. This accomodates for
235  // the corresponding code in Executor.cpp for handling calls to bitcasted
236  // functions.
237  LLVM_TYPE_Q Type *argTy = (i < FTy->getNumParams() ? FTy->getParamType(i) :
238  (*ai)->getType());
239  Instruction *argI64p =
240  GetElementPtrInst::Create(argI64s,
241  ConstantInt::get(Type::getInt32Ty(getGlobalContext()),
242  idx),
243  "", dBB);
244 
245  Instruction *argp = new BitCastInst(argI64p, PointerType::getUnqual(argTy),
246  "", dBB);
247  args[i] = new LoadInst(argp, "", dBB);
248 
249  unsigned argSize = argTy->getPrimitiveSizeInBits();
250  idx += ((!!argSize ? argSize : 64) + 63)/64;
251  }
252 
253  Constant *dispatchTarget =
254  dispatchModule->getOrInsertFunction(target->getName(), FTy,
255  target->getAttributes());
256 #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 0)
257  Instruction *result = CallInst::Create(dispatchTarget,
258  llvm::ArrayRef<Value *>(args, args+i),
259  "", dBB);
260 #else
261  Instruction *result = CallInst::Create(dispatchTarget, args, args+i, "", dBB);
262 #endif
263  if (result->getType() != Type::getVoidTy(getGlobalContext())) {
264  Instruction *resp =
265  new BitCastInst(argI64s, PointerType::getUnqual(result->getType()),
266  "", dBB);
267  new StoreInst(result, resp, dBB);
268  }
269 
270  ReturnInst::Create(getGlobalContext(), dBB);
271 
272  delete[] args;
273 
274  return dispatcher;
275 }
static void sigsegv_handler(int signal, siginfo_t *info, void *context)
static jmp_buf escapeCallJmpBuf
#define LLVM_TYPE_Q
Definition: Version.h:21
static uint64_t * gTheArgsP