X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTransforms%2FInstrumentation%2FAddressSanitizer.cpp;h=3f0db3630b983af2c631efcdd8647bb863a5f133;hp=d0cf40307060ac11f7b4cb0466fdea66f0fdb21e;hb=866ee52df37b5b2229bdae201f8d5ecad41d4326;hpb=0059dd4dd1b567c79c05d781363e28da17088f0a;ds=inline diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index d0cf4030706..3f0db3630b9 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -83,6 +83,7 @@ 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"; @@ -136,7 +137,8 @@ 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"), + "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 " @@ -387,7 +389,10 @@ struct AddressSanitizer : public FunctionPass { bool LooksLikeCodeInBug11395(Instruction *I); bool GlobalIsLinkerInitialized(GlobalVariable *G); - bool InjectCoverage(Function &F, ArrayRef AllBlocks); + void InjectCoverageForIndirectCalls(Function &F, + ArrayRef IndirCalls); + bool InjectCoverage(Function &F, ArrayRef AllBlocks, + ArrayRef IndirCalls); void InjectCoverageAtBlock(Function &F, BasicBlock &BB); LLVMContext *C; @@ -399,6 +404,7 @@ struct AddressSanitizer : public FunctionPass { Function *AsanInitFunction; Function *AsanHandleNoReturnFunc; Function *AsanCovFunction; + Function *AsanCovIndirCallFunction; Function *AsanPtrCmpFunction, *AsanPtrSubFunction; // This array is indexed by AccessIsWrite and log2(AccessSize). Function *AsanErrorCallback[2][kNumberOfAccessSizes]; @@ -1255,6 +1261,9 @@ void AddressSanitizer::initializeCallbacks(Module &M) { 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)); AsanPtrSubFunction = checkInterfaceFunction(M.getOrInsertFunction( @@ -1368,7 +1377,8 @@ void AddressSanitizer::InjectCoverageAtBlock(Function &F, BasicBlock &BB) { // 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 AllBlocks, + ArrayRef IndirCalls) { if (!ClCoverage) return false; if (ClCoverage == 1 || @@ -1378,9 +1388,36 @@ bool AddressSanitizer::InjectCoverage(Function &F, 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); + GlobalVariable *CalleeCache = + new GlobalVariable(*F.getParent(), Ty, false, GlobalValue::PrivateLinkage, + Constant::getNullValue(Ty), "__asan_gen_callee_cache"); + CalleeCache->setAlignment(kCacheAlignment); + for (auto I : IndirCalls) { + IRBuilder<> IRB(I); + CallSite CS(I); + IRB.CreateCall2(AsanCovIndirCallFunction, + IRB.CreatePointerCast(CS.getCalledValue(), IntptrTy), + IRB.CreatePointerCast(CalleeCache, IntptrTy)); + } +} + bool AddressSanitizer::runOnFunction(Function &F) { if (&F == AsanCtorFunction) return false; if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return false; @@ -1403,6 +1440,7 @@ bool AddressSanitizer::runOnFunction(Function &F) { SmallVector NoReturnCalls; SmallVector AllBlocks; SmallVector PointerComparisonsOrSubtracts; + SmallVector IndirCalls; int NumAllocas = 0; bool IsWrite; unsigned Alignment; @@ -1435,6 +1473,8 @@ 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; } @@ -1491,7 +1531,7 @@ bool AddressSanitizer::runOnFunction(Function &F) { bool res = NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty(); - if (InjectCoverage(F, AllBlocks)) + if (InjectCoverage(F, AllBlocks, IndirCalls)) res = true; DEBUG(dbgs() << "ASAN done instrumenting: " << res << " " << F << "\n");