1616#include " llvm/Analysis/GlobalsModRef.h"
1717#include " llvm/Analysis/PostDominators.h"
1818#include " llvm/IR/Constant.h"
19+ #include " llvm/IR/Constants.h"
1920#include " llvm/IR/DataLayout.h"
2021#include " llvm/IR/Dominators.h"
2122#include " llvm/IR/EHPersonalities.h"
2829#include " llvm/IR/MDBuilder.h"
2930#include " llvm/IR/Module.h"
3031#include " llvm/IR/Type.h"
32+ #include " llvm/IR/ValueSymbolTable.h"
33+ #include " llvm/InitializePasses.h"
3134#include " llvm/Support/CommandLine.h"
3235#include " llvm/Support/SpecialCaseList.h"
3336#include " llvm/Support/VirtualFileSystem.h"
@@ -82,8 +85,10 @@ const char SanCovCountersSectionName[] = "sancov_cntrs";
8285const char SanCovBoolFlagSectionName[] = " sancov_bools" ;
8386const char SanCovPCsSectionName[] = " sancov_pcs" ;
8487const char SanCovCFsSectionName[] = " sancov_cfs" ;
88+ const char SanCovCallbackGateSectionName[] = " sancov_gate" ;
8589
8690const char SanCovLowestStackName[] = " __sancov_lowest_stack" ;
91+ const char SanCovCallbackGateName[] = " __sancov_should_track" ;
8792
8893static cl::opt<int > ClCoverageLevel (
8994 " sanitizer-coverage-level" ,
@@ -152,6 +157,12 @@ static cl::opt<bool>
152157 ClCollectCF (" sanitizer-coverage-control-flow" ,
153158 cl::desc (" collect control flow for each function" ), cl::Hidden);
154159
160+ static cl::opt<bool > ClGatedCallbacks (
161+ " sanitizer-coverage-gated-trace-callbacks" ,
162+ cl::desc (" Gate the invocation of the tracing callbacks on a global "
163+ " variable. Currently only supported for trace-pc-guard." ),
164+ cl::Hidden, cl::init(false ));
165+
155166namespace {
156167
157168SanitizerCoverageOptions getOptions (int LegacyCoverageLevel) {
@@ -194,6 +205,7 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
194205 Options.StackDepth |= ClStackDepth;
195206 Options.TraceLoads |= ClLoadTracing;
196207 Options.TraceStores |= ClStoreTracing;
208+ Options.GatedCallbacks |= ClGatedCallbacks;
197209 if (!Options.TracePCGuard && !Options.TracePC &&
198210 !Options.Inline8bitCounters && !Options.StackDepth &&
199211 !Options.InlineBoolFlag && !Options.TraceLoads && !Options.TraceStores )
@@ -239,8 +251,9 @@ class ModuleSanitizerCoverage {
239251 const char *Section);
240252 GlobalVariable *CreatePCArray (Function &F, ArrayRef<BasicBlock *> AllBlocks);
241253 void CreateFunctionLocalArrays (Function &F, ArrayRef<BasicBlock *> AllBlocks);
254+ Value *CreateFunctionLocalGateCmp (IRBuilder<> &IRB);
242255 void InjectCoverageAtBlock (Function &F, BasicBlock &BB, size_t Idx,
243- bool IsLeafFunc = true );
256+ Value *&FunctionGateCmp, bool IsLeafFunc = true );
244257 Function *CreateInitCallsForSections (Module &M, const char *CtorName,
245258 const char *InitFunctionName, Type *Ty,
246259 const char *Section);
@@ -265,6 +278,7 @@ class ModuleSanitizerCoverage {
265278 FunctionCallee SanCovTraceGepFunction;
266279 FunctionCallee SanCovTraceSwitchFunction;
267280 GlobalVariable *SanCovLowestStack;
281+ GlobalVariable *SanCovCallbackGate;
268282 Type *PtrTy, *IntptrTy, *Int64Ty, *Int32Ty, *Int16Ty, *Int8Ty, *Int1Ty;
269283 Module *CurModule;
270284 std::string CurModuleUniqueId;
@@ -478,6 +492,23 @@ bool ModuleSanitizerCoverage::instrumentModule() {
478492 if (Options.StackDepth && !SanCovLowestStack->isDeclaration ())
479493 SanCovLowestStack->setInitializer (Constant::getAllOnesValue (IntptrTy));
480494
495+ if (Options.GatedCallbacks ) {
496+ if (!Options.TracePCGuard ) {
497+ C->emitError (StringRef (" '" ) + ClGatedCallbacks.ArgStr +
498+ " ' is only supported with trace-pc-guard" );
499+ return true ;
500+ }
501+
502+ SanCovCallbackGate = cast<GlobalVariable>(
503+ M.getOrInsertGlobal (SanCovCallbackGateName, Int64Ty));
504+ SanCovCallbackGate->setSection (
505+ getSectionName (SanCovCallbackGateSectionName));
506+ SanCovCallbackGate->setInitializer (Constant::getNullValue (Int64Ty));
507+ SanCovCallbackGate->setLinkage (GlobalVariable::LinkOnceAnyLinkage);
508+ SanCovCallbackGate->setVisibility (GlobalVariable::HiddenVisibility);
509+ appendToCompilerUsed (M, SanCovCallbackGate);
510+ }
511+
481512 SanCovTracePC = M.getOrInsertFunction (SanCovTracePCName, VoidTy);
482513 SanCovTracePCGuard =
483514 M.getOrInsertFunction (SanCovTracePCGuardName, VoidTy, PtrTy);
@@ -777,13 +808,22 @@ void ModuleSanitizerCoverage::CreateFunctionLocalArrays(
777808 FunctionPCsArray = CreatePCArray (F, AllBlocks);
778809}
779810
811+ Value *ModuleSanitizerCoverage::CreateFunctionLocalGateCmp (IRBuilder<> &IRB) {
812+ auto Load = IRB.CreateLoad (Int64Ty, SanCovCallbackGate);
813+ Load->setNoSanitizeMetadata ();
814+ auto Cmp = IRB.CreateIsNotNull (Load);
815+ Cmp->setName (" sancov gate cmp" );
816+ return Cmp;
817+ }
818+
780819bool ModuleSanitizerCoverage::InjectCoverage (Function &F,
781820 ArrayRef<BasicBlock *> AllBlocks,
782821 bool IsLeafFunc) {
783822 if (AllBlocks.empty ()) return false ;
784823 CreateFunctionLocalArrays (F, AllBlocks);
824+ Value *FunctionGateCmp = nullptr ;
785825 for (size_t i = 0 , N = AllBlocks.size (); i < N; i++)
786- InjectCoverageAtBlock (F, *AllBlocks[i], i, IsLeafFunc);
826+ InjectCoverageAtBlock (F, *AllBlocks[i], i, FunctionGateCmp, IsLeafFunc);
787827 return true ;
788828}
789829
@@ -946,6 +986,7 @@ void ModuleSanitizerCoverage::InjectTraceForCmp(
946986
947987void ModuleSanitizerCoverage::InjectCoverageAtBlock (Function &F, BasicBlock &BB,
948988 size_t Idx,
989+ Value *&FunctionGateCmp,
949990 bool IsLeafFunc) {
950991 BasicBlock::iterator IP = BB.getFirstInsertionPt ();
951992 bool IsEntryBB = &BB == &F.getEntryBlock ();
@@ -971,7 +1012,23 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
9711012 IRB.CreateAdd (IRB.CreatePointerCast (FunctionGuardArray, IntptrTy),
9721013 ConstantInt::get (IntptrTy, Idx * 4 )),
9731014 PtrTy);
974- IRB.CreateCall (SanCovTracePCGuard, GuardPtr)->setCannotMerge ();
1015+ if (Options.GatedCallbacks ) {
1016+ if (!FunctionGateCmp) {
1017+ // Create this in the entry block
1018+ assert (IsEntryBB);
1019+ FunctionGateCmp = CreateFunctionLocalGateCmp (IRB);
1020+ }
1021+ // Set the branch weights in order to minimize the price paid when the
1022+ // gate is turned off, allowing the default enablement of this
1023+ // instrumentation with as little of a performance cost as possible
1024+ auto Weights = MDBuilder (*C).createBranchWeights (1 , 100000 );
1025+ auto ThenTerm =
1026+ SplitBlockAndInsertIfThen (FunctionGateCmp, &*IP, false , Weights);
1027+ IRBuilder<> ThenIRB (ThenTerm);
1028+ ThenIRB.CreateCall (SanCovTracePCGuard, GuardPtr)->setCannotMerge ();
1029+ } else {
1030+ IRB.CreateCall (SanCovTracePCGuard, GuardPtr)->setCannotMerge ();
1031+ }
9751032 }
9761033 if (Options.Inline8bitCounters ) {
9771034 auto CounterPtr = IRB.CreateGEP (
0 commit comments