Skip to content

Commit 7800d59

Browse files
[SanitizerCoverage] Add gated tracing callbacks support to trace-cmp (#113227)
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 387be04 commit 7800d59

File tree

3 files changed

+59
-18
lines changed

3 files changed

+59
-18
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: 11 additions & 2 deletions
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 or trace-cmp
1315

1416
int x[10];
1517

@@ -23,6 +25,11 @@ void foo(int n, int m) {
2325
// GATED-NEXT: br i1 [[CMP]], label %[[L_TRUE:.*]], label %[[L_FALSE:.*]], !prof [[WEIGHTS:!.+]]
2426
// GATED: [[L_TRUE]]:
2527
// GATED-NEXT: call void @__sanitizer_cov_trace_pc_guard
28+
// COM: Check the trace-cmp instrumentation of the if (n) branch
29+
// GATEDCMP: [[OPERAND:%.*]] = load i32, {{.*}}
30+
// GATEDCMP-NEXT: br i1 [[CMP]], label %[[L_TRUE_1:.*]], label %[[L_FALSE_1:.*]]
31+
// GATEDCMP: [[L_TRUE_1]]:
32+
// GATEDCMP-NEXT: call void @__sanitizer_cov_trace_const_cmp4(i32 0, i32 [[OPERAND]])
2633
// GATED: br i1 [[CMP]], label %[[L_TRUE_2:.*]], label %[[L_FALSE_2:.*]]
2734
// GATED: [[L_TRUE_2]]:
2835
// GATED-NEXT: call void @__sanitizer_cov_trace_pc_guard
@@ -33,10 +40,12 @@ void foo(int n, int m) {
3340
// PLAIN-NOT: __sancov_should_track
3441
// But we should still be emitting the calls to the callback.
3542
// PLAIN: call void @__sanitizer_cov_trace_pc_guard
43+
// PLAINCMP: [[OPERAND:%.*]] = load i32, {{.*}}
44+
// PLAINCMP-NEXT: call void @__sanitizer_cov_trace_const_cmp4(i32 0, i32 [[OPERAND]])
3645
if (n) {
3746
x[n] = 42;
3847
if (m) {
3948
x[m] = 41;
4049
}
4150
}
42-
}
51+
}

llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ static cl::opt<bool>
158158

159159
static cl::opt<bool> ClGatedCallbacks(
160160
"sanitizer-coverage-gated-trace-callbacks",
161-
cl::desc("Gate the invocation of the tracing callbacks on a global "
162-
"variable. Currently only supported for trace-pc-guard."),
161+
cl::desc("Gate the invocation of the tracing callbacks on a global variable"
162+
". Currently only supported for trace-pc-guard and trace-cmp."),
163163
cl::Hidden, cl::init(false));
164164

165165
namespace {
@@ -234,17 +234,19 @@ class ModuleSanitizerCoverage {
234234
void instrumentFunction(Function &F);
235235
void InjectCoverageForIndirectCalls(Function &F,
236236
ArrayRef<Instruction *> IndirCalls);
237-
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
237+
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets,
238+
Value *&FunctionGateCmp);
238239
void InjectTraceForDiv(Function &F,
239240
ArrayRef<BinaryOperator *> DivTraceTargets);
240241
void InjectTraceForGep(Function &F,
241242
ArrayRef<GetElementPtrInst *> GepTraceTargets);
242243
void InjectTraceForLoadsAndStores(Function &F, ArrayRef<LoadInst *> Loads,
243244
ArrayRef<StoreInst *> Stores);
244245
void InjectTraceForSwitch(Function &F,
245-
ArrayRef<Instruction *> SwitchTraceTargets);
246+
ArrayRef<Instruction *> SwitchTraceTargets,
247+
Value *&FunctionGateCmp);
246248
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
247-
bool IsLeafFunc);
249+
Value *&FunctionGateCmp, bool IsLeafFunc);
248250
GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements,
249251
Function &F, Type *Ty,
250252
const char *Section);
@@ -494,9 +496,9 @@ bool ModuleSanitizerCoverage::instrumentModule() {
494496
SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
495497

496498
if (Options.GatedCallbacks) {
497-
if (!Options.TracePCGuard) {
499+
if (!Options.TracePCGuard && !Options.TraceCmp) {
498500
C->emitError(StringRef("'") + ClGatedCallbacks.ArgStr +
499-
"' is only supported with trace-pc-guard");
501+
"' is only supported with trace-pc-guard or trace-cmp");
500502
return true;
501503
}
502504

@@ -725,10 +727,11 @@ void ModuleSanitizerCoverage::instrumentFunction(Function &F) {
725727
if (Options.CollectControlFlow)
726728
createFunctionControlFlow(F);
727729

728-
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
730+
Value *FunctionGateCmp = nullptr;
731+
InjectCoverage(F, BlocksToInstrument, FunctionGateCmp, IsLeafFunc);
729732
InjectCoverageForIndirectCalls(F, IndirCalls);
730-
InjectTraceForCmp(F, CmpTraceTargets);
731-
InjectTraceForSwitch(F, SwitchTraceTargets);
733+
InjectTraceForCmp(F, CmpTraceTargets, FunctionGateCmp);
734+
InjectTraceForSwitch(F, SwitchTraceTargets, FunctionGateCmp);
732735
InjectTraceForDiv(F, DivTraceTargets);
733736
InjectTraceForGep(F, GepTraceTargets);
734737
InjectTraceForLoadsAndStores(F, Loads, Stores);
@@ -837,10 +840,10 @@ Instruction *ModuleSanitizerCoverage::CreateGateBranch(Function &F,
837840

838841
bool ModuleSanitizerCoverage::InjectCoverage(Function &F,
839842
ArrayRef<BasicBlock *> AllBlocks,
843+
Value *&FunctionGateCmp,
840844
bool IsLeafFunc) {
841845
if (AllBlocks.empty()) return false;
842846
CreateFunctionLocalArrays(F, AllBlocks);
843-
Value *FunctionGateCmp = nullptr;
844847
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
845848
InjectCoverageAtBlock(F, *AllBlocks[i], i, FunctionGateCmp, IsLeafFunc);
846849
return true;
@@ -874,7 +877,8 @@ void ModuleSanitizerCoverage::InjectCoverageForIndirectCalls(
874877
// {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... })
875878

876879
void ModuleSanitizerCoverage::InjectTraceForSwitch(
877-
Function &, ArrayRef<Instruction *> SwitchTraceTargets) {
880+
Function &F, ArrayRef<Instruction *> SwitchTraceTargets,
881+
Value *&FunctionGateCmp) {
878882
for (auto *I : SwitchTraceTargets) {
879883
if (SwitchInst *SI = dyn_cast<SwitchInst>(I)) {
880884
InstrumentationIRBuilder IRB(I);
@@ -905,7 +909,13 @@ void ModuleSanitizerCoverage::InjectTraceForSwitch(
905909
*CurModule, ArrayOfInt64Ty, false, GlobalVariable::InternalLinkage,
906910
ConstantArray::get(ArrayOfInt64Ty, Initializers),
907911
"__sancov_gen_cov_switch_values");
908-
IRB.CreateCall(SanCovTraceSwitchFunction, {Cond, GV});
912+
if (Options.GatedCallbacks) {
913+
auto GateBranch = CreateGateBranch(F, FunctionGateCmp, I);
914+
IRBuilder<> GateIRB(GateBranch);
915+
GateIRB.CreateCall(SanCovTraceSwitchFunction, {Cond, GV});
916+
} else {
917+
IRB.CreateCall(SanCovTraceSwitchFunction, {Cond, GV});
918+
}
909919
}
910920
}
911921
}
@@ -969,7 +979,8 @@ void ModuleSanitizerCoverage::InjectTraceForLoadsAndStores(
969979
}
970980

971981
void ModuleSanitizerCoverage::InjectTraceForCmp(
972-
Function &, ArrayRef<Instruction *> CmpTraceTargets) {
982+
Function &F, ArrayRef<Instruction *> CmpTraceTargets,
983+
Value *&FunctionGateCmp) {
973984
for (auto *I : CmpTraceTargets) {
974985
if (ICmpInst *ICMP = dyn_cast<ICmpInst>(I)) {
975986
InstrumentationIRBuilder IRB(ICMP);
@@ -997,8 +1008,15 @@ void ModuleSanitizerCoverage::InjectTraceForCmp(
9971008
}
9981009

9991010
auto Ty = Type::getIntNTy(*C, TypeSize);
1000-
IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true),
1001-
IRB.CreateIntCast(A1, Ty, true)});
1011+
if (Options.GatedCallbacks) {
1012+
auto GateBranch = CreateGateBranch(F, FunctionGateCmp, I);
1013+
IRBuilder<> GateIRB(GateBranch);
1014+
GateIRB.CreateCall(CallbackFunc, {GateIRB.CreateIntCast(A0, Ty, true),
1015+
GateIRB.CreateIntCast(A1, Ty, true)});
1016+
} else {
1017+
IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true),
1018+
IRB.CreateIntCast(A1, Ty, true)});
1019+
}
10021020
}
10031021
}
10041022
}

0 commit comments

Comments
 (0)