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); }