diff options
Diffstat (limited to 'llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp')
-rw-r--r-- | llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | 124 |
1 files changed, 95 insertions, 29 deletions
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index e6dc684c2e77..b6a9df57e431 100644 --- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -16,7 +16,6 @@ #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/CFG.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/Constant.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" @@ -35,6 +34,8 @@ #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/SpecialCaseList.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -67,6 +68,8 @@ static const char *const SanCovModuleCtorTracePcGuardName = "sancov.module_ctor_trace_pc_guard"; static const char *const SanCovModuleCtor8bitCountersName = "sancov.module_ctor_8bit_counters"; +static const char *const SanCovModuleCtorBoolFlagName = + "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; static const char *const SanCovTracePCGuardName = @@ -75,10 +78,13 @@ static const char *const SanCovTracePCGuardInitName = "__sanitizer_cov_trace_pc_guard_init"; static const char *const SanCov8bitCountersInitName = "__sanitizer_cov_8bit_counters_init"; +static const char *const SanCovBoolFlagInitName = + "__sanitizer_cov_bool_flag_init"; static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init"; static const char *const SanCovGuardsSectionName = "sancov_guards"; static const char *const SanCovCountersSectionName = "sancov_cntrs"; +static const char *const SanCovBoolFlagSectionName = "sancov_bools"; static const char *const SanCovPCsSectionName = "sancov_pcs"; static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; @@ -101,7 +107,8 @@ static cl::opt<bool> ClTracePCGuard("sanitizer-coverage-trace-pc-guard", // BBs, put this global into a named section, and pass this section's bounds // to __sanitizer_cov_pcs_init. // This way the coverage instrumentation does not need to acquire the PCs -// at run-time. Works with trace-pc-guard and inline-8bit-counters. +// at run-time. Works with trace-pc-guard, inline-8bit-counters, and +// inline-bool-flag. static cl::opt<bool> ClCreatePCTable("sanitizer-coverage-pc-table", cl::desc("create a static PC table"), cl::Hidden, cl::init(false)); @@ -112,6 +119,11 @@ static cl::opt<bool> cl::Hidden, cl::init(false)); static cl::opt<bool> + ClInlineBoolFlag("sanitizer-coverage-inline-bool-flag", + cl::desc("sets a boolean flag for every edge"), cl::Hidden, + cl::init(false)); + +static cl::opt<bool> ClCMPTracing("sanitizer-coverage-trace-compares", cl::desc("Tracing of CMP and similar instructions"), cl::Hidden, cl::init(false)); @@ -169,11 +181,13 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { Options.TracePC |= ClTracePC; Options.TracePCGuard |= ClTracePCGuard; Options.Inline8bitCounters |= ClInline8bitCounters; + Options.InlineBoolFlag |= ClInlineBoolFlag; Options.PCTable |= ClCreatePCTable; Options.NoPrune |= !ClPruneBlocks; Options.StackDepth |= ClStackDepth; if (!Options.TracePCGuard && !Options.TracePC && - !Options.Inline8bitCounters && !Options.StackDepth) + !Options.Inline8bitCounters && !Options.StackDepth && + !Options.InlineBoolFlag) Options.TracePCGuard = true; // TracePCGuard is default. return Options; } @@ -185,8 +199,11 @@ using PostDomTreeCallback = class ModuleSanitizerCoverage { public: ModuleSanitizerCoverage( - const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()) - : Options(OverrideFromCL(Options)) {} + const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(), + const SpecialCaseList *Allowlist = nullptr, + const SpecialCaseList *Blocklist = nullptr) + : Options(OverrideFromCL(Options)), Allowlist(Allowlist), + Blocklist(Blocklist) {} bool instrumentModule(Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback); @@ -233,9 +250,8 @@ private: FunctionCallee SanCovTraceGepFunction; FunctionCallee SanCovTraceSwitchFunction; GlobalVariable *SanCovLowestStack; - InlineAsm *EmptyAsm; Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, - *Int16Ty, *Int8Ty, *Int8PtrTy; + *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy; Module *CurModule; std::string CurModuleUniqueId; Triple TargetTriple; @@ -244,23 +260,38 @@ private: GlobalVariable *FunctionGuardArray; // for trace-pc-guard. GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters. + GlobalVariable *FunctionBoolArray; // for inline-bool-flag. GlobalVariable *FunctionPCsArray; // for pc-table. SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed; SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed; SanitizerCoverageOptions Options; + + const SpecialCaseList *Allowlist; + const SpecialCaseList *Blocklist; }; class ModuleSanitizerCoverageLegacyPass : public ModulePass { public: ModuleSanitizerCoverageLegacyPass( - const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()) + const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(), + const std::vector<std::string> &AllowlistFiles = + std::vector<std::string>(), + const std::vector<std::string> &BlocklistFiles = + std::vector<std::string>()) : ModulePass(ID), Options(Options) { + if (AllowlistFiles.size() > 0) + Allowlist = SpecialCaseList::createOrDie(AllowlistFiles, + *vfs::getRealFileSystem()); + if (BlocklistFiles.size() > 0) + Blocklist = SpecialCaseList::createOrDie(BlocklistFiles, + *vfs::getRealFileSystem()); initializeModuleSanitizerCoverageLegacyPassPass( *PassRegistry::getPassRegistry()); } bool runOnModule(Module &M) override { - ModuleSanitizerCoverage ModuleSancov(Options); + ModuleSanitizerCoverage ModuleSancov(Options, Allowlist.get(), + Blocklist.get()); auto DTCallback = [this](Function &F) -> const DominatorTree * { return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(); }; @@ -281,13 +312,17 @@ public: private: SanitizerCoverageOptions Options; + + std::unique_ptr<SpecialCaseList> Allowlist; + std::unique_ptr<SpecialCaseList> Blocklist; }; } // namespace PreservedAnalyses ModuleSanitizerCoveragePass::run(Module &M, ModuleAnalysisManager &MAM) { - ModuleSanitizerCoverage ModuleSancov(Options); + ModuleSanitizerCoverage ModuleSancov(Options, Allowlist.get(), + Blocklist.get()); auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); auto DTCallback = [&FAM](Function &F) -> const DominatorTree * { return &FAM.getResult<DominatorTreeAnalysis>(F); @@ -360,6 +395,12 @@ bool ModuleSanitizerCoverage::instrumentModule( Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false; + if (Allowlist && + !Allowlist->inSection("coverage", "src", M.getSourceFileName())) + return false; + if (Blocklist && + Blocklist->inSection("coverage", "src", M.getSourceFileName())) + return false; C = &(M.getContext()); DL = &M.getDataLayout(); CurModule = &M; @@ -367,6 +408,7 @@ bool ModuleSanitizerCoverage::instrumentModule( TargetTriple = Triple(M.getTargetTriple()); FunctionGuardArray = nullptr; Function8bitCounterArray = nullptr; + FunctionBoolArray = nullptr; FunctionPCsArray = nullptr; IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits()); IntptrPtrTy = PointerType::getUnqual(IntptrTy); @@ -375,10 +417,12 @@ bool ModuleSanitizerCoverage::instrumentModule( Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty()); Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty()); + Int1PtrTy = PointerType::getUnqual(IRB.getInt1Ty()); Int64Ty = IRB.getInt64Ty(); Int32Ty = IRB.getInt32Ty(); Int16Ty = IRB.getInt16Ty(); Int8Ty = IRB.getInt8Ty(); + Int1Ty = IRB.getInt1Ty(); SanCovTracePCIndir = M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy); @@ -440,11 +484,6 @@ bool ModuleSanitizerCoverage::instrumentModule( if (Options.StackDepth && !SanCovLowestStack->isDeclaration()) SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy)); - // We insert an empty inline asm after cov callbacks to avoid callback merge. - EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false), - StringRef(""), StringRef(""), - /*hasSideEffects=*/true); - SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy); SanCovTracePCGuard = M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy); @@ -462,6 +501,11 @@ bool ModuleSanitizerCoverage::instrumentModule( Ctor = CreateInitCallsForSections(M, SanCovModuleCtor8bitCountersName, SanCov8bitCountersInitName, Int8PtrTy, SanCovCountersSectionName); + if (FunctionBoolArray) { + Ctor = CreateInitCallsForSections(M, SanCovModuleCtorBoolFlagName, + SanCovBoolFlagInitName, Int1PtrTy, + SanCovBoolFlagSectionName); + } if (Ctor && Options.PCTable) { auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrPtrTy); FunctionCallee InitFunction = declareSanitizerInitFunction( @@ -589,6 +633,10 @@ void ModuleSanitizerCoverage::instrumentFunction( if (F.hasPersonalityFn() && isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) return; + if (Allowlist && !Allowlist->inSection("coverage", "fun", F.getName())) + return; + if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName())) + return; if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge) SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests()); SmallVector<Instruction *, 8> IndirCalls; @@ -607,8 +655,8 @@ void ModuleSanitizerCoverage::instrumentFunction( BlocksToInstrument.push_back(&BB); for (auto &Inst : BB) { if (Options.IndirectCalls) { - CallSite CS(&Inst); - if (CS && !CS.getCalledFunction()) + CallBase *CB = dyn_cast<CallBase>(&Inst); + if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst); } if (Options.TraceCmp) { @@ -653,9 +701,7 @@ GlobalVariable *ModuleSanitizerCoverage::CreateFunctionLocalArrayInSection( GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId)) Array->setComdat(Comdat); Array->setSection(getSectionName(Section)); - Array->setAlignment(Align(Ty->isPointerTy() - ? DL->getPointerSize() - : Ty->getPrimitiveSizeInBits() / 8)); + Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize())); GlobalsToAppendToUsed.push_back(Array); GlobalsToAppendToCompilerUsed.push_back(Array); MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F)); @@ -701,6 +747,9 @@ void ModuleSanitizerCoverage::CreateFunctionLocalArrays( if (Options.Inline8bitCounters) Function8bitCounterArray = CreateFunctionLocalArrayInSection( AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName); + if (Options.InlineBoolFlag) + FunctionBoolArray = CreateFunctionLocalArrayInSection( + AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName); if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks); @@ -727,11 +776,12 @@ void ModuleSanitizerCoverage::InjectCoverageForIndirectCalls( Function &F, ArrayRef<Instruction *> IndirCalls) { if (IndirCalls.empty()) return; - assert(Options.TracePC || Options.TracePCGuard || Options.Inline8bitCounters); + assert(Options.TracePC || Options.TracePCGuard || + Options.Inline8bitCounters || Options.InlineBoolFlag); for (auto I : IndirCalls) { IRBuilder<> IRB(I); - CallSite CS(I); - Value *Callee = CS.getCalledValue(); + CallBase &CB = cast<CallBase>(*I); + Value *Callee = CB.getCalledOperand(); if (isa<InlineAsm>(Callee)) continue; IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy)); @@ -865,16 +915,15 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, IRBuilder<> IRB(&*IP); IRB.SetCurrentDebugLocation(EntryLoc); if (Options.TracePC) { - IRB.CreateCall(SanCovTracePC); // gets the PC using GET_CALLER_PC. - IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. + IRB.CreateCall(SanCovTracePC) + ->setCannotMerge(); // gets the PC using GET_CALLER_PC. } if (Options.TracePCGuard) { auto GuardPtr = IRB.CreateIntToPtr( IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), ConstantInt::get(IntptrTy, Idx * 4)), Int32PtrTy); - IRB.CreateCall(SanCovTracePCGuard, GuardPtr); - IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. + IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge(); } if (Options.Inline8bitCounters) { auto CounterPtr = IRB.CreateGEP( @@ -886,6 +935,18 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, SetNoSanitizeMetadata(Load); SetNoSanitizeMetadata(Store); } + if (Options.InlineBoolFlag) { + auto FlagPtr = IRB.CreateGEP( + FunctionBoolArray->getValueType(), FunctionBoolArray, + {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)}); + auto Load = IRB.CreateLoad(Int1Ty, FlagPtr); + auto ThenTerm = + SplitBlockAndInsertIfThen(IRB.CreateIsNull(Load), &*IP, false); + IRBuilder<> ThenIRB(ThenTerm); + auto Store = ThenIRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr); + SetNoSanitizeMetadata(Load); + SetNoSanitizeMetadata(Store); + } if (Options.StackDepth && IsEntryBB && !IsLeafFunc) { // Check stack depth. If it's the deepest so far, record it. Module *M = F.getParent(); @@ -910,6 +971,8 @@ ModuleSanitizerCoverage::getSectionName(const std::string &Section) const { if (TargetTriple.isOSBinFormatCOFF()) { if (Section == SanCovCountersSectionName) return ".SCOV$CM"; + if (Section == SanCovBoolFlagSectionName) + return ".SCOV$BM"; if (Section == SanCovPCsSectionName) return ".SCOVP$M"; return ".SCOV$GM"; // For SanCovGuardsSectionName. @@ -943,6 +1006,9 @@ INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov", "Pass for instrumenting coverage on functions", false, false) ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( - const SanitizerCoverageOptions &Options) { - return new ModuleSanitizerCoverageLegacyPass(Options); + const SanitizerCoverageOptions &Options, + const std::vector<std::string> &AllowlistFiles, + const std::vector<std::string> &BlocklistFiles) { + return new ModuleSanitizerCoverageLegacyPass(Options, AllowlistFiles, + BlocklistFiles); } |