summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2016-02-17 21:34:43 +0000
committerKostya Serebryany <kcc@google.com>2016-02-17 21:34:43 +0000
commitd4590c7304575702731b00749ae22e1298a98eba (patch)
tree7bf5023a60a9e44773fef4c7c704b3c89250b328
parent2af1e3e963d5af7a674f101cfebbddd7e74460ae (diff)
downloadbcm5719-llvm-d4590c7304575702731b00749ae22e1298a98eba.tar.gz
bcm5719-llvm-d4590c7304575702731b00749ae22e1298a98eba.zip
[sanitizer-coverage] implement -fsanitize-coverage=trace-pc. This is similar to trace-bb, but has a different API. We already use the equivalent flag in GCC for Linux kernel fuzzing. We may be able to use this flag with AFL too
llvm-svn: 261159
-rw-r--r--clang/docs/SanitizerCoverage.rst11
-rw-r--r--clang/include/clang/Driver/CC1Options.td3
-rw-r--r--clang/include/clang/Frontend/CodeGenOptions.def2
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp1
-rw-r--r--clang/lib/Driver/SanitizerArgs.cpp10
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--clang/test/Driver/fsanitize-coverage.c3
-rw-r--r--compiler-rt/test/asan/TestCases/coverage-trace-pc.cc31
-rw-r--r--llvm/include/llvm/Transforms/Instrumentation.h3
-rw-r--r--llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp30
-rw-r--r--llvm/test/Instrumentation/SanitizerCoverage/coverage.ll6
-rw-r--r--llvm/test/Instrumentation/SanitizerCoverage/tracing.ll9
12 files changed, 101 insertions, 9 deletions
diff --git a/clang/docs/SanitizerCoverage.rst b/clang/docs/SanitizerCoverage.rst
index 0e493400b4e..6d6e576e464 100644
--- a/clang/docs/SanitizerCoverage.rst
+++ b/clang/docs/SanitizerCoverage.rst
@@ -291,6 +291,17 @@ With ``-fsanitize-coverage=trace-bb`` the compiler will insert
``__sanitizer_cov_trace_basic_block(s32 *id)`` before every function, basic block, or edge
(depending on the value of ``-fsanitize-coverage=[func,bb,edge]``).
+Tracing PCs
+===========
+*Experimental* feature similar to tracing basic blocks, but with a different API.
+With ``-fsanitize-coverage=[func,bb,edge],trace-pc`` the compiler will insert
+``__sanitizer_cov_trace_pc()`` on every function/block/edge.
+With and additional ``indirect-calls`` flag
+``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
+These callbacks are not implemented in the Sanitizer run-time and should be defined
+by the user.
+This mechanism is used for fuzzing the Linux kernel (https://github.com/google/syzkaller).
+
Tracing data flow
=================
diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td
index c1c4035016c..00ca505afd2 100644
--- a/clang/include/clang/Driver/CC1Options.td
+++ b/clang/include/clang/Driver/CC1Options.td
@@ -270,6 +270,9 @@ def fsanitize_coverage_trace_cmp
def fsanitize_coverage_8bit_counters
: Flag<["-"], "fsanitize-coverage-8bit-counters">,
HelpText<"Enable frequency counters in sanitizer coverage">;
+def fsanitize_coverage_trace_pc
+ : Flag<["-"], "fsanitize-coverage-trace-pc">,
+ HelpText<"Enable PC tracing in sanitizer coverage">;
def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">,
HelpText<"Enable PGO instrumentation. The accepted values is clang or "
"none">;
diff --git a/clang/include/clang/Frontend/CodeGenOptions.def b/clang/include/clang/Frontend/CodeGenOptions.def
index 4b89ee32016..bffe85bdbda 100644
--- a/clang/include/clang/Frontend/CodeGenOptions.def
+++ b/clang/include/clang/Frontend/CodeGenOptions.def
@@ -134,6 +134,8 @@ CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters
///< in sanitizer coverage.
+CODEGENOPT(SanitizeCoverageTracePC, 1, 0) ///< Enable PC tracing
+ ///< in sanitizer coverage.
CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 0cb039bb07a..f5afc68eddc 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -189,6 +189,7 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
Opts.TraceBB = CGOpts.SanitizeCoverageTraceBB;
Opts.TraceCmp = CGOpts.SanitizeCoverageTraceCmp;
Opts.Use8bitCounters = CGOpts.SanitizeCoverage8bitCounters;
+ Opts.TracePC = CGOpts.SanitizeCoverageTracePC;
PM.add(createSanitizerCoverageModulePass(Opts));
}
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index cf8d39d6efe..1614ee439c2 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -49,6 +49,7 @@ enum CoverageFeature {
CoverageTraceBB = 1 << 4,
CoverageTraceCmp = 1 << 5,
Coverage8bitCounters = 1 << 6,
+ CoverageTracePC = 1 << 7,
};
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
@@ -498,6 +499,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< "-fsanitize-coverage=8bit-counters"
<< "-fsanitize-coverage=(func|bb|edge)";
+ if ((CoverageFeatures & CoverageTracePC) &&
+ !(CoverageFeatures & CoverageTypes))
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << "-fsanitize-coverage=trace-pc"
+ << "-fsanitize-coverage=(func|bb|edge)";
if (AllAddedKinds & Address) {
AsanSharedRuntime =
@@ -615,7 +621,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"),
std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"),
std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"),
- std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters")};
+ std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"),
+ std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc")};
for (auto F : CoverageFlags) {
if (CoverageFeatures & F.first)
CmdArgs.push_back(Args.MakeArgString(F.second));
@@ -696,6 +703,7 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
.Case("trace-bb", CoverageTraceBB)
.Case("trace-cmp", CoverageTraceCmp)
.Case("8bit-counters", Coverage8bitCounters)
+ .Case("trace-pc", CoverageTracePC)
.Default(0);
if (F == 0)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 2b191ca8dc3..c822bccaa3c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -637,6 +637,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeCoverageTraceCmp = Args.hasArg(OPT_fsanitize_coverage_trace_cmp);
Opts.SanitizeCoverage8bitCounters =
Args.hasArg(OPT_fsanitize_coverage_8bit_counters);
+ Opts.SanitizeCoverageTracePC = Args.hasArg(OPT_fsanitize_coverage_trace_pc);
Opts.SanitizeMemoryTrackOrigins =
getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
Opts.SanitizeMemoryUseAfterDtor =
diff --git a/clang/test/Driver/fsanitize-coverage.c b/clang/test/Driver/fsanitize-coverage.c
index fdaa9faf890..8ad20f1b9d8 100644
--- a/clang/test/Driver/fsanitize-coverage.c
+++ b/clang/test/Driver/fsanitize-coverage.c
@@ -31,12 +31,13 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=1 -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-SAN-DISABLED
// CHECK-SANITIZE-COVERAGE-SAN-DISABLED-NOT: argument unused
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-bb,trace-cmp,8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-bb,trace-pc,trace-cmp,8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-type=3
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-indirect-calls
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-bb
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-cmp
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-8bit-counters
+// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-pc
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,edge,indirect-calls,trace-bb,trace-cmp -fno-sanitize-coverage=edge,indirect-calls,trace-bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MASK
// CHECK-MASK: -fsanitize-coverage-type=1
diff --git a/compiler-rt/test/asan/TestCases/coverage-trace-pc.cc b/compiler-rt/test/asan/TestCases/coverage-trace-pc.cc
new file mode 100644
index 00000000000..c03a6f02f77
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/coverage-trace-pc.cc
@@ -0,0 +1,31 @@
+// Test -fsanitize-coverage=edge,indirect-call,trace-pc
+// RUN: %clangxx_asan -O0 -DTRACE_RT %s -o %t-rt.o -c
+// RUN: %clangxx_asan -O0 -fsanitize-coverage=edge,trace-pc,indirect-calls %s -o %t %t-rt.o
+// RUN: %run %t
+#ifdef TRACE_RT
+int pc_count;
+void *last_callee;
+extern "C" void __sanitizer_cov_trace_pc() {
+ pc_count++;
+}
+extern "C" void __sanitizer_cov_trace_pc_indir(void *callee) {
+ last_callee = callee;
+}
+#else
+#include <stdio.h>
+#include <assert.h>
+extern int pc_count;
+extern void *last_callee;
+
+__attribute__((noinline)) void foo() { printf("foo\n"); }
+__attribute__((noinline)) void bar() { printf("bar\n"); }
+
+int main(int argc, char **argv) {
+ void (*f)(void) = argc ? foo : bar;
+ int c1 = pc_count;
+ f();
+ int c2 = pc_count;
+ assert(c1 < c2);
+ assert(last_callee == foo);
+}
+#endif
diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h
index d9402631574..ad65e0db9ba 100644
--- a/llvm/include/llvm/Transforms/Instrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation.h
@@ -120,7 +120,7 @@ ModulePass *createDataFlowSanitizerPass(
struct SanitizerCoverageOptions {
SanitizerCoverageOptions()
: CoverageType(SCK_None), IndirectCalls(false), TraceBB(false),
- TraceCmp(false), Use8bitCounters(false) {}
+ TraceCmp(false), Use8bitCounters(false), TracePC(false) {}
enum Type {
SCK_None = 0,
@@ -132,6 +132,7 @@ struct SanitizerCoverageOptions {
bool TraceBB;
bool TraceCmp;
bool Use8bitCounters;
+ bool TracePC;
};
// Insert SanitizerCoverage instrumentation.
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
index 82a070843bf..34e8b579c1c 100644
--- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -57,8 +57,10 @@ static const char *const kSanCovModuleInitName = "__sanitizer_cov_module_init";
static const char *const kSanCovName = "__sanitizer_cov";
static const char *const kSanCovWithCheckName = "__sanitizer_cov_with_check";
static const char *const kSanCovIndirCallName = "__sanitizer_cov_indir_call16";
+static const char *const kSanCovTracePCIndir = "__sanitizer_cov_trace_pc_indir";
static const char *const kSanCovTraceEnter = "__sanitizer_cov_trace_func_enter";
static const char *const kSanCovTraceBB = "__sanitizer_cov_trace_basic_block";
+static const char *const kSanCovTracePC = "__sanitizer_cov_trace_pc";
static const char *const kSanCovTraceCmp = "__sanitizer_cov_trace_cmp";
static const char *const kSanCovTraceSwitch = "__sanitizer_cov_trace_switch";
static const char *const kSanCovModuleCtorName = "sancov.module_ctor";
@@ -82,6 +84,10 @@ static cl::opt<bool>
"callbacks at every basic block"),
cl::Hidden, cl::init(false));
+static cl::opt<bool> ClExperimentalTracePC("sanitizer-coverage-trace-pc",
+ cl::desc("Experimental pc tracing"),
+ cl::Hidden, cl::init(false));
+
static cl::opt<bool>
ClExperimentalCMPTracing("sanitizer-coverage-experimental-trace-compares",
cl::desc("Experimental tracing of CMP and similar "
@@ -131,6 +137,7 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
Options.TraceBB |= ClExperimentalTracing;
Options.TraceCmp |= ClExperimentalCMPTracing;
Options.Use8bitCounters |= ClUse8bitCounters;
+ Options.TracePC |= ClExperimentalTracePC;
return Options;
}
@@ -162,8 +169,8 @@ class SanitizerCoverageModule : public ModulePass {
}
Function *SanCovFunction;
Function *SanCovWithCheckFunction;
- Function *SanCovIndirCallFunction;
- Function *SanCovTraceEnter, *SanCovTraceBB;
+ Function *SanCovIndirCallFunction, *SanCovTracePCIndir;
+ Function *SanCovTraceEnter, *SanCovTraceBB, *SanCovTracePC;
Function *SanCovTraceCmpFunction;
Function *SanCovTraceSwitchFunction;
InlineAsm *EmptyAsm;
@@ -198,6 +205,9 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {
M.getOrInsertFunction(kSanCovName, VoidTy, Int32PtrTy, nullptr));
SanCovWithCheckFunction = checkSanitizerInterfaceFunction(
M.getOrInsertFunction(kSanCovWithCheckName, VoidTy, Int32PtrTy, nullptr));
+ SanCovTracePCIndir =
+ checkSanitizerInterfaceFunction(M.getOrInsertFunction(
+ kSanCovTracePCIndir, VoidTy, IntptrTy, nullptr));
SanCovIndirCallFunction =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
kSanCovIndirCallName, VoidTy, IntptrTy, IntptrTy, nullptr));
@@ -213,6 +223,8 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {
StringRef(""), StringRef(""),
/*hasSideEffects=*/true);
+ SanCovTracePC = checkSanitizerInterfaceFunction(
+ M.getOrInsertFunction(kSanCovTracePC, VoidTy, nullptr));
SanCovTraceEnter = checkSanitizerInterfaceFunction(
M.getOrInsertFunction(kSanCovTraceEnter, VoidTy, Int32PtrTy, nullptr));
SanCovTraceBB = checkSanitizerInterfaceFunction(
@@ -364,9 +376,13 @@ void SanitizerCoverageModule::InjectCoverageForIndirectCalls(
*F.getParent(), Ty, false, GlobalValue::PrivateLinkage,
Constant::getNullValue(Ty), "__sancov_gen_callee_cache");
CalleeCache->setAlignment(kCacheAlignment);
- IRB.CreateCall(SanCovIndirCallFunction,
- {IRB.CreatePointerCast(Callee, IntptrTy),
- IRB.CreatePointerCast(CalleeCache, IntptrTy)});
+ if (Options.TracePC)
+ IRB.CreateCall(SanCovTracePCIndir,
+ IRB.CreatePointerCast(Callee, IntptrTy));
+ else
+ IRB.CreateCall(SanCovIndirCallFunction,
+ {IRB.CreatePointerCast(Callee, IntptrTy),
+ IRB.CreatePointerCast(CalleeCache, IntptrTy)});
}
}
@@ -464,7 +480,9 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
ConstantInt::get(IntptrTy, (1 + NumberOfInstrumentedBlocks()) * 4));
Type *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty());
GuardP = IRB.CreateIntToPtr(GuardP, Int32PtrTy);
- if (Options.TraceBB) {
+ if (Options.TracePC) {
+ IRB.CreateCall(SanCovTracePC);
+ } else if (Options.TraceBB) {
IRB.CreateCall(IsEntryBB ? SanCovTraceEnter : SanCovTraceBB, GuardP);
} else if (UseCalls) {
IRB.CreateCall(SanCovWithCheckFunction, GuardP);
diff --git a/llvm/test/Instrumentation/SanitizerCoverage/coverage.ll b/llvm/test/Instrumentation/SanitizerCoverage/coverage.ll
index 71fdbbb5ada..f7fa983a002 100644
--- a/llvm/test/Instrumentation/SanitizerCoverage/coverage.ll
+++ b/llvm/test/Instrumentation/SanitizerCoverage/coverage.ll
@@ -6,6 +6,7 @@
; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-block-threshold=1 -S | FileCheck %s --check-prefix=CHECK_WITH_CHECK
; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-block-threshold=10 -S | FileCheck %s --check-prefix=CHECK3
; RUN: opt < %s -sancov -sanitizer-coverage-level=4 -S | FileCheck %s --check-prefix=CHECK4
+; RUN: opt < %s -sancov -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc -S | FileCheck %s --check-prefix=CHECK_TRACE_PC_INDIR
; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-8bit-counters=1 -S | FileCheck %s --check-prefix=CHECK-8BIT
; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-block-threshold=10 \
@@ -120,6 +121,11 @@ entry:
; CHECK4-NOT: call void @__sanitizer_cov_indir_call16({{.*}},[[CACHE]])
; CHECK4: ret void
+; CHECK_TRACE_PC_INDIR-LABEL: define void @CallViaVptr
+; CHECK_TRACE_PC_INDIR: call void @__sanitizer_cov_trace_pc_indir
+; CHECK_TRACE_PC_INDIR: call void @__sanitizer_cov_trace_pc_indir
+; CHECK_TRACE_PC_INDIR: ret void
+
define void @call_unreachable() uwtable sanitize_address {
entry:
unreachable
diff --git a/llvm/test/Instrumentation/SanitizerCoverage/tracing.ll b/llvm/test/Instrumentation/SanitizerCoverage/tracing.ll
index 8c3a6df93a0..e6b9ae8538a 100644
--- a/llvm/test/Instrumentation/SanitizerCoverage/tracing.ll
+++ b/llvm/test/Instrumentation/SanitizerCoverage/tracing.ll
@@ -1,6 +1,7 @@
; Test -sanitizer-coverage-experimental-tracing
; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-experimental-tracing -S | FileCheck %s --check-prefix=CHECK1
; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-experimental-tracing -S | FileCheck %s --check-prefix=CHECK3
+; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-trace-pc -S | FileCheck %s --check-prefix=CHECK_PC
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
@@ -31,3 +32,11 @@ entry:
; CHECK3: call void @__sanitizer_cov_trace_basic_block
; CHECK3-NOT: call void @__sanitizer_cov_trace_basic_block
; CHECK3: ret void
+
+; CHECK_PC-LABEL: define void @foo
+; CHECK_PC: call void @__sanitizer_cov_trace_pc
+; CHECK_PC: call void @__sanitizer_cov_trace_pc
+; CHECK_PC: call void @__sanitizer_cov_trace_pc
+; CHECK_PC: call void @__sanitizer_cov_trace_pc
+; CHECK_PC-NOT: call void @__sanitizer_cov_trace_pc
+; CHECK_PC: ret void
OpenPOWER on IntegriCloud