Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -126,6 +126,7 @@ void initializeAddressSanitizerModulePass(PassRegistry&); void initializeMemorySanitizerPass(PassRegistry&); void initializeThreadSanitizerPass(PassRegistry&); +void initializeSanitizerCoverageModulePass(PassRegistry&); void initializeDataFlowSanitizerPass(PassRegistry&); void initializeScalarizerPass(PassRegistry&); void initializeEarlyCSEPass(PassRegistry&); Index: include/llvm/Transforms/Instrumentation.h =================================================================== --- include/llvm/Transforms/Instrumentation.h +++ include/llvm/Transforms/Instrumentation.h @@ -78,6 +78,9 @@ 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()) { Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -81,9 +81,6 @@ 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 @@ // 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", @@ -358,9 +346,7 @@ /// 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"; } @@ -381,21 +367,11 @@ 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; @@ -405,8 +381,6 @@ 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]; @@ -450,7 +424,6 @@ Function *AsanUnpoisonGlobals; Function *AsanRegisterGlobals; Function *AsanUnregisterGlobals; - Function *AsanCovModuleInit; }; // Stack poisoning does not play well with exception handling. @@ -1039,10 +1012,6 @@ 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 @@ -1200,13 +1169,6 @@ 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); @@ -1256,10 +1218,6 @@ 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)); @@ -1318,105 +1276,6 @@ 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; @@ -1439,7 +1298,6 @@ SmallVector NoReturnCalls; SmallVector AllBlocks; SmallVector PointerComparisonsOrSubtracts; - SmallVector IndirCalls; int NumAllocas = 0; bool IsWrite; unsigned Alignment; @@ -1472,8 +1330,6 @@ TempsToInstrument.clear(); if (CS.doesNotReturn()) NoReturnCalls.push_back(CS.getInstruction()); - if (ClCoverage >= 4 && !CS.getCalledFunction()) - IndirCalls.push_back(&Inst); } continue; } @@ -1530,9 +1386,6 @@ bool res = NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty(); - if (InjectCoverage(F, AllBlocks, IndirCalls)) - res = true; - DEBUG(dbgs() << "ASAN done instrumenting: " << res << " " << F << "\n"); if (ClKeepUninstrumented) { Index: lib/Transforms/Instrumentation/CMakeLists.txt =================================================================== --- lib/Transforms/Instrumentation/CMakeLists.txt +++ lib/Transforms/Instrumentation/CMakeLists.txt @@ -6,6 +6,7 @@ GCOVProfiling.cpp MemorySanitizer.cpp Instrumentation.cpp + SanitizerCoverage.cpp ThreadSanitizer.cpp ) Index: lib/Transforms/Instrumentation/Instrumentation.cpp =================================================================== --- lib/Transforms/Instrumentation/Instrumentation.cpp +++ lib/Transforms/Instrumentation/Instrumentation.cpp @@ -27,6 +27,7 @@ initializeGCOVProfilerPass(Registry); initializeMemorySanitizerPass(Registry); initializeThreadSanitizerPass(Registry); + initializeSanitizerCoverageModulePass(Registry); initializeDataFlowSanitizerPass(Registry); } Index: lib/Transforms/Instrumentation/SanitizerCoverage.cpp =================================================================== --- /dev/null +++ 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); +} Index: test/Instrumentation/AddressSanitizer/coverage-dbg.ll =================================================================== --- test/Instrumentation/AddressSanitizer/coverage-dbg.ll +++ test/Instrumentation/AddressSanitizer/coverage-dbg.ll @@ -1,67 +0,0 @@ -; Test that coverage instrumentation does not lose debug location. - -; RUN: opt < %s -asan -asan-module -asan-coverage=1 -S | FileCheck %s - -; C++ source: -; 1: struct A { -; 2: int f(); -; 3: int x; -; 4: }; -; 5: -; 6: int A::f() { -; 7: return x; -; 8: } -; clang++ ../1.cc -O3 -g -S -emit-llvm -fno-strict-aliasing -; and add sanitize_address to @_ZN1A1fEv - -; Test that __sanitizer_cov call has !dbg pointing to the opening { of A::f(). -; CHECK: call void @__sanitizer_cov(), !dbg [[A:!.*]] -; CHECK: [[A]] = metadata !{i32 6, i32 0, metadata !{{.*}}, null} - - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -%struct.A = type { i32 } - -; Function Attrs: nounwind readonly uwtable -define i32 @_ZN1A1fEv(%struct.A* nocapture readonly %this) #0 align 2 { -entry: - tail call void @llvm.dbg.value(metadata !{%struct.A* %this}, i64 0, metadata !15, metadata !{metadata !"0x102"}), !dbg !20 - %x = getelementptr inbounds %struct.A* %this, i64 0, i32 0, !dbg !21 - %0 = load i32* %x, align 4, !dbg !21 - ret i32 %0, !dbg !21 -} - -; Function Attrs: nounwind readnone -declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1 - -attributes #0 = { sanitize_address nounwind readonly uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { nounwind readnone } - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!17, !18} -!llvm.ident = !{!19} - -!0 = metadata !{metadata !"0x11\004\00clang version 3.5.0 (210251)\001\00\000\00\001", metadata !1, metadata !2, metadata !3, metadata !12, metadata !2, metadata !2} ; [ DW_TAG_compile_unit ] [/code/llvm/build0/../1.cc] [DW_LANG_C_plus_plus] -!1 = metadata !{metadata !"../1.cc", metadata !"/code/llvm/build0"} -!2 = metadata !{} -!3 = metadata !{metadata !4} -!4 = metadata !{metadata !"0x13\00A\001\0032\0032\000\000\000", metadata !1, null, null, metadata !5, null, null, metadata !"_ZTS1A"} ; [ DW_TAG_structure_type ] [A] [line 1, size 32, align 32, offset 0] [def] [from ] -!5 = metadata !{metadata !6, metadata !8} -!6 = metadata !{metadata !"0xd\00x\003\0032\0032\000\000", metadata !1, metadata !"_ZTS1A", metadata !7} ; [ DW_TAG_member ] [x] [line 3, size 32, align 32, offset 0] [from int] -!7 = metadata !{metadata !"0x24\00int\000\0032\0032\000\000\005", null, null} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] -!8 = metadata !{metadata !"0x2e\00f\00f\00_ZN1A1fEv\002\000\000\000\006\00256\001\002", metadata !1, metadata !"_ZTS1A", metadata !9, null, null, null, i32 0, null} ; [ DW_TAG_subprogram ] [line 2] [f] -!9 = metadata !{metadata !"0x15\00\000\000\000\000\000\000", i32 0, null, null, metadata !10, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] -!10 = metadata !{metadata !7, metadata !11} -!11 = metadata !{metadata !"0xf\00\000\0064\0064\000\001088", null, null, metadata !"_ZTS1A"} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS1A] -!12 = metadata !{metadata !13} -!13 = metadata !{metadata !"0x2e\00f\00f\00_ZN1A1fEv\006\000\001\000\006\00256\001\006", metadata !1, metadata !"_ZTS1A", metadata !9, null, i32 (%struct.A*)* @_ZN1A1fEv, null, metadata !8, metadata !14} ; [ DW_TAG_subprogram ] [line 6] [def] [f] -!14 = metadata !{metadata !15} -!15 = metadata !{metadata !"0x101\00this\0016777216\001088", metadata !13, null, metadata !16} ; [ DW_TAG_arg_variable ] [this] [line 0] -!16 = metadata !{metadata !"0xf\00\000\0064\0064\000\000", null, null, metadata !"_ZTS1A"} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from _ZTS1A] -!17 = metadata !{i32 2, metadata !"Dwarf Version", i32 4} -!18 = metadata !{i32 2, metadata !"Debug Info Version", i32 2} -!19 = metadata !{metadata !"clang version 3.5.0 (210251)"} -!20 = metadata !{i32 0, i32 0, metadata !13, null} -!21 = metadata !{i32 7, i32 0, metadata !13, null} Index: test/Instrumentation/AddressSanitizer/coverage.ll =================================================================== --- test/Instrumentation/AddressSanitizer/coverage.ll +++ test/Instrumentation/AddressSanitizer/coverage.ll @@ -1,91 +0,0 @@ -; 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 -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 - -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 -} - -; CHECK0-NOT: call void @__sanitizer_cov( -; 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: %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-LABEL: define internal void @asan.module_ctor -; CHECK1-NOT: ret -; CHECK1: call void @__sanitizer_cov_module_init(i64 2) -; CHECK1: ret - - -; CHECK2-LABEL: define void @foo -; CHECK2: call void @__sanitizer_cov -; CHECK2: call void @__sanitizer_cov -; CHECK2: call void @__sanitizer_cov -; CHECK2-NOT: call void @__sanitizer_cov -; CHECK2: ret void - -; CHECK2-LABEL: define internal void @asan.module_ctor -; CHECK2-NOT: ret -; CHECK2: call void @__sanitizer_cov_module_init(i64 4) -; CHECK2: ret - -; CHECK3-LABEL: define void @foo -; CHECK3: call void @__sanitizer_cov -; CHECK3: call void @__sanitizer_cov -; CHECK3: call void @__sanitizer_cov -; CHECK3: call void @__sanitizer_cov -; CHECK3-NOT: call void @__sanitizer_cov -; CHECK3: ret void - - -%struct.StructWithVptr = type { i32 (...)** } - -define void @CallViaVptr(%struct.StructWithVptr* %foo) uwtable sanitize_address { -entry: - %0 = bitcast %struct.StructWithVptr* %foo to void (%struct.StructWithVptr*)*** - %vtable = load void (%struct.StructWithVptr*)*** %0, align 8 - %1 = load void (%struct.StructWithVptr*)** %vtable, align 8 - tail call void %1(%struct.StructWithVptr* %foo) - tail call void %1(%struct.StructWithVptr* %foo) - tail call void asm sideeffect "", ""() - ret void -} - -; We expect to see two calls to __sanitizer_cov_indir_call16 -; with different values of second argument. -; CHECK4-LABEL: define void @CallViaVptr -; CHECK4: call void @__sanitizer_cov_indir_call16({{.*}},[[CACHE:.*]]) -; CHECK4-NOT: call void @__sanitizer_cov_indir_call16({{.*}},[[CACHE]]) -; CHECK4: ret void Index: test/Instrumentation/AddressSanitizer/coverage2-dbg.ll =================================================================== --- test/Instrumentation/AddressSanitizer/coverage2-dbg.ll +++ test/Instrumentation/AddressSanitizer/coverage2-dbg.ll @@ -1,75 +0,0 @@ -; Test that coverage instrumentation does not lose debug location. - -; RUN: opt < %s -asan -asan-module -asan-coverage=2 -S | FileCheck %s - -; C++ source: -; 1: void foo(int *a) { -; 2: if (a) -; 3: *a = 0; -; 4: } -; clang++ if.cc -O3 -g -S -emit-llvm -; and add sanitize_address to @_Z3fooPi - - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -; Check that __sanitizer_cov call has !dgb pointing to the beginning -; of appropriate basic blocks. -; CHECK-LABEL:_Z3fooPi -; CHECK: call void @__sanitizer_cov(), !dbg [[A:!.*]] -; CHECK: call void @__sanitizer_cov(), !dbg [[B:!.*]] -; CHECK: call void @__sanitizer_cov(), !dbg [[C:!.*]] -; CHECK: ret void -; CHECK: [[A]] = metadata !{i32 1, i32 0, metadata !{{.*}}, null} -; CHECK: [[B]] = metadata !{i32 3, i32 5, metadata !{{.*}}, null} -; CHECK: [[C]] = metadata !{i32 4, i32 1, metadata !{{.*}}, null} - -define void @_Z3fooPi(i32* %a) #0 { -entry: - tail call void @llvm.dbg.value(metadata !{i32* %a}, i64 0, metadata !11, metadata !{metadata !"0x102"}), !dbg !15 - %tobool = icmp eq i32* %a, null, !dbg !16 - br i1 %tobool, label %if.end, label %if.then, !dbg !16 - -if.then: ; preds = %entry - store i32 0, i32* %a, align 4, !dbg !18, !tbaa !19 - br label %if.end, !dbg !18 - -if.end: ; preds = %entry, %if.then - ret void, !dbg !23 -} - -; Function Attrs: nounwind readnone -declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1 - -attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" sanitize_address} -attributes #1 = { nounwind readnone } - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!12, !13} -!llvm.ident = !{!14} - -!0 = metadata !{metadata !"0x11\004\00clang version 3.6.0 (217079)\001\00\000\00\001", metadata !1, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2} ; [ DW_TAG_compile_unit ] [FOO/if.cc] [DW_LANG_C_plus_plus] -!1 = metadata !{metadata !"if.cc", metadata !"FOO"} -!2 = metadata !{} -!3 = metadata !{metadata !4} -!4 = metadata !{metadata !"0x2e\00foo\00foo\00_Z3fooPi\001\000\001\000\006\00256\001\001", metadata !1, metadata !5, metadata !6, null, void (i32*)* @_Z3fooPi, null, null, metadata !10} ; [ DW_TAG_subprogram ] [line 1] [def] [foo] -!5 = metadata !{metadata !"0x29", metadata !1} ; [ DW_TAG_file_type ] [FOO/if.cc] -!6 = metadata !{metadata !"0x15\00\000\000\000\000\000\000", i32 0, null, null, metadata !7, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] -!7 = metadata !{null, metadata !8} -!8 = metadata !{metadata !"0xf\00\000\0064\0064\000\000", null, null, metadata !9} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from int] -!9 = metadata !{metadata !"0x24\00int\000\0032\0032\000\000\005", null, null} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] -!10 = metadata !{metadata !11} -!11 = metadata !{metadata !"0x101\00a\0016777217\000", metadata !4, metadata !5, metadata !8} ; [ DW_TAG_arg_variable ] [a] [line 1] -!12 = metadata !{i32 2, metadata !"Dwarf Version", i32 4} -!13 = metadata !{i32 2, metadata !"Debug Info Version", i32 2} -!14 = metadata !{metadata !"clang version 3.6.0 (217079)"} -!15 = metadata !{i32 1, i32 15, metadata !4, null} -!16 = metadata !{i32 2, i32 7, metadata !17, null} -!17 = metadata !{metadata !"0xb\002\007\000", metadata !1, metadata !4} ; [ DW_TAG_lexical_block ] [FOO/if.cc] -!18 = metadata !{i32 3, i32 5, metadata !17, null} -!19 = metadata !{metadata !20, metadata !20, i64 0} -!20 = metadata !{metadata !"int", metadata !21, i64 0} -!21 = metadata !{metadata !"omnipotent char", metadata !22, i64 0} -!22 = metadata !{metadata !"Simple C/C++ TBAA"} -!23 = metadata !{i32 4, i32 1, metadata !4, null} Index: test/Instrumentation/SanitizerCoverage/coverage-dbg.ll =================================================================== --- test/Instrumentation/SanitizerCoverage/coverage-dbg.ll +++ 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 { Index: test/Instrumentation/SanitizerCoverage/coverage.ll =================================================================== --- test/Instrumentation/SanitizerCoverage/coverage.ll +++ 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 -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 -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 -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 @@ ; 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 @@ ; 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 Index: test/Instrumentation/SanitizerCoverage/coverage2-dbg.ll =================================================================== --- test/Instrumentation/SanitizerCoverage/coverage2-dbg.ll +++ 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) {