diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
commit | d8e91e46262bc44006913e6796843909f1ac7bcd (patch) | |
tree | 7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Transforms/Instrumentation/HWAddressSanitizer.cpp | |
parent | b7eb8e35e481a74962664b63dfb09483b200209a (diff) |
Notes
Diffstat (limited to 'lib/Transforms/Instrumentation/HWAddressSanitizer.cpp')
-rw-r--r-- | lib/Transforms/Instrumentation/HWAddressSanitizer.cpp | 366 |
1 files changed, 322 insertions, 44 deletions
diff --git a/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp index d62598bb5d4f..d04c2b76288f 100644 --- a/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -44,6 +44,7 @@ #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" +#include <sstream> using namespace llvm; @@ -63,6 +64,8 @@ static const uint64_t kDynamicShadowSentinel = std::numeric_limits<uint64_t>::max(); static const unsigned kPointerTagShift = 56; +static const unsigned kShadowBaseAlignment = 32; + static cl::opt<std::string> ClMemoryAccessCallbackPrefix( "hwasan-memory-access-callback-prefix", cl::desc("Prefix for memory access callbacks"), cl::Hidden, @@ -127,6 +130,32 @@ static cl::opt<unsigned long long> ClMappingOffset( cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"), cl::Hidden, cl::init(0)); +static cl::opt<bool> + ClWithIfunc("hwasan-with-ifunc", + cl::desc("Access dynamic shadow through an ifunc global on " + "platforms that support this"), + cl::Hidden, cl::init(false)); + +static cl::opt<bool> ClWithTls( + "hwasan-with-tls", + cl::desc("Access dynamic shadow through an thread-local pointer on " + "platforms that support this"), + cl::Hidden, cl::init(true)); + +static cl::opt<bool> + ClRecordStackHistory("hwasan-record-stack-history", + cl::desc("Record stack frames with tagged allocations " + "in a thread-local ring buffer"), + cl::Hidden, cl::init(true)); +static cl::opt<bool> + ClCreateFrameDescriptions("hwasan-create-frame-descriptions", + cl::desc("create static frame descriptions"), + cl::Hidden, cl::init(true)); + +static cl::opt<bool> + ClInstrumentMemIntrinsics("hwasan-instrument-mem-intrinsics", + cl::desc("instrument memory intrinsics"), + cl::Hidden, cl::init(true)); namespace { /// An instrumentation pass implementing detection of addressability bugs @@ -150,13 +179,14 @@ public: void initializeCallbacks(Module &M); - void maybeInsertDynamicShadowAtFunctionEntry(Function &F); + Value *getDynamicShadowNonTls(IRBuilder<> &IRB); void untagPointerOperand(Instruction *I, Value *Addr); Value *memToShadow(Value *Shadow, Type *Ty, IRBuilder<> &IRB); void instrumentMemAccessInline(Value *PtrLong, bool IsWrite, unsigned AccessSizeIndex, Instruction *InsertBefore); + void instrumentMemIntrinsic(MemIntrinsic *MI); bool instrumentMemAccess(Instruction *I); Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite, uint64_t *TypeSize, unsigned *Alignment, @@ -167,26 +197,53 @@ public: Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag); Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong); bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas, - SmallVectorImpl<Instruction *> &RetVec); + SmallVectorImpl<Instruction *> &RetVec, Value *StackTag); Value *getNextTagWithCall(IRBuilder<> &IRB); Value *getStackBaseTag(IRBuilder<> &IRB); Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI, unsigned AllocaNo); Value *getUARTag(IRBuilder<> &IRB, Value *StackTag); + Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty); + Value *emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord); + private: LLVMContext *C; + std::string CurModuleUniqueId; Triple TargetTriple; + Function *HWAsanMemmove, *HWAsanMemcpy, *HWAsanMemset; + + // Frame description is a way to pass names/sizes of local variables + // to the run-time w/o adding extra executable code in every function. + // We do this by creating a separate section with {PC,Descr} pairs and passing + // the section beg/end to __hwasan_init_frames() at module init time. + std::string createFrameString(ArrayRef<AllocaInst*> Allocas); + void createFrameGlobal(Function &F, const std::string &FrameString); + // Get the section name for frame descriptions. Currently ELF-only. + const char *getFrameSection() { return "__hwasan_frames"; } + const char *getFrameSectionBeg() { return "__start___hwasan_frames"; } + const char *getFrameSectionEnd() { return "__stop___hwasan_frames"; } + GlobalVariable *createFrameSectionBound(Module &M, Type *Ty, + const char *Name) { + auto GV = new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage, + nullptr, Name); + GV->setVisibility(GlobalValue::HiddenVisibility); + return GV; + } /// This struct defines the shadow mapping using the rule: /// shadow = (mem >> Scale) + Offset. /// If InGlobal is true, then /// extern char __hwasan_shadow[]; /// shadow = (mem >> Scale) + &__hwasan_shadow + /// If InTls is true, then + /// extern char *__hwasan_tls; + /// shadow = (mem>>Scale) + align_up(__hwasan_shadow, kShadowBaseAlignment) struct ShadowMapping { int Scale; uint64_t Offset; bool InGlobal; + bool InTls; void init(Triple &TargetTriple); unsigned getAllocaAlignment() const { return 1U << Scale; } @@ -194,6 +251,7 @@ private: ShadowMapping Mapping; Type *IntptrTy; + Type *Int8PtrTy; Type *Int8Ty; bool CompileKernel; @@ -206,10 +264,12 @@ private: Function *HwasanTagMemoryFunc; Function *HwasanGenerateTagFunc; + Function *HwasanThreadEnterFunc; Constant *ShadowGlobal; Value *LocalDynamicShadow = nullptr; + GlobalValue *ThreadPtrGlobal = nullptr; }; } // end anonymous namespace @@ -243,8 +303,10 @@ bool HWAddressSanitizer::doInitialization(Module &M) { Mapping.init(TargetTriple); C = &(M.getContext()); + CurModuleUniqueId = getUniqueModuleId(&M); IRBuilder<> IRB(*C); IntptrTy = IRB.getIntPtrTy(DL); + Int8PtrTy = IRB.getInt8PtrTy(); Int8Ty = IRB.getInt8Ty(); HwasanCtorFunction = nullptr; @@ -254,8 +316,38 @@ bool HWAddressSanitizer::doInitialization(Module &M) { kHwasanInitName, /*InitArgTypes=*/{}, /*InitArgs=*/{}); - appendToGlobalCtors(M, HwasanCtorFunction, 0); + Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); + HwasanCtorFunction->setComdat(CtorComdat); + appendToGlobalCtors(M, HwasanCtorFunction, 0, HwasanCtorFunction); + + // Create a zero-length global in __hwasan_frame so that the linker will + // always create start and stop symbols. + // + // N.B. If we ever start creating associated metadata in this pass this + // global will need to be associated with the ctor. + Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0); + auto GV = + new GlobalVariable(M, Int8Arr0Ty, /*isConstantGlobal*/ true, + GlobalVariable::PrivateLinkage, + Constant::getNullValue(Int8Arr0Ty), "__hwasan"); + GV->setSection(getFrameSection()); + GV->setComdat(CtorComdat); + appendToCompilerUsed(M, GV); + + IRBuilder<> IRBCtor(HwasanCtorFunction->getEntryBlock().getTerminator()); + IRBCtor.CreateCall( + declareSanitizerInitFunction(M, "__hwasan_init_frames", + {Int8PtrTy, Int8PtrTy}), + {createFrameSectionBound(M, Int8Ty, getFrameSectionBeg()), + createFrameSectionBound(M, Int8Ty, getFrameSectionEnd())}); } + + if (!TargetTriple.isAndroid()) + appendToCompilerUsed( + M, ThreadPtrGlobal = new GlobalVariable( + M, IntptrTy, false, GlobalVariable::ExternalLinkage, nullptr, + "__hwasan_tls", nullptr, GlobalVariable::InitialExecTLSModel)); + return true; } @@ -281,21 +373,35 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) { } HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction( - "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy)); + "__hwasan_tag_memory", IRB.getVoidTy(), Int8PtrTy, Int8Ty, IntptrTy)); HwasanGenerateTagFunc = checkSanitizerInterfaceFunction( M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty)); if (Mapping.InGlobal) ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow", ArrayType::get(IRB.getInt8Ty(), 0)); + + const std::string MemIntrinCallbackPrefix = + CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix; + HWAsanMemmove = checkSanitizerInterfaceFunction(M.getOrInsertFunction( + MemIntrinCallbackPrefix + "memmove", IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy)); + HWAsanMemcpy = checkSanitizerInterfaceFunction(M.getOrInsertFunction( + MemIntrinCallbackPrefix + "memcpy", IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy)); + HWAsanMemset = checkSanitizerInterfaceFunction(M.getOrInsertFunction( + MemIntrinCallbackPrefix + "memset", IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy)); + + HwasanThreadEnterFunc = checkSanitizerInterfaceFunction( + M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy())); } -void HWAddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) { +Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) { // Generate code only when dynamic addressing is needed. if (Mapping.Offset != kDynamicShadowSentinel) - return; + return nullptr; - IRBuilder<> IRB(&F.front().front()); if (Mapping.InGlobal) { // An empty inline asm with input reg == output reg. // An opaque pointer-to-int cast, basically. @@ -303,11 +409,12 @@ void HWAddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) { FunctionType::get(IntptrTy, {ShadowGlobal->getType()}, false), StringRef(""), StringRef("=r,0"), /*hasSideEffects=*/false); - LocalDynamicShadow = IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow"); + return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow"); } else { - Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( - kHwasanShadowMemoryDynamicAddress, IntptrTy); - LocalDynamicShadow = IRB.CreateLoad(GlobalDynamicAddress); + Value *GlobalDynamicAddress = + IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal( + kHwasanShadowMemoryDynamicAddress, IntptrTy); + return IRB.CreateLoad(GlobalDynamicAddress); } } @@ -421,8 +528,7 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite, IRB.getInt8Ty()); Value *AddrLong = untagPointer(IRB, PtrLong); Value *ShadowLong = memToShadow(AddrLong, PtrLong->getType(), IRB); - Value *MemTag = - IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy())); + Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, Int8PtrTy)); Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag); int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ? @@ -433,7 +539,7 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite, TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored); } - TerminatorInst *CheckTerm = + Instruction *CheckTerm = SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover, MDBuilder(*C).createBranchWeights(1, 100000)); @@ -464,12 +570,36 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite, IRB.CreateCall(Asm, PtrLong); } +void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { + IRBuilder<> IRB(MI); + if (isa<MemTransferInst>(MI)) { + IRB.CreateCall( + isa<MemMoveInst>(MI) ? HWAsanMemmove : HWAsanMemcpy, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } else if (isa<MemSetInst>(MI)) { + IRB.CreateCall( + HWAsanMemset, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } + MI->eraseFromParent(); +} + bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) { LLVM_DEBUG(dbgs() << "Instrumenting: " << *I << "\n"); bool IsWrite = false; unsigned Alignment = 0; uint64_t TypeSize = 0; Value *MaybeMask = nullptr; + + if (ClInstrumentMemIntrinsics && isa<MemIntrinsic>(I)) { + instrumentMemIntrinsic(cast<MemIntrinsic>(I)); + return true; + } + Value *Addr = isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask); @@ -521,13 +651,13 @@ bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty()); if (ClInstrumentWithCalls) { IRB.CreateCall(HwasanTagMemoryFunc, - {IRB.CreatePointerCast(AI, IntptrTy), JustTag, + {IRB.CreatePointerCast(AI, Int8PtrTy), JustTag, ConstantInt::get(IntptrTy, Size)}); } else { size_t ShadowSize = Size >> Mapping.Scale; Value *ShadowPtr = IRB.CreateIntToPtr( memToShadow(IRB.CreatePointerCast(AI, IntptrTy), AI->getType(), IRB), - IRB.getInt8PtrTy()); + Int8PtrTy); // If this memset is not inlined, it will be intercepted in the hwasan // runtime library. That's OK, because the interceptor skips the checks if // the address is in the shadow region. @@ -557,7 +687,7 @@ Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) { Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) { if (ClGenerateTagsWithCalls) - return nullptr; + return getNextTagWithCall(IRB); // FIXME: use addressofreturnaddress (but implement it in aarch64 backend // first). Module *M = IRB.GetInsertBlock()->getParent()->getParent(); @@ -625,15 +755,141 @@ Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) { return UntaggedPtrLong; } -bool HWAddressSanitizer::instrumentStack( - SmallVectorImpl<AllocaInst *> &Allocas, - SmallVectorImpl<Instruction *> &RetVec) { - Function *F = Allocas[0]->getParent()->getParent(); - Instruction *InsertPt = &*F->getEntryBlock().begin(); - IRBuilder<> IRB(InsertPt); +Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) { + Module *M = IRB.GetInsertBlock()->getParent()->getParent(); + if (TargetTriple.isAArch64() && TargetTriple.isAndroid()) { + // Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER + // in Bionic's libc/private/bionic_tls.h. + Function *ThreadPointerFunc = + Intrinsic::getDeclaration(M, Intrinsic::thread_pointer); + Value *SlotPtr = IRB.CreatePointerCast( + IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), 0x30), + Ty->getPointerTo(0)); + return SlotPtr; + } + if (ThreadPtrGlobal) + return ThreadPtrGlobal; + + + return nullptr; +} + +// Creates a string with a description of the stack frame (set of Allocas). +// The string is intended to be human readable. +// The current form is: Size1 Name1; Size2 Name2; ... +std::string +HWAddressSanitizer::createFrameString(ArrayRef<AllocaInst *> Allocas) { + std::ostringstream Descr; + for (auto AI : Allocas) + Descr << getAllocaSizeInBytes(*AI) << " " << AI->getName().str() << "; "; + return Descr.str(); +} - Value *StackTag = getStackBaseTag(IRB); +// Creates a global in the frame section which consists of two pointers: +// the function PC and the frame string constant. +void HWAddressSanitizer::createFrameGlobal(Function &F, + const std::string &FrameString) { + Module &M = *F.getParent(); + auto DescrGV = createPrivateGlobalForString(M, FrameString, true); + auto PtrPairTy = StructType::get(F.getType(), DescrGV->getType()); + auto GV = new GlobalVariable( + M, PtrPairTy, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage, + ConstantStruct::get(PtrPairTy, (Constant *)&F, (Constant *)DescrGV), + "__hwasan"); + GV->setSection(getFrameSection()); + appendToCompilerUsed(M, GV); + // Put GV into the F's Comadat so that if F is deleted GV can be deleted too. + if (auto Comdat = + GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId)) + GV->setComdat(Comdat); +} + +Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, + bool WithFrameRecord) { + if (!Mapping.InTls) + return getDynamicShadowNonTls(IRB); + + Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy); + assert(SlotPtr); + + Instruction *ThreadLong = IRB.CreateLoad(SlotPtr); + + Function *F = IRB.GetInsertBlock()->getParent(); + if (F->getFnAttribute("hwasan-abi").getValueAsString() == "interceptor") { + Value *ThreadLongEqZero = + IRB.CreateICmpEQ(ThreadLong, ConstantInt::get(IntptrTy, 0)); + auto *Br = cast<BranchInst>(SplitBlockAndInsertIfThen( + ThreadLongEqZero, cast<Instruction>(ThreadLongEqZero)->getNextNode(), + false, MDBuilder(*C).createBranchWeights(1, 100000))); + + IRB.SetInsertPoint(Br); + // FIXME: This should call a new runtime function with a custom calling + // convention to avoid needing to spill all arguments here. + IRB.CreateCall(HwasanThreadEnterFunc); + LoadInst *ReloadThreadLong = IRB.CreateLoad(SlotPtr); + + IRB.SetInsertPoint(&*Br->getSuccessor(0)->begin()); + PHINode *ThreadLongPhi = IRB.CreatePHI(IntptrTy, 2); + ThreadLongPhi->addIncoming(ThreadLong, ThreadLong->getParent()); + ThreadLongPhi->addIncoming(ReloadThreadLong, ReloadThreadLong->getParent()); + ThreadLong = ThreadLongPhi; + } + + // Extract the address field from ThreadLong. Unnecessary on AArch64 with TBI. + Value *ThreadLongMaybeUntagged = + TargetTriple.isAArch64() ? ThreadLong : untagPointer(IRB, ThreadLong); + + if (WithFrameRecord) { + // Prepare ring buffer data. + auto PC = IRB.CreatePtrToInt(F, IntptrTy); + auto GetStackPointerFn = + Intrinsic::getDeclaration(F->getParent(), Intrinsic::frameaddress); + Value *SP = IRB.CreatePtrToInt( + IRB.CreateCall(GetStackPointerFn, + {Constant::getNullValue(IRB.getInt32Ty())}), + IntptrTy); + // Mix SP and PC. TODO: also add the tag to the mix. + // Assumptions: + // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero) + // SP is 0xsssssssssssSSSS0 (4 lower bits are zero) + // We only really need ~20 lower non-zero bits (SSSS), so we mix like this: + // 0xSSSSPPPPPPPPPPPP + SP = IRB.CreateShl(SP, 44); + + // Store data to ring buffer. + Value *RecordPtr = + IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IntptrTy->getPointerTo(0)); + IRB.CreateStore(IRB.CreateOr(PC, SP), RecordPtr); + + // Update the ring buffer. Top byte of ThreadLong defines the size of the + // buffer in pages, it must be a power of two, and the start of the buffer + // must be aligned by twice that much. Therefore wrap around of the ring + // buffer is simply Addr &= ~((ThreadLong >> 56) << 12). + // The use of AShr instead of LShr is due to + // https://bugs.llvm.org/show_bug.cgi?id=39030 + // Runtime library makes sure not to use the highest bit. + Value *WrapMask = IRB.CreateXor( + IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true), + ConstantInt::get(IntptrTy, (uint64_t)-1)); + Value *ThreadLongNew = IRB.CreateAnd( + IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask); + IRB.CreateStore(ThreadLongNew, SlotPtr); + } + // Get shadow base address by aligning RecordPtr up. + // Note: this is not correct if the pointer is already aligned. + // Runtime library will make sure this never happens. + Value *ShadowBase = IRB.CreateAdd( + IRB.CreateOr( + ThreadLongMaybeUntagged, + ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)), + ConstantInt::get(IntptrTy, 1), "hwasan.shadow"); + return ShadowBase; +} + +bool HWAddressSanitizer::instrumentStack( + SmallVectorImpl<AllocaInst *> &Allocas, + SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) { // Ideally, we want to calculate tagged stack base pointer, and rewrite all // alloca addresses using that. Unfortunately, offsets are not known yet // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a @@ -641,7 +897,7 @@ bool HWAddressSanitizer::instrumentStack( // This generates one extra instruction per alloca use. for (unsigned N = 0; N < Allocas.size(); ++N) { auto *AI = Allocas[N]; - IRB.SetInsertPoint(AI->getNextNode()); + IRBuilder<> IRB(AI->getNextNode()); // Replace uses of the alloca with tagged address. Value *Tag = getAllocaTag(IRB, StackTag, AI, N); @@ -696,12 +952,6 @@ bool HWAddressSanitizer::runOnFunction(Function &F) { LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n"); - initializeCallbacks(*F.getParent()); - - assert(!LocalDynamicShadow); - maybeInsertDynamicShadowAtFunctionEntry(F); - - bool Changed = false; SmallVector<Instruction*, 16> ToInstrument; SmallVector<AllocaInst*, 8> AllocasToInstrument; SmallVector<Instruction*, 8> RetVec; @@ -734,8 +984,28 @@ bool HWAddressSanitizer::runOnFunction(Function &F) { } } - if (!AllocasToInstrument.empty()) - Changed |= instrumentStack(AllocasToInstrument, RetVec); + if (AllocasToInstrument.empty() && ToInstrument.empty()) + return false; + + if (ClCreateFrameDescriptions && !AllocasToInstrument.empty()) + createFrameGlobal(F, createFrameString(AllocasToInstrument)); + + initializeCallbacks(*F.getParent()); + + assert(!LocalDynamicShadow); + + Instruction *InsertPt = &*F.getEntryBlock().begin(); + IRBuilder<> EntryIRB(InsertPt); + LocalDynamicShadow = emitPrologue(EntryIRB, + /*WithFrameRecord*/ ClRecordStackHistory && + !AllocasToInstrument.empty()); + + bool Changed = false; + if (!AllocasToInstrument.empty()) { + Value *StackTag = + ClGenerateTagsWithCalls ? nullptr : getStackBaseTag(EntryIRB); + Changed |= instrumentStack(AllocasToInstrument, RetVec, StackTag); + } for (auto Inst : ToInstrument) Changed |= instrumentMemAccess(Inst); @@ -746,18 +1016,26 @@ bool HWAddressSanitizer::runOnFunction(Function &F) { } void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) { - const bool IsAndroid = TargetTriple.isAndroid(); - const bool IsAndroidWithIfuncSupport = - IsAndroid && !TargetTriple.isAndroidVersionLT(21); - Scale = kDefaultShadowScale; - - if (ClEnableKhwasan || ClInstrumentWithCalls || !IsAndroidWithIfuncSupport) + if (ClMappingOffset.getNumOccurrences() > 0) { + InGlobal = false; + InTls = false; + Offset = ClMappingOffset; + } else if (ClEnableKhwasan || ClInstrumentWithCalls) { + InGlobal = false; + InTls = false; Offset = 0; - else + } else if (ClWithIfunc) { + InGlobal = true; + InTls = false; Offset = kDynamicShadowSentinel; - if (ClMappingOffset.getNumOccurrences() > 0) - Offset = ClMappingOffset; - - InGlobal = IsAndroidWithIfuncSupport; + } else if (ClWithTls) { + InGlobal = false; + InTls = true; + Offset = kDynamicShadowSentinel; + } else { + InGlobal = false; + InTls = false; + Offset = kDynamicShadowSentinel; + } } |