/// Get the specified modules ready for code generator testing. /// static void CleanupAndPrepareModules(BugDriver &BD, std::unique_ptr<Module> &Test, Module *Safe) { // Clean up the modules, removing extra cruft that we don't need anymore... Test = BD.performFinalCleanups(Test.get()); // If we are executing the JIT, we have several nasty issues to take care of. if (!BD.isExecutingJIT()) return; // First, if the main function is in the Safe module, we must add a stub to // the Test module to call into it. Thus, we create a new function `main' // which just calls the old one. if (Function *oldMain = Safe->getFunction("main")) if (!oldMain->isDeclaration()) { // Rename it oldMain->setName("llvm_bugpoint_old_main"); // Create a NEW `main' function with same type in the test module. Function *newMain = Function::Create(oldMain->getFunctionType(), GlobalValue::ExternalLinkage, "main", Test.get()); // Create an `oldmain' prototype in the test module, which will // corresponds to the real main function in the same module. Function *oldMainProto = Function::Create(oldMain->getFunctionType(), GlobalValue::ExternalLinkage, oldMain->getName(), Test.get()); // Set up and remember the argument list for the main function. std::vector<Value*> args; for (Function::arg_iterator I = newMain->arg_begin(), E = newMain->arg_end(), OI = oldMain->arg_begin(); I != E; ++I, ++OI) { I->setName(OI->getName()); // Copy argument names from oldMain args.push_back(&*I); } // Call the old main function and return its result BasicBlock *BB = BasicBlock::Create(Safe->getContext(), "entry", newMain); CallInst *call = CallInst::Create(oldMainProto, args, "", BB); // If the type of old function wasn't void, return value of call ReturnInst::Create(Safe->getContext(), call, BB); } // The second nasty issue we must deal with in the JIT is that the Safe // module cannot directly reference any functions defined in the test // module. Instead, we use a JIT API call to dynamically resolve the // symbol. // Add the resolver to the Safe module. // Prototype: void *getPointerToNamedFunction(const char* Name) Constant *resolverFunc = Safe->getOrInsertFunction("getPointerToNamedFunction", Type::getInt8PtrTy(Safe->getContext()), Type::getInt8PtrTy(Safe->getContext()), (Type *)nullptr); // Use the function we just added to get addresses of functions we need. for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) { if (F->isDeclaration() && !F->use_empty() && &*F != resolverFunc && !F->isIntrinsic() /* ignore intrinsics */) { Function *TestFn = Test->getFunction(F->getName()); // Don't forward functions which are external in the test module too. if (TestFn && !TestFn->isDeclaration()) { // 1. Add a string constant with its name to the global file Constant *InitArray = ConstantDataArray::getString(F->getContext(), F->getName()); GlobalVariable *funcName = new GlobalVariable(*Safe, InitArray->getType(), true /*isConstant*/, GlobalValue::InternalLinkage, InitArray, F->getName() + "_name"); // 2. Use `GetElementPtr *funcName, 0, 0' to convert the string to an // sbyte* so it matches the signature of the resolver function. // GetElementPtr *funcName, ulong 0, ulong 0 std::vector<Constant*> GEPargs(2, Constant::getNullValue(Type::getInt32Ty(F->getContext()))); Value *GEP = ConstantExpr::getGetElementPtr(InitArray->getType(), funcName, GEPargs); std::vector<Value*> ResolverArgs; ResolverArgs.push_back(GEP); // Rewrite uses of F in global initializers, etc. to uses of a wrapper // function that dynamically resolves the calls to F via our JIT API if (!F->use_empty()) { // Create a new global to hold the cached function pointer. Constant *NullPtr = ConstantPointerNull::get(F->getType()); GlobalVariable *Cache = new GlobalVariable(*F->getParent(), F->getType(), false, GlobalValue::InternalLinkage, NullPtr,F->getName()+".fpcache"); // Construct a new stub function that will re-route calls to F FunctionType *FuncTy = F->getFunctionType(); Function *FuncWrapper = Function::Create(FuncTy, GlobalValue::InternalLinkage, F->getName() + "_wrapper", F->getParent()); BasicBlock *EntryBB = BasicBlock::Create(F->getContext(), "entry", FuncWrapper); BasicBlock *DoCallBB = BasicBlock::Create(F->getContext(), "usecache", FuncWrapper); BasicBlock *LookupBB = BasicBlock::Create(F->getContext(), "lookupfp", FuncWrapper); // Check to see if we already looked up the value. Value *CachedVal = new LoadInst(Cache, "fpcache", EntryBB); Value *IsNull = new ICmpInst(*EntryBB, ICmpInst::ICMP_EQ, CachedVal, NullPtr, "isNull"); BranchInst::Create(LookupBB, DoCallBB, IsNull, EntryBB); // Resolve the call to function F via the JIT API: // // call resolver(GetElementPtr...) CallInst *Resolver = CallInst::Create(resolverFunc, ResolverArgs, "resolver", LookupBB); // Cast the result from the resolver to correctly-typed function. CastInst *CastedResolver = new BitCastInst(Resolver, PointerType::getUnqual(F->getFunctionType()), "resolverCast", LookupBB); // Save the value in our cache. new StoreInst(CastedResolver, Cache, LookupBB); BranchInst::Create(DoCallBB, LookupBB); PHINode *FuncPtr = PHINode::Create(NullPtr->getType(), 2, "fp", DoCallBB); FuncPtr->addIncoming(CastedResolver, LookupBB); FuncPtr->addIncoming(CachedVal, EntryBB); // Save the argument list. std::vector<Value*> Args; for (Argument &A : FuncWrapper->args()) Args.push_back(&A); // Pass on the arguments to the real function, return its result if (F->getReturnType()->isVoidTy()) { CallInst::Create(FuncPtr, Args, "", DoCallBB); ReturnInst::Create(F->getContext(), DoCallBB); } else { CallInst *Call = CallInst::Create(FuncPtr, Args, "retval", DoCallBB); ReturnInst::Create(F->getContext(),Call, DoCallBB); } // Use the wrapper function instead of the old function F->replaceAllUsesWith(FuncWrapper); } } } } if (verifyModule(*Test) || verifyModule(*Safe)) { errs() << "Bugpoint has a bug, which corrupted a module!!\n"; abort(); } }
bool SpBasicBlockInstrumenter::runOnModule(Module &M) { cerr << "instrument: --- Basic Block Spectrum ---\n"; Function *Main = M.getFunction("main"); LLVMContext &C = M.getContext(); if (Main == 0) { cerr << "WARNING: cannot insert block instrumentation into a module" << " with no main function!\n"; return false; // No main, no instrumentation! } // Add library function prototype Constant *SpFn = M.getOrInsertFunction("_updateSpectrum", Type::getVoidTy(C), Type::getInt32Ty(C), // spectrum index Type::getInt32Ty(C), // component index NULL); unsigned spectrumIndex = IndexManager::getSpectrumIndex(); unsigned nComponents = 0; // Loop through all functions within module for (Module::iterator F = M.begin(), ME = M.end(); F != ME; ++F) { // skip function declarations if(F->isDeclaration()) continue; // skip the _registerAll function if(F->getName()=="_registerAll") continue; // Loop through all basic blocks within function for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { //skip dead blocks //is this really safe?? BasicBlock *bb = B; if (B!=F->begin() && (pred_begin(bb)==pred_end(bb))) continue; //skip dead blocks // Loop through all instructions within basic block for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE; I++) { if(isa<DbgStopPointInst>(*I)) { DbgStopPointInst &DSPI = cast<DbgStopPointInst>(*I); std::string file, dir, name="-"; llvm::GetConstantStringInfo(DSPI.getDirectory(), dir); llvm::GetConstantStringInfo(DSPI.getFileName(), file); int line = DSPI.getLine(); // add source context of this invariant to context file ContextManager::addSpectrumContext( spectrumIndex, // spectrumIndex nComponents, // componentIndex dir, // path file, // file line, // line name); // name // add call to lib function std::vector<Value*> Args(2); Args[0] = ConstantInt::get(Type::getInt32Ty(C), spectrumIndex); Args[1] = ConstantInt::get(Type::getInt32Ty(C), nComponents++); CallInst::Create(SpFn, Args.begin(), Args.end(), "", I); break; } } } } // add the registration of the instrumented spectrum points in the _registerAll() function addSpectrumRegistration(M, spectrumIndex, nComponents, "Basic_Blocks"); llvm::cerr << "instrument: " << nComponents << " basic blocks instrumented\n"; // notify change of program return true; }
/// Given a reduced list of functions that still exposed the bug, check to see /// if we can extract the loops in the region without obscuring the bug. If so, /// it reduces the amount of code identified. /// static bool ExtractLoops(BugDriver &BD, bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, std::unique_ptr<Module>, std::string &), std::vector<Function *> &MiscompiledFunctions, std::string &Error) { bool MadeChange = false; while (1) { if (BugpointIsInterrupted) return MadeChange; ValueToValueMapTy VMap; std::unique_ptr<Module> ToNotOptimize = CloneModule(BD.getProgram(), VMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize.get(), MiscompiledFunctions, VMap) .release(); std::unique_ptr<Module> ToOptimizeLoopExtracted = BD.extractLoop(ToOptimize); if (!ToOptimizeLoopExtracted) { // If the loop extractor crashed or if there were no extractible loops, // then this chapter of our odyssey is over with. delete ToOptimize; return MadeChange; } errs() << "Extracted a loop from the breaking portion of the program.\n"; // Bugpoint is intentionally not very trusting of LLVM transformations. In // particular, we're not going to assume that the loop extractor works, so // we're going to test the newly loop extracted program to make sure nothing // has broken. If something broke, then we'll inform the user and stop // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); bool Failure; std::unique_ptr<Module> New = testMergedProgram(BD, std::move(ToOptimizeLoopExtracted), std::move(ToNotOptimize), Error, Failure); if (!New) return false; // Delete the original and set the new program. Module *Old = BD.swapProgramIn(New.release()); for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); delete Old; if (Failure) { BD.switchToInterpreter(AI); // Merged program doesn't work anymore! errs() << " *** ERROR: Loop extraction broke the program. :(" << " Please report a bug!\n"; errs() << " Continuing on with un-loop-extracted version.\n"; BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-tno.bc", ToNotOptimize.get()); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to.bc", ToOptimize); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc", ToOptimizeLoopExtracted.get()); errs() << "Please submit the " << OutputPrefix << "-loop-extract-fail-*.bc files.\n"; delete ToOptimize; return MadeChange; } delete ToOptimize; BD.switchToInterpreter(AI); outs() << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. std::unique_ptr<Module> TOLEBackup = CloneModule(ToOptimizeLoopExtracted.get(), VMap); std::unique_ptr<Module> TNOBackup = CloneModule(ToNotOptimize.get(), VMap); for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); Failure = TestFn(BD, std::move(ToOptimizeLoopExtracted), std::move(ToNotOptimize), Error); if (!Error.empty()) return false; ToOptimizeLoopExtracted = std::move(TOLEBackup); ToNotOptimize = std::move(TNOBackup); if (!Failure) { outs() << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; for (Function *F : MiscompiledFunctions) { MisCompFunctions.emplace_back(F->getName(), F->getFunctionType()); } if (Linker::linkModules(*ToNotOptimize, std::move(ToOptimizeLoopExtracted))) exit(1); MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); MiscompiledFunctions.push_back(NewF); } BD.setNewProgram(ToNotOptimize.release()); return MadeChange; } outs() << "*** Loop extraction successful!\n"; std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; for (Module::iterator I = ToOptimizeLoopExtracted->begin(), E = ToOptimizeLoopExtracted->end(); I != E; ++I) if (!I->isDeclaration()) MisCompFunctions.emplace_back(I->getName(), I->getFunctionType()); // Okay, great! Now we know that we extracted a loop and that loop // extraction both didn't break the program, and didn't mask the problem. // Replace the current program with the loop extracted version, and try to // extract another loop. if (Linker::linkModules(*ToNotOptimize, std::move(ToOptimizeLoopExtracted))) exit(1); // All of the Function*'s in the MiscompiledFunctions list are in the old // module. Update this list to include all of the functions in the // optimized and loop extracted module. MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); MiscompiledFunctions.push_back(NewF); } BD.setNewProgram(ToNotOptimize.release()); MadeChange = true; } }
/// Given a reduced list of functions that still expose the bug, extract as many /// basic blocks from the region as possible without obscuring the bug. /// static bool ExtractBlocks(BugDriver &BD, bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, std::unique_ptr<Module>, std::string &), std::vector<Function *> &MiscompiledFunctions, std::string &Error) { if (BugpointIsInterrupted) return false; std::vector<BasicBlock*> Blocks; for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) for (BasicBlock &BB : *MiscompiledFunctions[i]) Blocks.push_back(&BB); // Use the list reducer to identify blocks that can be extracted without // obscuring the bug. The Blocks list will end up containing blocks that must // be retained from the original program. unsigned OldSize = Blocks.size(); // Check to see if all blocks are extractible first. bool Ret = ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions) .TestFuncs(std::vector<BasicBlock*>(), Error); if (!Error.empty()) return false; if (Ret) { Blocks.clear(); } else { ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions).reduceList(Blocks, Error); if (!Error.empty()) return false; if (Blocks.size() == OldSize) return false; } ValueToValueMapTy VMap; Module *ProgClone = CloneModule(BD.getProgram(), VMap).release(); Module *ToExtract = SplitFunctionsOutOfModule(ProgClone, MiscompiledFunctions, VMap) .release(); std::unique_ptr<Module> Extracted = BD.extractMappedBlocksFromModule(Blocks, ToExtract); if (!Extracted) { // Weird, extraction should have worked. errs() << "Nondeterministic problem extracting blocks??\n"; delete ProgClone; delete ToExtract; return false; } // Otherwise, block extraction succeeded. Link the two program fragments back // together. delete ToExtract; std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; for (Module::iterator I = Extracted->begin(), E = Extracted->end(); I != E; ++I) if (!I->isDeclaration()) MisCompFunctions.emplace_back(I->getName(), I->getFunctionType()); if (Linker::linkModules(*ProgClone, std::move(Extracted))) exit(1); // Set the new program and delete the old one. BD.setNewProgram(ProgClone); // Update the list of miscompiled functions. MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); MiscompiledFunctions.push_back(NewF); } return true; }
void StatsTracker::writeIStats() { Module *m = executor.kmodule->module; uint64_t istatsMask = 0; llvm::raw_fd_ostream &of = *istatsFile; // We assume that we didn't move the file pointer unsigned istatsSize = of.tell(); of.seek(0); of << "version: 1\n"; of << "creator: klee\n"; of << "pid: " << getpid() << "\n"; of << "cmd: " << m->getModuleIdentifier() << "\n\n"; of << "\n"; StatisticManager &sm = *theStatisticManager; unsigned nStats = sm.getNumStatistics(); // Max is 13, sadly istatsMask |= 1<<sm.getStatisticID("Queries"); istatsMask |= 1<<sm.getStatisticID("QueriesValid"); istatsMask |= 1<<sm.getStatisticID("QueriesInvalid"); istatsMask |= 1<<sm.getStatisticID("QueryTime"); istatsMask |= 1<<sm.getStatisticID("ResolveTime"); istatsMask |= 1<<sm.getStatisticID("Instructions"); istatsMask |= 1<<sm.getStatisticID("InstructionTimes"); istatsMask |= 1<<sm.getStatisticID("InstructionRealTimes"); istatsMask |= 1<<sm.getStatisticID("Forks"); istatsMask |= 1<<sm.getStatisticID("CoveredInstructions"); istatsMask |= 1<<sm.getStatisticID("UncoveredInstructions"); istatsMask |= 1<<sm.getStatisticID("States"); istatsMask |= 1<<sm.getStatisticID("MinDistToUncovered"); of << "positions: instr line\n"; for (unsigned i=0; i<nStats; i++) { if (istatsMask & (1<<i)) { Statistic &s = sm.getStatistic(i); of << "event: " << s.getShortName() << " : " << s.getName() << "\n"; } } of << "events: "; for (unsigned i=0; i<nStats; i++) { if (istatsMask & (1<<i)) of << sm.getStatistic(i).getShortName() << " "; } of << "\n"; // set state counts, decremented after we process so that we don't // have to zero all records each time. if (istatsMask & (1<<stats::states.getID())) updateStateStatistics(1); std::string sourceFile = ""; CallSiteSummaryTable callSiteStats; if (UseCallPaths) callPathManager.getSummaryStatistics(callSiteStats); of << "ob=" << objectFilename << "\n"; for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); fnIt != fn_ie; ++fnIt) { if (!fnIt->isDeclaration()) { // Always try to write the filename before the function name, as otherwise // KCachegrind can create two entries for the function, one with an // unnamed file and one without. const InstructionInfo &ii = executor.kmodule->infos->getFunctionInfo(fnIt); if (ii.file != sourceFile) { of << "fl=" << ii.file << "\n"; sourceFile = ii.file; } of << "fn=" << fnIt->getName().str() << "\n"; for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); bbIt != bb_ie; ++bbIt) { for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); it != ie; ++it) { Instruction *instr = &*it; const InstructionInfo &ii = executor.kmodule->infos->getInfo(instr); unsigned index = ii.id; if (ii.file!=sourceFile) { of << "fl=" << ii.file << "\n"; sourceFile = ii.file; } of << ii.assemblyLine << " "; of << ii.line << " "; for (unsigned i=0; i<nStats; i++) if (istatsMask&(1<<i)) of << sm.getIndexedValue(sm.getStatistic(i), index) << " "; of << "\n"; if (UseCallPaths && (isa<CallInst>(instr) || isa<InvokeInst>(instr))) { CallSiteSummaryTable::iterator it = callSiteStats.find(instr); if (it!=callSiteStats.end()) { for (std::map<llvm::Function*, CallSiteInfo>::iterator fit = it->second.begin(), fie = it->second.end(); fit != fie; ++fit) { Function *f = fit->first; CallSiteInfo &csi = fit->second; const InstructionInfo &fii = executor.kmodule->infos->getFunctionInfo(f); if (fii.file!="" && fii.file!=sourceFile) of << "cfl=" << fii.file << "\n"; of << "cfn=" << f->getName().str() << "\n"; of << "calls=" << csi.count << " "; of << fii.assemblyLine << " "; of << fii.line << "\n"; of << ii.assemblyLine << " "; of << ii.line << " "; for (unsigned i=0; i<nStats; i++) { if (istatsMask&(1<<i)) { Statistic &s = sm.getStatistic(i); uint64_t value; // Hack, ignore things that don't make sense on // call paths. if (&s == &stats::uncoveredInstructions) { value = 0; } else { value = csi.statistics.getValue(s); } of << value << " "; } } of << "\n"; } } } } } } } if (istatsMask & (1<<stats::states.getID())) updateStateStatistics((uint64_t)-1); // Clear then end of the file if necessary (no truncate op?). unsigned pos = of.tell(); for (unsigned i=pos; i<istatsSize; ++i) of << '\n'; of.flush(); }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); // Use lazy loading, since we only care about selected global values. SMDiagnostic Err; std::auto_ptr<Module> M; M.reset(getLazyIRFileModule(InputFilename, Err, Context)); if (M.get() == 0) { Err.Print(argv[0], errs()); return 1; } // Use SetVector to avoid duplicates. SetVector<GlobalValue *> GVs; // Figure out which globals we should extract. for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) { GlobalValue *GV = M.get()->getNamedGlobal(ExtractGlobals[i]); if (!GV) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractGlobals[i] << "'!\n"; return 1; } GVs.insert(GV); } // Extract globals via regular expression matching. for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) { std::string Error; Regex RegEx(ExtractRegExpGlobals[i]); if (!RegEx.isValid(Error)) { errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' " "invalid regex: " << Error; } bool match = false; for (Module::global_iterator GV = M.get()->global_begin(), E = M.get()->global_end(); GV != E; GV++) { if (RegEx.match(GV->getName())) { GVs.insert(&*GV); match = true; } } if (!match) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractRegExpGlobals[i] << "'!\n"; return 1; } } // Figure out which functions we should extract. for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) { GlobalValue *GV = M.get()->getFunction(ExtractFuncs[i]); if (!GV) { errs() << argv[0] << ": program doesn't contain function named '" << ExtractFuncs[i] << "'!\n"; return 1; } GVs.insert(GV); } // Extract functions via regular expression matching. for (size_t i = 0, e = ExtractRegExpFuncs.size(); i != e; ++i) { std::string Error; StringRef RegExStr = ExtractRegExpFuncs[i]; Regex RegEx(RegExStr); if (!RegEx.isValid(Error)) { errs() << argv[0] << ": '" << ExtractRegExpFuncs[i] << "' " "invalid regex: " << Error; } bool match = false; for (Module::iterator F = M.get()->begin(), E = M.get()->end(); F != E; F++) { if (RegEx.match(F->getName())) { GVs.insert(&*F); match = true; } } if (!match) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractRegExpFuncs[i] << "'!\n"; return 1; } } // Materialize requisite global values. if (!DeleteFn) for (size_t i = 0, e = GVs.size(); i != e; ++i) { GlobalValue *GV = GVs[i]; if (GV->isMaterializable()) { std::string ErrInfo; if (GV->Materialize(&ErrInfo)) { errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; return 1; } } } else { // Deleting. Materialize every GV that's *not* in GVs. SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end()); for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) { GlobalVariable *G = I; if (!GVSet.count(G) && G->isMaterializable()) { std::string ErrInfo; if (G->Materialize(&ErrInfo)) { errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; return 1; } } } for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { Function *F = I; if (!GVSet.count(F) && F->isMaterializable()) { std::string ErrInfo; if (F->Materialize(&ErrInfo)) { errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; return 1; } } } } // In addition to deleting all other functions, we also want to spiff it // up a little bit. Do this now. PassManager Passes; Passes.add(new TargetData(M.get())); // Use correct TargetData std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); Passes.add(createGVExtractionPass(Gvs, DeleteFn)); if (!DeleteFn) Passes.add(createGlobalDCEPass()); // Delete unreachable globals Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls std::string ErrorInfo; tool_output_file Out(OutputFilename.c_str(), ErrorInfo, raw_fd_ostream::F_Binary); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } if (OutputAssembly) Passes.add(createPrintModulePass(&Out.os())); else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) Passes.add(createBitcodeWriterPass(Out.os())); Passes.run(*M.get()); // Declare success. Out.keep(); return 0; }
/// Based on GetAllUndefinedSymbols() from LLVM3.2 /// /// GetAllUndefinedSymbols - calculates the set of undefined symbols that still /// exist in an LLVM module. This is a bit tricky because there may be two /// symbols with the same name but different LLVM types that will be resolved to /// each other but aren't currently (thus we need to treat it as resolved). /// /// Inputs: /// M - The module in which to find undefined symbols. /// /// Outputs: /// UndefinedSymbols - A set of C++ strings containing the name of all /// undefined symbols. /// static void GetAllUndefinedSymbols(Module *M, std::set<std::string> &UndefinedSymbols) { static const std::string llvmIntrinsicPrefix="llvm."; std::set<std::string> DefinedSymbols; UndefinedSymbols.clear(); KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "*** Computing undefined symbols ***\n"); for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) if (I->hasName()) { if (I->isDeclaration()) UndefinedSymbols.insert(I->getName()); else if (!I->hasLocalLinkage()) { #if LLVM_VERSION_CODE < LLVM_VERSION(3, 5) assert(!I->hasDLLImportLinkage() && "Found dllimported non-external symbol!"); #else assert(!I->hasDLLImportStorageClass() && "Found dllimported non-external symbol!"); #endif DefinedSymbols.insert(I->getName()); } } for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) if (I->hasName()) { if (I->isDeclaration()) UndefinedSymbols.insert(I->getName()); else if (!I->hasLocalLinkage()) { #if LLVM_VERSION_CODE < LLVM_VERSION(3, 5) assert(!I->hasDLLImportLinkage() && "Found dllimported non-external symbol!"); #else assert(!I->hasDLLImportStorageClass() && "Found dllimported non-external symbol!"); #endif DefinedSymbols.insert(I->getName()); } } for (Module::alias_iterator I = M->alias_begin(), E = M->alias_end(); I != E; ++I) if (I->hasName()) DefinedSymbols.insert(I->getName()); // Prune out any defined symbols from the undefined symbols set // and other symbols we don't want to treat as an undefined symbol std::vector<std::string> SymbolsToRemove; for (std::set<std::string>::iterator I = UndefinedSymbols.begin(); I != UndefinedSymbols.end(); ++I ) { if (DefinedSymbols.count(*I)) { SymbolsToRemove.push_back(*I); continue; } // Strip out llvm intrinsics if ( (I->size() >= llvmIntrinsicPrefix.size() ) && (I->compare(0, llvmIntrinsicPrefix.size(), llvmIntrinsicPrefix) == 0) ) { KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "LLVM intrinsic " << *I << " has will be removed from undefined symbols"<< "\n"); SymbolsToRemove.push_back(*I); continue; } // Symbol really is undefined KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Symbol " << *I << " is undefined.\n"); } // Remove KLEE intrinsics from set of undefined symbols for (SpecialFunctionHandler::const_iterator sf = SpecialFunctionHandler::begin(), se = SpecialFunctionHandler::end(); sf != se; ++sf) { if (UndefinedSymbols.find(sf->name) == UndefinedSymbols.end()) continue; SymbolsToRemove.push_back(sf->name); KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "KLEE intrinsic " << sf->name << " has will be removed from undefined symbols"<< "\n"); } // Now remove the symbols from undefined set. for (size_t i = 0, j = SymbolsToRemove.size(); i < j; ++i ) UndefinedSymbols.erase(SymbolsToRemove[i]); KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "*** Finished computing undefined symbols ***\n"); }
bool BUDataStructures::runOnModuleInternal(Module& M) { std::vector<const Function*> Stack; hash_map<const Function*, unsigned> ValMap; unsigned NextID = 1; Function *MainFunc = M.getFunction("main"); if (MainFunc && !MainFunc->isDeclaration()) { calculateGraphs(MainFunc, Stack, NextID, ValMap); CloneAuxIntoGlobal(getDSGraph(MainFunc)); } else { DEBUG(errs() << debugname << ": No 'main' function found!\n"); } // Calculate the graphs for any functions that are unreachable from main... for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration() && !hasDSGraph(I)) { if (MainFunc) DEBUG(errs() << debugname << ": Function unreachable from main: " << I->getName() << "\n"); calculateGraphs(I, Stack, NextID, ValMap); // Calculate all graphs. CloneAuxIntoGlobal(getDSGraph(I)); } // If we computed any temporary indcallgraphs, free them now. for (std::map<std::vector<const Function*>, std::pair<DSGraph*, std::vector<DSNodeHandle> > >::iterator I = IndCallGraphMap.begin(), E = IndCallGraphMap.end(); I != E; ++I) { I->second.second.clear(); // Drop arg refs into the graph. delete I->second.first; } IndCallGraphMap.clear(); // At the end of the bottom-up pass, the globals graph becomes complete. // FIXME: This is not the right way to do this, but it is sorta better than // nothing! In particular, externally visible globals and unresolvable call // nodes at the end of the BU phase should make things that they point to // incomplete in the globals graph. // finalizeGlobals(); GlobalsGraph->removeTriviallyDeadNodes(true); GlobalsGraph->maskIncompleteMarkers(); // Mark external globals incomplete. GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); formGlobalECs(); // Merge the globals variables (not the calls) from the globals graph back // into the main function's graph so that the main function contains all of // the information about global pools and GV usage in the program. if (MainFunc && !MainFunc->isDeclaration()) { DSGraph* MainGraph = getDSGraph(MainFunc); const DSGraph* GG = MainGraph->getGlobalsGraph(); ReachabilityCloner RC(MainGraph, GG, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); // Clone the global nodes into this graph. for (DSScalarMap::global_iterator I = GG->getScalarMap().global_begin(), E = GG->getScalarMap().global_end(); I != E; ++I) if (isa<GlobalVariable>(*I)) RC.getClonedNH(GG->getNodeForValue(*I)); MainGraph->maskIncompleteMarkers(); MainGraph->markIncompleteNodes(DSGraph::MarkFormalArgs | DSGraph::IgnoreGlobals); } NumCallEdges += callee.size(); return false; }
Module *klee::linkWithLibrary(Module *module, const std::string &libraryName, std::set<std::string>* kleeFunctions, std::set<std::string>* intrinsicFunctions) { DEBUG_WITH_TYPE("klee_linker", dbgs() << "Linking file " << libraryName << "\n"); #if 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()); if (kleeFunctions && intrinsicFunctions) { for (Module::iterator fi = Result->begin(), fe = Result->end(); fi != fe; fi++) { std::string functionName = fi->getName().str(); if (fi->getName().startswith("klee") || fi->getName().startswith("llvm")) { kleeFunctions->insert(functionName); } else { intrinsicFunctions->insert(functionName); } } } 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 }
bool InternalizePass::runOnModule(Module &M) { CallGraph *CG = getAnalysisIfAvailable<CallGraph>(); CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : 0; bool Changed = false; // Never internalize functions which code-gen might insert. // FIXME: We should probably add this (and the __stack_chk_guard) via some // type of call-back in CodeGen. ExternalNames.insert("__stack_chk_fail"); // Mark all functions not in the api as internal. // FIXME: maybe use private linkage? for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration() && // Function must be defined here // Available externally is really just a "declaration with a body". !I->hasAvailableExternallyLinkage() && !I->hasLocalLinkage() && // Can't already have internal linkage !ExternalNames.count(I->getName())) {// Not marked to keep external? I->setLinkage(GlobalValue::InternalLinkage); // Remove a callgraph edge from the external node to this function. if (ExternalNode) ExternalNode->removeOneAbstractEdgeTo((*CG)[I]); Changed = true; ++NumFunctions; DEBUG(dbgs() << "Internalizing func " << I->getName() << "\n"); } // Never internalize the llvm.used symbol. It is used to implement // attribute((used)). // FIXME: Shouldn't this just filter on llvm.metadata section?? ExternalNames.insert("llvm.used"); ExternalNames.insert("llvm.compiler.used"); // Never internalize anchors used by the machine module info, else the info // won't find them. (see MachineModuleInfo.) ExternalNames.insert("llvm.global_ctors"); ExternalNames.insert("llvm.global_dtors"); ExternalNames.insert("llvm.global.annotations"); // Never internalize symbols code-gen inserts. ExternalNames.insert("__stack_chk_guard"); // Mark all global variables with initializers that are not in the api as // internal as well. // FIXME: maybe use private linkage? for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) if (!I->isDeclaration() && !I->hasLocalLinkage() && // Available externally is really just a "declaration with a body". !I->hasAvailableExternallyLinkage() && !ExternalNames.count(I->getName())) { I->setLinkage(GlobalValue::InternalLinkage); Changed = true; ++NumGlobals; DEBUG(dbgs() << "Internalized gvar " << I->getName() << "\n"); } // Mark all aliases that are not in the api as internal as well. for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end(); I != E; ++I) if (!I->isDeclaration() && !I->hasInternalLinkage() && // Available externally is really just a "declaration with a body". !I->hasAvailableExternallyLinkage() && !ExternalNames.count(I->getName())) { I->setLinkage(GlobalValue::InternalLinkage); Changed = true; ++NumAliases; DEBUG(dbgs() << "Internalized alias " << I->getName() << "\n"); } return Changed; }
bool InvLoadInstrumenter::runOnModule(Module &M) { Function *Main = M.getFunction("main"); LLVMContext &C = M.getContext(); cerr << "instrument: --- Load Invariant ---\n"; if (Main == 0) { cerr << "WARNING: cannot insert load instrumentation into a module" << " with no main function!\n"; return false; // No main, no instrumentation! } // Add library function prototypes Constant *LoadDoubleFn = M.getOrInsertFunction("_handleInvariantChangeDouble", Type::getVoidTy(C), // returns void Type::getInt32Ty(C), // invTypeIndex Type::getInt32Ty(C), // invIndex Type::getDoubleTy(C), // val NULL); Constant *LoadIntegerFn = M.getOrInsertFunction("_handleInvariantChangeInt", Type::getVoidTy(C), // returns void Type::getInt32Ty(C), // invTypeIndex Type::getInt32Ty(C), // invIndex Type::getInt32Ty(C), // val NULL); Constant *LoadPointerFn = M.getOrInsertFunction("_handleInvariantChangePtr", Type::getVoidTy(C), // returns void Type::getInt32Ty(C), // invTypeIndex Type::getInt32Ty(C), // invIndex PointerType::getUnqual(Type::getInt32Ty(C)), // val NULL); Constant *LoadUintFn = M.getOrInsertFunction("_handleInvariantChangeUInt", Type::getVoidTy(C), // returns void Type::getInt32Ty(C), // invTypeIndex Type::getInt32Ty(C), // invIndex Type::getInt32Ty(C), // val NULL); TargetData targetData(&M); unsigned int nInvariants = 0; unsigned int invariantTypeIndex = IndexManager::getInvariantTypeIndex(); // Loop through all functions within module for (Module::iterator F = M.begin(), ME = M.end(); F != ME; ++F) { std::string dir="-", file="-", name="-"; int line = 0; // skip the _registerAll function if(F->getName()=="_registerAll") continue; // Loop through all basic blocks within function for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { // Loop through all instructions within basic block for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE; I++) { // remember information of the last known debug stoppoint if(isa<DbgStopPointInst>(*I)) { DbgStopPointInst &DSPI = cast<DbgStopPointInst>(*I); llvm::GetConstantStringInfo(DSPI.getDirectory(), dir); llvm::GetConstantStringInfo(DSPI.getFileName(), file); line = DSPI.getLine(); } // Consider only load instructions if(isa<LoadInst>(*I)) { LoadInst &LD = cast<LoadInst>(*I); Value *Val = LD.getOperand(0); // value to be loaded const Type *InstType = LD.getType(); // type of loaded value std::vector<Value*> Args(3); // try to get name of the loaded value: // "variableName" // "-" if it cannot be found if(Val->hasName()) { name = Val->getName(); } else if(Val->getUnderlyingObject()->hasName()) { name = Val->getUnderlyingObject()->getName(); } else { name = "-"; } // add source context of this invariant to context file ContextManager::addInvariantTypeContext( invariantTypeIndex, // invariantTypeIndex nInvariants, // invariantIndex dir, // path file, // file line, // line name); // name // needs to be instrumented after the value has been loaded I++; // insert call to correct library function, // which depends on the type of the loaded value, // after the current load instruction if(InstType->isInteger()) { Args[0] = ConstantInt::get(Type::getInt32Ty(C), invariantTypeIndex); Args[1] = ConstantInt::get(Type::getInt32Ty(C), nInvariants++); Args[2] = CastInst::CreateIntegerCast(&LD, Type::getInt32Ty(C), true, "ld.cast", I); CallInst::Create(LoadIntegerFn, Args.begin(), Args.end(), "", I); } else if(InstType->isFloatingPoint()) { Args[0] = ConstantInt::get(Type::getInt32Ty(C), invariantTypeIndex); Args[1] = ConstantInt::get(Type::getInt32Ty(C), nInvariants++); Args[2] = CastInst::CreateFPCast(&LD, Type::getDoubleTy(C), "ld.cast", I); CallInst::Create(LoadDoubleFn, Args.begin(), Args.end(), "", I); } else if(isa<PointerType>(InstType)) { Args[0] = ConstantInt::get(Type::getInt32Ty(C), invariantTypeIndex); Args[1] = ConstantInt::get(Type::getInt32Ty(C), nInvariants++); Args[2] = CastInst::CreatePointerCast(&LD, PointerType::getUnqual(Type::getInt32Ty(C)), "ld.cast", I); CallInst::Create(LoadPointerFn, Args.begin(), Args.end(), "", I); } else { Args[0] = ConstantInt::get(Type::getInt32Ty(C), invariantTypeIndex); Args[1] = ConstantInt::get(Type::getInt32Ty(C), nInvariants++); Args[2] = ConstantInt::get(Type::getInt32Ty(C), 0); CallInst::Create(LoadUintFn, Args.begin(), Args.end(), "", I); } I--; } } } } // add the registration of the instrumented invariants in the _registerAll() function addInvariantTypeRegistration(M, invariantTypeIndex, nInvariants, "Loads", 0); llvm::cerr << "instrument: " << nInvariants << " load operations instrumented\n"; // notify change of program return true; }
void ComputeSSO::HandleQueries(Module& M) { for(set<QueryInput*>::iterator qit = queryinputs.begin();qit!=queryinputs.end();++qit) { bool constCheck; errs()<<"\n\n\n\n*******************************************************Query "; errs()<<"\nOperation : "<<(*qit)->operation; errs()<<"\nConstCheck : "<<(*qit)->constcheck; string operation = (*qit)->operation; set<string> labels = (*qit)->labels; set<Value*> vals = (*qit)->labVals; std::set<GraphNode*> taintedA; std::set<GraphNode*> taintedB; std::set<GraphNode*> intersectGraph; for(set<string>::iterator label = labels.begin();label != labels.end();++label) errs()<<" - "<<*label; errs()<<"\n*******************************************************\n "; constCheck = (*qit)->constcheck; if(constCheck) { for(set<Value*>::iterator val = vals.begin();val != vals.end();++val) { taintedA = taintGraphMap[*val]; } intersectGraph = taintedA; } else { for(set<Value*>::iterator val = vals.begin();val != vals.end();++val) { taintedA = taintGraphMap[*val]; ++val; if(val!=vals.end()) taintedB = taintGraphMap[*val]; } if(strcmp(operation.c_str(),"intersect")==0) { // intersectGraph = getIntersect(taintedA,taintedB); for(set<GraphNode*>::iterator gnode = taintedA.begin();gnode != taintedA.end();++gnode) { if(taintedB.count(*gnode) > 0) { GraphNode* interNode = (*gnode)->clone(); intersectGraph.insert(interNode); } } } } int branches =0; errs()<<"\n Intersect graph size :"<<intersectGraph.size(); //print intersect graph nodes: // PrintTainted(intersectGraph); // for(set<GraphNode*>::iterator gnode = intersectGraph.begin();gnode != intersectGraph.end();++gnode) // { // errs()<<"\n Node: "<<(*gnode)->getLabel(); // } //Print appropriate vals....: for (Module::iterator F = M.begin(), endF = M.end(); F != endF; ++F) { string funcName = F->getName(); // errs()<<"\nTaints in function: "<<funcName; for (Function::iterator BB = F->begin(), endBB = F->end(); BB != endBB; ++BB) { string bbName ="noName"; if(BB->hasName()) { bbName = BB->getName(); } // errs()<<" - block: "<<bbName; for (BasicBlock::iterator I = BB->begin(), endI = BB->end(); I != endI; ++I) { GraphNode* g = depGraph->findNode(I); if (intersectGraph.count(g)) { errs()<<"\n Node found..:"; I->dump(); errs()<<"Taint in function : "<<funcName<<" :"; I->dump(); if (BranchInst *BI = dyn_cast<BranchInst>(I)) { if(constCheck) { Value* conditional = BI->getCondition(); for (unsigned int i = 0; i < cast<User> (conditional)->getNumOperands(); i++) { Value *v1 = cast<User> (conditional)->getOperand(i); if(isa<ConstantInt>(v1)) { errs()<<"Branch Inst tainted in func : "<<funcName<<" :"; BI->dump(); branches++; } } } else { // BI->getCondition()->dump(); errs()<<"Branch Inst tainted : "; BI->dump(); branches++; } } } } } } errs()<<"\n Number of conditionals tainted : " <<branches; } errs()<<"\n*******************************************************\n "; }
// Entry point of the module bool PrepareCSI::runOnModule(Module &M){ vector<pair<string, set<set<string> > > > schemeData; if(VariantsFile.empty()){ outs() << "Reading stdin for instrumentation scheme...\n"; schemeData = readScheme(cin); outs() << "Finished reading stdin for scheme\n"; } else{ ifstream inFile(VariantsFile.c_str(), ios::in); if(!inFile || !inFile.is_open()) report_fatal_error("cannot open specified instrumentation scheme file: " + VariantsFile); schemeData = readScheme(inFile); } DEBUG(printScheme(schemeData)); // verify that all passes provided exist DEBUG(dbgs() << "verifying...\n"); verifyScheme(schemeData); DEBUG(printScheme(schemeData)); Context = &M.getContext(); // Find the matching pattern for each function map<Function*, set<set<string> >*> matches; for(Module::iterator F = M.begin(), E = M.end(); F != E; ++F){ if(F->isDeclaration() || F->isIntrinsic()) continue; bool found = false; for(vector<pair<string, set<set<string> > > >::iterator i = schemeData.begin(), e = schemeData.end(); i != e; ++i){ if(patternMatch(F->getName(), i->first)){ matches[F] = &(i->second); found = true; break; } } if(!found){ errs() << "WARNING: No scheme match found for function '" << F->getName() << "'. Skipping.\n"; continue; } } // Filter patterns matched to each function, and replicate for(map<Function*, set<set<string> >*>::iterator i = matches.begin(), e = matches.end(); i != e; ++i){ Function* F = i->first; // go through all filters for each possible scheme. if it passes all // filters, make a replica of this function with those tags on it, and add // that replica to the "replicas" set. else, print warning set<const set<string>*> replicas; for(set<set<string> >::iterator j = i->second->begin(), je = i->second->end(); j != je; ++j){ bool passed = true; if(!NoFilter){ for(vector<FilterFn>::const_iterator fi = Filters.begin(), fe = Filters.end(); fi != fe; ++fi){ if(!(*fi)(*j, F)){ passed = false; break; } } } if(passed) replicas.insert(&*j); else{ outs() << "WARNING: filtered out scheme '"; for(set<string>::iterator k = j->begin(), ke = j->end(); k != ke; ++k){ if(k != j->begin()) outs() << ","; outs() << *k; } outs() << "' for function '" << F->getName().str() << "'\n"; continue; } } switch (replicas.size()) { case 0: continue; case 1: { // instrument the original body (don't replicate and trampoline) const set<string>* scheme = *(replicas.begin()); for(set<string>::iterator j = scheme->begin(), je = scheme->end(); j != je; ++j) addInstrumentationType(*F, *j); break; } default: // if the function is variable-argument, currently don't support if(F->isVarArg()){ outs() << "WARNING: cannot instrument variable-argument function '" << F->getName() << "'\n"; continue; } // make a function for each scheme vector<Function*> funcReplicas; for(set<const set<string>*>::iterator j = replicas.begin(), je = replicas.end(); j != je; ++j){ ValueToValueMapTy valueMap; SmallVector<ReturnInst*, 1> returns; Function* newF = CloneFunction(F, valueMap, false, NULL); string name = F->getName().str(); if((*j)->begin() == (*j)->end()) name += "$none"; for(set<string>::iterator k = (*j)->begin(), ke = (*j)->end(); k != ke; ++k){ name += "$" + *k; addInstrumentationType(*newF, *k); } newF->setName(name); // NOTE: this does not preserve function ordering, thus it could // randomly slightly impact performance positively or negatively F->getParent()->getFunctionList().push_back(newF); funcReplicas.push_back(newF); } // assign this function a global switcher variable IntegerType* tInt = Type::getInt32Ty(*Context); string globalName = "__CSI_inst_"+getUniqueCFunctionName(*F); const GlobalValue::LinkageTypes linkage = F->hasAvailableExternallyLinkage() ? GlobalValue::WeakAnyLinkage : GlobalValue::ExternalLinkage; GlobalVariable * const functionGlobal = new GlobalVariable(M, tInt, true, linkage, ConstantInt::get(tInt, 0), globalName); functionGlobal->setSection("__CSI_func_inst"); // set up the trampoline call for this function switchIndirect(F, functionGlobal, funcReplicas); } } return(true); }
bool PoolAllocateSimple::runOnModule(Module &M) { if (M.begin() == M.end()) return false; // // Get pointers to 8 and 32 bit LLVM integer types. // VoidType = Type::getVoidTy(M.getContext()); Int8Type = IntegerType::getInt8Ty(M.getContext()); Int32Type = IntegerType::getInt32Ty(M.getContext()); // Get the Target Data information and the Graphs if (CompleteDSA) { Graphs = &getAnalysis<EQTDDataStructures>(); } else { Graphs = &getAnalysis<BasicDataStructures>(); } assert (Graphs && "No DSA pass available!\n"); DataLayout & TD = getAnalysis<DataLayout>(); // Add the pool* prototypes to the module AddPoolPrototypes(&M); // // Create a single DSGraph which contains all of the information found in all // the DSGraphs we got from DSA. We do this because we're going to start // making modifications to the points-to results. // GlobalECs = Graphs->getGlobalECs(); CombinedDSGraph = new DSGraph (GlobalECs, TD, Graphs->getTypeSS(), Graphs->getGlobalsGraph()); for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { if (Graphs->hasDSGraph (*I)) CombinedDSGraph->cloneInto (Graphs->getDSGraph(*I)); } // // Now fold all of the heap nodes in our DSGraph (i.e., make them // type-unknown). We do this because heap nodes may change type if we // consider the effects of dangling pointers. // FoldNodesInDSGraph (*CombinedDSGraph); FoldNodesInDSGraph (*(CombinedDSGraph->getGlobalsGraph())); // // Create the global pool. // TheGlobalPool = CreateGlobalPool(1, 1, M); // // Now that all call targets are available, rewrite the function bodies of // the clones. // for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { // // Skip functions that this pass added. // std::string name = I->getName(); if (name == "__poolalloc_init") continue; if (name == PoolInit->getName().str()) continue; // // Skip declarations. // if (!(I->isDeclaration())) ProcessFunctionBodySimple(*I, TD); } return true; }
bool LoaderPass::runOnModule(Module &M) { ProfileInfoLoader PIL("profile-loader", Filename); EdgeInformation.clear(); std::vector<unsigned> Counters = PIL.getRawEdgeCounts(); if (Counters.size() > 0) { ReadCount = 0; for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { if (F->isDeclaration()) continue; DEBUG(dbgs() << "Working on " << F->getName() << "\n"); readEdge(getEdge(0,&F->getEntryBlock()), Counters); for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { TerminatorInst *TI = BB->getTerminator(); for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) { readEdge(getEdge(BB,TI->getSuccessor(s)), Counters); } } } if (ReadCount != Counters.size()) { errs() << "WARNING: profile information is inconsistent with " << "the current program!\n"; } NumEdgesRead = ReadCount; } Counters = PIL.getRawOptimalEdgeCounts(); if (Counters.size() > 0) { ReadCount = 0; for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { if (F->isDeclaration()) continue; DEBUG(dbgs() << "Working on " << F->getName() << "\n"); readEdge(getEdge(0,&F->getEntryBlock()), Counters); for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { TerminatorInst *TI = BB->getTerminator(); if (TI->getNumSuccessors() == 0) { readEdge(getEdge(BB,0), Counters); } for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) { readEdge(getEdge(BB,TI->getSuccessor(s)), Counters); } } while (SpanningTree.size() > 0) { unsigned size = SpanningTree.size(); BBisUnvisited.clear(); for (std::set<Edge>::iterator ei = SpanningTree.begin(), ee = SpanningTree.end(); ei != ee; ++ei) { BBisUnvisited.insert(ei->first); BBisUnvisited.insert(ei->second); } while (BBisUnvisited.size() > 0) { recurseBasicBlock(*BBisUnvisited.begin()); } if (SpanningTree.size() == size) { DEBUG(dbgs()<<"{"); for (std::set<Edge>::iterator ei = SpanningTree.begin(), ee = SpanningTree.end(); ei != ee; ++ei) { DEBUG(dbgs()<< *ei <<","); } assert(0 && "No edge calculated!"); } } } if (ReadCount != Counters.size()) { errs() << "WARNING: profile information is inconsistent with " << "the current program!\n"; } NumEdgesRead = ReadCount; } BlockInformation.clear(); Counters = PIL.getRawBlockCounts(); if (Counters.size() > 0) { ReadCount = 0; for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { if (F->isDeclaration()) continue; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) if (ReadCount < Counters.size()) // Here the data realm changes from the unsigned of the file to the // double of the ProfileInfo. This conversion is save because we know // that everything thats representable in unsinged is also // representable in double. BlockInformation[F][BB] = (double)Counters[ReadCount++]; } if (ReadCount != Counters.size()) { errs() << "WARNING: profile information is inconsistent with " << "the current program!\n"; } } FunctionInformation.clear(); Counters = PIL.getRawFunctionCounts(); if (Counters.size() > 0) { ReadCount = 0; for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { if (F->isDeclaration()) continue; if (ReadCount < Counters.size()) // Here the data realm changes from the unsigned of the file to the // double of the ProfileInfo. This conversion is save because we know // that everything thats representable in unsinged is also // representable in double. FunctionInformation[F] = (double)Counters[ReadCount++]; } if (ReadCount != Counters.size()) { errs() << "WARNING: profile information is inconsistent with " << "the current program!\n"; } } return false; }
/// ExtractLoops - Given a reduced list of functions that still exposed the bug, /// check to see if we can extract the loops in the region without obscuring the /// bug. If so, it reduces the amount of code identified. /// static bool ExtractLoops(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *, Module *), std::vector<Function*> &MiscompiledFunctions) { bool MadeChange = false; while (1) { if (BugpointIsInterrupted) return MadeChange; DenseMap<const Value*, Value*> ValueMap; Module *ToNotOptimize = CloneModule(BD.getProgram(), ValueMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, MiscompiledFunctions, ValueMap); Module *ToOptimizeLoopExtracted = BD.ExtractLoop(ToOptimize); if (!ToOptimizeLoopExtracted) { // If the loop extractor crashed or if there were no extractible loops, // then this chapter of our odyssey is over with. delete ToNotOptimize; delete ToOptimize; return MadeChange; } errs() << "Extracted a loop from the breaking portion of the program.\n"; // Bugpoint is intentionally not very trusting of LLVM transformations. In // particular, we're not going to assume that the loop extractor works, so // we're going to test the newly loop extracted program to make sure nothing // has broken. If something broke, then we'll inform the user and stop // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); if (TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, false)) { BD.switchToInterpreter(AI); // Merged program doesn't work anymore! errs() << " *** ERROR: Loop extraction broke the program. :(" << " Please report a bug!\n"; errs() << " Continuing on with un-loop-extracted version.\n"; BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-tno.bc", ToNotOptimize); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to.bc", ToOptimize); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc", ToOptimizeLoopExtracted); errs() << "Please submit the " << OutputPrefix << "-loop-extract-fail-*.bc files.\n"; delete ToOptimize; delete ToNotOptimize; delete ToOptimizeLoopExtracted; return MadeChange; } delete ToOptimize; BD.switchToInterpreter(AI); outs() << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); Module *TNOBackup = CloneModule(ToNotOptimize); if (!TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize)) { outs() << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. delete TOLEBackup; delete TNOBackup; return MadeChange; } ToOptimizeLoopExtracted = TOLEBackup; ToNotOptimize = TNOBackup; outs() << "*** Loop extraction successful!\n"; std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; for (Module::iterator I = ToOptimizeLoopExtracted->begin(), E = ToOptimizeLoopExtracted->end(); I != E; ++I) if (!I->isDeclaration()) MisCompFunctions.push_back(std::make_pair(I->getName(), I->getFunctionType())); // Okay, great! Now we know that we extracted a loop and that loop // extraction both didn't break the program, and didn't mask the problem. // Replace the current program with the loop extracted version, and try to // extract another loop. std::string ErrorMsg; if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, &ErrorMsg)){ errs() << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << '\n'; exit(1); } delete ToOptimizeLoopExtracted; // All of the Function*'s in the MiscompiledFunctions list are in the old // module. Update this list to include all of the functions in the // optimized and loop extracted module. MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); assert(NewF->getFunctionType() == MisCompFunctions[i].second && "found wrong function type?"); MiscompiledFunctions.push_back(NewF); } BD.setNewProgram(ToNotOptimize); MadeChange = true; } }
// the verifier iterates through each path to gather the total // number of edge frequencies bool PathProfileVerifier::runOnModule (Module &M) { PathProfileInfo& pathProfileInfo = getAnalysis<PathProfileInfo>(); // setup a data structure to map path edges which index an // array of edge counters NestedBlockToIndexMap arrayMap; unsigned i = 0; for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { if (F->isDeclaration()) continue; arrayMap[0][F->begin()][0] = i++; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { TerminatorInst *TI = BB->getTerminator(); unsigned duplicate = 0; BasicBlock* prev = 0; for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; prev = TI->getSuccessor(s), ++s) { if (prev == TI->getSuccessor(s)) duplicate++; else duplicate = 0; arrayMap[BB][TI->getSuccessor(s)][duplicate] = i++; } } } std::vector<unsigned> edgeArray(i); // iterate through each path and increment the edge counters as needed for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { if (F->isDeclaration()) continue; pathProfileInfo.setCurrentFunction(F); DEBUG(dbgs() << "function '" << F->getName() << "' ran " << pathProfileInfo.pathsRun() << "/" << pathProfileInfo.getPotentialPathCount() << " potential paths\n"); for( ProfilePathIterator nextPath = pathProfileInfo.pathBegin(), endPath = pathProfileInfo.pathEnd(); nextPath != endPath; nextPath++ ) { ProfilePath* currentPath = nextPath->second; ProfilePathEdgeVector* pev = currentPath->getPathEdges(); DEBUG(dbgs () << "path #" << currentPath->getNumber() << ": " << currentPath->getCount() << "\n"); // setup the entry edge (normally path profiling doesn't care about this) if (currentPath->getFirstBlockInPath() == &F->getEntryBlock()) edgeArray[arrayMap[0][currentPath->getFirstBlockInPath()][0]] += currentPath->getCount(); for( ProfilePathEdgeIterator nextEdge = pev->begin(), endEdge = pev->end(); nextEdge != endEdge; nextEdge++ ) { if (nextEdge != pev->begin()) DEBUG(dbgs() << " :: "); BasicBlock* source = nextEdge->getSource(); BasicBlock* target = nextEdge->getTarget(); unsigned duplicateNumber = nextEdge->getDuplicateNumber(); DEBUG(dbgs () << source->getNameStr() << " --{" << duplicateNumber << "}--> " << target->getNameStr()); // Ensure all the referenced edges exist // TODO: make this a separate function if( !arrayMap.count(source) ) { errs() << " error [" << F->getNameStr() << "()]: source '" << source->getNameStr() << "' does not exist in the array map.\n"; } else if( !arrayMap[source].count(target) ) { errs() << " error [" << F->getNameStr() << "()]: target '" << target->getNameStr() << "' does not exist in the array map.\n"; } else if( !arrayMap[source][target].count(duplicateNumber) ) { errs() << " error [" << F->getNameStr() << "()]: edge " << source->getNameStr() << " -> " << target->getNameStr() << " duplicate number " << duplicateNumber << " does not exist in the array map.\n"; } else { edgeArray[arrayMap[source][target][duplicateNumber]] += currentPath->getCount(); } } DEBUG(errs() << "\n"); delete pev; } } std::string errorInfo; std::string filename = EdgeProfileFilename; // Open a handle to the file FILE* edgeFile = fopen(filename.c_str(),"wb"); if (!edgeFile) { errs() << "error: unable to open file '" << filename << "' for output.\n"; return false; } errs() << "Generating edge profile '" << filename << "' ...\n"; // write argument info unsigned type = ArgumentInfo; unsigned num = pathProfileInfo.argList.size(); int zeros = 0; fwrite(&type,sizeof(unsigned),1,edgeFile); fwrite(&num,sizeof(unsigned),1,edgeFile); fwrite(pathProfileInfo.argList.c_str(),1,num,edgeFile); if (num&3) fwrite(&zeros, 1, 4-(num&3), edgeFile); type = EdgeInfo; num = edgeArray.size(); fwrite(&type,sizeof(unsigned),1,edgeFile); fwrite(&num,sizeof(unsigned),1,edgeFile); // write each edge to the file for( std::vector<unsigned>::iterator s = edgeArray.begin(), e = edgeArray.end(); s != e; s++) fwrite(&*s, sizeof (unsigned), 1, edgeFile); fclose (edgeFile); return true; }