From 29a18dcbc531a0a30c9cabbb4e02b306d95d4f9b Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 11 Nov 2014 22:14:37 +0000 Subject: [PATCH] Move asan-coverage into a separate phase. Summary: This change moves asan-coverage instrumentation into a separate Module pass. The other part of the change in clang introduces a new flag -fsanitize-coverage=N. Another small patch will update tests in compiler-rt. With this patch no functionality change is expected except for the flag name. The following changes will make the coverage instrumentation work with tsan/msan Test Plan: Run regression tests, chromium. Reviewers: nlewycky, samsonov Reviewed By: nlewycky, samsonov Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D6152 llvm-svn: 221718 --- llvm/include/llvm/InitializePasses.h | 1 + llvm/include/llvm/Transforms/Instrumentation.h | 3 + .../Instrumentation/AddressSanitizer.cpp | 149 +----------- llvm/lib/Transforms/Instrumentation/CMakeLists.txt | 1 + .../Transforms/Instrumentation/Instrumentation.cpp | 1 + .../Instrumentation/SanitizerCoverage.cpp | 260 +++++++++++++++++++++ .../coverage-dbg.ll | 2 +- .../coverage.ll | 39 ++-- .../coverage2-dbg.ll | 2 +- 9 files changed, 287 insertions(+), 171 deletions(-) create mode 100644 llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp rename llvm/test/Instrumentation/{AddressSanitizer => SanitizerCoverage}/coverage-dbg.ll (98%) rename llvm/test/Instrumentation/{AddressSanitizer => SanitizerCoverage}/coverage.ll (60%) rename llvm/test/Instrumentation/{AddressSanitizer => SanitizerCoverage}/coverage2-dbg.ll (98%) diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index 6583df5..2489882 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -126,6 +126,7 @@ void initializeAddressSanitizerPass(PassRegistry&); void initializeAddressSanitizerModulePass(PassRegistry&); void initializeMemorySanitizerPass(PassRegistry&); void initializeThreadSanitizerPass(PassRegistry&); +void initializeSanitizerCoverageModulePass(PassRegistry&); void initializeDataFlowSanitizerPass(PassRegistry&); void initializeScalarizerPass(PassRegistry&); void initializeEarlyCSEPass(PassRegistry&); diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h index c6a339b..87422df 100644 --- a/llvm/include/llvm/Transforms/Instrumentation.h +++ b/llvm/include/llvm/Transforms/Instrumentation.h @@ -78,6 +78,9 @@ ModulePass *createDataFlowSanitizerPass(StringRef ABIListFile = StringRef(), void *(*getArgTLS)() = nullptr, void *(*getRetValTLS)() = nullptr); +// Insert SanitizerCoverage instrumentation. +ModulePass *createSanitizerCoverageModulePass(int CoverageLevel); + #if defined(__GNUC__) && defined(__linux__) && !defined(ANDROID) inline ModulePass *createDataFlowSanitizerPassForJIT(StringRef ABIListFile = StringRef()) { diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 3e62165..c3bc1e8 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -81,9 +81,6 @@ static const char *const kAsanUnregisterGlobalsName = static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init"; static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; static const char *const kAsanInitName = "__asan_init_v4"; -static const char *const kAsanCovModuleInitName = "__sanitizer_cov_module_init"; -static const char *const kAsanCovName = "__sanitizer_cov"; -static const char *const kAsanCovIndirCallName = "__sanitizer_cov_indir_call16"; static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp"; static const char *const kAsanPtrSub = "__sanitizer_ptr_sub"; static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return"; @@ -135,15 +132,6 @@ static cl::opt ClUseAfterReturn("asan-use-after-return", // This flag may need to be replaced with -f[no]asan-globals. static cl::opt ClGlobals("asan-globals", cl::desc("Handle global objects"), cl::Hidden, cl::init(true)); -static cl::opt ClCoverage("asan-coverage", - cl::desc("ASan coverage. 0: none, 1: entry block, 2: all blocks, " - "3: all blocks and critical edges, " - "4: above plus indirect calls"), - cl::Hidden, cl::init(false)); -static cl::opt ClCoverageBlockThreshold("asan-coverage-block-threshold", - cl::desc("Add coverage instrumentation only to the entry block if there " - "are more than this number of blocks."), - cl::Hidden, cl::init(1500)); static cl::opt ClInitializers("asan-initialization-order", cl::desc("Handle C++ initializer order"), cl::Hidden, cl::init(true)); static cl::opt ClInvalidPointerPairs("asan-detect-invalid-pointer-pair", @@ -356,9 +344,7 @@ static size_t RedzoneSizeForScale(int MappingScale) { /// AddressSanitizer: instrument the code in module to find memory bugs. struct AddressSanitizer : public FunctionPass { - AddressSanitizer() : FunctionPass(ID) { - initializeBreakCriticalEdgesPass(*PassRegistry::getPassRegistry()); - } + AddressSanitizer() : FunctionPass(ID) {} const char *getPassName() const override { return "AddressSanitizerFunctionPass"; } @@ -379,21 +365,11 @@ struct AddressSanitizer : public FunctionPass { bool doInitialization(Module &M) override; static char ID; // Pass identification, replacement for typeid - void getAnalysisUsage(AnalysisUsage &AU) const override { - if (ClCoverage >= 3) - AU.addRequiredID(BreakCriticalEdgesID); - } - private: void initializeCallbacks(Module &M); bool LooksLikeCodeInBug11395(Instruction *I); bool GlobalIsLinkerInitialized(GlobalVariable *G); - void InjectCoverageForIndirectCalls(Function &F, - ArrayRef IndirCalls); - bool InjectCoverage(Function &F, ArrayRef AllBlocks, - ArrayRef IndirCalls); - void InjectCoverageAtBlock(Function &F, BasicBlock &BB); LLVMContext *C; const DataLayout *DL; @@ -403,8 +379,6 @@ struct AddressSanitizer : public FunctionPass { Function *AsanCtorFunction; Function *AsanInitFunction; Function *AsanHandleNoReturnFunc; - Function *AsanCovFunction; - Function *AsanCovIndirCallFunction; Function *AsanPtrCmpFunction, *AsanPtrSubFunction; // This array is indexed by AccessIsWrite and log2(AccessSize). Function *AsanErrorCallback[2][kNumberOfAccessSizes]; @@ -448,7 +422,6 @@ class AddressSanitizerModule : public ModulePass { Function *AsanUnpoisonGlobals; Function *AsanRegisterGlobals; Function *AsanUnregisterGlobals; - Function *AsanCovModuleInit; }; // Stack poisoning does not play well with exception handling. @@ -1037,10 +1010,6 @@ void AddressSanitizerModule::initializeCallbacks(Module &M) { kAsanUnregisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL)); AsanUnregisterGlobals->setLinkage(Function::ExternalLinkage); - AsanCovModuleInit = checkInterfaceFunction(M.getOrInsertFunction( - kAsanCovModuleInitName, - IRB.getVoidTy(), IntptrTy, NULL)); - AsanCovModuleInit->setLinkage(Function::ExternalLinkage); } // This function replaces all global variables with new variables that have @@ -1198,13 +1167,6 @@ bool AddressSanitizerModule::runOnModule(Module &M) { assert(CtorFunc); IRBuilder<> IRB(CtorFunc->getEntryBlock().getTerminator()); - if (ClCoverage > 0) { - Function *CovFunc = M.getFunction(kAsanCovName); - int nCov = CovFunc ? CovFunc->getNumUses() : 0; - IRB.CreateCall(AsanCovModuleInit, ConstantInt::get(IntptrTy, nCov)); - Changed = true; - } - if (ClGlobals) Changed |= InstrumentGlobals(IRB, M); @@ -1254,10 +1216,6 @@ void AddressSanitizer::initializeCallbacks(Module &M) { AsanHandleNoReturnFunc = checkInterfaceFunction( M.getOrInsertFunction(kAsanHandleNoReturnName, IRB.getVoidTy(), NULL)); - AsanCovFunction = checkInterfaceFunction(M.getOrInsertFunction( - kAsanCovName, IRB.getVoidTy(), NULL)); - AsanCovIndirCallFunction = checkInterfaceFunction(M.getOrInsertFunction( - kAsanCovIndirCallName, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL)); AsanPtrCmpFunction = checkInterfaceFunction(M.getOrInsertFunction( kAsanPtrCmp, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL)); @@ -1316,105 +1274,6 @@ bool AddressSanitizer::maybeInsertAsanInitAtFunctionEntry(Function &F) { return false; } -void AddressSanitizer::InjectCoverageAtBlock(Function &F, BasicBlock &BB) { - BasicBlock::iterator IP = BB.getFirstInsertionPt(), BE = BB.end(); - // Skip static allocas at the top of the entry block so they don't become - // dynamic when we split the block. If we used our optimized stack layout, - // then there will only be one alloca and it will come first. - for (; IP != BE; ++IP) { - AllocaInst *AI = dyn_cast(IP); - if (!AI || !AI->isStaticAlloca()) - break; - } - - DebugLoc EntryLoc = &BB == &F.getEntryBlock() - ? IP->getDebugLoc().getFnDebugLoc(*C) - : IP->getDebugLoc(); - IRBuilder<> IRB(IP); - IRB.SetCurrentDebugLocation(EntryLoc); - Type *Int8Ty = IRB.getInt8Ty(); - GlobalVariable *Guard = new GlobalVariable( - *F.getParent(), Int8Ty, false, GlobalValue::PrivateLinkage, - Constant::getNullValue(Int8Ty), "__asan_gen_cov_" + F.getName()); - LoadInst *Load = IRB.CreateLoad(Guard); - Load->setAtomic(Monotonic); - Load->setAlignment(1); - Value *Cmp = IRB.CreateICmpEQ(Constant::getNullValue(Int8Ty), Load); - Instruction *Ins = SplitBlockAndInsertIfThen( - Cmp, IP, false, MDBuilder(*C).createBranchWeights(1, 100000)); - IRB.SetInsertPoint(Ins); - IRB.SetCurrentDebugLocation(EntryLoc); - // __sanitizer_cov gets the PC of the instruction using GET_CALLER_PC. - IRB.CreateCall(AsanCovFunction); - StoreInst *Store = IRB.CreateStore(ConstantInt::get(Int8Ty, 1), Guard); - Store->setAtomic(Monotonic); - Store->setAlignment(1); -} - -// Poor man's coverage that works with ASan. -// We create a Guard boolean variable with the same linkage -// as the function and inject this code into the entry block (-asan-coverage=1) -// or all blocks (-asan-coverage=2): -// if (*Guard) { -// __sanitizer_cov(); -// *Guard = 1; -// } -// The accesses to Guard are atomic. The rest of the logic is -// in __sanitizer_cov (it's fine to call it more than once). -// -// This coverage implementation provides very limited data: -// it only tells if a given function (block) was ever executed. -// No counters, no per-edge data. -// But for many use cases this is what we need and the added slowdown -// is negligible. This simple implementation will probably be obsoleted -// by the upcoming Clang-based coverage implementation. -// By having it here and now we hope to -// a) get the functionality to users earlier and -// b) collect usage statistics to help improve Clang coverage design. -bool AddressSanitizer::InjectCoverage(Function &F, - ArrayRef AllBlocks, - ArrayRef IndirCalls) { - if (!ClCoverage) return false; - - if (ClCoverage == 1 || - (unsigned)ClCoverageBlockThreshold < AllBlocks.size()) { - InjectCoverageAtBlock(F, F.getEntryBlock()); - } else { - for (auto BB : AllBlocks) - InjectCoverageAtBlock(F, *BB); - } - InjectCoverageForIndirectCalls(F, IndirCalls); - return true; -} - -// On every indirect call we call a run-time function -// __sanitizer_cov_indir_call* with two parameters: -// - callee address, -// - global cache array that contains kCacheSize pointers (zero-initialed). -// The cache is used to speed up recording the caller-callee pairs. -// The address of the caller is passed implicitly via caller PC. -// kCacheSize is encoded in the name of the run-time function. -void AddressSanitizer::InjectCoverageForIndirectCalls( - Function &F, ArrayRef IndirCalls) { - if (ClCoverage < 4 || IndirCalls.empty()) return; - const int kCacheSize = 16; - const int kCacheAlignment = 64; // Align for better performance. - Type *Ty = ArrayType::get(IntptrTy, kCacheSize); - for (auto I : IndirCalls) { - IRBuilder<> IRB(I); - CallSite CS(I); - Value *Callee = CS.getCalledValue(); - if (dyn_cast(Callee)) continue; - GlobalVariable *CalleeCache = new GlobalVariable( - *F.getParent(), Ty, false, GlobalValue::PrivateLinkage, - Constant::getNullValue(Ty), "__asan_gen_callee_cache"); - CalleeCache->setAlignment(kCacheAlignment); - IRB.CreateCall2(AsanCovIndirCallFunction, - IRB.CreatePointerCast(Callee, IntptrTy), - IRB.CreatePointerCast(CalleeCache, IntptrTy)); - } -} - bool AddressSanitizer::runOnFunction(Function &F) { if (&F == AsanCtorFunction) return false; if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return false; @@ -1437,7 +1296,6 @@ bool AddressSanitizer::runOnFunction(Function &F) { SmallVector NoReturnCalls; SmallVector AllBlocks; SmallVector PointerComparisonsOrSubtracts; - SmallVector IndirCalls; int NumAllocas = 0; bool IsWrite; unsigned Alignment; @@ -1470,8 +1328,6 @@ bool AddressSanitizer::runOnFunction(Function &F) { TempsToInstrument.clear(); if (CS.doesNotReturn()) NoReturnCalls.push_back(CS.getInstruction()); - if (ClCoverage >= 4 && !CS.getCalledFunction()) - IndirCalls.push_back(&Inst); } continue; } @@ -1528,9 +1384,6 @@ bool AddressSanitizer::runOnFunction(Function &F) { bool res = NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty(); - if (InjectCoverage(F, AllBlocks, IndirCalls)) - res = true; - DEBUG(dbgs() << "ASAN done instrumenting: " << res << " " << F << "\n"); if (ClKeepUninstrumented) { diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt index 3563593..139e514 100644 --- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_library(LLVMInstrumentation GCOVProfiling.cpp MemorySanitizer.cpp Instrumentation.cpp + SanitizerCoverage.cpp ThreadSanitizer.cpp ) diff --git a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp index ac1dd43..8e95367 100644 --- a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -27,6 +27,7 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) { initializeGCOVProfilerPass(Registry); initializeMemorySanitizerPass(Registry); initializeThreadSanitizerPass(Registry); + initializeSanitizerCoverageModulePass(Registry); initializeDataFlowSanitizerPass(Registry); } diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp new file mode 100644 index 0000000..2f33ee8 --- /dev/null +++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -0,0 +1,260 @@ +//===-- SanitizerCoverage.cpp - coverage instrumentation for sanitizers ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Coverage instrumentation that works with AddressSanitizer +// and potentially with other Sanitizers. +// +// We create a Guard boolean variable with the same linkage +// as the function and inject this code into the entry block (CoverageLevel=1) +// or all blocks (CoverageLevel>=2): +// if (*Guard) { +// __sanitizer_cov(); +// *Guard = 1; +// } +// The accesses to Guard are atomic. The rest of the logic is +// in __sanitizer_cov (it's fine to call it more than once). +// +// With CoverageLevel>=3 we also split critical edges this effectively +// instrumenting all edges. +// +// CoverageLevel>=4 add indirect call profiling implented as a function call. +// +// This coverage implementation provides very limited data: +// it only tells if a given function (block) was ever executed. No counters. +// But for many use cases this is what we need and the added slowdown small. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; + +#define DEBUG_TYPE "sancov" + +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 kSanCovModuleCtorName = "sancov.module_ctor"; +static const uint64_t kSanCtorAndDtorPriority = 1; + +static cl::opt ClCoverageLevel("sanitizer-coverage-level", + cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, " + "3: all blocks and critical edges, " + "4: above plus indirect calls"), + cl::Hidden, cl::init(0)); + +static cl::opt ClCoverageBlockThreshold( + "sanitizer-coverage-block-threshold", + cl::desc("Add coverage instrumentation only to the entry block if there " + "are more than this number of blocks."), + cl::Hidden, cl::init(1500)); + +namespace { + +class SanitizerCoverageModule : public ModulePass { + public: + SanitizerCoverageModule(int CoverageLevel = 0) + : ModulePass(ID), + CoverageLevel(std::max(CoverageLevel, (int)ClCoverageLevel)) { + initializeBreakCriticalEdgesPass(*PassRegistry::getPassRegistry()); + } + bool runOnModule(Module &M) override; + bool runOnFunction(Function &F); + static char ID; // Pass identification, replacement for typeid + const char *getPassName() const override { + return "SanitizerCoverageModule"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + if (CoverageLevel >= 3) + AU.addRequiredID(BreakCriticalEdgesID); + AU.addRequired(); + } + + private: + void InjectCoverageForIndirectCalls(Function &F, + ArrayRef IndirCalls); + bool InjectCoverage(Function &F, ArrayRef AllBlocks, + ArrayRef IndirCalls); + void InjectCoverageAtBlock(Function &F, BasicBlock &BB); + Function *SanCovFunction; + Function *SanCovIndirCallFunction; + Function *SanCovModuleInit; + Type *IntptrTy; + LLVMContext *C; + + int CoverageLevel; +}; + +} // namespace + +static Function *checkInterfaceFunction(Constant *FuncOrBitcast) { + if (Function *F = dyn_cast(FuncOrBitcast)) + return F; + std::string Err; + raw_string_ostream Stream(Err); + Stream << "SanitizerCoverage interface function redefined: " + << *FuncOrBitcast; + report_fatal_error(Err); +} + +bool SanitizerCoverageModule::runOnModule(Module &M) { + if (!CoverageLevel) return false; + C = &(M.getContext()); + DataLayoutPass *DLP = &getAnalysis(); + IntptrTy = Type::getIntNTy(*C, DLP->getDataLayout().getPointerSizeInBits()); + Type *VoidTy = Type::getVoidTy(*C); + + Function *CtorFunc = + Function::Create(FunctionType::get(VoidTy, false), + GlobalValue::InternalLinkage, kSanCovModuleCtorName, &M); + ReturnInst::Create(*C, BasicBlock::Create(*C, "", CtorFunc)); + appendToGlobalCtors(M, CtorFunc, kSanCtorAndDtorPriority); + + SanCovFunction = + checkInterfaceFunction(M.getOrInsertFunction(kSanCovName, VoidTy, NULL)); + SanCovIndirCallFunction = checkInterfaceFunction(M.getOrInsertFunction( + kSanCovIndirCallName, VoidTy, IntptrTy, IntptrTy, NULL)); + SanCovModuleInit = checkInterfaceFunction(M.getOrInsertFunction( + kSanCovModuleInitName, Type::getVoidTy(*C), IntptrTy, NULL)); + SanCovModuleInit->setLinkage(Function::ExternalLinkage); + + for (auto &F : M) + runOnFunction(F); + + IRBuilder<> IRB(CtorFunc->getEntryBlock().getTerminator()); + IRB.CreateCall(SanCovModuleInit, + ConstantInt::get(IntptrTy, SanCovFunction->getNumUses())); + return true; +} + +bool SanitizerCoverageModule::runOnFunction(Function &F) { + if (F.empty()) return false; + // For now instrument only functions that will also be asan-instrumented. + if (!F.hasFnAttribute(Attribute::SanitizeAddress)) + return false; + SmallVector IndirCalls; + SmallVector AllBlocks; + for (auto &BB : F) { + AllBlocks.push_back(&BB); + if (CoverageLevel >= 4) + for (auto &Inst : BB) { + CallSite CS(&Inst); + if (CS && !CS.getCalledFunction()) + IndirCalls.push_back(&Inst); + } + } + InjectCoverage(F, AllBlocks, IndirCalls); + return true; +} + +bool +SanitizerCoverageModule::InjectCoverage(Function &F, + ArrayRef AllBlocks, + ArrayRef IndirCalls) { + if (!CoverageLevel) return false; + + if (CoverageLevel == 1 || + (unsigned)ClCoverageBlockThreshold < AllBlocks.size()) { + InjectCoverageAtBlock(F, F.getEntryBlock()); + } else { + for (auto BB : AllBlocks) + InjectCoverageAtBlock(F, *BB); + } + InjectCoverageForIndirectCalls(F, IndirCalls); + return true; +} + +// On every indirect call we call a run-time function +// __sanitizer_cov_indir_call* with two parameters: +// - callee address, +// - global cache array that contains kCacheSize pointers (zero-initialized). +// The cache is used to speed up recording the caller-callee pairs. +// The address of the caller is passed implicitly via caller PC. +// kCacheSize is encoded in the name of the run-time function. +void SanitizerCoverageModule::InjectCoverageForIndirectCalls( + Function &F, ArrayRef IndirCalls) { + if (IndirCalls.empty()) return; + const int kCacheSize = 16; + const int kCacheAlignment = 64; // Align for better performance. + Type *Ty = ArrayType::get(IntptrTy, kCacheSize); + for (auto I : IndirCalls) { + IRBuilder<> IRB(I); + CallSite CS(I); + Value *Callee = CS.getCalledValue(); + if (dyn_cast(Callee)) continue; + GlobalVariable *CalleeCache = new GlobalVariable( + *F.getParent(), Ty, false, GlobalValue::PrivateLinkage, + Constant::getNullValue(Ty), "__sancov_gen_callee_cache"); + CalleeCache->setAlignment(kCacheAlignment); + IRB.CreateCall2(SanCovIndirCallFunction, + IRB.CreatePointerCast(Callee, IntptrTy), + IRB.CreatePointerCast(CalleeCache, IntptrTy)); + } +} + +void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, + BasicBlock &BB) { + BasicBlock::iterator IP = BB.getFirstInsertionPt(), BE = BB.end(); + // Skip static allocas at the top of the entry block so they don't become + // dynamic when we split the block. If we used our optimized stack layout, + // then there will only be one alloca and it will come first. + for (; IP != BE; ++IP) { + AllocaInst *AI = dyn_cast(IP); + if (!AI || !AI->isStaticAlloca()) + break; + } + + DebugLoc EntryLoc = &BB == &F.getEntryBlock() + ? IP->getDebugLoc().getFnDebugLoc(*C) + : IP->getDebugLoc(); + IRBuilder<> IRB(IP); + IRB.SetCurrentDebugLocation(EntryLoc); + Type *Int8Ty = IRB.getInt8Ty(); + GlobalVariable *Guard = new GlobalVariable( + *F.getParent(), Int8Ty, false, GlobalValue::PrivateLinkage, + Constant::getNullValue(Int8Ty), "__sancov_gen_cov_" + F.getName()); + LoadInst *Load = IRB.CreateLoad(Guard); + Load->setAtomic(Monotonic); + Load->setAlignment(1); + Value *Cmp = IRB.CreateICmpEQ(Constant::getNullValue(Int8Ty), Load); + Instruction *Ins = SplitBlockAndInsertIfThen( + Cmp, IP, false, MDBuilder(*C).createBranchWeights(1, 100000)); + IRB.SetInsertPoint(Ins); + IRB.SetCurrentDebugLocation(EntryLoc); + // __sanitizer_cov gets the PC of the instruction using GET_CALLER_PC. + IRB.CreateCall(SanCovFunction); + StoreInst *Store = IRB.CreateStore(ConstantInt::get(Int8Ty, 1), Guard); + Store->setAtomic(Monotonic); + Store->setAlignment(1); +} + +char SanitizerCoverageModule::ID = 0; +INITIALIZE_PASS(SanitizerCoverageModule, "sancov", + "SanitizerCoverage: TODO." + "ModulePass", false, false) +ModulePass *llvm::createSanitizerCoverageModulePass(int CoverageLevel) { + return new SanitizerCoverageModule(CoverageLevel); +} diff --git a/llvm/test/Instrumentation/AddressSanitizer/coverage-dbg.ll b/llvm/test/Instrumentation/SanitizerCoverage/coverage-dbg.ll similarity index 98% rename from llvm/test/Instrumentation/AddressSanitizer/coverage-dbg.ll rename to llvm/test/Instrumentation/SanitizerCoverage/coverage-dbg.ll index ef40a77..eea93b8 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/coverage-dbg.ll +++ b/llvm/test/Instrumentation/SanitizerCoverage/coverage-dbg.ll @@ -1,6 +1,6 @@ ; Test that coverage instrumentation does not lose debug location. -; RUN: opt < %s -asan -asan-module -asan-coverage=1 -S | FileCheck %s +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -S | FileCheck %s ; C++ source: ; 1: struct A { diff --git a/llvm/test/Instrumentation/AddressSanitizer/coverage.ll b/llvm/test/Instrumentation/SanitizerCoverage/coverage.ll similarity index 60% rename from llvm/test/Instrumentation/AddressSanitizer/coverage.ll rename to llvm/test/Instrumentation/SanitizerCoverage/coverage.ll index d3de7d2..a3b1131 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/coverage.ll +++ b/llvm/test/Instrumentation/SanitizerCoverage/coverage.ll @@ -1,21 +1,18 @@ -; RUN: opt < %s -asan -asan-module -asan-coverage=0 -S | FileCheck %s --check-prefix=CHECK0 -; RUN: opt < %s -asan -asan-module -asan-coverage=1 -S | FileCheck %s --check-prefix=CHECK1 -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -S | FileCheck %s --check-prefix=CHECK2 -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -asan-coverage-block-threshold=10 -S | FileCheck %s --check-prefix=CHECK2 -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -asan-coverage-block-threshold=1 -S | FileCheck %s --check-prefix=CHECK1 -; RUN: opt < %s -asan -asan-module -asan-coverage=3 -asan-coverage-block-threshold=10 -S | FileCheck %s --check-prefix=CHECK3 -; RUN: opt < %s -asan -asan-module -asan-coverage=4 -S | FileCheck %s --check-prefix=CHECK4 +; RUN: opt < %s -sancov -sanitizer-coverage-level=0 -S | FileCheck %s --check-prefix=CHECK0 +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -S | FileCheck %s --check-prefix=CHECK1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -S | FileCheck %s --check-prefix=CHECK2 +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-block-threshold=10 -S | FileCheck %s --check-prefix=CHECK2 +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-block-threshold=1 -S | FileCheck %s --check-prefix=CHECK1 +; 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 -asan -asan-module -asan-coverage=0 -asan-globals=0 -S | \ -; RUN: FileCheck %s --check-prefix=CHECK0 -; RUN: opt < %s -asan -asan-module -asan-coverage=1 -asan-globals=0 -S | \ -; RUN: FileCheck %s --check-prefix=CHECK1 -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -asan-globals=0 -S | \ -; RUN: FileCheck %s --check-prefix=CHECK2 -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -asan-coverage-block-threshold=10 \ -; RUN: -asan-globals=0 -S | FileCheck %s --check-prefix=CHECK2 -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -asan-coverage-block-threshold=1 \ -; RUN: -asan-globals=0 -S | FileCheck %s --check-prefix=CHECK1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=0 -S | FileCheck %s --check-prefix=CHECK0 +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -S | FileCheck %s --check-prefix=CHECK1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -S | FileCheck %s --check-prefix=CHECK2 +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-block-threshold=10 \ +; RUN: -S | FileCheck %s --check-prefix=CHECK2 +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-block-threshold=1 \ +; RUN: -S | FileCheck %s --check-prefix=CHECK1 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" @@ -36,14 +33,14 @@ entry: ; CHECK0-NOT: call void @__sanitizer_cov_module_init( ; CHECK1-LABEL: define void @foo -; CHECK1: %0 = load atomic i8* @__asan_gen_cov_foo monotonic, align 1 +; CHECK1: %0 = load atomic i8* @__sancov_gen_cov_foo monotonic, align 1 ; CHECK1: %1 = icmp eq i8 0, %0 ; CHECK1: br i1 %1, label %2, label %3 ; CHECK1: call void @__sanitizer_cov ; CHECK1-NOT: call void @__sanitizer_cov -; CHECK1: store atomic i8 1, i8* @__asan_gen_cov_foo monotonic, align 1 +; CHECK1: store atomic i8 1, i8* @__sancov_gen_cov_foo monotonic, align 1 -; CHECK1-LABEL: define internal void @asan.module_ctor +; CHECK1-LABEL: define internal void @sancov.module_ctor ; CHECK1-NOT: ret ; CHECK1: call void @__sanitizer_cov_module_init(i64 2) ; CHECK1: ret @@ -56,7 +53,7 @@ entry: ; CHECK2-NOT: call void @__sanitizer_cov ; CHECK2: ret void -; CHECK2-LABEL: define internal void @asan.module_ctor +; CHECK2-LABEL: define internal void @sancov.module_ctor ; CHECK2-NOT: ret ; CHECK2: call void @__sanitizer_cov_module_init(i64 4) ; CHECK2: ret diff --git a/llvm/test/Instrumentation/AddressSanitizer/coverage2-dbg.ll b/llvm/test/Instrumentation/SanitizerCoverage/coverage2-dbg.ll similarity index 98% rename from llvm/test/Instrumentation/AddressSanitizer/coverage2-dbg.ll rename to llvm/test/Instrumentation/SanitizerCoverage/coverage2-dbg.ll index 2b0f7ef..9b26329 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/coverage2-dbg.ll +++ b/llvm/test/Instrumentation/SanitizerCoverage/coverage2-dbg.ll @@ -1,6 +1,6 @@ ; Test that coverage instrumentation does not lose debug location. -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -S | FileCheck %s +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -S | FileCheck %s ; C++ source: ; 1: void foo(int *a) { -- 2.7.4