Skip to content

Commit dd972e6

Browse files
committed
[SanitizerCoverage] Add gated tracing callbacks support to trace-cmp
The option -sanitizer-coverage-gated-trace-callbacks gates the invocation of the trace-pc-guard callbacks based on the value of a global variable, which is stored in a specific section. In this commit, we extend this feature to trace-cmp and gate the cmp callbacks to the same variable used for trace-pc-guard. Update SanitizerCoverage doc with this flag. rdar://135404160 Patch by: Andrea Fioraldi
1 parent ed5072e commit dd972e6

File tree

3 files changed

+75
-30
lines changed

3 files changed

+75
-30
lines changed

clang/docs/SanitizerCoverage.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,20 @@ Users need to implement a single function to capture the CF table at startup:
385385
// the collected control flow.
386386
}
387387
388+
Gated Trace Callbacks
389+
=====================
390+
391+
Gate the invocation of the tracing callbacks with
392+
``-sanitizer-coverage-gated-trace-callbacks``.
393+
394+
When this option is enabled, the instrumentation will not call into the
395+
runtime-provided callbacks for tracing, thus only incurring in a trivial
396+
branch without going through a function call.
397+
398+
It is up to the runtime to toggle the value of the global variable in order to
399+
enable tracing.
400+
401+
This option is only supported for trace-pc-guard and trace-cmp.
388402

389403
Disabling instrumentation with ``__attribute__((no_sanitize("coverage")))``
390404
===========================================================================

clang/test/CodeGen/sanitize-coverage-gated-callbacks.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc-guard -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o - | FileCheck %s --check-prefixes=CHECK,GATED
22
// RUN: %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc-guard -mllvm -sanitizer-coverage-gated-trace-callbacks=0 -o - | FileCheck %s --check-prefixes=CHECK,PLAIN
3+
// RUN: %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc-guard,trace-cmp -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o - | FileCheck %s --check-prefixes=CHECK,GATED,GATEDCMP
4+
// RUN: %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc-guard,trace-cmp -mllvm -sanitizer-coverage-gated-trace-callbacks=0 -o - | FileCheck %s --check-prefixes=CHECK,PLAIN,PLAINCMP
35
// RUN: not %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o /dev/null 2>&1 | FileCheck %s --check-prefixes=INCOMPATIBLE
46
// RUN: not %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=inline-8bit-counters -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o /dev/null 2>&1 | FileCheck %s --check-prefixes=INCOMPATIBLE
57
// RUN: not %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=inline-bool-flag -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o /dev/null 2>&1 | FileCheck %s --check-prefixes=INCOMPATIBLE
@@ -9,7 +11,7 @@
911
// PLAIN-NOT: section "__DATA,__sancov_gate"
1012

1113
// Produce an error for all incompatible sanitizer coverage modes.
12-
// INCOMPATIBLE: error: 'sanitizer-coverage-gated-trace-callbacks' is only supported with trace-pc-guard
14+
// INCOMPATIBLE: error: 'sanitizer-coverage-gated-trace-callbacks' is only supported with trace-pc-guard and trace-cmp
1315

1416
int x[10];
1517

llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ static cl::opt<bool>
159159

160160
static cl::opt<bool> ClGatedCallbacks(
161161
"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."),
162+
cl::desc("Gate the invocation of the tracing callbacks on a global variable"
163+
". Currently only supported for trace-pc-guard and trace-cmp."),
164164
cl::Hidden, cl::init(false));
165165

166166
namespace {
@@ -235,22 +235,26 @@ class ModuleSanitizerCoverage {
235235
void instrumentFunction(Function &F);
236236
void InjectCoverageForIndirectCalls(Function &F,
237237
ArrayRef<Instruction *> IndirCalls);
238-
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
238+
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets,
239+
Value *&FunctionGateCmp);
239240
void InjectTraceForDiv(Function &F,
240241
ArrayRef<BinaryOperator *> DivTraceTargets);
241242
void InjectTraceForGep(Function &F,
242243
ArrayRef<GetElementPtrInst *> GepTraceTargets);
243244
void InjectTraceForLoadsAndStores(Function &F, ArrayRef<LoadInst *> Loads,
244245
ArrayRef<StoreInst *> Stores);
245246
void InjectTraceForSwitch(Function &F,
246-
ArrayRef<Instruction *> SwitchTraceTargets);
247+
ArrayRef<Instruction *> SwitchTraceTargets,
248+
Value *&FunctionGateCmp);
247249
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
248-
bool IsLeafFunc = true);
250+
Value *&FunctionGateCmp, bool IsLeafFunc = true);
249251
GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements,
250252
Function &F, Type *Ty,
251253
const char *Section);
252254
GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks);
253255
void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks);
256+
Instruction *CreateGateBranch(Function &F, Value *&FunctionGateCmp,
257+
Instruction *I);
254258
Value *CreateFunctionLocalGateCmp(IRBuilder<> &IRB);
255259
void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx,
256260
Value *&FunctionGateCmp, bool IsLeafFunc = true);
@@ -493,9 +497,9 @@ bool ModuleSanitizerCoverage::instrumentModule() {
493497
SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
494498

495499
if (Options.GatedCallbacks) {
496-
if (!Options.TracePCGuard) {
500+
if (!Options.TracePCGuard && !Options.TraceCmp) {
497501
C->emitError(StringRef("'") + ClGatedCallbacks.ArgStr +
498-
"' is only supported with trace-pc-guard");
502+
"' is only supported with trace-pc-guard or trace-cmp");
499503
return true;
500504
}
501505

@@ -724,10 +728,11 @@ void ModuleSanitizerCoverage::instrumentFunction(Function &F) {
724728
if (Options.CollectControlFlow)
725729
createFunctionControlFlow(F);
726730

727-
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
731+
Value *FunctionGateCmp = nullptr;
732+
InjectCoverage(F, BlocksToInstrument, FunctionGateCmp, IsLeafFunc);
728733
InjectCoverageForIndirectCalls(F, IndirCalls);
729-
InjectTraceForCmp(F, CmpTraceTargets);
730-
InjectTraceForSwitch(F, SwitchTraceTargets);
734+
InjectTraceForCmp(F, CmpTraceTargets, FunctionGateCmp);
735+
InjectTraceForSwitch(F, SwitchTraceTargets, FunctionGateCmp);
731736
InjectTraceForDiv(F, DivTraceTargets);
732737
InjectTraceForGep(F, GepTraceTargets);
733738
InjectTraceForLoadsAndStores(F, Loads, Stores);
@@ -816,12 +821,30 @@ Value *ModuleSanitizerCoverage::CreateFunctionLocalGateCmp(IRBuilder<> &IRB) {
816821
return Cmp;
817822
}
818823

824+
Instruction *ModuleSanitizerCoverage::CreateGateBranch(Function &F,
825+
Value *&FunctionGateCmp,
826+
Instruction *IP) {
827+
if (!FunctionGateCmp) {
828+
// Create this in the entry block
829+
BasicBlock &BB = F.getEntryBlock();
830+
BasicBlock::iterator IP = BB.getFirstInsertionPt();
831+
IP = PrepareToSplitEntryBlock(BB, IP);
832+
IRBuilder<> EntryIRB(&*IP);
833+
FunctionGateCmp = CreateFunctionLocalGateCmp(EntryIRB);
834+
}
835+
// Set the branch weights in order to minimize the price paid when the
836+
// gate is turned off, allowing the default enablement of this
837+
// instrumentation with as little of a performance cost as possible
838+
auto Weights = MDBuilder(*C).createBranchWeights(1, 100000);
839+
return SplitBlockAndInsertIfThen(FunctionGateCmp, IP, false, Weights);
840+
}
841+
819842
bool ModuleSanitizerCoverage::InjectCoverage(Function &F,
820843
ArrayRef<BasicBlock *> AllBlocks,
844+
Value *&FunctionGateCmp,
821845
bool IsLeafFunc) {
822846
if (AllBlocks.empty()) return false;
823847
CreateFunctionLocalArrays(F, AllBlocks);
824-
Value *FunctionGateCmp = nullptr;
825848
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
826849
InjectCoverageAtBlock(F, *AllBlocks[i], i, FunctionGateCmp, IsLeafFunc);
827850
return true;
@@ -855,7 +878,8 @@ void ModuleSanitizerCoverage::InjectCoverageForIndirectCalls(
855878
// {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... })
856879

857880
void ModuleSanitizerCoverage::InjectTraceForSwitch(
858-
Function &, ArrayRef<Instruction *> SwitchTraceTargets) {
881+
Function &F, ArrayRef<Instruction *> SwitchTraceTargets,
882+
Value *&FunctionGateCmp) {
859883
for (auto *I : SwitchTraceTargets) {
860884
if (SwitchInst *SI = dyn_cast<SwitchInst>(I)) {
861885
InstrumentationIRBuilder IRB(I);
@@ -886,7 +910,13 @@ void ModuleSanitizerCoverage::InjectTraceForSwitch(
886910
*CurModule, ArrayOfInt64Ty, false, GlobalVariable::InternalLinkage,
887911
ConstantArray::get(ArrayOfInt64Ty, Initializers),
888912
"__sancov_gen_cov_switch_values");
889-
IRB.CreateCall(SanCovTraceSwitchFunction, {Cond, GV});
913+
if (Options.GatedCallbacks) {
914+
auto GateBranch = CreateGateBranch(F, FunctionGateCmp, I);
915+
IRBuilder<> GateIRB(GateBranch);
916+
GateIRB.CreateCall(SanCovTraceSwitchFunction, {Cond, GV});
917+
} else {
918+
IRB.CreateCall(SanCovTraceSwitchFunction, {Cond, GV});
919+
}
890920
}
891921
}
892922
}
@@ -950,7 +980,8 @@ void ModuleSanitizerCoverage::InjectTraceForLoadsAndStores(
950980
}
951981

952982
void ModuleSanitizerCoverage::InjectTraceForCmp(
953-
Function &, ArrayRef<Instruction *> CmpTraceTargets) {
983+
Function &F, ArrayRef<Instruction *> CmpTraceTargets,
984+
Value *&FunctionGateCmp) {
954985
for (auto *I : CmpTraceTargets) {
955986
if (ICmpInst *ICMP = dyn_cast<ICmpInst>(I)) {
956987
InstrumentationIRBuilder IRB(ICMP);
@@ -978,8 +1009,15 @@ void ModuleSanitizerCoverage::InjectTraceForCmp(
9781009
}
9791010

9801011
auto Ty = Type::getIntNTy(*C, TypeSize);
981-
IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true),
982-
IRB.CreateIntCast(A1, Ty, true)});
1012+
if (Options.GatedCallbacks) {
1013+
auto GateBranch = CreateGateBranch(F, FunctionGateCmp, I);
1014+
IRBuilder<> GateIRB(GateBranch);
1015+
GateIRB.CreateCall(CallbackFunc, {GateIRB.CreateIntCast(A0, Ty, true),
1016+
GateIRB.CreateIntCast(A1, Ty, true)});
1017+
} else {
1018+
IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true),
1019+
IRB.CreateIntCast(A1, Ty, true)});
1020+
}
9831021
}
9841022
}
9851023
}
@@ -1013,19 +1051,10 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
10131051
ConstantInt::get(IntptrTy, Idx * 4)),
10141052
PtrTy);
10151053
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();
1054+
Instruction *I = &*IP;
1055+
auto GateBranch = CreateGateBranch(F, FunctionGateCmp, I);
1056+
IRBuilder<> GateIRB(GateBranch);
1057+
GateIRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
10291058
} else {
10301059
IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
10311060
}

0 commit comments

Comments
 (0)