static bool valueIsOnlyCalled(const Value *v) { #if LLVM_VERSION_CODE < LLVM_VERSION(3, 5) for (auto it = v->use_begin(), ie = v->use_end(); it != ie; ++it) { auto user = *it; #else for (auto user : v->users()) { #endif if (const auto *instr = dyn_cast<Instruction>(user)) { // Make sure the instruction is a call or invoke. CallSite cs(const_cast<Instruction *>(instr)); if (!cs) return false; // Make sure that the value is only the target of this call and // not an argument. if (cs.hasArgument(v)) return false; } else if (const auto *ce = dyn_cast<ConstantExpr>(user)) { if (ce->getOpcode() == Instruction::BitCast) if (valueIsOnlyCalled(ce)) continue; return false; } else if (const auto *ga = dyn_cast<GlobalAlias>(user)) { if (v == ga->getAliasee() && !valueIsOnlyCalled(ga)) return false; } else if (isa<BlockAddress>(user)) { // only valid as operand to indirectbr or comparison against null continue; } else { return false; } } return true; } bool klee::functionEscapes(const Function *f) { return !valueIsOnlyCalled(f); } bool klee::loadFile(const std::string &fileName, LLVMContext &context, std::vector<std::unique_ptr<llvm::Module>> &modules, std::string &errorMsg) { KLEE_DEBUG_WITH_TYPE("klee_loader", dbgs() << "Load file " << fileName << "\n"); #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) ErrorOr<std::unique_ptr<MemoryBuffer>> bufferErr = MemoryBuffer::getFileOrSTDIN(fileName); std::error_code ec = bufferErr.getError(); #else OwningPtr<MemoryBuffer> Buffer; error_code ec = MemoryBuffer::getFileOrSTDIN(fileName, Buffer); #endif if (ec) { klee_error("Loading file %s failed: %s", fileName.c_str(), ec.message().c_str()); } #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) MemoryBufferRef Buffer = bufferErr.get()->getMemBufferRef(); #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) MemoryBuffer *Buffer = bufferErr->get(); #endif #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) sys::fs::file_magic magic = sys::fs::identify_magic(Buffer.getBuffer()); #else sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); #endif if (magic == sys::fs::file_magic::bitcode) { SMDiagnostic Err; #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) std::unique_ptr<llvm::Module> module(parseIR(Buffer, Err, context)); #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) std::unique_ptr<llvm::Module> module(ParseIR(Buffer, Err, context)); #else std::unique_ptr<llvm::Module> module(ParseIR(Buffer.take(), Err, context)); #endif if (!module) { klee_error("Loading file %s failed: %s", fileName.c_str(), Err.getMessage().str().c_str()); } modules.push_back(std::move(module)); return true; } if (magic == sys::fs::file_magic::archive) { #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) ErrorOr<std::unique_ptr<object::Binary>> archOwner = object::createBinary(Buffer, &context); ec = archOwner.getError(); llvm::object::Binary *arch = archOwner.get().get(); #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) ErrorOr<object::Binary *> archOwner = object::createBinary(std::move(bufferErr.get()), &context); ec = archOwner.getError(); llvm::object::Binary *arch = archOwner.get(); #else OwningPtr<object::Binary> archOwner; ec = object::createBinary(Buffer.take(), archOwner); llvm::object::Binary *arch = archOwner.get(); #endif if (ec) klee_error("Loading file %s failed: %s", fileName.c_str(), ec.message().c_str()); if (auto archive = dyn_cast<object::Archive>(arch)) { // Load all bitcode files into memory #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) for (object::Archive::child_iterator AI = archive->child_begin(), AE = archive->child_end(); AI != AE; ++AI) #else for (object::Archive::child_iterator AI = archive->begin_children(), AE = archive->end_children(); AI != AE; ++AI) #endif { StringRef memberName; #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) std::error_code ec; #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 8) ErrorOr<object::Archive::Child> childOrErr = *AI; ec = childOrErr.getError(); if (ec) { errorMsg = ec.message(); return false; } #else object::Archive::child_iterator childOrErr = AI; #endif ErrorOr<StringRef> memberNameErr = childOrErr->getName(); ec = memberNameErr.getError(); if (!ec) { memberName = memberNameErr.get(); #else error_code ec = AI->getName(memberName); if (ec == errc::success) { #endif KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Loading archive member " << memberName << "\n"); } else { errorMsg = "Archive member does not have a name!\n"; return false; } #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) ErrorOr<std::unique_ptr<llvm::object::Binary>> child = childOrErr->getAsBinary(); ec = child.getError(); #else OwningPtr<object::Binary> child; ec = AI->getAsBinary(child); #endif if (ec) { // If we can't open as a binary object file its hopefully a bitcode file #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) ErrorOr<MemoryBufferRef> buff = childOrErr->getMemoryBufferRef(); ec = buff.getError(); #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) ErrorOr<std::unique_ptr<MemoryBuffer>> buffErr = AI->getMemoryBuffer(); std::unique_ptr<MemoryBuffer> buff = nullptr; ec = buffErr.getError(); if (!ec) buff = std::move(buffErr.get()); #else OwningPtr<MemoryBuffer> buff; ec = AI->getMemoryBuffer(buff); #endif if (ec) { errorMsg = "Failed to get MemoryBuffer: " + ec.message(); return false; } if (buff) { // FIXME: Maybe load bitcode file lazily? Then if we need to link, // materialise // the module SMDiagnostic Err; #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) std::unique_ptr<llvm::Module> module = parseIR(buff.get(), Err, context); #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) std::unique_ptr<llvm::Module> module( ParseIR(buff.get(), Err, context)); #else std::unique_ptr<llvm::Module> module( ParseIR(buff.take(), Err, context)); #endif if (!module) { klee_error("Loading file %s failed: %s", fileName.c_str(), Err.getMessage().str().c_str()); } modules.push_back(std::move(module)); } else { errorMsg = "Buffer was NULL!"; return false; } } else if (child.get()->isObject()) { errorMsg = "Object file " + child.get()->getFileName().str() + " in archive is not supported"; return false; } else { errorMsg = "Loading archive child with error " + ec.message(); return false; } } } return true; } if (magic.is_object()) { errorMsg = "Loading file " + fileName + " Object file as input is currently not supported"; return false; } // This might still be an assembly file. Let's try to parse it. SMDiagnostic Err; #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) std::unique_ptr<llvm::Module> module(parseIR(Buffer, Err, context)); #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) std::unique_ptr<llvm::Module> module(ParseIR(Buffer, Err, context)); #else std::unique_ptr<llvm::Module> module(ParseIR(Buffer.take(), Err, context)); #endif if (!module) { klee_error("Loading file %s failed: Unrecognized file type.", fileName.c_str()); } modules.push_back(std::move(module)); return true; } void klee::checkModule(llvm::Module *m) { LegacyLLVMPassManagerTy pm; pm.add(createVerifierPass()); pm.run(*m); }
Module *klee::linkWithLibrary(Module *module, const std::string &libraryName) { KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Linking file " << libraryName << "\n"); #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) if (!sys::fs::exists(libraryName)) { klee_error("Link with library %s failed. No such file.", libraryName.c_str()); } ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = MemoryBuffer::getFile(libraryName); std::error_code ec; if ((ec = Buffer.getError())) { klee_error("Link with library %s failed: %s", libraryName.c_str(), ec.message().c_str()); } sys::fs::file_magic magic = sys::fs::identify_magic(Buffer.get()->getBuffer()); MemoryBufferRef BufferRef = Buffer.get()->getMemBufferRef(); LLVMContext &Context = getGlobalContext(); std::string ErrorMessage; if (magic == sys::fs::file_magic::bitcode) { ErrorOr<Module *> Result = parseBitcodeFile(BufferRef, Context); if ((ec = Buffer.getError()) || Linker::LinkModules(module, Result.get())) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); delete Result.get(); } else if (magic == sys::fs::file_magic::archive) { ErrorOr<std::unique_ptr<object::Binary>> arch = object::createBinary(BufferRef, &Context); if ((ec = arch.getError())) klee_error("Link with library %s failed: %s", libraryName.c_str(), arch.getError().message().c_str()); if (object::Archive *a = dyn_cast<object::Archive>(arch.get().get())) { // Handle in helper if (!linkBCA(a, module, ErrorMessage)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); } else { klee_error("Link with library %s failed: Cast to archive failed", libraryName.c_str()); } } else if (magic.is_object()) { std::unique_ptr<object::Binary> obj; if (object::ObjectFile *o = dyn_cast<object::ObjectFile>(obj.get())) { klee_warning("Link with library: Object file %s in archive %s found. " "Currently not supported.", o->getFileName().data(), libraryName.c_str()); } } else { klee_error("Link with library %s failed: Unrecognized file type.", libraryName.c_str()); } return module; #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) if (!sys::fs::exists(libraryName)) { klee_error("Link with library %s failed. No such file.", libraryName.c_str()); } OwningPtr<MemoryBuffer> Buffer; if (error_code ec = MemoryBuffer::getFile(libraryName, Buffer)) { klee_error("Link with library %s failed: %s", libraryName.c_str(), ec.message().c_str()); } sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); LLVMContext &Context = getGlobalContext(); std::string ErrorMessage; if (magic == sys::fs::file_magic::bitcode) { Module *Result = 0; Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); if (!Result || Linker::LinkModules(module, Result, Linker::DestroySource, &ErrorMessage)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); delete Result; } else if (magic == sys::fs::file_magic::archive) { OwningPtr<object::Binary> arch; if (error_code ec = object::createBinary(Buffer.take(), arch)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ec.message().c_str()); if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { // Handle in helper if (!linkBCA(a, module, ErrorMessage)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); } else { klee_error("Link with library %s failed: Cast to archive failed", libraryName.c_str()); } } else if (magic.is_object()) { OwningPtr<object::Binary> obj; if (object::ObjectFile *o = dyn_cast<object::ObjectFile>(obj.get())) { klee_warning("Link with library: Object file %s in archive %s found. " "Currently not supported.", o->getFileName().data(), libraryName.c_str()); } } else { klee_error("Link with library %s failed: Unrecognized file type.", libraryName.c_str()); } return module; #else Linker linker("klee", module, false); llvm::sys::Path libraryPath(libraryName); bool native = false; if (linker.LinkInFile(libraryPath, native)) { klee_error("Linking library %s failed", libraryName.c_str()); } return linker.releaseModule(); #endif }