From 0dd5e22d895a71b5a2d8eb06cedcf8a431290513 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 19 Nov 2014 00:22:58 +0000 Subject: [PATCH] [asan] add experimental basic-block tracing to asan-coverage; also fix -fsanitize-coverage=3 which was broken by r221718 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222290 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Instrumentation/AddressSanitizer.cpp | 4 +- .../Instrumentation/SanitizerCoverage.cpp | 46 ++++++++++++++++--- .../SanitizerCoverage/coverage.ll | 1 + .../SanitizerCoverage/tracing.ll | 33 +++++++++++++ 4 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 test/Instrumentation/SanitizerCoverage/tracing.ll diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 1c5f5af12a5..3d8d84f366f 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -89,6 +89,7 @@ static const int kMaxAsanStackMallocSizeClass = 10; static const char *const kAsanStackMallocNameTemplate = "__asan_stack_malloc_"; static const char *const kAsanStackFreeNameTemplate = "__asan_stack_free_"; static const char *const kAsanGenPrefix = "__asan_gen_"; +static const char *const kSanCovGenPrefix = "__sancov_gen_"; static const char *const kAsanPoisonStackMemoryName = "__asan_poison_stack_memory"; static const char *const kAsanUnpoisonStackMemoryName = @@ -619,7 +620,8 @@ static GlobalVariable *createPrivateGlobalForSourceLoc(Module &M, } static bool GlobalWasGeneratedByAsan(GlobalVariable *G) { - return G->getName().find(kAsanGenPrefix) == 0; + return G->getName().find(kAsanGenPrefix) == 0 || + G->getName().find(kSanCovGenPrefix) == 0; } Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) { diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index dcdcfa12878..f882072e619 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -56,6 +56,8 @@ using namespace llvm; static const char *const kSanCovModuleInitName = "__sanitizer_cov_module_init"; static const char *const kSanCovName = "__sanitizer_cov"; static const char *const kSanCovIndirCallName = "__sanitizer_cov_indir_call16"; +static const char *const kSanCovTraceEnter = "__sanitizer_cov_trace_func_enter"; +static const char *const kSanCovTraceBB = "__sanitizer_cov_trace_basic_block"; static const char *const kSanCovModuleCtorName = "sancov.module_ctor"; static const uint64_t kSanCtorAndDtorPriority = 1; @@ -71,15 +73,19 @@ static cl::opt ClCoverageBlockThreshold( "are more than this number of blocks."), cl::Hidden, cl::init(1500)); +static cl::opt + ClExperimentalTracing("sanitizer-coverage-experimental-tracing", + cl::desc("Experimental basic-block tracing: insert " + "callbacks at every basic block"), + cl::Hidden, cl::init(false)); + namespace { class SanitizerCoverageModule : public ModulePass { public: - SanitizerCoverageModule(int CoverageLevel = 0) + SanitizerCoverageModule(int CoverageLevel = 0) : ModulePass(ID), - CoverageLevel(std::max(CoverageLevel, (int)ClCoverageLevel)) { - initializeBreakCriticalEdgesPass(*PassRegistry::getPassRegistry()); - } + CoverageLevel(std::max(CoverageLevel, (int)ClCoverageLevel)) {} bool runOnModule(Module &M) override; bool runOnFunction(Function &F); static char ID; // Pass identification, replacement for typeid @@ -88,8 +94,6 @@ class SanitizerCoverageModule : public ModulePass { } void getAnalysisUsage(AnalysisUsage &AU) const override { - if (CoverageLevel >= 3) - AU.addRequiredID(BreakCriticalEdgesID); AU.addRequired(); } @@ -98,10 +102,12 @@ class SanitizerCoverageModule : public ModulePass { ArrayRef IndirCalls); bool InjectCoverage(Function &F, ArrayRef AllBlocks, ArrayRef IndirCalls); + bool InjectTracing(Function &F, ArrayRef AllBlocks); void InjectCoverageAtBlock(Function &F, BasicBlock &BB); Function *SanCovFunction; Function *SanCovIndirCallFunction; Function *SanCovModuleInit; + Function *SanCovTraceEnter, *SanCovTraceBB; Type *IntptrTy; LLVMContext *C; @@ -141,6 +147,13 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { kSanCovModuleInitName, Type::getVoidTy(*C), IntptrTy, nullptr)); SanCovModuleInit->setLinkage(Function::ExternalLinkage); + if (ClExperimentalTracing) { + SanCovTraceEnter = checkInterfaceFunction( + M.getOrInsertFunction(kSanCovTraceEnter, VoidTy, IntptrTy, nullptr)); + SanCovTraceBB = checkInterfaceFunction( + M.getOrInsertFunction(kSanCovTraceBB, VoidTy, IntptrTy, nullptr)); + } + for (auto &F : M) runOnFunction(F); @@ -155,6 +168,8 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { // For now instrument only functions that will also be asan-instrumented. if (!F.hasFnAttribute(Attribute::SanitizeAddress)) return false; + if (CoverageLevel >= 3) + SplitAllCriticalEdges(F, this); SmallVector IndirCalls; SmallVector AllBlocks; for (auto &BB : F) { @@ -167,6 +182,25 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { } } InjectCoverage(F, AllBlocks, IndirCalls); + InjectTracing(F, AllBlocks); + return true; +} + +// Experimental support for tracing. +// Basicaly, insert a callback at the beginning of every basic block. +// Every callback gets a pointer to a uniqie global for internal storage. +bool SanitizerCoverageModule::InjectTracing(Function &F, + ArrayRef AllBlocks) { + if (!ClExperimentalTracing) return false; + Type *Ty = ArrayType::get(IntptrTy, 1); // May need to use more words later. + for (auto BB : AllBlocks) { + IRBuilder<> IRB(BB->getFirstInsertionPt()); + GlobalVariable *TraceCache = new GlobalVariable( + *F.getParent(), Ty, false, GlobalValue::PrivateLinkage, + Constant::getNullValue(Ty), "__sancov_gen_trace_cache"); + IRB.CreateCall(&F.getEntryBlock() == BB ? SanCovTraceEnter : SanCovTraceBB, + IRB.CreatePointerCast(TraceCache, IntptrTy)); + } return true; } diff --git a/test/Instrumentation/SanitizerCoverage/coverage.ll b/test/Instrumentation/SanitizerCoverage/coverage.ll index a3b1131968a..da0498db642 100644 --- a/test/Instrumentation/SanitizerCoverage/coverage.ll +++ b/test/Instrumentation/SanitizerCoverage/coverage.ll @@ -62,6 +62,7 @@ entry: ; CHECK3: call void @__sanitizer_cov ; CHECK3: call void @__sanitizer_cov ; CHECK3: call void @__sanitizer_cov +; CHECK3-NOT: ret void ; CHECK3: call void @__sanitizer_cov ; CHECK3-NOT: call void @__sanitizer_cov ; CHECK3: ret void diff --git a/test/Instrumentation/SanitizerCoverage/tracing.ll b/test/Instrumentation/SanitizerCoverage/tracing.ll new file mode 100644 index 00000000000..c39cb1cfbb3 --- /dev/null +++ b/test/Instrumentation/SanitizerCoverage/tracing.ll @@ -0,0 +1,33 @@ +; Test -sanitizer-coverage-experimental-tracing +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -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 + +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" +define void @foo(i32* %a) sanitize_address { +entry: + %tobool = icmp eq i32* %a, null + br i1 %tobool, label %if.end, label %if.then + + if.then: ; preds = %entry + store i32 0, i32* %a, align 4 + br label %if.end + + if.end: ; preds = %entry, %if.then + ret void +} + +; CHECK1-LABEL: define void @foo +; CHECK1: call void @__sanitizer_cov_trace_func_enter +; CHECK1: call void @__sanitizer_cov_trace_basic_block +; CHECK1: call void @__sanitizer_cov_trace_basic_block +; CHECK1-NOT: call void @__sanitizer_cov_trace_basic_block +; CHECK1: ret void + +; CHECK3-LABEL: define void @foo +; CHECK3: call void @__sanitizer_cov_trace_func_enter +; CHECK3: call void @__sanitizer_cov_trace_basic_block +; CHECK3: call void @__sanitizer_cov_trace_basic_block +; CHECK3: call void @__sanitizer_cov_trace_basic_block +; CHECK3-NOT: call void @__sanitizer_cov_trace_basic_block +; CHECK3: ret void