diff options
Diffstat (limited to 'llvm/lib/Transforms/Instrumentation')
-rw-r--r-- | llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | 155 |
1 files changed, 91 insertions, 64 deletions
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index e26fdb42c99..774fe2ff059 100644 --- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -207,8 +207,10 @@ private: void InjectTraceForSwitch(Function &F, ArrayRef<Instruction *> SwitchTraceTargets); bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks); + void CreateFunctionGuardArray(size_t NumGuards, Function &F); void SetNoSanitizeMetadata(Instruction *I); - void InjectCoverageAtBlock(Function &F, BasicBlock &BB, bool UseCalls); + void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, + bool UseCalls); unsigned NumberOfInstrumentedBlocks() { return SanCovFunction->getNumUses() + SanCovWithCheckFunction->getNumUses() + SanCovTraceBB->getNumUses() + @@ -223,12 +225,13 @@ private: Function *SanCovTraceGepFunction; Function *SanCovTraceSwitchFunction; InlineAsm *EmptyAsm; - Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy; + Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy; Module *CurModule; LLVMContext *C; const DataLayout *DL; GlobalVariable *GuardArray; + GlobalVariable *FunctionGuardArray; // for trace-pc-guard. GlobalVariable *EightBitCounterArray; bool HasSancovGuardsSection; @@ -249,9 +252,10 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { Type *VoidTy = Type::getVoidTy(*C); IRBuilder<> IRB(*C); Type *Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty()); - Type *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty()); + Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); Int64Ty = IRB.getInt64Ty(); + Int32Ty = IRB.getInt32Ty(); SanCovFunction = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovName, VoidTy, Int32PtrTy, nullptr)); @@ -296,7 +300,7 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { SanCovTracePC = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovTracePCName, VoidTy, nullptr)); SanCovTracePCGuard = checkSanitizerInterfaceFunction(M.getOrInsertFunction( - SanCovTracePCGuardName, VoidTy, IntptrPtrTy, nullptr)); + SanCovTracePCGuardName, VoidTy, Int32PtrTy, nullptr)); SanCovTraceEnter = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovTraceEnterName, VoidTy, Int32PtrTy, nullptr)); SanCovTraceBB = checkSanitizerInterfaceFunction( @@ -307,9 +311,10 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { Type *Int32Ty = IRB.getInt32Ty(); Type *Int8Ty = IRB.getInt8Ty(); - GuardArray = - new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, - nullptr, "__sancov_gen_cov_tmp"); + if (!Options.TracePCGuard) + GuardArray = + new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, + nullptr, "__sancov_gen_cov_tmp"); if (Options.Use8bitCounters) EightBitCounterArray = new GlobalVariable(M, Int8Ty, false, GlobalVariable::ExternalLinkage, @@ -320,17 +325,20 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { auto N = NumberOfInstrumentedBlocks(); - // Now we know how many elements we need. Create an array of guards - // with one extra element at the beginning for the size. - Type *Int32ArrayNTy = ArrayType::get(Int32Ty, N + 1); - GlobalVariable *RealGuardArray = new GlobalVariable( - M, Int32ArrayNTy, false, GlobalValue::PrivateLinkage, - Constant::getNullValue(Int32ArrayNTy), "__sancov_gen_cov"); - - // Replace the dummy array with the real one. - GuardArray->replaceAllUsesWith( - IRB.CreatePointerCast(RealGuardArray, Int32PtrTy)); - GuardArray->eraseFromParent(); + GlobalVariable *RealGuardArray = nullptr; + if (!Options.TracePCGuard) { + // Now we know how many elements we need. Create an array of guards + // with one extra element at the beginning for the size. + Type *Int32ArrayNTy = ArrayType::get(Int32Ty, N + 1); + RealGuardArray = new GlobalVariable( + M, Int32ArrayNTy, false, GlobalValue::PrivateLinkage, + Constant::getNullValue(Int32ArrayNTy), "__sancov_gen_cov"); + + // Replace the dummy array with the real one. + GuardArray->replaceAllUsesWith( + IRB.CreatePointerCast(RealGuardArray, Int32PtrTy)); + GuardArray->eraseFromParent(); + } GlobalVariable *RealEightBitCounterArray; if (Options.Use8bitCounters) { @@ -359,16 +367,16 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { GlobalVariable *Bounds[2]; const char *Prefix[2] = {"__start_", "__stop_"}; for (int i = 0; i < 2; i++) { - Bounds[i] = new GlobalVariable(M, IntptrPtrTy, false, + Bounds[i] = new GlobalVariable(M, Int32PtrTy, false, GlobalVariable::ExternalLinkage, nullptr, Prefix[i] + SectionName); Bounds[i]->setVisibility(GlobalValue::HiddenVisibility); } std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions( M, SanCovModuleCtorName, SanCovTracePCGuardInitName, - {IntptrPtrTy, IntptrPtrTy}, - {IRB.CreatePointerCast(Bounds[0], IntptrPtrTy), - IRB.CreatePointerCast(Bounds[1], IntptrPtrTy)}); + {Int32PtrTy, Int32PtrTy}, + {IRB.CreatePointerCast(Bounds[0], Int32PtrTy), + IRB.CreatePointerCast(Bounds[1], Int32PtrTy)}); appendToGlobalCtors(M, CtorFunc, SanCtorAndDtorPriority); } @@ -419,6 +427,14 @@ static bool isFullPostDominator(const BasicBlock *BB, static bool shouldInstrumentBlock(const Function& F, const BasicBlock *BB, const DominatorTree *DT, const PostDominatorTree *PDT) { + // Don't insert coverage for unreachable blocks: we will never call + // __sanitizer_cov() for them, so counting them in + // NumberOfInstrumentedBlocks() might complicate calculation of code coverage + // percentage. Also, unreachable instructions frequently have no debug + // locations. + if (isa<UnreachableInst>(BB->getTerminator())) + return false; + if (!ClPruneBlocks || &F.getEntryBlock() == BB) return true; @@ -486,19 +502,34 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { InjectTraceForGep(F, GepTraceTargets); return true; } +void SanitizerCoverageModule::CreateFunctionGuardArray(size_t NumGuards, Function &F) { + if (!Options.TracePCGuard) return; + HasSancovGuardsSection = true; + ArrayType *ArrayOfInt32Ty = ArrayType::get(Int32Ty, NumGuards); + FunctionGuardArray = new GlobalVariable( + *CurModule, ArrayOfInt32Ty, false, GlobalVariable::LinkOnceODRLinkage, + Constant::getNullValue(ArrayOfInt32Ty), "__sancov_guard." + F.getName()); + if (auto Comdat = F.getComdat()) + FunctionGuardArray->setComdat(Comdat); + FunctionGuardArray->setSection(SanCovTracePCGuardSection); + FunctionGuardArray->setVisibility(GlobalValue::HiddenVisibility); +} bool SanitizerCoverageModule::InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks) { + if (AllBlocks.empty()) return false; switch (Options.CoverageType) { case SanitizerCoverageOptions::SCK_None: return false; case SanitizerCoverageOptions::SCK_Function: - InjectCoverageAtBlock(F, F.getEntryBlock(), false); + CreateFunctionGuardArray(1, F); + InjectCoverageAtBlock(F, F.getEntryBlock(), 0, false); return true; default: { bool UseCalls = ClCoverageBlockThreshold < AllBlocks.size(); - for (auto BB : AllBlocks) - InjectCoverageAtBlock(F, *BB, UseCalls); + CreateFunctionGuardArray(AllBlocks.size(), F); + for (size_t i = 0, N = AllBlocks.size(); i < N; i++) + InjectCoverageAtBlock(F, *AllBlocks[i], i, UseCalls); return true; } } @@ -635,16 +666,8 @@ void SanitizerCoverageModule::SetNoSanitizeMetadata(Instruction *I) { } void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, - bool UseCalls) { - // Don't insert coverage for unreachable blocks: we will never call - // __sanitizer_cov() for them, so counting them in - // NumberOfInstrumentedBlocks() might complicate calculation of code coverage - // percentage. Also, unreachable instructions frequently have no debug - // locations. - if (isa<UnreachableInst>(BB.getTerminator())) - return; + size_t Idx, bool UseCalls) { BasicBlock::iterator IP = BB.getFirstInsertionPt(); - bool IsEntryBB = &BB == &F.getEntryBlock(); DebugLoc EntryLoc; if (IsEntryBB) { @@ -660,24 +683,22 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, IRBuilder<> IRB(&*IP); IRB.SetCurrentDebugLocation(EntryLoc); - Value *GuardP = IRB.CreateAdd( - IRB.CreatePointerCast(GuardArray, IntptrTy), - ConstantInt::get(IntptrTy, (1 + NumberOfInstrumentedBlocks()) * 4)); - Type *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); - GuardP = IRB.CreateIntToPtr(GuardP, Int32PtrTy); if (Options.TracePC) { IRB.CreateCall(SanCovTracePC); // gets the PC using GET_CALLER_PC. IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. } else if (Options.TracePCGuard) { - auto GuardVar = new GlobalVariable( - *F.getParent(), Int64Ty, false, GlobalVariable::LinkOnceODRLinkage, - Constant::getNullValue(Int64Ty), "__sancov_guard." + F.getName()); - if (auto Comdat = F.getComdat()) - GuardVar->setComdat(Comdat); + //auto GuardVar = new GlobalVariable( + // *F.getParent(), Int64Ty, false, GlobalVariable::LinkOnceODRLinkage, + // Constant::getNullValue(Int64Ty), "__sancov_guard." + F.getName()); + // if (auto Comdat = F.getComdat()) + // GuardVar->setComdat(Comdat); // TODO: add debug into to GuardVar. - GuardVar->setSection(SanCovTracePCGuardSection); - HasSancovGuardsSection = true; - auto GuardPtr = IRB.CreatePointerCast(GuardVar, IntptrPtrTy); + // GuardVar->setSection(SanCovTracePCGuardSection); + // auto GuardPtr = IRB.CreatePointerCast(GuardVar, IntptrPtrTy); + auto GuardPtr = IRB.CreateIntToPtr( + IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get(IntptrTy, Idx * 4)), + Int32PtrTy); if (!UseCalls) { auto GuardLoad = IRB.CreateLoad(GuardPtr); GuardLoad->setAtomic(AtomicOrdering::Monotonic); @@ -692,24 +713,30 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } IRB.CreateCall(SanCovTracePCGuard, GuardPtr); IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. - } else if (Options.TraceBB) { - IRB.CreateCall(IsEntryBB ? SanCovTraceEnter : SanCovTraceBB, GuardP); - } else if (UseCalls) { - IRB.CreateCall(SanCovWithCheckFunction, GuardP); } else { - LoadInst *Load = IRB.CreateLoad(GuardP); - Load->setAtomic(AtomicOrdering::Monotonic); - Load->setAlignment(4); - SetNoSanitizeMetadata(Load); - Value *Cmp = - IRB.CreateICmpSGE(Constant::getNullValue(Load->getType()), Load); - Instruction *Ins = SplitBlockAndInsertIfThen( - Cmp, &*IP, false, MDBuilder(*C).createBranchWeights(1, 100000)); - IRB.SetInsertPoint(Ins); - IRB.SetCurrentDebugLocation(EntryLoc); - // __sanitizer_cov gets the PC of the instruction using GET_CALLER_PC. - IRB.CreateCall(SanCovFunction, GuardP); - IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. + Value *GuardP = IRB.CreateAdd( + IRB.CreatePointerCast(GuardArray, IntptrTy), + ConstantInt::get(IntptrTy, (1 + NumberOfInstrumentedBlocks()) * 4)); + GuardP = IRB.CreateIntToPtr(GuardP, Int32PtrTy); + if (Options.TraceBB) { + IRB.CreateCall(IsEntryBB ? SanCovTraceEnter : SanCovTraceBB, GuardP); + } else if (UseCalls) { + IRB.CreateCall(SanCovWithCheckFunction, GuardP); + } else { + LoadInst *Load = IRB.CreateLoad(GuardP); + Load->setAtomic(AtomicOrdering::Monotonic); + Load->setAlignment(4); + SetNoSanitizeMetadata(Load); + Value *Cmp = + IRB.CreateICmpSGE(Constant::getNullValue(Load->getType()), Load); + Instruction *Ins = SplitBlockAndInsertIfThen( + Cmp, &*IP, false, MDBuilder(*C).createBranchWeights(1, 100000)); + IRB.SetInsertPoint(Ins); + IRB.SetCurrentDebugLocation(EntryLoc); + // __sanitizer_cov gets the PC of the instruction using GET_CALLER_PC. + IRB.CreateCall(SanCovFunction, GuardP); + IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. + } } if (Options.Use8bitCounters) { |