106c3fb27SDimitry Andric //===- HWAddressSanitizer.cpp - memory access error detector --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
104824e7fdSDimitry Andric /// This file is a part of HWAddressSanitizer, an address basic correctness
114824e7fdSDimitry Andric /// checker based on tagged addressing.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
158bcb0991SDimitry Andric #include "llvm/ADT/MapVector.h"
1681ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
18*0fca6ea1SDimitry Andric #include "llvm/ADT/Statistic.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
21*0fca6ea1SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h"
225f757f3fSDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h"
23bdd1243dSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
24*0fca6ea1SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
25349cc55cSDimitry Andric #include "llvm/Analysis/PostDominators.h"
26*0fca6ea1SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
27fe6060f1SDimitry Andric #include "llvm/Analysis/StackSafetyAnalysis.h"
285f757f3fSDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h"
29349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
3081ad6265SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
318bcb0991SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
320b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
330b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
340b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
350b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
360b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
370b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
380b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
39349cc55cSDimitry Andric #include "llvm/IR/Dominators.h"
400b57cec5SDimitry Andric #include "llvm/IR/Function.h"
410b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
420b57cec5SDimitry Andric #include "llvm/IR/InlineAsm.h"
4381ad6265SDimitry Andric #include "llvm/IR/InstIterator.h"
440b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
450b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
460b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
470b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
480b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
490b57cec5SDimitry Andric #include "llvm/IR/MDBuilder.h"
500b57cec5SDimitry Andric #include "llvm/IR/Module.h"
510b57cec5SDimitry Andric #include "llvm/IR/Type.h"
520b57cec5SDimitry Andric #include "llvm/IR/Value.h"
530b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
540b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
550b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
56*0fca6ea1SDimitry Andric #include "llvm/Support/MD5.h"
57*0fca6ea1SDimitry Andric #include "llvm/Support/RandomNumberGenerator.h"
580b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
5906c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
605ffd83dbSDimitry Andric #include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
610b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
625f757f3fSDimitry Andric #include "llvm/Transforms/Utils/Local.h"
6381ad6265SDimitry Andric #include "llvm/Transforms/Utils/MemoryTaggingSupport.h"
640b57cec5SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
650b57cec5SDimitry Andric #include "llvm/Transforms/Utils/PromoteMemToReg.h"
66bdd1243dSDimitry Andric #include <optional>
67*0fca6ea1SDimitry Andric #include <random>
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric using namespace llvm;
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric #define DEBUG_TYPE "hwasan"
720b57cec5SDimitry Andric
73e8d8bef9SDimitry Andric const char kHwasanModuleCtorName[] = "hwasan.module_ctor";
74e8d8bef9SDimitry Andric const char kHwasanNoteName[] = "hwasan.note";
75e8d8bef9SDimitry Andric const char kHwasanInitName[] = "__hwasan_init";
76e8d8bef9SDimitry Andric const char kHwasanPersonalityThunkName[] = "__hwasan_personality_thunk";
770b57cec5SDimitry Andric
78e8d8bef9SDimitry Andric const char kHwasanShadowMemoryDynamicAddress[] =
790b57cec5SDimitry Andric "__hwasan_shadow_memory_dynamic_address";
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric // Accesses sizes are powers of two: 1, 2, 4, 8, 16.
820b57cec5SDimitry Andric static const size_t kNumberOfAccessSizes = 5;
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric static const size_t kDefaultShadowScale = 4;
850b57cec5SDimitry Andric static const uint64_t kDynamicShadowSentinel =
860b57cec5SDimitry Andric std::numeric_limits<uint64_t>::max();
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric static const unsigned kShadowBaseAlignment = 32;
890b57cec5SDimitry Andric
90fe6060f1SDimitry Andric static cl::opt<std::string>
91fe6060f1SDimitry Andric ClMemoryAccessCallbackPrefix("hwasan-memory-access-callback-prefix",
92fe6060f1SDimitry Andric cl::desc("Prefix for memory access callbacks"),
93fe6060f1SDimitry Andric cl::Hidden, cl::init("__hwasan_"));
940b57cec5SDimitry Andric
9581ad6265SDimitry Andric static cl::opt<bool> ClKasanMemIntrinCallbackPrefix(
9681ad6265SDimitry Andric "hwasan-kernel-mem-intrinsic-prefix",
9781ad6265SDimitry Andric cl::desc("Use prefix for memory intrinsics in KASAN mode"), cl::Hidden,
9881ad6265SDimitry Andric cl::init(false));
9981ad6265SDimitry Andric
100fe6060f1SDimitry Andric static cl::opt<bool> ClInstrumentWithCalls(
101fe6060f1SDimitry Andric "hwasan-instrument-with-calls",
102fe6060f1SDimitry Andric cl::desc("instrument reads and writes with callbacks"), cl::Hidden,
103fe6060f1SDimitry Andric cl::init(false));
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",
1060b57cec5SDimitry Andric cl::desc("instrument read instructions"),
1070b57cec5SDimitry Andric cl::Hidden, cl::init(true));
1080b57cec5SDimitry Andric
109fe6060f1SDimitry Andric static cl::opt<bool>
110fe6060f1SDimitry Andric ClInstrumentWrites("hwasan-instrument-writes",
111fe6060f1SDimitry Andric cl::desc("instrument write instructions"), cl::Hidden,
112fe6060f1SDimitry Andric cl::init(true));
1130b57cec5SDimitry Andric
1140b57cec5SDimitry Andric static cl::opt<bool> ClInstrumentAtomics(
1150b57cec5SDimitry Andric "hwasan-instrument-atomics",
1160b57cec5SDimitry Andric cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
1170b57cec5SDimitry Andric cl::init(true));
1180b57cec5SDimitry Andric
1195ffd83dbSDimitry Andric static cl::opt<bool> ClInstrumentByval("hwasan-instrument-byval",
1205ffd83dbSDimitry Andric cl::desc("instrument byval arguments"),
1215ffd83dbSDimitry Andric cl::Hidden, cl::init(true));
1225ffd83dbSDimitry Andric
123fe6060f1SDimitry Andric static cl::opt<bool>
124fe6060f1SDimitry Andric ClRecover("hwasan-recover",
1250b57cec5SDimitry Andric cl::desc("Enable recovery mode (continue-after-error)."),
1260b57cec5SDimitry Andric cl::Hidden, cl::init(false));
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
1290b57cec5SDimitry Andric cl::desc("instrument stack (allocas)"),
1300b57cec5SDimitry Andric cl::Hidden, cl::init(true));
1310b57cec5SDimitry Andric
132fe6060f1SDimitry Andric static cl::opt<bool>
133fe6060f1SDimitry Andric ClUseStackSafety("hwasan-use-stack-safety", cl::Hidden, cl::init(true),
134fe6060f1SDimitry Andric cl::Hidden, cl::desc("Use Stack Safety analysis results"),
135fe6060f1SDimitry Andric cl::Optional);
136fe6060f1SDimitry Andric
137349cc55cSDimitry Andric static cl::opt<size_t> ClMaxLifetimes(
138349cc55cSDimitry Andric "hwasan-max-lifetimes-for-alloca", cl::Hidden, cl::init(3),
139349cc55cSDimitry Andric cl::ReallyHidden,
140349cc55cSDimitry Andric cl::desc("How many lifetime ends to handle for a single alloca."),
141349cc55cSDimitry Andric cl::Optional);
142349cc55cSDimitry Andric
143349cc55cSDimitry Andric static cl::opt<bool>
144349cc55cSDimitry Andric ClUseAfterScope("hwasan-use-after-scope",
145349cc55cSDimitry Andric cl::desc("detect use after scope within function"),
1465f757f3fSDimitry Andric cl::Hidden, cl::init(true));
147349cc55cSDimitry Andric
1480b57cec5SDimitry Andric static cl::opt<bool> ClGenerateTagsWithCalls(
1490b57cec5SDimitry Andric "hwasan-generate-tags-with-calls",
1500b57cec5SDimitry Andric cl::desc("generate new tags with runtime library calls"), cl::Hidden,
1510b57cec5SDimitry Andric cl::init(false));
1520b57cec5SDimitry Andric
1538bcb0991SDimitry Andric static cl::opt<bool> ClGlobals("hwasan-globals", cl::desc("Instrument globals"),
15481ad6265SDimitry Andric cl::Hidden, cl::init(false));
1558bcb0991SDimitry Andric
1560b57cec5SDimitry Andric static cl::opt<int> ClMatchAllTag(
1570b57cec5SDimitry Andric "hwasan-match-all-tag",
1580b57cec5SDimitry Andric cl::desc("don't report bad accesses via pointers with this tag"),
1590b57cec5SDimitry Andric cl::Hidden, cl::init(-1));
1600b57cec5SDimitry Andric
161fe6060f1SDimitry Andric static cl::opt<bool>
162fe6060f1SDimitry Andric ClEnableKhwasan("hwasan-kernel",
1630b57cec5SDimitry Andric cl::desc("Enable KernelHWAddressSanitizer instrumentation"),
1640b57cec5SDimitry Andric cl::Hidden, cl::init(false));
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andric // These flags allow to change the shadow mapping and control how shadow memory
1670b57cec5SDimitry Andric // is accessed. The shadow mapping looks like:
1680b57cec5SDimitry Andric // Shadow = (Mem >> scale) + offset
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric static cl::opt<uint64_t>
1710b57cec5SDimitry Andric ClMappingOffset("hwasan-mapping-offset",
1720b57cec5SDimitry Andric cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"),
1730b57cec5SDimitry Andric cl::Hidden, cl::init(0));
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric static cl::opt<bool>
1760b57cec5SDimitry Andric ClWithIfunc("hwasan-with-ifunc",
1770b57cec5SDimitry Andric cl::desc("Access dynamic shadow through an ifunc global on "
1780b57cec5SDimitry Andric "platforms that support this"),
1790b57cec5SDimitry Andric cl::Hidden, cl::init(false));
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric static cl::opt<bool> ClWithTls(
1820b57cec5SDimitry Andric "hwasan-with-tls",
1830b57cec5SDimitry Andric cl::desc("Access dynamic shadow through an thread-local pointer on "
1840b57cec5SDimitry Andric "platforms that support this"),
1850b57cec5SDimitry Andric cl::Hidden, cl::init(true));
1860b57cec5SDimitry Andric
187*0fca6ea1SDimitry Andric static cl::opt<int> ClHotPercentileCutoff("hwasan-percentile-cutoff-hot",
188*0fca6ea1SDimitry Andric cl::desc("Hot percentile cuttoff."));
189*0fca6ea1SDimitry Andric
190*0fca6ea1SDimitry Andric static cl::opt<float>
191*0fca6ea1SDimitry Andric ClRandomSkipRate("hwasan-random-rate",
192*0fca6ea1SDimitry Andric cl::desc("Probability value in the range [0.0, 1.0] "
193*0fca6ea1SDimitry Andric "to keep instrumentation of a function."));
194*0fca6ea1SDimitry Andric
195*0fca6ea1SDimitry Andric STATISTIC(NumTotalFuncs, "Number of total funcs");
196*0fca6ea1SDimitry Andric STATISTIC(NumInstrumentedFuncs, "Number of instrumented funcs");
197*0fca6ea1SDimitry Andric STATISTIC(NumNoProfileSummaryFuncs, "Number of funcs without PS");
198*0fca6ea1SDimitry Andric
199753f127fSDimitry Andric // Mode for selecting how to insert frame record info into the stack ring
200753f127fSDimitry Andric // buffer.
201753f127fSDimitry Andric enum RecordStackHistoryMode {
202753f127fSDimitry Andric // Do not record frame record info.
203753f127fSDimitry Andric none,
204753f127fSDimitry Andric
205753f127fSDimitry Andric // Insert instructions into the prologue for storing into the stack ring
206753f127fSDimitry Andric // buffer directly.
207753f127fSDimitry Andric instr,
208753f127fSDimitry Andric
209753f127fSDimitry Andric // Add a call to __hwasan_add_frame_record in the runtime.
210753f127fSDimitry Andric libcall,
211753f127fSDimitry Andric };
212753f127fSDimitry Andric
213753f127fSDimitry Andric static cl::opt<RecordStackHistoryMode> ClRecordStackHistory(
214753f127fSDimitry Andric "hwasan-record-stack-history",
215753f127fSDimitry Andric cl::desc("Record stack frames with tagged allocations in a thread-local "
216753f127fSDimitry Andric "ring buffer"),
217753f127fSDimitry Andric cl::values(clEnumVal(none, "Do not record stack ring history"),
218753f127fSDimitry Andric clEnumVal(instr, "Insert instructions into the prologue for "
219753f127fSDimitry Andric "storing into the stack ring buffer directly"),
220753f127fSDimitry Andric clEnumVal(libcall, "Add a call to __hwasan_add_frame_record for "
221753f127fSDimitry Andric "storing into the stack ring buffer")),
222753f127fSDimitry Andric cl::Hidden, cl::init(instr));
223753f127fSDimitry Andric
2240b57cec5SDimitry Andric static cl::opt<bool>
2250b57cec5SDimitry Andric ClInstrumentMemIntrinsics("hwasan-instrument-mem-intrinsics",
2260b57cec5SDimitry Andric cl::desc("instrument memory intrinsics"),
2270b57cec5SDimitry Andric cl::Hidden, cl::init(true));
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric static cl::opt<bool>
2300b57cec5SDimitry Andric ClInstrumentLandingPads("hwasan-instrument-landing-pads",
2310b57cec5SDimitry Andric cl::desc("instrument landing pads"), cl::Hidden,
23281ad6265SDimitry Andric cl::init(false));
2338bcb0991SDimitry Andric
2348bcb0991SDimitry Andric static cl::opt<bool> ClUseShortGranules(
2358bcb0991SDimitry Andric "hwasan-use-short-granules",
2368bcb0991SDimitry Andric cl::desc("use short granules in allocas and outlined checks"), cl::Hidden,
23781ad6265SDimitry Andric cl::init(false));
2388bcb0991SDimitry Andric
2398bcb0991SDimitry Andric static cl::opt<bool> ClInstrumentPersonalityFunctions(
2408bcb0991SDimitry Andric "hwasan-instrument-personality-functions",
24181ad6265SDimitry Andric cl::desc("instrument personality functions"), cl::Hidden);
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric static cl::opt<bool> ClInlineAllChecks("hwasan-inline-all-checks",
2440b57cec5SDimitry Andric cl::desc("inline all checks"),
2450b57cec5SDimitry Andric cl::Hidden, cl::init(false));
2460b57cec5SDimitry Andric
2475f757f3fSDimitry Andric static cl::opt<bool> ClInlineFastPathChecks("hwasan-inline-fast-path-checks",
2485f757f3fSDimitry Andric cl::desc("inline all checks"),
2495f757f3fSDimitry Andric cl::Hidden, cl::init(false));
2505f757f3fSDimitry Andric
251fe6060f1SDimitry Andric // Enabled from clang by "-fsanitize-hwaddress-experimental-aliasing".
252fe6060f1SDimitry Andric static cl::opt<bool> ClUsePageAliases("hwasan-experimental-use-page-aliases",
253fe6060f1SDimitry Andric cl::desc("Use page aliasing in HWASan"),
254fe6060f1SDimitry Andric cl::Hidden, cl::init(false));
255fe6060f1SDimitry Andric
2560b57cec5SDimitry Andric namespace {
2570b57cec5SDimitry Andric
optOr(cl::opt<T> & Opt,T Other)258*0fca6ea1SDimitry Andric template <typename T> T optOr(cl::opt<T> &Opt, T Other) {
259*0fca6ea1SDimitry Andric return Opt.getNumOccurrences() ? Opt : Other;
260*0fca6ea1SDimitry Andric }
261*0fca6ea1SDimitry Andric
shouldUsePageAliases(const Triple & TargetTriple)262fe6060f1SDimitry Andric bool shouldUsePageAliases(const Triple &TargetTriple) {
263fe6060f1SDimitry Andric return ClUsePageAliases && TargetTriple.getArch() == Triple::x86_64;
264fe6060f1SDimitry Andric }
265fe6060f1SDimitry Andric
shouldInstrumentStack(const Triple & TargetTriple)266fe6060f1SDimitry Andric bool shouldInstrumentStack(const Triple &TargetTriple) {
267fe6060f1SDimitry Andric return !shouldUsePageAliases(TargetTriple) && ClInstrumentStack;
268fe6060f1SDimitry Andric }
269fe6060f1SDimitry Andric
shouldInstrumentWithCalls(const Triple & TargetTriple)270fe6060f1SDimitry Andric bool shouldInstrumentWithCalls(const Triple &TargetTriple) {
271*0fca6ea1SDimitry Andric return optOr(ClInstrumentWithCalls, TargetTriple.getArch() == Triple::x86_64);
272fe6060f1SDimitry Andric }
273fe6060f1SDimitry Andric
mightUseStackSafetyAnalysis(bool DisableOptimization)274fe6060f1SDimitry Andric bool mightUseStackSafetyAnalysis(bool DisableOptimization) {
275*0fca6ea1SDimitry Andric return optOr(ClUseStackSafety, !DisableOptimization);
276fe6060f1SDimitry Andric }
277fe6060f1SDimitry Andric
shouldUseStackSafetyAnalysis(const Triple & TargetTriple,bool DisableOptimization)278fe6060f1SDimitry Andric bool shouldUseStackSafetyAnalysis(const Triple &TargetTriple,
279fe6060f1SDimitry Andric bool DisableOptimization) {
280fe6060f1SDimitry Andric return shouldInstrumentStack(TargetTriple) &&
281fe6060f1SDimitry Andric mightUseStackSafetyAnalysis(DisableOptimization);
282fe6060f1SDimitry Andric }
283349cc55cSDimitry Andric
shouldDetectUseAfterScope(const Triple & TargetTriple)284349cc55cSDimitry Andric bool shouldDetectUseAfterScope(const Triple &TargetTriple) {
285349cc55cSDimitry Andric return ClUseAfterScope && shouldInstrumentStack(TargetTriple);
286349cc55cSDimitry Andric }
287349cc55cSDimitry Andric
2880b57cec5SDimitry Andric /// An instrumentation pass implementing detection of addressability bugs
2890b57cec5SDimitry Andric /// using tagged pointers.
2900b57cec5SDimitry Andric class HWAddressSanitizer {
2910b57cec5SDimitry Andric public:
HWAddressSanitizer(Module & M,bool CompileKernel,bool Recover,const StackSafetyGlobalInfo * SSI)292fe6060f1SDimitry Andric HWAddressSanitizer(Module &M, bool CompileKernel, bool Recover,
293fe6060f1SDimitry Andric const StackSafetyGlobalInfo *SSI)
294fe6060f1SDimitry Andric : M(M), SSI(SSI) {
295*0fca6ea1SDimitry Andric this->Recover = optOr(ClRecover, Recover);
296*0fca6ea1SDimitry Andric this->CompileKernel = optOr(ClEnableKhwasan, CompileKernel);
297*0fca6ea1SDimitry Andric this->Rng = ClRandomSkipRate.getNumOccurrences() ? M.createRNG(DEBUG_TYPE)
298*0fca6ea1SDimitry Andric : nullptr;
2990b57cec5SDimitry Andric
3008bcb0991SDimitry Andric initializeModule();
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric
3035f757f3fSDimitry Andric void sanitizeFunction(Function &F, FunctionAnalysisManager &FAM);
3045f757f3fSDimitry Andric
3055f757f3fSDimitry Andric private:
3065f757f3fSDimitry Andric struct ShadowTagCheckInfo {
3075f757f3fSDimitry Andric Instruction *TagMismatchTerm = nullptr;
3085f757f3fSDimitry Andric Value *PtrLong = nullptr;
3095f757f3fSDimitry Andric Value *AddrLong = nullptr;
3105f757f3fSDimitry Andric Value *PtrTag = nullptr;
3115f757f3fSDimitry Andric Value *MemTag = nullptr;
3125f757f3fSDimitry Andric };
313fe6060f1SDimitry Andric
314*0fca6ea1SDimitry Andric bool selectiveInstrumentationShouldSkip(Function &F,
315*0fca6ea1SDimitry Andric FunctionAnalysisManager &FAM) const;
3168bcb0991SDimitry Andric void initializeModule();
317e8d8bef9SDimitry Andric void createHwasanCtorComdat();
3180b57cec5SDimitry Andric
3190b57cec5SDimitry Andric void initializeCallbacks(Module &M);
3200b57cec5SDimitry Andric
321e8d8bef9SDimitry Andric Value *getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val);
322e8d8bef9SDimitry Andric
3230b57cec5SDimitry Andric Value *getDynamicShadowIfunc(IRBuilder<> &IRB);
324e8d8bef9SDimitry Andric Value *getShadowNonTls(IRBuilder<> &IRB);
3250b57cec5SDimitry Andric
3260b57cec5SDimitry Andric void untagPointerOperand(Instruction *I, Value *Addr);
3270b57cec5SDimitry Andric Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
328349cc55cSDimitry Andric
329349cc55cSDimitry Andric int64_t getAccessInfo(bool IsWrite, unsigned AccessSizeIndex);
3305f757f3fSDimitry Andric ShadowTagCheckInfo insertShadowTagCheck(Value *Ptr, Instruction *InsertBefore,
3315f757f3fSDimitry Andric DomTreeUpdater &DTU, LoopInfo *LI);
332349cc55cSDimitry Andric void instrumentMemAccessOutline(Value *Ptr, bool IsWrite,
333349cc55cSDimitry Andric unsigned AccessSizeIndex,
3345f757f3fSDimitry Andric Instruction *InsertBefore,
3355f757f3fSDimitry Andric DomTreeUpdater &DTU, LoopInfo *LI);
3360b57cec5SDimitry Andric void instrumentMemAccessInline(Value *Ptr, bool IsWrite,
3370b57cec5SDimitry Andric unsigned AccessSizeIndex,
3385f757f3fSDimitry Andric Instruction *InsertBefore, DomTreeUpdater &DTU,
3395f757f3fSDimitry Andric LoopInfo *LI);
340*0fca6ea1SDimitry Andric bool ignoreMemIntrinsic(OptimizationRemarkEmitter &ORE, MemIntrinsic *MI);
3410b57cec5SDimitry Andric void instrumentMemIntrinsic(MemIntrinsic *MI);
3425f757f3fSDimitry Andric bool instrumentMemAccess(InterestingMemoryOperand &O, DomTreeUpdater &DTU,
3435f757f3fSDimitry Andric LoopInfo *LI);
344*0fca6ea1SDimitry Andric bool ignoreAccessWithoutRemark(Instruction *Inst, Value *Ptr);
345*0fca6ea1SDimitry Andric bool ignoreAccess(OptimizationRemarkEmitter &ORE, Instruction *Inst,
346*0fca6ea1SDimitry Andric Value *Ptr);
347*0fca6ea1SDimitry Andric
3485ffd83dbSDimitry Andric void getInterestingMemoryOperands(
349*0fca6ea1SDimitry Andric OptimizationRemarkEmitter &ORE, Instruction *I,
350*0fca6ea1SDimitry Andric const TargetLibraryInfo &TLI,
3515f757f3fSDimitry Andric SmallVectorImpl<InterestingMemoryOperand> &Interesting);
3520b57cec5SDimitry Andric
353349cc55cSDimitry Andric void tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag, size_t Size);
3540b57cec5SDimitry Andric Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
3550b57cec5SDimitry Andric Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
35606c3fb27SDimitry Andric bool instrumentStack(memtag::StackInfo &Info, Value *StackTag, Value *UARTag,
35781ad6265SDimitry Andric const DominatorTree &DT, const PostDominatorTree &PDT,
35881ad6265SDimitry Andric const LoopInfo &LI);
3590b57cec5SDimitry Andric bool instrumentLandingPads(SmallVectorImpl<Instruction *> &RetVec);
3600b57cec5SDimitry Andric Value *getNextTagWithCall(IRBuilder<> &IRB);
3610b57cec5SDimitry Andric Value *getStackBaseTag(IRBuilder<> &IRB);
36206c3fb27SDimitry Andric Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, unsigned AllocaNo);
36306c3fb27SDimitry Andric Value *getUARTag(IRBuilder<> &IRB);
3640b57cec5SDimitry Andric
365*0fca6ea1SDimitry Andric Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB);
366fe6060f1SDimitry Andric Value *applyTagMask(IRBuilder<> &IRB, Value *OldTag);
367fe6060f1SDimitry Andric unsigned retagMask(unsigned AllocaNo);
368fe6060f1SDimitry Andric
3690b57cec5SDimitry Andric void emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);
3700b57cec5SDimitry Andric
3718bcb0991SDimitry Andric void instrumentGlobal(GlobalVariable *GV, uint8_t Tag);
3728bcb0991SDimitry Andric void instrumentGlobals();
3738bcb0991SDimitry Andric
374*0fca6ea1SDimitry Andric Value *getCachedFP(IRBuilder<> &IRB);
375753f127fSDimitry Andric Value *getFrameRecordInfo(IRBuilder<> &IRB);
37681ad6265SDimitry Andric
3778bcb0991SDimitry Andric void instrumentPersonalityFunctions();
3788bcb0991SDimitry Andric
3790b57cec5SDimitry Andric LLVMContext *C;
3808bcb0991SDimitry Andric Module &M;
381fe6060f1SDimitry Andric const StackSafetyGlobalInfo *SSI;
3820b57cec5SDimitry Andric Triple TargetTriple;
383*0fca6ea1SDimitry Andric std::unique_ptr<RandomNumberGenerator> Rng;
3840b57cec5SDimitry Andric
3850b57cec5SDimitry Andric /// This struct defines the shadow mapping using the rule:
3860b57cec5SDimitry Andric /// shadow = (mem >> Scale) + Offset.
3870b57cec5SDimitry Andric /// If InGlobal is true, then
3880b57cec5SDimitry Andric /// extern char __hwasan_shadow[];
3890b57cec5SDimitry Andric /// shadow = (mem >> Scale) + &__hwasan_shadow
3900b57cec5SDimitry Andric /// If InTls is true, then
3910b57cec5SDimitry Andric /// extern char *__hwasan_tls;
3920b57cec5SDimitry Andric /// shadow = (mem>>Scale) + align_up(__hwasan_shadow, kShadowBaseAlignment)
393fe6060f1SDimitry Andric ///
394fe6060f1SDimitry Andric /// If WithFrameRecord is true, then __hwasan_tls will be used to access the
395fe6060f1SDimitry Andric /// ring buffer for storing stack allocations on targets that support it.
3960b57cec5SDimitry Andric struct ShadowMapping {
397bdd1243dSDimitry Andric uint8_t Scale;
3980b57cec5SDimitry Andric uint64_t Offset;
3990b57cec5SDimitry Andric bool InGlobal;
4000b57cec5SDimitry Andric bool InTls;
401fe6060f1SDimitry Andric bool WithFrameRecord;
4020b57cec5SDimitry Andric
403fe6060f1SDimitry Andric void init(Triple &TargetTriple, bool InstrumentWithCalls);
getObjectAlignment__anon1b7bdbef0111::HWAddressSanitizer::ShadowMapping404bdd1243dSDimitry Andric Align getObjectAlignment() const { return Align(1ULL << Scale); }
4050b57cec5SDimitry Andric };
406349cc55cSDimitry Andric
4070b57cec5SDimitry Andric ShadowMapping Mapping;
4080b57cec5SDimitry Andric
4098bcb0991SDimitry Andric Type *VoidTy = Type::getVoidTy(M.getContext());
410*0fca6ea1SDimitry Andric Type *IntptrTy = M.getDataLayout().getIntPtrType(M.getContext());
411*0fca6ea1SDimitry Andric PointerType *PtrTy = PointerType::getUnqual(M.getContext());
412*0fca6ea1SDimitry Andric Type *Int8Ty = Type::getInt8Ty(M.getContext());
413*0fca6ea1SDimitry Andric Type *Int32Ty = Type::getInt32Ty(M.getContext());
4148bcb0991SDimitry Andric Type *Int64Ty = Type::getInt64Ty(M.getContext());
4150b57cec5SDimitry Andric
4160b57cec5SDimitry Andric bool CompileKernel;
4170b57cec5SDimitry Andric bool Recover;
418e8d8bef9SDimitry Andric bool OutlinedChecks;
4195f757f3fSDimitry Andric bool InlineFastPath;
4208bcb0991SDimitry Andric bool UseShortGranules;
4218bcb0991SDimitry Andric bool InstrumentLandingPads;
422fe6060f1SDimitry Andric bool InstrumentWithCalls;
423fe6060f1SDimitry Andric bool InstrumentStack;
424*0fca6ea1SDimitry Andric bool InstrumentGlobals;
425349cc55cSDimitry Andric bool DetectUseAfterScope;
426fe6060f1SDimitry Andric bool UsePageAliases;
42706c3fb27SDimitry Andric bool UseMatchAllCallback;
4280b57cec5SDimitry Andric
429bdd1243dSDimitry Andric std::optional<uint8_t> MatchAllTag;
430e8d8bef9SDimitry Andric
431fe6060f1SDimitry Andric unsigned PointerTagShift;
432fe6060f1SDimitry Andric uint64_t TagMaskByte;
433fe6060f1SDimitry Andric
4340b57cec5SDimitry Andric Function *HwasanCtorFunction;
4350b57cec5SDimitry Andric
4360b57cec5SDimitry Andric FunctionCallee HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
4370b57cec5SDimitry Andric FunctionCallee HwasanMemoryAccessCallbackSized[2];
4380b57cec5SDimitry Andric
43906c3fb27SDimitry Andric FunctionCallee HwasanMemmove, HwasanMemcpy, HwasanMemset;
44006c3fb27SDimitry Andric FunctionCallee HwasanHandleVfork;
44106c3fb27SDimitry Andric
4420b57cec5SDimitry Andric FunctionCallee HwasanTagMemoryFunc;
4430b57cec5SDimitry Andric FunctionCallee HwasanGenerateTagFunc;
444753f127fSDimitry Andric FunctionCallee HwasanRecordFrameRecordFunc;
4450b57cec5SDimitry Andric
4460b57cec5SDimitry Andric Constant *ShadowGlobal;
4470b57cec5SDimitry Andric
448e8d8bef9SDimitry Andric Value *ShadowBase = nullptr;
4490b57cec5SDimitry Andric Value *StackBaseTag = nullptr;
450*0fca6ea1SDimitry Andric Value *CachedFP = nullptr;
4510b57cec5SDimitry Andric GlobalValue *ThreadPtrGlobal = nullptr;
4520b57cec5SDimitry Andric };
4530b57cec5SDimitry Andric
4540b57cec5SDimitry Andric } // end anonymous namespace
4550b57cec5SDimitry Andric
run(Module & M,ModuleAnalysisManager & MAM)4560b57cec5SDimitry Andric PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
4570b57cec5SDimitry Andric ModuleAnalysisManager &MAM) {
458fe6060f1SDimitry Andric const StackSafetyGlobalInfo *SSI = nullptr;
459349cc55cSDimitry Andric auto TargetTriple = llvm::Triple(M.getTargetTriple());
460349cc55cSDimitry Andric if (shouldUseStackSafetyAnalysis(TargetTriple, Options.DisableOptimization))
461fe6060f1SDimitry Andric SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
462349cc55cSDimitry Andric
463349cc55cSDimitry Andric HWAddressSanitizer HWASan(M, Options.CompileKernel, Options.Recover, SSI);
464349cc55cSDimitry Andric auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
46581ad6265SDimitry Andric for (Function &F : M)
46606c3fb27SDimitry Andric HWASan.sanitizeFunction(F, FAM);
467bdd1243dSDimitry Andric
468bdd1243dSDimitry Andric PreservedAnalyses PA = PreservedAnalyses::none();
4695f757f3fSDimitry Andric // DominatorTreeAnalysis, PostDominatorTreeAnalysis, and LoopAnalysis
4705f757f3fSDimitry Andric // are incrementally updated throughout this pass whenever
4715f757f3fSDimitry Andric // SplitBlockAndInsertIfThen is called.
4725f757f3fSDimitry Andric PA.preserve<DominatorTreeAnalysis>();
4735f757f3fSDimitry Andric PA.preserve<PostDominatorTreeAnalysis>();
4745f757f3fSDimitry Andric PA.preserve<LoopAnalysis>();
475bdd1243dSDimitry Andric // GlobalsAA is considered stateless and does not get invalidated unless
476bdd1243dSDimitry Andric // explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers
477bdd1243dSDimitry Andric // make changes that require GlobalsAA to be invalidated.
478bdd1243dSDimitry Andric PA.abandon<GlobalsAA>();
479bdd1243dSDimitry Andric return PA;
4800b57cec5SDimitry Andric }
printPipeline(raw_ostream & OS,function_ref<StringRef (StringRef)> MapClassName2PassName)481349cc55cSDimitry Andric void HWAddressSanitizerPass::printPipeline(
482349cc55cSDimitry Andric raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
483349cc55cSDimitry Andric static_cast<PassInfoMixin<HWAddressSanitizerPass> *>(this)->printPipeline(
484349cc55cSDimitry Andric OS, MapClassName2PassName);
48506c3fb27SDimitry Andric OS << '<';
486349cc55cSDimitry Andric if (Options.CompileKernel)
487349cc55cSDimitry Andric OS << "kernel;";
488349cc55cSDimitry Andric if (Options.Recover)
489349cc55cSDimitry Andric OS << "recover";
49006c3fb27SDimitry Andric OS << '>';
491349cc55cSDimitry Andric }
4920b57cec5SDimitry Andric
createHwasanCtorComdat()493e8d8bef9SDimitry Andric void HWAddressSanitizer::createHwasanCtorComdat() {
494e8d8bef9SDimitry Andric std::tie(HwasanCtorFunction, std::ignore) =
495e8d8bef9SDimitry Andric getOrCreateSanitizerCtorAndInitFunctions(
496e8d8bef9SDimitry Andric M, kHwasanModuleCtorName, kHwasanInitName,
497e8d8bef9SDimitry Andric /*InitArgTypes=*/{},
498e8d8bef9SDimitry Andric /*InitArgs=*/{},
499e8d8bef9SDimitry Andric // This callback is invoked when the functions are created the first
500e8d8bef9SDimitry Andric // time. Hook them into the global ctors list in that case:
501e8d8bef9SDimitry Andric [&](Function *Ctor, FunctionCallee) {
502e8d8bef9SDimitry Andric Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName);
503e8d8bef9SDimitry Andric Ctor->setComdat(CtorComdat);
504e8d8bef9SDimitry Andric appendToGlobalCtors(M, Ctor, 0, Ctor);
505e8d8bef9SDimitry Andric });
506e8d8bef9SDimitry Andric
507e8d8bef9SDimitry Andric // Create a note that contains pointers to the list of global
508e8d8bef9SDimitry Andric // descriptors. Adding a note to the output file will cause the linker to
509e8d8bef9SDimitry Andric // create a PT_NOTE program header pointing to the note that we can use to
510e8d8bef9SDimitry Andric // find the descriptor list starting from the program headers. A function
511e8d8bef9SDimitry Andric // provided by the runtime initializes the shadow memory for the globals by
512e8d8bef9SDimitry Andric // accessing the descriptor list via the note. The dynamic loader needs to
513e8d8bef9SDimitry Andric // call this function whenever a library is loaded.
514e8d8bef9SDimitry Andric //
515e8d8bef9SDimitry Andric // The reason why we use a note for this instead of a more conventional
516e8d8bef9SDimitry Andric // approach of having a global constructor pass a descriptor list pointer to
517e8d8bef9SDimitry Andric // the runtime is because of an order of initialization problem. With
518e8d8bef9SDimitry Andric // constructors we can encounter the following problematic scenario:
519e8d8bef9SDimitry Andric //
520e8d8bef9SDimitry Andric // 1) library A depends on library B and also interposes one of B's symbols
521e8d8bef9SDimitry Andric // 2) B's constructors are called before A's (as required for correctness)
522e8d8bef9SDimitry Andric // 3) during construction, B accesses one of its "own" globals (actually
523e8d8bef9SDimitry Andric // interposed by A) and triggers a HWASAN failure due to the initialization
524e8d8bef9SDimitry Andric // for A not having happened yet
525e8d8bef9SDimitry Andric //
526e8d8bef9SDimitry Andric // Even without interposition it is possible to run into similar situations in
527e8d8bef9SDimitry Andric // cases where two libraries mutually depend on each other.
528e8d8bef9SDimitry Andric //
529e8d8bef9SDimitry Andric // We only need one note per binary, so put everything for the note in a
530e8d8bef9SDimitry Andric // comdat. This needs to be a comdat with an .init_array section to prevent
531e8d8bef9SDimitry Andric // newer versions of lld from discarding the note.
532e8d8bef9SDimitry Andric //
533e8d8bef9SDimitry Andric // Create the note even if we aren't instrumenting globals. This ensures that
534e8d8bef9SDimitry Andric // binaries linked from object files with both instrumented and
535e8d8bef9SDimitry Andric // non-instrumented globals will end up with a note, even if a comdat from an
536e8d8bef9SDimitry Andric // object file with non-instrumented globals is selected. The note is harmless
537e8d8bef9SDimitry Andric // if the runtime doesn't support it, since it will just be ignored.
538e8d8bef9SDimitry Andric Comdat *NoteComdat = M.getOrInsertComdat(kHwasanModuleCtorName);
539e8d8bef9SDimitry Andric
540e8d8bef9SDimitry Andric Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0);
541bdd1243dSDimitry Andric auto *Start =
542e8d8bef9SDimitry Andric new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage,
543e8d8bef9SDimitry Andric nullptr, "__start_hwasan_globals");
544e8d8bef9SDimitry Andric Start->setVisibility(GlobalValue::HiddenVisibility);
545bdd1243dSDimitry Andric auto *Stop =
546e8d8bef9SDimitry Andric new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage,
547e8d8bef9SDimitry Andric nullptr, "__stop_hwasan_globals");
548e8d8bef9SDimitry Andric Stop->setVisibility(GlobalValue::HiddenVisibility);
549e8d8bef9SDimitry Andric
550e8d8bef9SDimitry Andric // Null-terminated so actually 8 bytes, which are required in order to align
551e8d8bef9SDimitry Andric // the note properly.
552e8d8bef9SDimitry Andric auto *Name = ConstantDataArray::get(*C, "LLVM\0\0\0");
553e8d8bef9SDimitry Andric
554e8d8bef9SDimitry Andric auto *NoteTy = StructType::get(Int32Ty, Int32Ty, Int32Ty, Name->getType(),
555e8d8bef9SDimitry Andric Int32Ty, Int32Ty);
556e8d8bef9SDimitry Andric auto *Note =
557e8d8bef9SDimitry Andric new GlobalVariable(M, NoteTy, /*isConstant=*/true,
558e8d8bef9SDimitry Andric GlobalValue::PrivateLinkage, nullptr, kHwasanNoteName);
559e8d8bef9SDimitry Andric Note->setSection(".note.hwasan.globals");
560e8d8bef9SDimitry Andric Note->setComdat(NoteComdat);
561e8d8bef9SDimitry Andric Note->setAlignment(Align(4));
562e8d8bef9SDimitry Andric
563e8d8bef9SDimitry Andric // The pointers in the note need to be relative so that the note ends up being
564e8d8bef9SDimitry Andric // placed in rodata, which is the standard location for notes.
565e8d8bef9SDimitry Andric auto CreateRelPtr = [&](Constant *Ptr) {
566e8d8bef9SDimitry Andric return ConstantExpr::getTrunc(
567e8d8bef9SDimitry Andric ConstantExpr::getSub(ConstantExpr::getPtrToInt(Ptr, Int64Ty),
568e8d8bef9SDimitry Andric ConstantExpr::getPtrToInt(Note, Int64Ty)),
569e8d8bef9SDimitry Andric Int32Ty);
570e8d8bef9SDimitry Andric };
571e8d8bef9SDimitry Andric Note->setInitializer(ConstantStruct::getAnon(
572e8d8bef9SDimitry Andric {ConstantInt::get(Int32Ty, 8), // n_namesz
573e8d8bef9SDimitry Andric ConstantInt::get(Int32Ty, 8), // n_descsz
574e8d8bef9SDimitry Andric ConstantInt::get(Int32Ty, ELF::NT_LLVM_HWASAN_GLOBALS), // n_type
575e8d8bef9SDimitry Andric Name, CreateRelPtr(Start), CreateRelPtr(Stop)}));
576e8d8bef9SDimitry Andric appendToCompilerUsed(M, Note);
577e8d8bef9SDimitry Andric
578e8d8bef9SDimitry Andric // Create a zero-length global in hwasan_globals so that the linker will
579e8d8bef9SDimitry Andric // always create start and stop symbols.
580bdd1243dSDimitry Andric auto *Dummy = new GlobalVariable(
581e8d8bef9SDimitry Andric M, Int8Arr0Ty, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage,
582e8d8bef9SDimitry Andric Constant::getNullValue(Int8Arr0Ty), "hwasan.dummy.global");
583e8d8bef9SDimitry Andric Dummy->setSection("hwasan_globals");
584e8d8bef9SDimitry Andric Dummy->setComdat(NoteComdat);
585e8d8bef9SDimitry Andric Dummy->setMetadata(LLVMContext::MD_associated,
586e8d8bef9SDimitry Andric MDNode::get(*C, ValueAsMetadata::get(Note)));
587e8d8bef9SDimitry Andric appendToCompilerUsed(M, Dummy);
588e8d8bef9SDimitry Andric }
589e8d8bef9SDimitry Andric
5900b57cec5SDimitry Andric /// Module-level initialization.
5910b57cec5SDimitry Andric ///
5920b57cec5SDimitry Andric /// inserts a call to __hwasan_init to the module's constructor list.
initializeModule()5938bcb0991SDimitry Andric void HWAddressSanitizer::initializeModule() {
5940b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");
5950b57cec5SDimitry Andric TargetTriple = Triple(M.getTargetTriple());
5960b57cec5SDimitry Andric
597fe6060f1SDimitry Andric // x86_64 currently has two modes:
598fe6060f1SDimitry Andric // - Intel LAM (default)
599fe6060f1SDimitry Andric // - pointer aliasing (heap only)
600fe6060f1SDimitry Andric bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64;
601fe6060f1SDimitry Andric UsePageAliases = shouldUsePageAliases(TargetTriple);
602fe6060f1SDimitry Andric InstrumentWithCalls = shouldInstrumentWithCalls(TargetTriple);
603fe6060f1SDimitry Andric InstrumentStack = shouldInstrumentStack(TargetTriple);
604349cc55cSDimitry Andric DetectUseAfterScope = shouldDetectUseAfterScope(TargetTriple);
605fe6060f1SDimitry Andric PointerTagShift = IsX86_64 ? 57 : 56;
606fe6060f1SDimitry Andric TagMaskByte = IsX86_64 ? 0x3F : 0xFF;
607fe6060f1SDimitry Andric
608fe6060f1SDimitry Andric Mapping.init(TargetTriple, InstrumentWithCalls);
6090b57cec5SDimitry Andric
6100b57cec5SDimitry Andric C = &(M.getContext());
6110b57cec5SDimitry Andric IRBuilder<> IRB(*C);
6120b57cec5SDimitry Andric
6130b57cec5SDimitry Andric HwasanCtorFunction = nullptr;
6148bcb0991SDimitry Andric
6158bcb0991SDimitry Andric // Older versions of Android do not have the required runtime support for
6168bcb0991SDimitry Andric // short granules, global or personality function instrumentation. On other
6178bcb0991SDimitry Andric // platforms we currently require using the latest version of the runtime.
6188bcb0991SDimitry Andric bool NewRuntime =
6198bcb0991SDimitry Andric !TargetTriple.isAndroid() || !TargetTriple.isAndroidVersionLT(30);
6208bcb0991SDimitry Andric
621*0fca6ea1SDimitry Andric UseShortGranules = optOr(ClUseShortGranules, NewRuntime);
622*0fca6ea1SDimitry Andric OutlinedChecks = (TargetTriple.isAArch64() || TargetTriple.isRISCV64()) &&
623bdd1243dSDimitry Andric TargetTriple.isOSBinFormatELF() &&
624*0fca6ea1SDimitry Andric !optOr(ClInlineAllChecks, Recover);
625e8d8bef9SDimitry Andric
626*0fca6ea1SDimitry Andric // These platforms may prefer less inlining to reduce binary size.
627*0fca6ea1SDimitry Andric InlineFastPath = optOr(ClInlineFastPathChecks, !(TargetTriple.isAndroid() ||
628*0fca6ea1SDimitry Andric TargetTriple.isOSFuchsia()));
6295f757f3fSDimitry Andric
630e8d8bef9SDimitry Andric if (ClMatchAllTag.getNumOccurrences()) {
631e8d8bef9SDimitry Andric if (ClMatchAllTag != -1) {
632e8d8bef9SDimitry Andric MatchAllTag = ClMatchAllTag & 0xFF;
633e8d8bef9SDimitry Andric }
634e8d8bef9SDimitry Andric } else if (CompileKernel) {
635e8d8bef9SDimitry Andric MatchAllTag = 0xFF;
636e8d8bef9SDimitry Andric }
63706c3fb27SDimitry Andric UseMatchAllCallback = !CompileKernel && MatchAllTag.has_value();
6388bcb0991SDimitry Andric
6398bcb0991SDimitry Andric // If we don't have personality function support, fall back to landing pads.
640*0fca6ea1SDimitry Andric InstrumentLandingPads = optOr(ClInstrumentLandingPads, !NewRuntime);
641*0fca6ea1SDimitry Andric
642*0fca6ea1SDimitry Andric InstrumentGlobals =
643*0fca6ea1SDimitry Andric !CompileKernel && !UsePageAliases && optOr(ClGlobals, NewRuntime);
6448bcb0991SDimitry Andric
6450b57cec5SDimitry Andric if (!CompileKernel) {
646e8d8bef9SDimitry Andric createHwasanCtorComdat();
647fe6060f1SDimitry Andric
648*0fca6ea1SDimitry Andric if (InstrumentGlobals)
6498bcb0991SDimitry Andric instrumentGlobals();
6508bcb0991SDimitry Andric
6518bcb0991SDimitry Andric bool InstrumentPersonalityFunctions =
652*0fca6ea1SDimitry Andric optOr(ClInstrumentPersonalityFunctions, NewRuntime);
6538bcb0991SDimitry Andric if (InstrumentPersonalityFunctions)
6548bcb0991SDimitry Andric instrumentPersonalityFunctions();
6550b57cec5SDimitry Andric }
6560b57cec5SDimitry Andric
6570b57cec5SDimitry Andric if (!TargetTriple.isAndroid()) {
6580b57cec5SDimitry Andric Constant *C = M.getOrInsertGlobal("__hwasan_tls", IntptrTy, [&] {
6590b57cec5SDimitry Andric auto *GV = new GlobalVariable(M, IntptrTy, /*isConstant=*/false,
6600b57cec5SDimitry Andric GlobalValue::ExternalLinkage, nullptr,
6610b57cec5SDimitry Andric "__hwasan_tls", nullptr,
6620b57cec5SDimitry Andric GlobalVariable::InitialExecTLSModel);
6630b57cec5SDimitry Andric appendToCompilerUsed(M, GV);
6640b57cec5SDimitry Andric return GV;
6650b57cec5SDimitry Andric });
6660b57cec5SDimitry Andric ThreadPtrGlobal = cast<GlobalVariable>(C);
6670b57cec5SDimitry Andric }
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric
initializeCallbacks(Module & M)6700b57cec5SDimitry Andric void HWAddressSanitizer::initializeCallbacks(Module &M) {
6710b57cec5SDimitry Andric IRBuilder<> IRB(*C);
67206c3fb27SDimitry Andric const std::string MatchAllStr = UseMatchAllCallback ? "_match_all" : "";
67306c3fb27SDimitry Andric FunctionType *HwasanMemoryAccessCallbackSizedFnTy,
67406c3fb27SDimitry Andric *HwasanMemoryAccessCallbackFnTy, *HwasanMemTransferFnTy,
67506c3fb27SDimitry Andric *HwasanMemsetFnTy;
67606c3fb27SDimitry Andric if (UseMatchAllCallback) {
67706c3fb27SDimitry Andric HwasanMemoryAccessCallbackSizedFnTy =
67806c3fb27SDimitry Andric FunctionType::get(VoidTy, {IntptrTy, IntptrTy, Int8Ty}, false);
67906c3fb27SDimitry Andric HwasanMemoryAccessCallbackFnTy =
68006c3fb27SDimitry Andric FunctionType::get(VoidTy, {IntptrTy, Int8Ty}, false);
6815f757f3fSDimitry Andric HwasanMemTransferFnTy =
6825f757f3fSDimitry Andric FunctionType::get(PtrTy, {PtrTy, PtrTy, IntptrTy, Int8Ty}, false);
6835f757f3fSDimitry Andric HwasanMemsetFnTy =
6845f757f3fSDimitry Andric FunctionType::get(PtrTy, {PtrTy, Int32Ty, IntptrTy, Int8Ty}, false);
68506c3fb27SDimitry Andric } else {
68606c3fb27SDimitry Andric HwasanMemoryAccessCallbackSizedFnTy =
68706c3fb27SDimitry Andric FunctionType::get(VoidTy, {IntptrTy, IntptrTy}, false);
68806c3fb27SDimitry Andric HwasanMemoryAccessCallbackFnTy =
68906c3fb27SDimitry Andric FunctionType::get(VoidTy, {IntptrTy}, false);
69006c3fb27SDimitry Andric HwasanMemTransferFnTy =
6915f757f3fSDimitry Andric FunctionType::get(PtrTy, {PtrTy, PtrTy, IntptrTy}, false);
69206c3fb27SDimitry Andric HwasanMemsetFnTy =
6935f757f3fSDimitry Andric FunctionType::get(PtrTy, {PtrTy, Int32Ty, IntptrTy}, false);
69406c3fb27SDimitry Andric }
69506c3fb27SDimitry Andric
6960b57cec5SDimitry Andric for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
6970b57cec5SDimitry Andric const std::string TypeStr = AccessIsWrite ? "store" : "load";
6980b57cec5SDimitry Andric const std::string EndingStr = Recover ? "_noabort" : "";
6990b57cec5SDimitry Andric
7000b57cec5SDimitry Andric HwasanMemoryAccessCallbackSized[AccessIsWrite] = M.getOrInsertFunction(
70106c3fb27SDimitry Andric ClMemoryAccessCallbackPrefix + TypeStr + "N" + MatchAllStr + EndingStr,
70206c3fb27SDimitry Andric HwasanMemoryAccessCallbackSizedFnTy);
7030b57cec5SDimitry Andric
7040b57cec5SDimitry Andric for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
7050b57cec5SDimitry Andric AccessSizeIndex++) {
7060b57cec5SDimitry Andric HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
70706c3fb27SDimitry Andric M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr +
70806c3fb27SDimitry Andric itostr(1ULL << AccessSizeIndex) +
70906c3fb27SDimitry Andric MatchAllStr + EndingStr,
71006c3fb27SDimitry Andric HwasanMemoryAccessCallbackFnTy);
7110b57cec5SDimitry Andric }
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric
7140b57cec5SDimitry Andric const std::string MemIntrinCallbackPrefix =
71581ad6265SDimitry Andric (CompileKernel && !ClKasanMemIntrinCallbackPrefix)
71681ad6265SDimitry Andric ? std::string("")
71781ad6265SDimitry Andric : ClMemoryAccessCallbackPrefix;
7180b57cec5SDimitry Andric
71906c3fb27SDimitry Andric HwasanMemmove = M.getOrInsertFunction(
72006c3fb27SDimitry Andric MemIntrinCallbackPrefix + "memmove" + MatchAllStr, HwasanMemTransferFnTy);
72106c3fb27SDimitry Andric HwasanMemcpy = M.getOrInsertFunction(
72206c3fb27SDimitry Andric MemIntrinCallbackPrefix + "memcpy" + MatchAllStr, HwasanMemTransferFnTy);
72306c3fb27SDimitry Andric HwasanMemset = M.getOrInsertFunction(
72406c3fb27SDimitry Andric MemIntrinCallbackPrefix + "memset" + MatchAllStr, HwasanMemsetFnTy);
72506c3fb27SDimitry Andric
72606c3fb27SDimitry Andric HwasanTagMemoryFunc = M.getOrInsertFunction("__hwasan_tag_memory", VoidTy,
7275f757f3fSDimitry Andric PtrTy, Int8Ty, IntptrTy);
72806c3fb27SDimitry Andric HwasanGenerateTagFunc =
72906c3fb27SDimitry Andric M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty);
73006c3fb27SDimitry Andric
73106c3fb27SDimitry Andric HwasanRecordFrameRecordFunc =
73206c3fb27SDimitry Andric M.getOrInsertFunction("__hwasan_add_frame_record", VoidTy, Int64Ty);
73306c3fb27SDimitry Andric
73406c3fb27SDimitry Andric ShadowGlobal =
73506c3fb27SDimitry Andric M.getOrInsertGlobal("__hwasan_shadow", ArrayType::get(Int8Ty, 0));
73606c3fb27SDimitry Andric
73706c3fb27SDimitry Andric HwasanHandleVfork =
73806c3fb27SDimitry Andric M.getOrInsertFunction("__hwasan_handle_vfork", VoidTy, IntptrTy);
7390b57cec5SDimitry Andric }
7400b57cec5SDimitry Andric
getOpaqueNoopCast(IRBuilder<> & IRB,Value * Val)741e8d8bef9SDimitry Andric Value *HWAddressSanitizer::getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val) {
7420b57cec5SDimitry Andric // An empty inline asm with input reg == output reg.
7430b57cec5SDimitry Andric // An opaque no-op cast, basically.
744e8d8bef9SDimitry Andric // This prevents code bloat as a result of rematerializing trivial definitions
745e8d8bef9SDimitry Andric // such as constants or global addresses at every load and store.
746e8d8bef9SDimitry Andric InlineAsm *Asm =
7475f757f3fSDimitry Andric InlineAsm::get(FunctionType::get(PtrTy, {Val->getType()}, false),
7480b57cec5SDimitry Andric StringRef(""), StringRef("=r,0"),
7490b57cec5SDimitry Andric /*hasSideEffects=*/false);
750e8d8bef9SDimitry Andric return IRB.CreateCall(Asm, {Val}, ".hwasan.shadow");
7510b57cec5SDimitry Andric }
7520b57cec5SDimitry Andric
getDynamicShadowIfunc(IRBuilder<> & IRB)753e8d8bef9SDimitry Andric Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) {
754e8d8bef9SDimitry Andric return getOpaqueNoopCast(IRB, ShadowGlobal);
755e8d8bef9SDimitry Andric }
756e8d8bef9SDimitry Andric
getShadowNonTls(IRBuilder<> & IRB)757e8d8bef9SDimitry Andric Value *HWAddressSanitizer::getShadowNonTls(IRBuilder<> &IRB) {
7580b57cec5SDimitry Andric if (Mapping.Offset != kDynamicShadowSentinel)
759e8d8bef9SDimitry Andric return getOpaqueNoopCast(
760e8d8bef9SDimitry Andric IRB, ConstantExpr::getIntToPtr(
7615f757f3fSDimitry Andric ConstantInt::get(IntptrTy, Mapping.Offset), PtrTy));
7620b57cec5SDimitry Andric
763bdd1243dSDimitry Andric if (Mapping.InGlobal)
7640b57cec5SDimitry Andric return getDynamicShadowIfunc(IRB);
765bdd1243dSDimitry Andric
7660b57cec5SDimitry Andric Value *GlobalDynamicAddress =
7670b57cec5SDimitry Andric IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
7685f757f3fSDimitry Andric kHwasanShadowMemoryDynamicAddress, PtrTy);
7695f757f3fSDimitry Andric return IRB.CreateLoad(PtrTy, GlobalDynamicAddress);
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric
ignoreAccessWithoutRemark(Instruction * Inst,Value * Ptr)772*0fca6ea1SDimitry Andric bool HWAddressSanitizer::ignoreAccessWithoutRemark(Instruction *Inst,
773*0fca6ea1SDimitry Andric Value *Ptr) {
774bdd1243dSDimitry Andric // Do not instrument accesses from different address spaces; we cannot deal
7750b57cec5SDimitry Andric // with them.
7765ffd83dbSDimitry Andric Type *PtrTy = cast<PointerType>(Ptr->getType()->getScalarType());
7770b57cec5SDimitry Andric if (PtrTy->getPointerAddressSpace() != 0)
7785ffd83dbSDimitry Andric return true;
7790b57cec5SDimitry Andric
7800b57cec5SDimitry Andric // Ignore swifterror addresses.
7810b57cec5SDimitry Andric // swifterror memory addresses are mem2reg promoted by instruction
7820b57cec5SDimitry Andric // selection. As such they cannot have regular uses like an instrumentation
7830b57cec5SDimitry Andric // function and it makes no sense to track them as memory.
7845ffd83dbSDimitry Andric if (Ptr->isSwiftError())
7855ffd83dbSDimitry Andric return true;
7865ffd83dbSDimitry Andric
787349cc55cSDimitry Andric if (findAllocaForValue(Ptr)) {
788349cc55cSDimitry Andric if (!InstrumentStack)
789349cc55cSDimitry Andric return true;
790349cc55cSDimitry Andric if (SSI && SSI->stackAccessIsSafe(*Inst))
791349cc55cSDimitry Andric return true;
792349cc55cSDimitry Andric }
793*0fca6ea1SDimitry Andric
794*0fca6ea1SDimitry Andric if (isa<GlobalVariable>(getUnderlyingObject(Ptr))) {
795*0fca6ea1SDimitry Andric if (!InstrumentGlobals)
796*0fca6ea1SDimitry Andric return true;
797*0fca6ea1SDimitry Andric // TODO: Optimize inbound global accesses, like Asan `instrumentMop`.
798*0fca6ea1SDimitry Andric }
799*0fca6ea1SDimitry Andric
8005ffd83dbSDimitry Andric return false;
8010b57cec5SDimitry Andric }
8020b57cec5SDimitry Andric
ignoreAccess(OptimizationRemarkEmitter & ORE,Instruction * Inst,Value * Ptr)803*0fca6ea1SDimitry Andric bool HWAddressSanitizer::ignoreAccess(OptimizationRemarkEmitter &ORE,
804*0fca6ea1SDimitry Andric Instruction *Inst, Value *Ptr) {
805*0fca6ea1SDimitry Andric bool Ignored = ignoreAccessWithoutRemark(Inst, Ptr);
806*0fca6ea1SDimitry Andric if (Ignored) {
807*0fca6ea1SDimitry Andric ORE.emit(
808*0fca6ea1SDimitry Andric [&]() { return OptimizationRemark(DEBUG_TYPE, "ignoreAccess", Inst); });
809*0fca6ea1SDimitry Andric } else {
810*0fca6ea1SDimitry Andric ORE.emit([&]() {
811*0fca6ea1SDimitry Andric return OptimizationRemarkMissed(DEBUG_TYPE, "ignoreAccess", Inst);
812*0fca6ea1SDimitry Andric });
813*0fca6ea1SDimitry Andric }
814*0fca6ea1SDimitry Andric return Ignored;
815*0fca6ea1SDimitry Andric }
816*0fca6ea1SDimitry Andric
getInterestingMemoryOperands(OptimizationRemarkEmitter & ORE,Instruction * I,const TargetLibraryInfo & TLI,SmallVectorImpl<InterestingMemoryOperand> & Interesting)8175ffd83dbSDimitry Andric void HWAddressSanitizer::getInterestingMemoryOperands(
818*0fca6ea1SDimitry Andric OptimizationRemarkEmitter &ORE, Instruction *I,
819*0fca6ea1SDimitry Andric const TargetLibraryInfo &TLI,
8205f757f3fSDimitry Andric SmallVectorImpl<InterestingMemoryOperand> &Interesting) {
8215ffd83dbSDimitry Andric // Skip memory accesses inserted by another instrumentation.
82281ad6265SDimitry Andric if (I->hasMetadata(LLVMContext::MD_nosanitize))
8235ffd83dbSDimitry Andric return;
8245ffd83dbSDimitry Andric
8255ffd83dbSDimitry Andric // Do not instrument the load fetching the dynamic shadow address.
826e8d8bef9SDimitry Andric if (ShadowBase == I)
8275ffd83dbSDimitry Andric return;
8285ffd83dbSDimitry Andric
8295ffd83dbSDimitry Andric if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
830*0fca6ea1SDimitry Andric if (!ClInstrumentReads || ignoreAccess(ORE, I, LI->getPointerOperand()))
8315ffd83dbSDimitry Andric return;
8325ffd83dbSDimitry Andric Interesting.emplace_back(I, LI->getPointerOperandIndex(), false,
8335ffd83dbSDimitry Andric LI->getType(), LI->getAlign());
8345ffd83dbSDimitry Andric } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
835*0fca6ea1SDimitry Andric if (!ClInstrumentWrites || ignoreAccess(ORE, I, SI->getPointerOperand()))
8365ffd83dbSDimitry Andric return;
8375ffd83dbSDimitry Andric Interesting.emplace_back(I, SI->getPointerOperandIndex(), true,
8385ffd83dbSDimitry Andric SI->getValueOperand()->getType(), SI->getAlign());
8395ffd83dbSDimitry Andric } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
840*0fca6ea1SDimitry Andric if (!ClInstrumentAtomics || ignoreAccess(ORE, I, RMW->getPointerOperand()))
8415ffd83dbSDimitry Andric return;
8425ffd83dbSDimitry Andric Interesting.emplace_back(I, RMW->getPointerOperandIndex(), true,
843bdd1243dSDimitry Andric RMW->getValOperand()->getType(), std::nullopt);
8445ffd83dbSDimitry Andric } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
845*0fca6ea1SDimitry Andric if (!ClInstrumentAtomics || ignoreAccess(ORE, I, XCHG->getPointerOperand()))
8465ffd83dbSDimitry Andric return;
8475ffd83dbSDimitry Andric Interesting.emplace_back(I, XCHG->getPointerOperandIndex(), true,
848bdd1243dSDimitry Andric XCHG->getCompareOperand()->getType(),
849bdd1243dSDimitry Andric std::nullopt);
850bdd1243dSDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(I)) {
851349cc55cSDimitry Andric for (unsigned ArgNo = 0; ArgNo < CI->arg_size(); ArgNo++) {
8525ffd83dbSDimitry Andric if (!ClInstrumentByval || !CI->isByValArgument(ArgNo) ||
853*0fca6ea1SDimitry Andric ignoreAccess(ORE, I, CI->getArgOperand(ArgNo)))
8545ffd83dbSDimitry Andric continue;
8555ffd83dbSDimitry Andric Type *Ty = CI->getParamByValType(ArgNo);
8565ffd83dbSDimitry Andric Interesting.emplace_back(I, ArgNo, false, Ty, Align(1));
8575ffd83dbSDimitry Andric }
8585f757f3fSDimitry Andric maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI);
8595ffd83dbSDimitry Andric }
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric
getPointerOperandIndex(Instruction * I)8620b57cec5SDimitry Andric static unsigned getPointerOperandIndex(Instruction *I) {
8630b57cec5SDimitry Andric if (LoadInst *LI = dyn_cast<LoadInst>(I))
8640b57cec5SDimitry Andric return LI->getPointerOperandIndex();
8650b57cec5SDimitry Andric if (StoreInst *SI = dyn_cast<StoreInst>(I))
8660b57cec5SDimitry Andric return SI->getPointerOperandIndex();
8670b57cec5SDimitry Andric if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))
8680b57cec5SDimitry Andric return RMW->getPointerOperandIndex();
8690b57cec5SDimitry Andric if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))
8700b57cec5SDimitry Andric return XCHG->getPointerOperandIndex();
8710b57cec5SDimitry Andric report_fatal_error("Unexpected instruction");
8720b57cec5SDimitry Andric return -1;
8730b57cec5SDimitry Andric }
8740b57cec5SDimitry Andric
TypeSizeToSizeIndex(uint32_t TypeSize)8750b57cec5SDimitry Andric static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
87606c3fb27SDimitry Andric size_t Res = llvm::countr_zero(TypeSize / 8);
8770b57cec5SDimitry Andric assert(Res < kNumberOfAccessSizes);
8780b57cec5SDimitry Andric return Res;
8790b57cec5SDimitry Andric }
8800b57cec5SDimitry Andric
untagPointerOperand(Instruction * I,Value * Addr)8810b57cec5SDimitry Andric void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
882bdd1243dSDimitry Andric if (TargetTriple.isAArch64() || TargetTriple.getArch() == Triple::x86_64 ||
883bdd1243dSDimitry Andric TargetTriple.isRISCV64())
8840b57cec5SDimitry Andric return;
8850b57cec5SDimitry Andric
8860b57cec5SDimitry Andric IRBuilder<> IRB(I);
8870b57cec5SDimitry Andric Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
8880b57cec5SDimitry Andric Value *UntaggedPtr =
8890b57cec5SDimitry Andric IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());
8900b57cec5SDimitry Andric I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
8910b57cec5SDimitry Andric }
8920b57cec5SDimitry Andric
memToShadow(Value * Mem,IRBuilder<> & IRB)8930b57cec5SDimitry Andric Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) {
8940b57cec5SDimitry Andric // Mem >> Scale
8950b57cec5SDimitry Andric Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);
8960b57cec5SDimitry Andric if (Mapping.Offset == 0)
8975f757f3fSDimitry Andric return IRB.CreateIntToPtr(Shadow, PtrTy);
8980b57cec5SDimitry Andric // (Mem >> Scale) + Offset
8997a6dacacSDimitry Andric return IRB.CreatePtrAdd(ShadowBase, Shadow);
9000b57cec5SDimitry Andric }
9010b57cec5SDimitry Andric
getAccessInfo(bool IsWrite,unsigned AccessSizeIndex)902349cc55cSDimitry Andric int64_t HWAddressSanitizer::getAccessInfo(bool IsWrite,
903349cc55cSDimitry Andric unsigned AccessSizeIndex) {
904bdd1243dSDimitry Andric return (CompileKernel << HWASanAccessInfo::CompileKernelShift) |
905bdd1243dSDimitry Andric (MatchAllTag.has_value() << HWASanAccessInfo::HasMatchAllShift) |
906bdd1243dSDimitry Andric (MatchAllTag.value_or(0) << HWASanAccessInfo::MatchAllShift) |
907bdd1243dSDimitry Andric (Recover << HWASanAccessInfo::RecoverShift) |
908bdd1243dSDimitry Andric (IsWrite << HWASanAccessInfo::IsWriteShift) |
909e8d8bef9SDimitry Andric (AccessSizeIndex << HWASanAccessInfo::AccessSizeShift);
910349cc55cSDimitry Andric }
9110b57cec5SDimitry Andric
9125f757f3fSDimitry Andric HWAddressSanitizer::ShadowTagCheckInfo
insertShadowTagCheck(Value * Ptr,Instruction * InsertBefore,DomTreeUpdater & DTU,LoopInfo * LI)9135f757f3fSDimitry Andric HWAddressSanitizer::insertShadowTagCheck(Value *Ptr, Instruction *InsertBefore,
9145f757f3fSDimitry Andric DomTreeUpdater &DTU, LoopInfo *LI) {
9155f757f3fSDimitry Andric ShadowTagCheckInfo R;
9165f757f3fSDimitry Andric
9175f757f3fSDimitry Andric IRBuilder<> IRB(InsertBefore);
9185f757f3fSDimitry Andric
9195f757f3fSDimitry Andric R.PtrLong = IRB.CreatePointerCast(Ptr, IntptrTy);
9205f757f3fSDimitry Andric R.PtrTag =
9215f757f3fSDimitry Andric IRB.CreateTrunc(IRB.CreateLShr(R.PtrLong, PointerTagShift), Int8Ty);
9225f757f3fSDimitry Andric R.AddrLong = untagPointer(IRB, R.PtrLong);
9235f757f3fSDimitry Andric Value *Shadow = memToShadow(R.AddrLong, IRB);
9245f757f3fSDimitry Andric R.MemTag = IRB.CreateLoad(Int8Ty, Shadow);
9255f757f3fSDimitry Andric Value *TagMismatch = IRB.CreateICmpNE(R.PtrTag, R.MemTag);
9265f757f3fSDimitry Andric
9275f757f3fSDimitry Andric if (MatchAllTag.has_value()) {
9285f757f3fSDimitry Andric Value *TagNotIgnored = IRB.CreateICmpNE(
9295f757f3fSDimitry Andric R.PtrTag, ConstantInt::get(R.PtrTag->getType(), *MatchAllTag));
9305f757f3fSDimitry Andric TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored);
9315f757f3fSDimitry Andric }
9325f757f3fSDimitry Andric
9335f757f3fSDimitry Andric R.TagMismatchTerm = SplitBlockAndInsertIfThen(
9345f757f3fSDimitry Andric TagMismatch, InsertBefore, false,
935*0fca6ea1SDimitry Andric MDBuilder(*C).createUnlikelyBranchWeights(), &DTU, LI);
9365f757f3fSDimitry Andric
9375f757f3fSDimitry Andric return R;
9385f757f3fSDimitry Andric }
9395f757f3fSDimitry Andric
instrumentMemAccessOutline(Value * Ptr,bool IsWrite,unsigned AccessSizeIndex,Instruction * InsertBefore,DomTreeUpdater & DTU,LoopInfo * LI)940349cc55cSDimitry Andric void HWAddressSanitizer::instrumentMemAccessOutline(Value *Ptr, bool IsWrite,
941349cc55cSDimitry Andric unsigned AccessSizeIndex,
9425f757f3fSDimitry Andric Instruction *InsertBefore,
9435f757f3fSDimitry Andric DomTreeUpdater &DTU,
9445f757f3fSDimitry Andric LoopInfo *LI) {
945349cc55cSDimitry Andric assert(!UsePageAliases);
946349cc55cSDimitry Andric const int64_t AccessInfo = getAccessInfo(IsWrite, AccessSizeIndex);
9475f757f3fSDimitry Andric
9485f757f3fSDimitry Andric if (InlineFastPath)
9495f757f3fSDimitry Andric InsertBefore =
9505f757f3fSDimitry Andric insertShadowTagCheck(Ptr, InsertBefore, DTU, LI).TagMismatchTerm;
9515f757f3fSDimitry Andric
952349cc55cSDimitry Andric IRBuilder<> IRB(InsertBefore);
9530b57cec5SDimitry Andric Module *M = IRB.GetInsertBlock()->getParent()->getParent();
954*0fca6ea1SDimitry Andric bool useFixedShadowIntrinsic = false;
955*0fca6ea1SDimitry Andric // The memaccess fixed shadow intrinsic is only supported on AArch64,
956*0fca6ea1SDimitry Andric // which allows a 16-bit immediate to be left-shifted by 32.
957*0fca6ea1SDimitry Andric // Since kShadowBaseAlignment == 32, and Linux by default will not
958*0fca6ea1SDimitry Andric // mmap above 48-bits, practically any valid shadow offset is
959*0fca6ea1SDimitry Andric // representable.
960*0fca6ea1SDimitry Andric // In particular, an offset of 4TB (1024 << 32) is representable, and
961*0fca6ea1SDimitry Andric // ought to be good enough for anybody.
962*0fca6ea1SDimitry Andric if (TargetTriple.isAArch64() && Mapping.Offset != kDynamicShadowSentinel) {
963*0fca6ea1SDimitry Andric uint16_t offset_shifted = Mapping.Offset >> 32;
964*0fca6ea1SDimitry Andric useFixedShadowIntrinsic = (uint64_t)offset_shifted << 32 == Mapping.Offset;
965*0fca6ea1SDimitry Andric }
966*0fca6ea1SDimitry Andric
967*0fca6ea1SDimitry Andric if (useFixedShadowIntrinsic)
968*0fca6ea1SDimitry Andric IRB.CreateCall(
969*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(
970*0fca6ea1SDimitry Andric M, UseShortGranules
971*0fca6ea1SDimitry Andric ? Intrinsic::hwasan_check_memaccess_shortgranules_fixedshadow
972*0fca6ea1SDimitry Andric : Intrinsic::hwasan_check_memaccess_fixedshadow),
973*0fca6ea1SDimitry Andric {Ptr, ConstantInt::get(Int32Ty, AccessInfo),
974*0fca6ea1SDimitry Andric ConstantInt::get(Int64Ty, Mapping.Offset)});
975*0fca6ea1SDimitry Andric else
9768bcb0991SDimitry Andric IRB.CreateCall(Intrinsic::getDeclaration(
9778bcb0991SDimitry Andric M, UseShortGranules
9788bcb0991SDimitry Andric ? Intrinsic::hwasan_check_memaccess_shortgranules
9798bcb0991SDimitry Andric : Intrinsic::hwasan_check_memaccess),
980e8d8bef9SDimitry Andric {ShadowBase, Ptr, ConstantInt::get(Int32Ty, AccessInfo)});
9810b57cec5SDimitry Andric }
9820b57cec5SDimitry Andric
instrumentMemAccessInline(Value * Ptr,bool IsWrite,unsigned AccessSizeIndex,Instruction * InsertBefore,DomTreeUpdater & DTU,LoopInfo * LI)983349cc55cSDimitry Andric void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite,
984349cc55cSDimitry Andric unsigned AccessSizeIndex,
9855f757f3fSDimitry Andric Instruction *InsertBefore,
9865f757f3fSDimitry Andric DomTreeUpdater &DTU,
9875f757f3fSDimitry Andric LoopInfo *LI) {
988349cc55cSDimitry Andric assert(!UsePageAliases);
989349cc55cSDimitry Andric const int64_t AccessInfo = getAccessInfo(IsWrite, AccessSizeIndex);
990349cc55cSDimitry Andric
9915f757f3fSDimitry Andric ShadowTagCheckInfo TCI = insertShadowTagCheck(Ptr, InsertBefore, DTU, LI);
9920b57cec5SDimitry Andric
9935f757f3fSDimitry Andric IRBuilder<> IRB(TCI.TagMismatchTerm);
9940b57cec5SDimitry Andric Value *OutOfShortGranuleTagRange =
9955f757f3fSDimitry Andric IRB.CreateICmpUGT(TCI.MemTag, ConstantInt::get(Int8Ty, 15));
9965f757f3fSDimitry Andric Instruction *CheckFailTerm = SplitBlockAndInsertIfThen(
9975f757f3fSDimitry Andric OutOfShortGranuleTagRange, TCI.TagMismatchTerm, !Recover,
998*0fca6ea1SDimitry Andric MDBuilder(*C).createUnlikelyBranchWeights(), &DTU, LI);
9990b57cec5SDimitry Andric
10005f757f3fSDimitry Andric IRB.SetInsertPoint(TCI.TagMismatchTerm);
10015f757f3fSDimitry Andric Value *PtrLowBits = IRB.CreateTrunc(IRB.CreateAnd(TCI.PtrLong, 15), Int8Ty);
10020b57cec5SDimitry Andric PtrLowBits = IRB.CreateAdd(
10030b57cec5SDimitry Andric PtrLowBits, ConstantInt::get(Int8Ty, (1 << AccessSizeIndex) - 1));
10045f757f3fSDimitry Andric Value *PtrLowBitsOOB = IRB.CreateICmpUGE(PtrLowBits, TCI.MemTag);
10055f757f3fSDimitry Andric SplitBlockAndInsertIfThen(PtrLowBitsOOB, TCI.TagMismatchTerm, false,
1006*0fca6ea1SDimitry Andric MDBuilder(*C).createUnlikelyBranchWeights(), &DTU,
10075f757f3fSDimitry Andric LI, CheckFailTerm->getParent());
10080b57cec5SDimitry Andric
10095f757f3fSDimitry Andric IRB.SetInsertPoint(TCI.TagMismatchTerm);
10105f757f3fSDimitry Andric Value *InlineTagAddr = IRB.CreateOr(TCI.AddrLong, 15);
10115f757f3fSDimitry Andric InlineTagAddr = IRB.CreateIntToPtr(InlineTagAddr, PtrTy);
10120b57cec5SDimitry Andric Value *InlineTag = IRB.CreateLoad(Int8Ty, InlineTagAddr);
10135f757f3fSDimitry Andric Value *InlineTagMismatch = IRB.CreateICmpNE(TCI.PtrTag, InlineTag);
10145f757f3fSDimitry Andric SplitBlockAndInsertIfThen(InlineTagMismatch, TCI.TagMismatchTerm, false,
1015*0fca6ea1SDimitry Andric MDBuilder(*C).createUnlikelyBranchWeights(), &DTU,
10165f757f3fSDimitry Andric LI, CheckFailTerm->getParent());
10170b57cec5SDimitry Andric
10180b57cec5SDimitry Andric IRB.SetInsertPoint(CheckFailTerm);
10190b57cec5SDimitry Andric InlineAsm *Asm;
10200b57cec5SDimitry Andric switch (TargetTriple.getArch()) {
10210b57cec5SDimitry Andric case Triple::x86_64:
10220b57cec5SDimitry Andric // The signal handler will find the data address in rdi.
10230b57cec5SDimitry Andric Asm = InlineAsm::get(
10245f757f3fSDimitry Andric FunctionType::get(VoidTy, {TCI.PtrLong->getType()}, false),
1025e8d8bef9SDimitry Andric "int3\nnopl " +
1026e8d8bef9SDimitry Andric itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)) +
1027e8d8bef9SDimitry Andric "(%rax)",
10280b57cec5SDimitry Andric "{rdi}",
10290b57cec5SDimitry Andric /*hasSideEffects=*/true);
10300b57cec5SDimitry Andric break;
10310b57cec5SDimitry Andric case Triple::aarch64:
10320b57cec5SDimitry Andric case Triple::aarch64_be:
10330b57cec5SDimitry Andric // The signal handler will find the data address in x0.
10340b57cec5SDimitry Andric Asm = InlineAsm::get(
10355f757f3fSDimitry Andric FunctionType::get(VoidTy, {TCI.PtrLong->getType()}, false),
1036fe6060f1SDimitry Andric "brk #" + itostr(0x900 + (AccessInfo & HWASanAccessInfo::RuntimeMask)),
10370b57cec5SDimitry Andric "{x0}",
10380b57cec5SDimitry Andric /*hasSideEffects=*/true);
10390b57cec5SDimitry Andric break;
1040bdd1243dSDimitry Andric case Triple::riscv64:
1041bdd1243dSDimitry Andric // The signal handler will find the data address in x10.
1042bdd1243dSDimitry Andric Asm = InlineAsm::get(
10435f757f3fSDimitry Andric FunctionType::get(VoidTy, {TCI.PtrLong->getType()}, false),
1044bdd1243dSDimitry Andric "ebreak\naddiw x0, x11, " +
1045bdd1243dSDimitry Andric itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)),
1046bdd1243dSDimitry Andric "{x10}",
1047bdd1243dSDimitry Andric /*hasSideEffects=*/true);
1048bdd1243dSDimitry Andric break;
10490b57cec5SDimitry Andric default:
10500b57cec5SDimitry Andric report_fatal_error("unsupported architecture");
10510b57cec5SDimitry Andric }
10525f757f3fSDimitry Andric IRB.CreateCall(Asm, TCI.PtrLong);
10530b57cec5SDimitry Andric if (Recover)
10545f757f3fSDimitry Andric cast<BranchInst>(CheckFailTerm)
10555f757f3fSDimitry Andric ->setSuccessor(0, TCI.TagMismatchTerm->getParent());
10560b57cec5SDimitry Andric }
10570b57cec5SDimitry Andric
ignoreMemIntrinsic(OptimizationRemarkEmitter & ORE,MemIntrinsic * MI)1058*0fca6ea1SDimitry Andric bool HWAddressSanitizer::ignoreMemIntrinsic(OptimizationRemarkEmitter &ORE,
1059*0fca6ea1SDimitry Andric MemIntrinsic *MI) {
1060349cc55cSDimitry Andric if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI)) {
1061*0fca6ea1SDimitry Andric return (!ClInstrumentWrites || ignoreAccess(ORE, MTI, MTI->getDest())) &&
1062*0fca6ea1SDimitry Andric (!ClInstrumentReads || ignoreAccess(ORE, MTI, MTI->getSource()));
1063349cc55cSDimitry Andric }
1064349cc55cSDimitry Andric if (isa<MemSetInst>(MI))
1065*0fca6ea1SDimitry Andric return !ClInstrumentWrites || ignoreAccess(ORE, MI, MI->getDest());
1066349cc55cSDimitry Andric return false;
1067349cc55cSDimitry Andric }
1068349cc55cSDimitry Andric
instrumentMemIntrinsic(MemIntrinsic * MI)10690b57cec5SDimitry Andric void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
10700b57cec5SDimitry Andric IRBuilder<> IRB(MI);
10710b57cec5SDimitry Andric if (isa<MemTransferInst>(MI)) {
10725f757f3fSDimitry Andric SmallVector<Value *, 4> Args{
10735f757f3fSDimitry Andric MI->getOperand(0), MI->getOperand(1),
10745f757f3fSDimitry Andric IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)};
10755f757f3fSDimitry Andric
10765f757f3fSDimitry Andric if (UseMatchAllCallback)
10775f757f3fSDimitry Andric Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));
10785f757f3fSDimitry Andric IRB.CreateCall(isa<MemMoveInst>(MI) ? HwasanMemmove : HwasanMemcpy, Args);
10790b57cec5SDimitry Andric } else if (isa<MemSetInst>(MI)) {
10805f757f3fSDimitry Andric SmallVector<Value *, 4> Args{
10815f757f3fSDimitry Andric MI->getOperand(0),
108206c3fb27SDimitry Andric IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
10835f757f3fSDimitry Andric IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)};
10845f757f3fSDimitry Andric if (UseMatchAllCallback)
10855f757f3fSDimitry Andric Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));
10865f757f3fSDimitry Andric IRB.CreateCall(HwasanMemset, Args);
108706c3fb27SDimitry Andric }
10880b57cec5SDimitry Andric MI->eraseFromParent();
10890b57cec5SDimitry Andric }
10900b57cec5SDimitry Andric
instrumentMemAccess(InterestingMemoryOperand & O,DomTreeUpdater & DTU,LoopInfo * LI)10915f757f3fSDimitry Andric bool HWAddressSanitizer::instrumentMemAccess(InterestingMemoryOperand &O,
10925f757f3fSDimitry Andric DomTreeUpdater &DTU,
10935f757f3fSDimitry Andric LoopInfo *LI) {
10945ffd83dbSDimitry Andric Value *Addr = O.getPtr();
10950b57cec5SDimitry Andric
10965ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Instrumenting: " << O.getInsn() << "\n");
10970b57cec5SDimitry Andric
10985ffd83dbSDimitry Andric if (O.MaybeMask)
10990b57cec5SDimitry Andric return false; // FIXME
11000b57cec5SDimitry Andric
11015ffd83dbSDimitry Andric IRBuilder<> IRB(O.getInsn());
110206c3fb27SDimitry Andric if (!O.TypeStoreSize.isScalable() && isPowerOf2_64(O.TypeStoreSize) &&
110306c3fb27SDimitry Andric (O.TypeStoreSize / 8 <= (1ULL << (kNumberOfAccessSizes - 1))) &&
1104bdd1243dSDimitry Andric (!O.Alignment || *O.Alignment >= Mapping.getObjectAlignment() ||
110506c3fb27SDimitry Andric *O.Alignment >= O.TypeStoreSize / 8)) {
110606c3fb27SDimitry Andric size_t AccessSizeIndex = TypeSizeToSizeIndex(O.TypeStoreSize);
1107fe6060f1SDimitry Andric if (InstrumentWithCalls) {
11085f757f3fSDimitry Andric SmallVector<Value *, 2> Args{IRB.CreatePointerCast(Addr, IntptrTy)};
11095f757f3fSDimitry Andric if (UseMatchAllCallback)
11105f757f3fSDimitry Andric Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));
111106c3fb27SDimitry Andric IRB.CreateCall(HwasanMemoryAccessCallback[O.IsWrite][AccessSizeIndex],
11125f757f3fSDimitry Andric Args);
1113349cc55cSDimitry Andric } else if (OutlinedChecks) {
11145f757f3fSDimitry Andric instrumentMemAccessOutline(Addr, O.IsWrite, AccessSizeIndex, O.getInsn(),
11155f757f3fSDimitry Andric DTU, LI);
11160b57cec5SDimitry Andric } else {
11175f757f3fSDimitry Andric instrumentMemAccessInline(Addr, O.IsWrite, AccessSizeIndex, O.getInsn(),
11185f757f3fSDimitry Andric DTU, LI);
11190b57cec5SDimitry Andric }
11200b57cec5SDimitry Andric } else {
11215f757f3fSDimitry Andric SmallVector<Value *, 3> Args{
11225f757f3fSDimitry Andric IRB.CreatePointerCast(Addr, IntptrTy),
112306c3fb27SDimitry Andric IRB.CreateUDiv(IRB.CreateTypeSize(IntptrTy, O.TypeStoreSize),
11245f757f3fSDimitry Andric ConstantInt::get(IntptrTy, 8))};
11255f757f3fSDimitry Andric if (UseMatchAllCallback)
11265f757f3fSDimitry Andric Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));
11275f757f3fSDimitry Andric IRB.CreateCall(HwasanMemoryAccessCallbackSized[O.IsWrite], Args);
11280b57cec5SDimitry Andric }
11295ffd83dbSDimitry Andric untagPointerOperand(O.getInsn(), Addr);
11300b57cec5SDimitry Andric
11310b57cec5SDimitry Andric return true;
11320b57cec5SDimitry Andric }
11330b57cec5SDimitry Andric
tagAlloca(IRBuilder<> & IRB,AllocaInst * AI,Value * Tag,size_t Size)1134349cc55cSDimitry Andric void HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag,
1135fe6060f1SDimitry Andric size_t Size) {
11368bcb0991SDimitry Andric size_t AlignedSize = alignTo(Size, Mapping.getObjectAlignment());
11378bcb0991SDimitry Andric if (!UseShortGranules)
11388bcb0991SDimitry Andric Size = AlignedSize;
11390b57cec5SDimitry Andric
114006c3fb27SDimitry Andric Tag = IRB.CreateTrunc(Tag, Int8Ty);
1141fe6060f1SDimitry Andric if (InstrumentWithCalls) {
11420b57cec5SDimitry Andric IRB.CreateCall(HwasanTagMemoryFunc,
11435f757f3fSDimitry Andric {IRB.CreatePointerCast(AI, PtrTy), Tag,
11440b57cec5SDimitry Andric ConstantInt::get(IntptrTy, AlignedSize)});
11450b57cec5SDimitry Andric } else {
11460b57cec5SDimitry Andric size_t ShadowSize = Size >> Mapping.Scale;
114706c3fb27SDimitry Andric Value *AddrLong = untagPointer(IRB, IRB.CreatePointerCast(AI, IntptrTy));
114806c3fb27SDimitry Andric Value *ShadowPtr = memToShadow(AddrLong, IRB);
11490b57cec5SDimitry Andric // If this memset is not inlined, it will be intercepted in the hwasan
11500b57cec5SDimitry Andric // runtime library. That's OK, because the interceptor skips the checks if
11510b57cec5SDimitry Andric // the address is in the shadow region.
11520b57cec5SDimitry Andric // FIXME: the interceptor is not as fast as real memset. Consider lowering
11530b57cec5SDimitry Andric // llvm.memset right here into either a sequence of stores, or a call to
11540b57cec5SDimitry Andric // hwasan_tag_memory.
11550b57cec5SDimitry Andric if (ShadowSize)
115606c3fb27SDimitry Andric IRB.CreateMemSet(ShadowPtr, Tag, ShadowSize, Align(1));
11570b57cec5SDimitry Andric if (Size != AlignedSize) {
1158bdd1243dSDimitry Andric const uint8_t SizeRemainder = Size % Mapping.getObjectAlignment().value();
1159bdd1243dSDimitry Andric IRB.CreateStore(ConstantInt::get(Int8Ty, SizeRemainder),
11600b57cec5SDimitry Andric IRB.CreateConstGEP1_32(Int8Ty, ShadowPtr, ShadowSize));
11615f757f3fSDimitry Andric IRB.CreateStore(
11625f757f3fSDimitry Andric Tag, IRB.CreateConstGEP1_32(Int8Ty, IRB.CreatePointerCast(AI, PtrTy),
11630b57cec5SDimitry Andric AlignedSize - 1));
11640b57cec5SDimitry Andric }
11650b57cec5SDimitry Andric }
11660b57cec5SDimitry Andric }
11670b57cec5SDimitry Andric
retagMask(unsigned AllocaNo)1168fe6060f1SDimitry Andric unsigned HWAddressSanitizer::retagMask(unsigned AllocaNo) {
1169fe6060f1SDimitry Andric if (TargetTriple.getArch() == Triple::x86_64)
1170fe6060f1SDimitry Andric return AllocaNo & TagMaskByte;
1171fe6060f1SDimitry Andric
11720b57cec5SDimitry Andric // A list of 8-bit numbers that have at most one run of non-zero bits.
11730b57cec5SDimitry Andric // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
11740b57cec5SDimitry Andric // masks.
11750b57cec5SDimitry Andric // The list does not include the value 255, which is used for UAR.
11760b57cec5SDimitry Andric //
11770b57cec5SDimitry Andric // Because we are more likely to use earlier elements of this list than later
11780b57cec5SDimitry Andric // ones, it is sorted in increasing order of probability of collision with a
11790b57cec5SDimitry Andric // mask allocated (temporally) nearby. The program that generated this list
11800b57cec5SDimitry Andric // can be found at:
11810b57cec5SDimitry Andric // https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/sort_masks.py
118206c3fb27SDimitry Andric static const unsigned FastMasks[] = {
118306c3fb27SDimitry Andric 0, 128, 64, 192, 32, 96, 224, 112, 240, 48, 16, 120,
118406c3fb27SDimitry Andric 248, 56, 24, 8, 124, 252, 60, 28, 12, 4, 126, 254,
118506c3fb27SDimitry Andric 62, 30, 14, 6, 2, 127, 63, 31, 15, 7, 3, 1};
1186bdd1243dSDimitry Andric return FastMasks[AllocaNo % std::size(FastMasks)];
11870b57cec5SDimitry Andric }
11880b57cec5SDimitry Andric
applyTagMask(IRBuilder<> & IRB,Value * OldTag)1189fe6060f1SDimitry Andric Value *HWAddressSanitizer::applyTagMask(IRBuilder<> &IRB, Value *OldTag) {
119006c3fb27SDimitry Andric if (TagMaskByte == 0xFF)
119106c3fb27SDimitry Andric return OldTag; // No need to clear the tag byte.
119206c3fb27SDimitry Andric return IRB.CreateAnd(OldTag,
119306c3fb27SDimitry Andric ConstantInt::get(OldTag->getType(), TagMaskByte));
1194fe6060f1SDimitry Andric }
1195fe6060f1SDimitry Andric
getNextTagWithCall(IRBuilder<> & IRB)11960b57cec5SDimitry Andric Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {
11970b57cec5SDimitry Andric return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);
11980b57cec5SDimitry Andric }
11990b57cec5SDimitry Andric
getStackBaseTag(IRBuilder<> & IRB)12000b57cec5SDimitry Andric Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {
12010b57cec5SDimitry Andric if (ClGenerateTagsWithCalls)
120206c3fb27SDimitry Andric return nullptr;
12030b57cec5SDimitry Andric if (StackBaseTag)
12040b57cec5SDimitry Andric return StackBaseTag;
12050b57cec5SDimitry Andric // Extract some entropy from the stack pointer for the tags.
12060b57cec5SDimitry Andric // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
12070b57cec5SDimitry Andric // between functions).
1208*0fca6ea1SDimitry Andric Value *FramePointerLong = getCachedFP(IRB);
12090b57cec5SDimitry Andric Value *StackTag =
1210*0fca6ea1SDimitry Andric applyTagMask(IRB, IRB.CreateXor(FramePointerLong,
1211*0fca6ea1SDimitry Andric IRB.CreateLShr(FramePointerLong, 20)));
1212fe6060f1SDimitry Andric StackTag->setName("hwasan.stack.base.tag");
12130b57cec5SDimitry Andric return StackTag;
12140b57cec5SDimitry Andric }
12150b57cec5SDimitry Andric
getAllocaTag(IRBuilder<> & IRB,Value * StackTag,unsigned AllocaNo)12160b57cec5SDimitry Andric Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
121706c3fb27SDimitry Andric unsigned AllocaNo) {
12180b57cec5SDimitry Andric if (ClGenerateTagsWithCalls)
12190b57cec5SDimitry Andric return getNextTagWithCall(IRB);
122006c3fb27SDimitry Andric return IRB.CreateXor(
122106c3fb27SDimitry Andric StackTag, ConstantInt::get(StackTag->getType(), retagMask(AllocaNo)));
12220b57cec5SDimitry Andric }
12230b57cec5SDimitry Andric
getUARTag(IRBuilder<> & IRB)122406c3fb27SDimitry Andric Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB) {
1225*0fca6ea1SDimitry Andric Value *FramePointerLong = getCachedFP(IRB);
122606c3fb27SDimitry Andric Value *UARTag =
1227*0fca6ea1SDimitry Andric applyTagMask(IRB, IRB.CreateLShr(FramePointerLong, PointerTagShift));
122806c3fb27SDimitry Andric
122906c3fb27SDimitry Andric UARTag->setName("hwasan.uar.tag");
123006c3fb27SDimitry Andric return UARTag;
12310b57cec5SDimitry Andric }
12320b57cec5SDimitry Andric
12330b57cec5SDimitry Andric // Add a tag to an address.
tagPointer(IRBuilder<> & IRB,Type * Ty,Value * PtrLong,Value * Tag)12340b57cec5SDimitry Andric Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,
12350b57cec5SDimitry Andric Value *PtrLong, Value *Tag) {
1236fe6060f1SDimitry Andric assert(!UsePageAliases);
12370b57cec5SDimitry Andric Value *TaggedPtrLong;
12380b57cec5SDimitry Andric if (CompileKernel) {
12390b57cec5SDimitry Andric // Kernel addresses have 0xFF in the most significant byte.
1240fe6060f1SDimitry Andric Value *ShiftedTag =
1241fe6060f1SDimitry Andric IRB.CreateOr(IRB.CreateShl(Tag, PointerTagShift),
1242fe6060f1SDimitry Andric ConstantInt::get(IntptrTy, (1ULL << PointerTagShift) - 1));
12430b57cec5SDimitry Andric TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);
12440b57cec5SDimitry Andric } else {
1245fe6060f1SDimitry Andric // Userspace can simply do OR (tag << PointerTagShift);
1246fe6060f1SDimitry Andric Value *ShiftedTag = IRB.CreateShl(Tag, PointerTagShift);
12470b57cec5SDimitry Andric TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);
12480b57cec5SDimitry Andric }
12490b57cec5SDimitry Andric return IRB.CreateIntToPtr(TaggedPtrLong, Ty);
12500b57cec5SDimitry Andric }
12510b57cec5SDimitry Andric
12520b57cec5SDimitry Andric // Remove tag from an address.
untagPointer(IRBuilder<> & IRB,Value * PtrLong)12530b57cec5SDimitry Andric Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {
1254fe6060f1SDimitry Andric assert(!UsePageAliases);
12550b57cec5SDimitry Andric Value *UntaggedPtrLong;
12560b57cec5SDimitry Andric if (CompileKernel) {
12570b57cec5SDimitry Andric // Kernel addresses have 0xFF in the most significant byte.
1258fe6060f1SDimitry Andric UntaggedPtrLong =
1259fe6060f1SDimitry Andric IRB.CreateOr(PtrLong, ConstantInt::get(PtrLong->getType(),
126006c3fb27SDimitry Andric TagMaskByte << PointerTagShift));
12610b57cec5SDimitry Andric } else {
12620b57cec5SDimitry Andric // Userspace addresses have 0x00.
126306c3fb27SDimitry Andric UntaggedPtrLong = IRB.CreateAnd(
126406c3fb27SDimitry Andric PtrLong, ConstantInt::get(PtrLong->getType(),
126506c3fb27SDimitry Andric ~(TagMaskByte << PointerTagShift)));
12660b57cec5SDimitry Andric }
12670b57cec5SDimitry Andric return UntaggedPtrLong;
12680b57cec5SDimitry Andric }
12690b57cec5SDimitry Andric
getHwasanThreadSlotPtr(IRBuilder<> & IRB)1270*0fca6ea1SDimitry Andric Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB) {
12710b57cec5SDimitry Andric // Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER
1272*0fca6ea1SDimitry Andric // in Bionic's libc/platform/bionic/tls_defines.h.
1273*0fca6ea1SDimitry Andric constexpr int SanitizerSlot = 6;
1274*0fca6ea1SDimitry Andric if (TargetTriple.isAArch64() && TargetTriple.isAndroid())
1275*0fca6ea1SDimitry Andric return memtag::getAndroidSlotPtr(IRB, SanitizerSlot);
12760b57cec5SDimitry Andric return ThreadPtrGlobal;
12770b57cec5SDimitry Andric }
12780b57cec5SDimitry Andric
getCachedFP(IRBuilder<> & IRB)1279*0fca6ea1SDimitry Andric Value *HWAddressSanitizer::getCachedFP(IRBuilder<> &IRB) {
1280*0fca6ea1SDimitry Andric if (!CachedFP)
1281*0fca6ea1SDimitry Andric CachedFP = memtag::getFP(IRB);
1282*0fca6ea1SDimitry Andric return CachedFP;
128381ad6265SDimitry Andric }
128481ad6265SDimitry Andric
getFrameRecordInfo(IRBuilder<> & IRB)1285753f127fSDimitry Andric Value *HWAddressSanitizer::getFrameRecordInfo(IRBuilder<> &IRB) {
12860b57cec5SDimitry Andric // Prepare ring buffer data.
1287*0fca6ea1SDimitry Andric Value *PC = memtag::getPC(TargetTriple, IRB);
1288*0fca6ea1SDimitry Andric Value *FP = getCachedFP(IRB);
128981ad6265SDimitry Andric
1290*0fca6ea1SDimitry Andric // Mix FP and PC.
12910b57cec5SDimitry Andric // Assumptions:
12920b57cec5SDimitry Andric // PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)
1293*0fca6ea1SDimitry Andric // FP is 0xfffffffffffFFFF0 (4 lower bits are zero)
1294*0fca6ea1SDimitry Andric // We only really need ~20 lower non-zero bits (FFFF), so we mix like this:
1295*0fca6ea1SDimitry Andric // 0xFFFFPPPPPPPPPPPP
1296*0fca6ea1SDimitry Andric //
1297*0fca6ea1SDimitry Andric // FP works because in AArch64FrameLowering::getFrameIndexReference, we
1298*0fca6ea1SDimitry Andric // prefer FP-relative offsets for functions compiled with HWASan.
1299*0fca6ea1SDimitry Andric FP = IRB.CreateShl(FP, 44);
1300*0fca6ea1SDimitry Andric return IRB.CreateOr(PC, FP);
1301753f127fSDimitry Andric }
1302753f127fSDimitry Andric
emitPrologue(IRBuilder<> & IRB,bool WithFrameRecord)1303753f127fSDimitry Andric void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) {
1304753f127fSDimitry Andric if (!Mapping.InTls)
1305753f127fSDimitry Andric ShadowBase = getShadowNonTls(IRB);
1306753f127fSDimitry Andric else if (!WithFrameRecord && TargetTriple.isAndroid())
1307753f127fSDimitry Andric ShadowBase = getDynamicShadowIfunc(IRB);
1308753f127fSDimitry Andric
1309753f127fSDimitry Andric if (!WithFrameRecord && ShadowBase)
1310753f127fSDimitry Andric return;
1311753f127fSDimitry Andric
1312753f127fSDimitry Andric Value *SlotPtr = nullptr;
1313753f127fSDimitry Andric Value *ThreadLong = nullptr;
1314753f127fSDimitry Andric Value *ThreadLongMaybeUntagged = nullptr;
1315753f127fSDimitry Andric
1316753f127fSDimitry Andric auto getThreadLongMaybeUntagged = [&]() {
1317753f127fSDimitry Andric if (!SlotPtr)
1318*0fca6ea1SDimitry Andric SlotPtr = getHwasanThreadSlotPtr(IRB);
1319753f127fSDimitry Andric if (!ThreadLong)
1320753f127fSDimitry Andric ThreadLong = IRB.CreateLoad(IntptrTy, SlotPtr);
1321753f127fSDimitry Andric // Extract the address field from ThreadLong. Unnecessary on AArch64 with
1322753f127fSDimitry Andric // TBI.
1323753f127fSDimitry Andric return TargetTriple.isAArch64() ? ThreadLong
1324753f127fSDimitry Andric : untagPointer(IRB, ThreadLong);
1325753f127fSDimitry Andric };
1326753f127fSDimitry Andric
1327753f127fSDimitry Andric if (WithFrameRecord) {
1328753f127fSDimitry Andric switch (ClRecordStackHistory) {
1329753f127fSDimitry Andric case libcall: {
1330753f127fSDimitry Andric // Emit a runtime call into hwasan rather than emitting instructions for
1331753f127fSDimitry Andric // recording stack history.
1332753f127fSDimitry Andric Value *FrameRecordInfo = getFrameRecordInfo(IRB);
1333753f127fSDimitry Andric IRB.CreateCall(HwasanRecordFrameRecordFunc, {FrameRecordInfo});
1334753f127fSDimitry Andric break;
1335753f127fSDimitry Andric }
1336753f127fSDimitry Andric case instr: {
1337753f127fSDimitry Andric ThreadLongMaybeUntagged = getThreadLongMaybeUntagged();
1338753f127fSDimitry Andric
1339753f127fSDimitry Andric StackBaseTag = IRB.CreateAShr(ThreadLong, 3);
13400b57cec5SDimitry Andric
13410b57cec5SDimitry Andric // Store data to ring buffer.
1342753f127fSDimitry Andric Value *FrameRecordInfo = getFrameRecordInfo(IRB);
13435f757f3fSDimitry Andric Value *RecordPtr =
13445f757f3fSDimitry Andric IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IRB.getPtrTy(0));
1345753f127fSDimitry Andric IRB.CreateStore(FrameRecordInfo, RecordPtr);
13460b57cec5SDimitry Andric
13470b57cec5SDimitry Andric // Update the ring buffer. Top byte of ThreadLong defines the size of the
13480b57cec5SDimitry Andric // buffer in pages, it must be a power of two, and the start of the buffer
13490b57cec5SDimitry Andric // must be aligned by twice that much. Therefore wrap around of the ring
13500b57cec5SDimitry Andric // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
13510b57cec5SDimitry Andric // The use of AShr instead of LShr is due to
13520b57cec5SDimitry Andric // https://bugs.llvm.org/show_bug.cgi?id=39030
13530b57cec5SDimitry Andric // Runtime library makes sure not to use the highest bit.
1354*0fca6ea1SDimitry Andric //
1355*0fca6ea1SDimitry Andric // Mechanical proof of this address calculation can be found at:
1356*0fca6ea1SDimitry Andric // https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/prove_hwasanwrap.smt2
1357*0fca6ea1SDimitry Andric //
1358*0fca6ea1SDimitry Andric // Example of the wrap case for N = 1
1359*0fca6ea1SDimitry Andric // Pointer: 0x01AAAAAAAAAAAFF8
1360*0fca6ea1SDimitry Andric // +
1361*0fca6ea1SDimitry Andric // 0x0000000000000008
1362*0fca6ea1SDimitry Andric // =
1363*0fca6ea1SDimitry Andric // 0x01AAAAAAAAAAB000
1364*0fca6ea1SDimitry Andric // &
1365*0fca6ea1SDimitry Andric // WrapMask: 0xFFFFFFFFFFFFF000
1366*0fca6ea1SDimitry Andric // =
1367*0fca6ea1SDimitry Andric // 0x01AAAAAAAAAAA000
1368*0fca6ea1SDimitry Andric //
1369*0fca6ea1SDimitry Andric // Then the WrapMask will be a no-op until the next wrap case.
13700b57cec5SDimitry Andric Value *WrapMask = IRB.CreateXor(
13710b57cec5SDimitry Andric IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
13720b57cec5SDimitry Andric ConstantInt::get(IntptrTy, (uint64_t)-1));
13730b57cec5SDimitry Andric Value *ThreadLongNew = IRB.CreateAnd(
13740b57cec5SDimitry Andric IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask);
13750b57cec5SDimitry Andric IRB.CreateStore(ThreadLongNew, SlotPtr);
1376753f127fSDimitry Andric break;
1377753f127fSDimitry Andric }
1378753f127fSDimitry Andric case none: {
1379753f127fSDimitry Andric llvm_unreachable(
1380753f127fSDimitry Andric "A stack history recording mode should've been selected.");
1381753f127fSDimitry Andric }
1382753f127fSDimitry Andric }
13830b57cec5SDimitry Andric }
13840b57cec5SDimitry Andric
1385fe6060f1SDimitry Andric if (!ShadowBase) {
1386753f127fSDimitry Andric if (!ThreadLongMaybeUntagged)
1387753f127fSDimitry Andric ThreadLongMaybeUntagged = getThreadLongMaybeUntagged();
1388753f127fSDimitry Andric
13890b57cec5SDimitry Andric // Get shadow base address by aligning RecordPtr up.
13900b57cec5SDimitry Andric // Note: this is not correct if the pointer is already aligned.
13910b57cec5SDimitry Andric // Runtime library will make sure this never happens.
1392e8d8bef9SDimitry Andric ShadowBase = IRB.CreateAdd(
13930b57cec5SDimitry Andric IRB.CreateOr(
13940b57cec5SDimitry Andric ThreadLongMaybeUntagged,
13950b57cec5SDimitry Andric ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
13960b57cec5SDimitry Andric ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
13975f757f3fSDimitry Andric ShadowBase = IRB.CreateIntToPtr(ShadowBase, PtrTy);
13980b57cec5SDimitry Andric }
1399fe6060f1SDimitry Andric }
14000b57cec5SDimitry Andric
instrumentLandingPads(SmallVectorImpl<Instruction * > & LandingPadVec)14010b57cec5SDimitry Andric bool HWAddressSanitizer::instrumentLandingPads(
14020b57cec5SDimitry Andric SmallVectorImpl<Instruction *> &LandingPadVec) {
14030b57cec5SDimitry Andric for (auto *LP : LandingPadVec) {
1404*0fca6ea1SDimitry Andric IRBuilder<> IRB(LP->getNextNonDebugInstruction());
14050b57cec5SDimitry Andric IRB.CreateCall(
140606c3fb27SDimitry Andric HwasanHandleVfork,
1407*0fca6ea1SDimitry Andric {memtag::readRegister(
1408*0fca6ea1SDimitry Andric IRB, (TargetTriple.getArch() == Triple::x86_64) ? "rsp" : "sp")});
14090b57cec5SDimitry Andric }
14100b57cec5SDimitry Andric return true;
14110b57cec5SDimitry Andric }
14120b57cec5SDimitry Andric
instrumentStack(memtag::StackInfo & SInfo,Value * StackTag,Value * UARTag,const DominatorTree & DT,const PostDominatorTree & PDT,const LoopInfo & LI)141381ad6265SDimitry Andric bool HWAddressSanitizer::instrumentStack(memtag::StackInfo &SInfo,
141406c3fb27SDimitry Andric Value *StackTag, Value *UARTag,
141581ad6265SDimitry Andric const DominatorTree &DT,
141681ad6265SDimitry Andric const PostDominatorTree &PDT,
141781ad6265SDimitry Andric const LoopInfo &LI) {
14180b57cec5SDimitry Andric // Ideally, we want to calculate tagged stack base pointer, and rewrite all
14190b57cec5SDimitry Andric // alloca addresses using that. Unfortunately, offsets are not known yet
14200b57cec5SDimitry Andric // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
14210b57cec5SDimitry Andric // temp, shift-OR it into each alloca address and xor with the retag mask.
14220b57cec5SDimitry Andric // This generates one extra instruction per alloca use.
1423349cc55cSDimitry Andric unsigned int I = 0;
1424349cc55cSDimitry Andric
142581ad6265SDimitry Andric for (auto &KV : SInfo.AllocasToInstrument) {
1426349cc55cSDimitry Andric auto N = I++;
1427349cc55cSDimitry Andric auto *AI = KV.first;
142881ad6265SDimitry Andric memtag::AllocaInfo &Info = KV.second;
1429*0fca6ea1SDimitry Andric IRBuilder<> IRB(AI->getNextNonDebugInstruction());
14300b57cec5SDimitry Andric
14310b57cec5SDimitry Andric // Replace uses of the alloca with tagged address.
143206c3fb27SDimitry Andric Value *Tag = getAllocaTag(IRB, StackTag, N);
14330b57cec5SDimitry Andric Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
143406c3fb27SDimitry Andric Value *AINoTagLong = untagPointer(IRB, AILong);
143506c3fb27SDimitry Andric Value *Replacement = tagPointer(IRB, AI->getType(), AINoTagLong, Tag);
14360b57cec5SDimitry Andric std::string Name =
14370b57cec5SDimitry Andric AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
14380b57cec5SDimitry Andric Replacement->setName(Name + ".hwasan");
14390b57cec5SDimitry Andric
144081ad6265SDimitry Andric size_t Size = memtag::getAllocaSizeInBytes(*AI);
144181ad6265SDimitry Andric size_t AlignedSize = alignTo(Size, Mapping.getObjectAlignment());
14420b57cec5SDimitry Andric
14435f757f3fSDimitry Andric Value *AICast = IRB.CreatePointerCast(AI, PtrTy);
144481ad6265SDimitry Andric
144581ad6265SDimitry Andric auto HandleLifetime = [&](IntrinsicInst *II) {
144681ad6265SDimitry Andric // Set the lifetime intrinsic to cover the whole alloca. This reduces the
144781ad6265SDimitry Andric // set of assumptions we need to make about the lifetime. Without this we
144881ad6265SDimitry Andric // would need to ensure that we can track the lifetime pointer to a
144981ad6265SDimitry Andric // constant offset from the alloca, and would still need to change the
145081ad6265SDimitry Andric // size to include the extra alignment we use for the untagging to make
145181ad6265SDimitry Andric // the size consistent.
145281ad6265SDimitry Andric //
145381ad6265SDimitry Andric // The check for standard lifetime below makes sure that we have exactly
145481ad6265SDimitry Andric // one set of start / end in any execution (i.e. the ends are not
145581ad6265SDimitry Andric // reachable from each other), so this will not cause any problems.
145681ad6265SDimitry Andric II->setArgOperand(0, ConstantInt::get(Int64Ty, AlignedSize));
145781ad6265SDimitry Andric II->setArgOperand(1, AICast);
145881ad6265SDimitry Andric };
145981ad6265SDimitry Andric llvm::for_each(Info.LifetimeStart, HandleLifetime);
146081ad6265SDimitry Andric llvm::for_each(Info.LifetimeEnd, HandleLifetime);
146181ad6265SDimitry Andric
146206c3fb27SDimitry Andric AI->replaceUsesWithIf(Replacement, [AICast, AILong](const Use &U) {
146381ad6265SDimitry Andric auto *User = U.getUser();
1464*0fca6ea1SDimitry Andric return User != AILong && User != AICast &&
1465*0fca6ea1SDimitry Andric !memtag::isLifetimeIntrinsic(User);
146681ad6265SDimitry Andric });
146781ad6265SDimitry Andric
1468*0fca6ea1SDimitry Andric memtag::annotateDebugRecords(Info, retagMask(N));
14690b57cec5SDimitry Andric
1470349cc55cSDimitry Andric auto TagEnd = [&](Instruction *Node) {
1471349cc55cSDimitry Andric IRB.SetInsertPoint(Node);
147281ad6265SDimitry Andric // When untagging, use the `AlignedSize` because we need to set the tags
147306c3fb27SDimitry Andric // for the entire alloca to original. If we used `Size` here, we would
147481ad6265SDimitry Andric // keep the last granule tagged, and store zero in the last byte of the
147581ad6265SDimitry Andric // last granule, due to how short granules are implemented.
1476349cc55cSDimitry Andric tagAlloca(IRB, AI, UARTag, AlignedSize);
1477349cc55cSDimitry Andric };
147881ad6265SDimitry Andric // Calls to functions that may return twice (e.g. setjmp) confuse the
147981ad6265SDimitry Andric // postdominator analysis, and will leave us to keep memory tagged after
148081ad6265SDimitry Andric // function return. Work around this by always untagging at every return
148181ad6265SDimitry Andric // statement if return_twice functions are called.
148204eeddc0SDimitry Andric bool StandardLifetime =
1483*0fca6ea1SDimitry Andric !SInfo.CallsReturnTwice &&
148481ad6265SDimitry Andric SInfo.UnrecognizedLifetimes.empty() &&
148581ad6265SDimitry Andric memtag::isStandardLifetime(Info.LifetimeStart, Info.LifetimeEnd, &DT,
1486*0fca6ea1SDimitry Andric &LI, ClMaxLifetimes);
148781ad6265SDimitry Andric if (DetectUseAfterScope && StandardLifetime) {
148804eeddc0SDimitry Andric IntrinsicInst *Start = Info.LifetimeStart[0];
148904eeddc0SDimitry Andric IRB.SetInsertPoint(Start->getNextNode());
14900b57cec5SDimitry Andric tagAlloca(IRB, AI, Tag, Size);
149181ad6265SDimitry Andric if (!memtag::forAllReachableExits(DT, PDT, LI, Start, Info.LifetimeEnd,
149281ad6265SDimitry Andric SInfo.RetVec, TagEnd)) {
1493349cc55cSDimitry Andric for (auto *End : Info.LifetimeEnd)
1494349cc55cSDimitry Andric End->eraseFromParent();
1495349cc55cSDimitry Andric }
1496349cc55cSDimitry Andric } else {
1497349cc55cSDimitry Andric tagAlloca(IRB, AI, Tag, Size);
149881ad6265SDimitry Andric for (auto *RI : SInfo.RetVec)
149904eeddc0SDimitry Andric TagEnd(RI);
150081ad6265SDimitry Andric // We inserted tagging outside of the lifetimes, so we have to remove
150181ad6265SDimitry Andric // them.
1502349cc55cSDimitry Andric for (auto &II : Info.LifetimeStart)
1503349cc55cSDimitry Andric II->eraseFromParent();
1504349cc55cSDimitry Andric for (auto &II : Info.LifetimeEnd)
1505349cc55cSDimitry Andric II->eraseFromParent();
15060b57cec5SDimitry Andric }
1507bdd1243dSDimitry Andric memtag::alignAndPadAlloca(Info, Mapping.getObjectAlignment());
15080b57cec5SDimitry Andric }
150981ad6265SDimitry Andric for (auto &I : SInfo.UnrecognizedLifetimes)
1510349cc55cSDimitry Andric I->eraseFromParent();
15110b57cec5SDimitry Andric return true;
15120b57cec5SDimitry Andric }
15130b57cec5SDimitry Andric
emitRemark(const Function & F,OptimizationRemarkEmitter & ORE,bool Skip)1514*0fca6ea1SDimitry Andric static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE,
1515*0fca6ea1SDimitry Andric bool Skip) {
1516*0fca6ea1SDimitry Andric if (Skip) {
1517*0fca6ea1SDimitry Andric ORE.emit([&]() {
1518*0fca6ea1SDimitry Andric return OptimizationRemark(DEBUG_TYPE, "Skip", &F)
1519*0fca6ea1SDimitry Andric << "Skipped: F=" << ore::NV("Function", &F);
1520*0fca6ea1SDimitry Andric });
1521*0fca6ea1SDimitry Andric } else {
1522*0fca6ea1SDimitry Andric ORE.emit([&]() {
1523*0fca6ea1SDimitry Andric return OptimizationRemarkMissed(DEBUG_TYPE, "Sanitize", &F)
1524*0fca6ea1SDimitry Andric << "Sanitized: F=" << ore::NV("Function", &F);
1525*0fca6ea1SDimitry Andric });
1526*0fca6ea1SDimitry Andric }
1527*0fca6ea1SDimitry Andric }
1528*0fca6ea1SDimitry Andric
selectiveInstrumentationShouldSkip(Function & F,FunctionAnalysisManager & FAM) const1529*0fca6ea1SDimitry Andric bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(
1530*0fca6ea1SDimitry Andric Function &F, FunctionAnalysisManager &FAM) const {
1531*0fca6ea1SDimitry Andric bool Skip = [&]() {
1532*0fca6ea1SDimitry Andric if (ClRandomSkipRate.getNumOccurrences()) {
1533*0fca6ea1SDimitry Andric std::bernoulli_distribution D(ClRandomSkipRate);
1534*0fca6ea1SDimitry Andric return !D(*Rng);
1535*0fca6ea1SDimitry Andric }
1536*0fca6ea1SDimitry Andric if (!ClHotPercentileCutoff.getNumOccurrences())
1537*0fca6ea1SDimitry Andric return false;
1538*0fca6ea1SDimitry Andric auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
1539*0fca6ea1SDimitry Andric ProfileSummaryInfo *PSI =
1540*0fca6ea1SDimitry Andric MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
1541*0fca6ea1SDimitry Andric if (!PSI || !PSI->hasProfileSummary()) {
1542*0fca6ea1SDimitry Andric ++NumNoProfileSummaryFuncs;
1543*0fca6ea1SDimitry Andric return false;
1544*0fca6ea1SDimitry Andric }
1545*0fca6ea1SDimitry Andric return PSI->isFunctionHotInCallGraphNthPercentile(
1546*0fca6ea1SDimitry Andric ClHotPercentileCutoff, &F, FAM.getResult<BlockFrequencyAnalysis>(F));
1547*0fca6ea1SDimitry Andric }();
1548*0fca6ea1SDimitry Andric emitRemark(F, FAM.getResult<OptimizationRemarkEmitterAnalysis>(F), Skip);
1549*0fca6ea1SDimitry Andric return Skip;
1550*0fca6ea1SDimitry Andric }
1551*0fca6ea1SDimitry Andric
sanitizeFunction(Function & F,FunctionAnalysisManager & FAM)155206c3fb27SDimitry Andric void HWAddressSanitizer::sanitizeFunction(Function &F,
155381ad6265SDimitry Andric FunctionAnalysisManager &FAM) {
15540b57cec5SDimitry Andric if (&F == HwasanCtorFunction)
155506c3fb27SDimitry Andric return;
15560b57cec5SDimitry Andric
15570b57cec5SDimitry Andric if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
155806c3fb27SDimitry Andric return;
15590b57cec5SDimitry Andric
1560*0fca6ea1SDimitry Andric if (F.empty())
1561*0fca6ea1SDimitry Andric return;
1562*0fca6ea1SDimitry Andric
1563*0fca6ea1SDimitry Andric NumTotalFuncs++;
1564*0fca6ea1SDimitry Andric
1565*0fca6ea1SDimitry Andric OptimizationRemarkEmitter &ORE =
1566*0fca6ea1SDimitry Andric FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
1567*0fca6ea1SDimitry Andric
1568*0fca6ea1SDimitry Andric if (selectiveInstrumentationShouldSkip(F, FAM))
1569*0fca6ea1SDimitry Andric return;
1570*0fca6ea1SDimitry Andric
1571*0fca6ea1SDimitry Andric NumInstrumentedFuncs++;
1572*0fca6ea1SDimitry Andric
15730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
15740b57cec5SDimitry Andric
15755ffd83dbSDimitry Andric SmallVector<InterestingMemoryOperand, 16> OperandsToInstrument;
15765ffd83dbSDimitry Andric SmallVector<MemIntrinsic *, 16> IntrinToInstrument;
15770b57cec5SDimitry Andric SmallVector<Instruction *, 8> LandingPadVec;
15785f757f3fSDimitry Andric const TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
157981ad6265SDimitry Andric
1580bdd1243dSDimitry Andric memtag::StackInfoBuilder SIB(SSI);
158181ad6265SDimitry Andric for (auto &Inst : instructions(F)) {
1582349cc55cSDimitry Andric if (InstrumentStack) {
158381ad6265SDimitry Andric SIB.visit(Inst);
1584fe6060f1SDimitry Andric }
15850b57cec5SDimitry Andric
15868bcb0991SDimitry Andric if (InstrumentLandingPads && isa<LandingPadInst>(Inst))
15870b57cec5SDimitry Andric LandingPadVec.push_back(&Inst);
15880b57cec5SDimitry Andric
1589*0fca6ea1SDimitry Andric getInterestingMemoryOperands(ORE, &Inst, TLI, OperandsToInstrument);
15905ffd83dbSDimitry Andric
15915ffd83dbSDimitry Andric if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&Inst))
1592*0fca6ea1SDimitry Andric if (!ignoreMemIntrinsic(ORE, MI))
15935ffd83dbSDimitry Andric IntrinToInstrument.push_back(MI);
15940b57cec5SDimitry Andric }
159581ad6265SDimitry Andric
159681ad6265SDimitry Andric memtag::StackInfo &SInfo = SIB.get();
15970b57cec5SDimitry Andric
15980b57cec5SDimitry Andric initializeCallbacks(*F.getParent());
15990b57cec5SDimitry Andric
16000b57cec5SDimitry Andric if (!LandingPadVec.empty())
160106c3fb27SDimitry Andric instrumentLandingPads(LandingPadVec);
16020b57cec5SDimitry Andric
160381ad6265SDimitry Andric if (SInfo.AllocasToInstrument.empty() && F.hasPersonalityFn() &&
16048bcb0991SDimitry Andric F.getPersonalityFn()->getName() == kHwasanPersonalityThunkName) {
16058bcb0991SDimitry Andric // __hwasan_personality_thunk is a no-op for functions without an
16068bcb0991SDimitry Andric // instrumented stack, so we can drop it.
16078bcb0991SDimitry Andric F.setPersonalityFn(nullptr);
16088bcb0991SDimitry Andric }
16098bcb0991SDimitry Andric
161081ad6265SDimitry Andric if (SInfo.AllocasToInstrument.empty() && OperandsToInstrument.empty() &&
16115ffd83dbSDimitry Andric IntrinToInstrument.empty())
161206c3fb27SDimitry Andric return;
16130b57cec5SDimitry Andric
1614e8d8bef9SDimitry Andric assert(!ShadowBase);
16150b57cec5SDimitry Andric
1616*0fca6ea1SDimitry Andric // Remove memory attributes that are about to become invalid.
1617*0fca6ea1SDimitry Andric // HWASan checks read from shadow, which invalidates memory(argmem: *)
1618*0fca6ea1SDimitry Andric // Short granule checks on function arguments read from the argument memory
1619*0fca6ea1SDimitry Andric // (last byte of the granule), which invalidates writeonly.
1620*0fca6ea1SDimitry Andric F.removeFnAttr(llvm::Attribute::Memory);
1621*0fca6ea1SDimitry Andric for (auto &A : F.args())
1622*0fca6ea1SDimitry Andric A.removeAttr(llvm::Attribute::WriteOnly);
1623*0fca6ea1SDimitry Andric
1624*0fca6ea1SDimitry Andric BasicBlock::iterator InsertPt = F.getEntryBlock().begin();
1625*0fca6ea1SDimitry Andric IRBuilder<> EntryIRB(&F.getEntryBlock(), InsertPt);
16260b57cec5SDimitry Andric emitPrologue(EntryIRB,
1627753f127fSDimitry Andric /*WithFrameRecord*/ ClRecordStackHistory != none &&
162881ad6265SDimitry Andric Mapping.WithFrameRecord &&
162981ad6265SDimitry Andric !SInfo.AllocasToInstrument.empty());
16300b57cec5SDimitry Andric
163181ad6265SDimitry Andric if (!SInfo.AllocasToInstrument.empty()) {
163281ad6265SDimitry Andric const DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
163381ad6265SDimitry Andric const PostDominatorTree &PDT = FAM.getResult<PostDominatorTreeAnalysis>(F);
163481ad6265SDimitry Andric const LoopInfo &LI = FAM.getResult<LoopAnalysis>(F);
163506c3fb27SDimitry Andric Value *StackTag = getStackBaseTag(EntryIRB);
163606c3fb27SDimitry Andric Value *UARTag = getUARTag(EntryIRB);
163706c3fb27SDimitry Andric instrumentStack(SInfo, StackTag, UARTag, DT, PDT, LI);
16380b57cec5SDimitry Andric }
16390b57cec5SDimitry Andric
16400b57cec5SDimitry Andric // If we split the entry block, move any allocas that were originally in the
16410b57cec5SDimitry Andric // entry block back into the entry block so that they aren't treated as
16420b57cec5SDimitry Andric // dynamic allocas.
16430b57cec5SDimitry Andric if (EntryIRB.GetInsertBlock() != &F.getEntryBlock()) {
1644*0fca6ea1SDimitry Andric InsertPt = F.getEntryBlock().begin();
1645349cc55cSDimitry Andric for (Instruction &I :
1646349cc55cSDimitry Andric llvm::make_early_inc_range(*EntryIRB.GetInsertBlock())) {
1647349cc55cSDimitry Andric if (auto *AI = dyn_cast<AllocaInst>(&I))
16480b57cec5SDimitry Andric if (isa<ConstantInt>(AI->getArraySize()))
1649*0fca6ea1SDimitry Andric I.moveBefore(F.getEntryBlock(), InsertPt);
16500b57cec5SDimitry Andric }
16510b57cec5SDimitry Andric }
16520b57cec5SDimitry Andric
16535f757f3fSDimitry Andric DominatorTree *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
16545f757f3fSDimitry Andric PostDominatorTree *PDT = FAM.getCachedResult<PostDominatorTreeAnalysis>(F);
16555f757f3fSDimitry Andric LoopInfo *LI = FAM.getCachedResult<LoopAnalysis>(F);
16565f757f3fSDimitry Andric DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
16575ffd83dbSDimitry Andric for (auto &Operand : OperandsToInstrument)
16585f757f3fSDimitry Andric instrumentMemAccess(Operand, DTU, LI);
16595f757f3fSDimitry Andric DTU.flush();
16605ffd83dbSDimitry Andric
16615ffd83dbSDimitry Andric if (ClInstrumentMemIntrinsics && !IntrinToInstrument.empty()) {
1662bdd1243dSDimitry Andric for (auto *Inst : IntrinToInstrument)
1663bdd1243dSDimitry Andric instrumentMemIntrinsic(Inst);
16645ffd83dbSDimitry Andric }
16650b57cec5SDimitry Andric
1666e8d8bef9SDimitry Andric ShadowBase = nullptr;
16670b57cec5SDimitry Andric StackBaseTag = nullptr;
1668*0fca6ea1SDimitry Andric CachedFP = nullptr;
16690b57cec5SDimitry Andric }
16700b57cec5SDimitry Andric
instrumentGlobal(GlobalVariable * GV,uint8_t Tag)16718bcb0991SDimitry Andric void HWAddressSanitizer::instrumentGlobal(GlobalVariable *GV, uint8_t Tag) {
1672fe6060f1SDimitry Andric assert(!UsePageAliases);
16738bcb0991SDimitry Andric Constant *Initializer = GV->getInitializer();
16748bcb0991SDimitry Andric uint64_t SizeInBytes =
16758bcb0991SDimitry Andric M.getDataLayout().getTypeAllocSize(Initializer->getType());
16768bcb0991SDimitry Andric uint64_t NewSize = alignTo(SizeInBytes, Mapping.getObjectAlignment());
16778bcb0991SDimitry Andric if (SizeInBytes != NewSize) {
16788bcb0991SDimitry Andric // Pad the initializer out to the next multiple of 16 bytes and add the
16798bcb0991SDimitry Andric // required short granule tag.
16808bcb0991SDimitry Andric std::vector<uint8_t> Init(NewSize - SizeInBytes, 0);
16818bcb0991SDimitry Andric Init.back() = Tag;
16828bcb0991SDimitry Andric Constant *Padding = ConstantDataArray::get(*C, Init);
16838bcb0991SDimitry Andric Initializer = ConstantStruct::getAnon({Initializer, Padding});
16848bcb0991SDimitry Andric }
16858bcb0991SDimitry Andric
16868bcb0991SDimitry Andric auto *NewGV = new GlobalVariable(M, Initializer->getType(), GV->isConstant(),
16878bcb0991SDimitry Andric GlobalValue::ExternalLinkage, Initializer,
16888bcb0991SDimitry Andric GV->getName() + ".hwasan");
16898bcb0991SDimitry Andric NewGV->copyAttributesFrom(GV);
16908bcb0991SDimitry Andric NewGV->setLinkage(GlobalValue::PrivateLinkage);
16918bcb0991SDimitry Andric NewGV->copyMetadata(GV, 0);
16928bcb0991SDimitry Andric NewGV->setAlignment(
1693bdd1243dSDimitry Andric std::max(GV->getAlign().valueOrOne(), Mapping.getObjectAlignment()));
16948bcb0991SDimitry Andric
16958bcb0991SDimitry Andric // It is invalid to ICF two globals that have different tags. In the case
16968bcb0991SDimitry Andric // where the size of the global is a multiple of the tag granularity the
16978bcb0991SDimitry Andric // contents of the globals may be the same but the tags (i.e. symbol values)
16988bcb0991SDimitry Andric // may be different, and the symbols are not considered during ICF. In the
16998bcb0991SDimitry Andric // case where the size is not a multiple of the granularity, the short granule
17008bcb0991SDimitry Andric // tags would discriminate two globals with different tags, but there would
17018bcb0991SDimitry Andric // otherwise be nothing stopping such a global from being incorrectly ICF'd
17028bcb0991SDimitry Andric // with an uninstrumented (i.e. tag 0) global that happened to have the short
17038bcb0991SDimitry Andric // granule tag in the last byte.
17048bcb0991SDimitry Andric NewGV->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
17058bcb0991SDimitry Andric
17068bcb0991SDimitry Andric // Descriptor format (assuming little-endian):
17078bcb0991SDimitry Andric // bytes 0-3: relative address of global
17088bcb0991SDimitry Andric // bytes 4-6: size of global (16MB ought to be enough for anyone, but in case
17098bcb0991SDimitry Andric // it isn't, we create multiple descriptors)
17108bcb0991SDimitry Andric // byte 7: tag
17118bcb0991SDimitry Andric auto *DescriptorTy = StructType::get(Int32Ty, Int32Ty);
17128bcb0991SDimitry Andric const uint64_t MaxDescriptorSize = 0xfffff0;
17138bcb0991SDimitry Andric for (uint64_t DescriptorPos = 0; DescriptorPos < SizeInBytes;
17148bcb0991SDimitry Andric DescriptorPos += MaxDescriptorSize) {
17158bcb0991SDimitry Andric auto *Descriptor =
17168bcb0991SDimitry Andric new GlobalVariable(M, DescriptorTy, true, GlobalValue::PrivateLinkage,
17178bcb0991SDimitry Andric nullptr, GV->getName() + ".hwasan.descriptor");
17188bcb0991SDimitry Andric auto *GVRelPtr = ConstantExpr::getTrunc(
17198bcb0991SDimitry Andric ConstantExpr::getAdd(
17208bcb0991SDimitry Andric ConstantExpr::getSub(
17218bcb0991SDimitry Andric ConstantExpr::getPtrToInt(NewGV, Int64Ty),
17228bcb0991SDimitry Andric ConstantExpr::getPtrToInt(Descriptor, Int64Ty)),
17238bcb0991SDimitry Andric ConstantInt::get(Int64Ty, DescriptorPos)),
17248bcb0991SDimitry Andric Int32Ty);
17258bcb0991SDimitry Andric uint32_t Size = std::min(SizeInBytes - DescriptorPos, MaxDescriptorSize);
17268bcb0991SDimitry Andric auto *SizeAndTag = ConstantInt::get(Int32Ty, Size | (uint32_t(Tag) << 24));
17278bcb0991SDimitry Andric Descriptor->setComdat(NewGV->getComdat());
17288bcb0991SDimitry Andric Descriptor->setInitializer(ConstantStruct::getAnon({GVRelPtr, SizeAndTag}));
17298bcb0991SDimitry Andric Descriptor->setSection("hwasan_globals");
17308bcb0991SDimitry Andric Descriptor->setMetadata(LLVMContext::MD_associated,
17318bcb0991SDimitry Andric MDNode::get(*C, ValueAsMetadata::get(NewGV)));
17328bcb0991SDimitry Andric appendToCompilerUsed(M, Descriptor);
17338bcb0991SDimitry Andric }
17348bcb0991SDimitry Andric
17358bcb0991SDimitry Andric Constant *Aliasee = ConstantExpr::getIntToPtr(
17368bcb0991SDimitry Andric ConstantExpr::getAdd(
17378bcb0991SDimitry Andric ConstantExpr::getPtrToInt(NewGV, Int64Ty),
1738fe6060f1SDimitry Andric ConstantInt::get(Int64Ty, uint64_t(Tag) << PointerTagShift)),
17398bcb0991SDimitry Andric GV->getType());
17408bcb0991SDimitry Andric auto *Alias = GlobalAlias::create(GV->getValueType(), GV->getAddressSpace(),
17418bcb0991SDimitry Andric GV->getLinkage(), "", Aliasee, &M);
17428bcb0991SDimitry Andric Alias->setVisibility(GV->getVisibility());
17438bcb0991SDimitry Andric Alias->takeName(GV);
17448bcb0991SDimitry Andric GV->replaceAllUsesWith(Alias);
17458bcb0991SDimitry Andric GV->eraseFromParent();
17468bcb0991SDimitry Andric }
17478bcb0991SDimitry Andric
instrumentGlobals()17488bcb0991SDimitry Andric void HWAddressSanitizer::instrumentGlobals() {
17498bcb0991SDimitry Andric std::vector<GlobalVariable *> Globals;
17508bcb0991SDimitry Andric for (GlobalVariable &GV : M.globals()) {
175181ad6265SDimitry Andric if (GV.hasSanitizerMetadata() && GV.getSanitizerMetadata().NoHWAddress)
1752fe6060f1SDimitry Andric continue;
1753fe6060f1SDimitry Andric
17545f757f3fSDimitry Andric if (GV.isDeclarationForLinker() || GV.getName().starts_with("llvm.") ||
17558bcb0991SDimitry Andric GV.isThreadLocal())
17568bcb0991SDimitry Andric continue;
17578bcb0991SDimitry Andric
17588bcb0991SDimitry Andric // Common symbols can't have aliases point to them, so they can't be tagged.
17598bcb0991SDimitry Andric if (GV.hasCommonLinkage())
17608bcb0991SDimitry Andric continue;
17618bcb0991SDimitry Andric
17628bcb0991SDimitry Andric // Globals with custom sections may be used in __start_/__stop_ enumeration,
17638bcb0991SDimitry Andric // which would be broken both by adding tags and potentially by the extra
17648bcb0991SDimitry Andric // padding/alignment that we insert.
17658bcb0991SDimitry Andric if (GV.hasSection())
17668bcb0991SDimitry Andric continue;
17678bcb0991SDimitry Andric
17688bcb0991SDimitry Andric Globals.push_back(&GV);
17698bcb0991SDimitry Andric }
17708bcb0991SDimitry Andric
17718bcb0991SDimitry Andric MD5 Hasher;
17728bcb0991SDimitry Andric Hasher.update(M.getSourceFileName());
17738bcb0991SDimitry Andric MD5::MD5Result Hash;
17748bcb0991SDimitry Andric Hasher.final(Hash);
1775349cc55cSDimitry Andric uint8_t Tag = Hash[0];
17768bcb0991SDimitry Andric
177706c3fb27SDimitry Andric assert(TagMaskByte >= 16);
177806c3fb27SDimitry Andric
17798bcb0991SDimitry Andric for (GlobalVariable *GV : Globals) {
178006c3fb27SDimitry Andric // Don't allow globals to be tagged with something that looks like a
178106c3fb27SDimitry Andric // short-granule tag, otherwise we lose inter-granule overflow detection, as
178206c3fb27SDimitry Andric // the fast path shadow-vs-address check succeeds.
178306c3fb27SDimitry Andric if (Tag < 16 || Tag > TagMaskByte)
178406c3fb27SDimitry Andric Tag = 16;
17858bcb0991SDimitry Andric instrumentGlobal(GV, Tag++);
17868bcb0991SDimitry Andric }
17878bcb0991SDimitry Andric }
17888bcb0991SDimitry Andric
instrumentPersonalityFunctions()17898bcb0991SDimitry Andric void HWAddressSanitizer::instrumentPersonalityFunctions() {
17908bcb0991SDimitry Andric // We need to untag stack frames as we unwind past them. That is the job of
17918bcb0991SDimitry Andric // the personality function wrapper, which either wraps an existing
17928bcb0991SDimitry Andric // personality function or acts as a personality function on its own. Each
17938bcb0991SDimitry Andric // function that has a personality function or that can be unwound past has
17948bcb0991SDimitry Andric // its personality function changed to a thunk that calls the personality
17958bcb0991SDimitry Andric // function wrapper in the runtime.
17968bcb0991SDimitry Andric MapVector<Constant *, std::vector<Function *>> PersonalityFns;
17978bcb0991SDimitry Andric for (Function &F : M) {
17988bcb0991SDimitry Andric if (F.isDeclaration() || !F.hasFnAttribute(Attribute::SanitizeHWAddress))
17998bcb0991SDimitry Andric continue;
18008bcb0991SDimitry Andric
18018bcb0991SDimitry Andric if (F.hasPersonalityFn()) {
18028bcb0991SDimitry Andric PersonalityFns[F.getPersonalityFn()->stripPointerCasts()].push_back(&F);
18038bcb0991SDimitry Andric } else if (!F.hasFnAttribute(Attribute::NoUnwind)) {
18048bcb0991SDimitry Andric PersonalityFns[nullptr].push_back(&F);
18058bcb0991SDimitry Andric }
18068bcb0991SDimitry Andric }
18078bcb0991SDimitry Andric
18088bcb0991SDimitry Andric if (PersonalityFns.empty())
18098bcb0991SDimitry Andric return;
18108bcb0991SDimitry Andric
18118bcb0991SDimitry Andric FunctionCallee HwasanPersonalityWrapper = M.getOrInsertFunction(
18125f757f3fSDimitry Andric "__hwasan_personality_wrapper", Int32Ty, Int32Ty, Int32Ty, Int64Ty, PtrTy,
18135f757f3fSDimitry Andric PtrTy, PtrTy, PtrTy, PtrTy);
18148bcb0991SDimitry Andric FunctionCallee UnwindGetGR = M.getOrInsertFunction("_Unwind_GetGR", VoidTy);
18158bcb0991SDimitry Andric FunctionCallee UnwindGetCFA = M.getOrInsertFunction("_Unwind_GetCFA", VoidTy);
18168bcb0991SDimitry Andric
18178bcb0991SDimitry Andric for (auto &P : PersonalityFns) {
18188bcb0991SDimitry Andric std::string ThunkName = kHwasanPersonalityThunkName;
18198bcb0991SDimitry Andric if (P.first)
18208bcb0991SDimitry Andric ThunkName += ("." + P.first->getName()).str();
18218bcb0991SDimitry Andric FunctionType *ThunkFnTy = FunctionType::get(
18225f757f3fSDimitry Andric Int32Ty, {Int32Ty, Int32Ty, Int64Ty, PtrTy, PtrTy}, false);
18238bcb0991SDimitry Andric bool IsLocal = P.first && (!isa<GlobalValue>(P.first) ||
18248bcb0991SDimitry Andric cast<GlobalValue>(P.first)->hasLocalLinkage());
18258bcb0991SDimitry Andric auto *ThunkFn = Function::Create(ThunkFnTy,
18268bcb0991SDimitry Andric IsLocal ? GlobalValue::InternalLinkage
18278bcb0991SDimitry Andric : GlobalValue::LinkOnceODRLinkage,
18288bcb0991SDimitry Andric ThunkName, &M);
18298bcb0991SDimitry Andric if (!IsLocal) {
18308bcb0991SDimitry Andric ThunkFn->setVisibility(GlobalValue::HiddenVisibility);
18318bcb0991SDimitry Andric ThunkFn->setComdat(M.getOrInsertComdat(ThunkName));
18328bcb0991SDimitry Andric }
18338bcb0991SDimitry Andric
18348bcb0991SDimitry Andric auto *BB = BasicBlock::Create(*C, "entry", ThunkFn);
18358bcb0991SDimitry Andric IRBuilder<> IRB(BB);
18368bcb0991SDimitry Andric CallInst *WrapperCall = IRB.CreateCall(
18378bcb0991SDimitry Andric HwasanPersonalityWrapper,
18388bcb0991SDimitry Andric {ThunkFn->getArg(0), ThunkFn->getArg(1), ThunkFn->getArg(2),
18398bcb0991SDimitry Andric ThunkFn->getArg(3), ThunkFn->getArg(4),
18405f757f3fSDimitry Andric P.first ? P.first : Constant::getNullValue(PtrTy),
18415f757f3fSDimitry Andric UnwindGetGR.getCallee(), UnwindGetCFA.getCallee()});
18428bcb0991SDimitry Andric WrapperCall->setTailCall();
18438bcb0991SDimitry Andric IRB.CreateRet(WrapperCall);
18448bcb0991SDimitry Andric
18458bcb0991SDimitry Andric for (Function *F : P.second)
18468bcb0991SDimitry Andric F->setPersonalityFn(ThunkFn);
18478bcb0991SDimitry Andric }
18488bcb0991SDimitry Andric }
18498bcb0991SDimitry Andric
init(Triple & TargetTriple,bool InstrumentWithCalls)1850fe6060f1SDimitry Andric void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple,
1851fe6060f1SDimitry Andric bool InstrumentWithCalls) {
18520b57cec5SDimitry Andric Scale = kDefaultShadowScale;
1853fe6060f1SDimitry Andric if (TargetTriple.isOSFuchsia()) {
1854fe6060f1SDimitry Andric // Fuchsia is always PIE, which means that the beginning of the address
1855fe6060f1SDimitry Andric // space is always available.
18560b57cec5SDimitry Andric InGlobal = false;
18570b57cec5SDimitry Andric InTls = false;
18580b57cec5SDimitry Andric Offset = 0;
1859fe6060f1SDimitry Andric WithFrameRecord = true;
1860fe6060f1SDimitry Andric } else if (ClMappingOffset.getNumOccurrences() > 0) {
1861fe6060f1SDimitry Andric InGlobal = false;
1862fe6060f1SDimitry Andric InTls = false;
1863fe6060f1SDimitry Andric Offset = ClMappingOffset;
1864fe6060f1SDimitry Andric WithFrameRecord = false;
1865fe6060f1SDimitry Andric } else if (ClEnableKhwasan || InstrumentWithCalls) {
1866fe6060f1SDimitry Andric InGlobal = false;
1867fe6060f1SDimitry Andric InTls = false;
1868fe6060f1SDimitry Andric Offset = 0;
1869fe6060f1SDimitry Andric WithFrameRecord = false;
18700b57cec5SDimitry Andric } else if (ClWithIfunc) {
18710b57cec5SDimitry Andric InGlobal = true;
18720b57cec5SDimitry Andric InTls = false;
18730b57cec5SDimitry Andric Offset = kDynamicShadowSentinel;
1874fe6060f1SDimitry Andric WithFrameRecord = false;
18750b57cec5SDimitry Andric } else if (ClWithTls) {
18760b57cec5SDimitry Andric InGlobal = false;
18770b57cec5SDimitry Andric InTls = true;
18780b57cec5SDimitry Andric Offset = kDynamicShadowSentinel;
1879fe6060f1SDimitry Andric WithFrameRecord = true;
18800b57cec5SDimitry Andric } else {
18810b57cec5SDimitry Andric InGlobal = false;
18820b57cec5SDimitry Andric InTls = false;
18830b57cec5SDimitry Andric Offset = kDynamicShadowSentinel;
1884fe6060f1SDimitry Andric WithFrameRecord = false;
18850b57cec5SDimitry Andric }
18860b57cec5SDimitry Andric }
1887