klee
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#if LLVM_VERSION_CODE < LLVM_VERSION(8, 0)
14#include "llvm/IR/CallSite.h"
15#endif
16#include "llvm/IR/Constants.h"
17#include "llvm/IR/DerivedTypes.h"
18#include "llvm/IR/IRBuilder.h"
19#include "llvm/IR/Instructions.h"
20#include "llvm/IR/LLVMContext.h"
21#include "llvm/IR/Module.h"
22#include "llvm/ExecutionEngine/GenericValue.h"
23#include "llvm/ExecutionEngine/MCJIT.h"
24#include "llvm/Support/DynamicLibrary.h"
25#include "llvm/Support/raw_ostream.h"
26#include "llvm/Support/TargetSelect.h"
27
28#include <csetjmp>
29#include <csignal>
30
31using namespace llvm;
32using namespace klee;
33
34/***/
35
36static sigjmp_buf escapeCallJmpBuf;
37
38extern "C" {
39
40static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
41 siglongjmp(escapeCallJmpBuf, 1);
42}
43}
44
45namespace klee {
46
48private:
49 typedef std::map<const llvm::Instruction *, llvm::Function *> dispatchers_ty;
51 llvm::Function *createDispatcher(llvm::Function *f, llvm::Instruction *i,
52 llvm::Module *module);
53 llvm::ExecutionEngine *executionEngine;
54 LLVMContext &ctx;
55 std::map<std::string, void *> preboundFunctions;
56 bool runProtectedCall(llvm::Function *f, uint64_t *args);
57 llvm::Module *singleDispatchModule;
58 std::vector<std::string> moduleIDs;
59 std::string &getFreshModuleID();
61
62public:
63 ExternalDispatcherImpl(llvm::LLVMContext &ctx);
65 bool executeCall(llvm::Function *function, llvm::Instruction *i,
66 uint64_t *args);
67 void *resolveSymbol(const std::string &name);
68 int getLastErrno();
69 void setLastErrno(int newErrno);
70};
71
73 // We store the module IDs because `llvm::Module` constructor takes the
74 // module ID as a StringRef so it doesn't own the ID. Therefore we need to
75 // own the ID.
76 static uint64_t counter = 0;
77 std::string underlyingString;
78 llvm::raw_string_ostream ss(underlyingString);
79 ss << "ExternalDispatcherModule_" << counter;
80 moduleIDs.push_back(ss.str()); // moduleIDs now has a copy
81 ++counter; // Increment for next call
82 return moduleIDs.back();
83}
84
85void *ExternalDispatcherImpl::resolveSymbol(const std::string &name) {
86 assert(executionEngine);
87
88 const char *str = name.c_str();
89
90 // We use this to validate that function names can be resolved so we
91 // need to match how the JIT does it. Unfortunately we can't
92 // directly access the JIT resolution function
93 // JIT::getPointerToNamedFunction so we emulate the important points.
94
95 if (str[0] == 1) // asm specifier, skipped
96 ++str;
97
98 void *addr = sys::DynamicLibrary::SearchForAddressOfSymbol(str);
99 if (addr)
100 return addr;
101
102 // If it has an asm specifier and starts with an underscore we retry
103 // without the underscore. I (DWD) don't know why.
104 if (name[0] == 1 && str[0] == '_') {
105 ++str;
106 addr = sys::DynamicLibrary::SearchForAddressOfSymbol(str);
107 }
108
109 return addr;
110}
111
113 : ctx(ctx), lastErrno(0) {
114 std::string error;
116 // The MCJIT JITs whole modules at a time rather than individual functions
117 // so we will let it manage the modules.
118 // Note that we don't do anything with `singleDispatchModule`. This is just
119 // so we can use the EngineBuilder API.
120 auto dispatchModuleUniq = std::unique_ptr<Module>(singleDispatchModule);
121 executionEngine = EngineBuilder(std::move(dispatchModuleUniq))
122 .setErrorStr(&error)
123 .setEngineKind(EngineKind::JIT)
124 .create();
125
126 if (!executionEngine) {
127 llvm::errs() << "unable to make jit: " << error << "\n";
128 abort();
129 }
130
131 // If we have a native target, initialize it to ensure it is linked in and
132 // usable by the JIT.
133 llvm::InitializeNativeTarget();
134 llvm::InitializeNativeTargetAsmParser();
135 llvm::InitializeNativeTargetAsmPrinter();
136
137 // from ExecutionEngine::create
138 if (executionEngine) {
139 // Make sure we can resolve symbols in the program as well. The zero arg
140 // to the function tells DynamicLibrary to load the program, not a library.
141 sys::DynamicLibrary::LoadLibraryPermanently(0);
142 }
143
144#ifdef WINDOWS
145 preboundFunctions["getpid"] = (void *)(long)getpid;
146 preboundFunctions["putchar"] = (void *)(long)putchar;
147 preboundFunctions["printf"] = (void *)(long)printf;
148 preboundFunctions["fprintf"] = (void *)(long)fprintf;
149 preboundFunctions["sprintf"] = (void *)(long)sprintf;
150#endif
151}
152
154 delete executionEngine;
155 // NOTE: the `executionEngine` owns all modules so
156 // we don't need to delete any of them.
157}
158
159bool ExternalDispatcherImpl::executeCall(Function *f, Instruction *i,
160 uint64_t *args) {
161 dispatchers_ty::iterator it = dispatchers.find(i);
162 if (it != dispatchers.end()) {
163 // Code already JIT'ed for this
164 return runProtectedCall(it->second, args);
165 }
166
167 // Code for this not JIT'ed. Do this now.
168 Function *dispatcher;
169#ifdef WINDOWS
170 std::map<std::string, void *>::iterator it2 =
171 preboundFunctions.find(f->getName());
172
173 if (it2 != preboundFunctions.end()) {
174 // only bind once
175 if (it2->second) {
176 executionEngine->addGlobalMapping(f, it2->second);
177 it2->second = 0;
178 }
179 }
180#endif
181
182 Module *dispatchModule = NULL;
183 // The MCJIT generates whole modules at a time so for every call that we
184 // haven't made before we need to create a new Module.
185 dispatchModule = new Module(getFreshModuleID(), ctx);
186 dispatcher = createDispatcher(f, i, dispatchModule);
187 dispatchers.insert(std::make_pair(i, dispatcher));
188
189 // Force the JIT execution engine to go ahead and build the function. This
190 // ensures that any errors or assertions in the compilation process will
191 // trigger crashes instead of being caught as aborts in the external
192 // function.
193 if (dispatcher) {
194 // The dispatchModule is now ready so tell MCJIT to generate the code for
195 // it.
196 auto dispatchModuleUniq = std::unique_ptr<Module>(dispatchModule);
197 executionEngine->addModule(
198 std::move(dispatchModuleUniq)); // MCJIT takes ownership
199 // Force code generation
200 uint64_t fnAddr =
201 executionEngine->getFunctionAddress(dispatcher->getName().str());
202 executionEngine->finalizeObject();
203 assert(fnAddr && "failed to get function address");
204 (void)fnAddr;
205 } else {
206 // MCJIT didn't take ownership of the module so delete it.
207 delete dispatchModule;
208 }
209 return runProtectedCall(dispatcher, args);
210}
211
212// FIXME: This is not reentrant.
213static uint64_t *gTheArgsP;
214bool ExternalDispatcherImpl::runProtectedCall(Function *f, uint64_t *args) {
215 struct sigaction segvAction, segvActionOld;
216 bool res;
217
218 if (!f)
219 return false;
220
221 std::vector<GenericValue> gvArgs;
222 gTheArgsP = args;
223
224 segvAction.sa_handler = nullptr;
225 sigemptyset(&(segvAction.sa_mask));
226 sigaddset(&(segvAction.sa_mask), SIGSEGV);
227 segvAction.sa_flags = SA_SIGINFO;
228 segvAction.sa_sigaction = ::sigsegv_handler;
229 sigaction(SIGSEGV, &segvAction, &segvActionOld);
230
231 if (sigsetjmp(escapeCallJmpBuf, 1)) {
232 res = false;
233 } else {
234 errno = lastErrno;
235 executionEngine->runFunction(f, gvArgs);
236 // Explicitly acquire errno information
237 lastErrno = errno;
238 res = true;
239 }
240
241 sigaction(SIGSEGV, &segvActionOld, nullptr);
242 return res;
243}
244
245// FIXME: This might have been relevant for the old JIT but the MCJIT
246// has a completly different implementation so this comment below is
247// likely irrelevant and misleading.
248//
249// For performance purposes we construct the stub in such a way that the
250// arguments pointer is passed through the static global variable gTheArgsP in
251// this file. This is done so that the stub function prototype trivially matches
252// the special cases that the JIT knows how to directly call. If this is not
253// done, then the jit will end up generating a nullary stub just to call our
254// stub, for every single function call.
256 Instruction *inst,
257 Module *module) {
258 if (!resolveSymbol(target->getName().str()))
259 return 0;
260
261#if LLVM_VERSION_CODE >= LLVM_VERSION(8, 0)
262 const CallBase &cs = cast<CallBase>(*inst);
263#else
264 const CallSite cs(inst->getOpcode() == Instruction::Call
265 ? CallSite(cast<CallInst>(inst))
266 : CallSite(cast<InvokeInst>(inst)));
267#endif
268
269 Value **args = new Value *[cs.arg_size()];
270
271 std::vector<Type *> nullary;
272
273 // MCJIT functions need unique names, or wrong function can be called.
274 // The module identifier is included because for the MCJIT we need
275 // unique function names across all `llvm::Modules`s.
276 std::string fnName =
277 "dispatcher_" + target->getName().str() + module->getModuleIdentifier();
278 Function *dispatcher =
279 Function::Create(FunctionType::get(Type::getVoidTy(ctx), nullary, false),
280 GlobalVariable::ExternalLinkage, fnName, module);
281
282 BasicBlock *dBB = BasicBlock::Create(ctx, "entry", dispatcher);
283
284 llvm::IRBuilder<> Builder(dBB);
285 // Get a Value* for &gTheArgsP, as an i64**.
286 auto argI64sp = Builder.CreateIntToPtr(
287 ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)(void *)&gTheArgsP),
288 PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))),
289 "argsp");
290 auto argI64s = Builder.CreateLoad(
291 argI64sp->getType()->getPointerElementType(), argI64sp, "args");
292
293 // Get the target function type.
294 FunctionType *FTy = cast<FunctionType>(
295 cast<PointerType>(target->getType())->getElementType());
296
297 // Each argument will be passed by writing it into gTheArgsP[i].
298 unsigned i = 0, idx = 2;
299 for (auto ai = cs.arg_begin(), ae = cs.arg_end(); ai != ae; ++ai, ++i) {
300 // Determine the type the argument will be passed as. This accommodates for
301 // the corresponding code in Executor.cpp for handling calls to bitcasted
302 // functions.
303 auto argTy =
304 (i < FTy->getNumParams() ? FTy->getParamType(i) : (*ai)->getType());
305
306 // fp80 must be aligned to 16 according to the System V AMD 64 ABI
307 if (argTy->isX86_FP80Ty() && idx & 0x01)
308 idx++;
309
310 auto argI64p =
311 Builder.CreateGEP(argI64s->getType()->getPointerElementType(), argI64s,
312 ConstantInt::get(Type::getInt32Ty(ctx), idx));
313
314 auto argp = Builder.CreateBitCast(argI64p, PointerType::getUnqual(argTy));
315 args[i] =
316 Builder.CreateLoad(argp->getType()->getPointerElementType(), argp);
317
318 unsigned argSize = argTy->getPrimitiveSizeInBits();
319 idx += ((!!argSize ? argSize : 64) + 63) / 64;
320 }
321
322 auto dispatchTarget = module->getOrInsertFunction(target->getName(), FTy,
323 target->getAttributes());
324 auto result = Builder.CreateCall(dispatchTarget,
325 llvm::ArrayRef<Value *>(args, args + i));
326 if (result->getType() != Type::getVoidTy(ctx)) {
327 auto resp = Builder.CreateBitCast(
328 argI64s, PointerType::getUnqual(result->getType()));
329 Builder.CreateStore(result, resp);
330 }
331
332 Builder.CreateRetVoid();
333
334 delete[] args;
335
336 return dispatcher;
337}
338
341 lastErrno = newErrno;
342}
343
345 : impl(new ExternalDispatcherImpl(ctx)) {}
346
348
349bool ExternalDispatcher::executeCall(llvm::Function *function,
350 llvm::Instruction *i, uint64_t *args) {
351 return impl->executeCall(function, i, args);
352}
353
354void *ExternalDispatcher::resolveSymbol(const std::string &name) {
355 return impl->resolveSymbol(name);
356}
357
360 impl->setLastErrno(newErrno);
361}
362}
static void sigsegv_handler(int signal, siginfo_t *info, void *context)
static sigjmp_buf escapeCallJmpBuf
bool runProtectedCall(llvm::Function *f, uint64_t *args)
bool executeCall(llvm::Function *function, llvm::Instruction *i, uint64_t *args)
std::vector< std::string > moduleIDs
ExternalDispatcherImpl(llvm::LLVMContext &ctx)
void * resolveSymbol(const std::string &name)
std::map< std::string, void * > preboundFunctions
llvm::ExecutionEngine * executionEngine
std::map< const llvm::Instruction *, llvm::Function * > dispatchers_ty
llvm::Function * createDispatcher(llvm::Function *f, llvm::Instruction *i, llvm::Module *module)
void * resolveSymbol(const std::string &name)
bool executeCall(llvm::Function *function, llvm::Instruction *i, uint64_t *args)
void setLastErrno(int newErrno)
ExternalDispatcher(llvm::LLVMContext &ctx)
ExternalDispatcherImpl * impl
Definition: main.cpp:291
static uint64_t * gTheArgsP