diff options
author | Kostya Serebryany <kcc@google.com> | 2016-02-17 21:34:43 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@google.com> | 2016-02-17 21:34:43 +0000 |
commit | d4590c7304575702731b00749ae22e1298a98eba (patch) | |
tree | 7bf5023a60a9e44773fef4c7c704b3c89250b328 | |
parent | 2af1e3e963d5af7a674f101cfebbddd7e74460ae (diff) | |
download | bcm5719-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.rst | 11 | ||||
-rw-r--r-- | clang/include/clang/Driver/CC1Options.td | 3 | ||||
-rw-r--r-- | clang/include/clang/Frontend/CodeGenOptions.def | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/BackendUtil.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Driver/SanitizerArgs.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 1 | ||||
-rw-r--r-- | clang/test/Driver/fsanitize-coverage.c | 3 | ||||
-rw-r--r-- | compiler-rt/test/asan/TestCases/coverage-trace-pc.cc | 31 | ||||
-rw-r--r-- | llvm/include/llvm/Transforms/Instrumentation.h | 3 | ||||
-rw-r--r-- | llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | 30 | ||||
-rw-r--r-- | llvm/test/Instrumentation/SanitizerCoverage/coverage.ll | 6 | ||||
-rw-r--r-- | llvm/test/Instrumentation/SanitizerCoverage/tracing.ll | 9 |
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 |