1 | //===-- SanitizerCoverage.cpp - coverage instrumentation for sanitizers ---===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Coverage instrumentation done on LLVM IR level, works with Sanitizers. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" |
14 | #include "llvm/ADT/ArrayRef.h" |
15 | #include "llvm/ADT/SmallVector.h" |
16 | #include "llvm/Analysis/GlobalsModRef.h" |
17 | #include "llvm/Analysis/PostDominators.h" |
18 | #include "llvm/IR/Constant.h" |
19 | #include "llvm/IR/DataLayout.h" |
20 | #include "llvm/IR/Dominators.h" |
21 | #include "llvm/IR/EHPersonalities.h" |
22 | #include "llvm/IR/Function.h" |
23 | #include "llvm/IR/GlobalVariable.h" |
24 | #include "llvm/IR/IRBuilder.h" |
25 | #include "llvm/IR/IntrinsicInst.h" |
26 | #include "llvm/IR/Intrinsics.h" |
27 | #include "llvm/IR/LLVMContext.h" |
28 | #include "llvm/IR/MDBuilder.h" |
29 | #include "llvm/IR/Module.h" |
30 | #include "llvm/IR/Type.h" |
31 | #include "llvm/Support/CommandLine.h" |
32 | #include "llvm/Support/SpecialCaseList.h" |
33 | #include "llvm/Support/VirtualFileSystem.h" |
34 | #include "llvm/TargetParser/Triple.h" |
35 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
36 | #include "llvm/Transforms/Utils/ModuleUtils.h" |
37 | |
38 | using namespace llvm; |
39 | |
40 | #define DEBUG_TYPE "sancov" |
41 | |
42 | const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir" ; |
43 | const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc" ; |
44 | const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1" ; |
45 | const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2" ; |
46 | const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4" ; |
47 | const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8" ; |
48 | const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1" ; |
49 | const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2" ; |
50 | const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4" ; |
51 | const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8" ; |
52 | const char SanCovLoad1[] = "__sanitizer_cov_load1" ; |
53 | const char SanCovLoad2[] = "__sanitizer_cov_load2" ; |
54 | const char SanCovLoad4[] = "__sanitizer_cov_load4" ; |
55 | const char SanCovLoad8[] = "__sanitizer_cov_load8" ; |
56 | const char SanCovLoad16[] = "__sanitizer_cov_load16" ; |
57 | const char SanCovStore1[] = "__sanitizer_cov_store1" ; |
58 | const char SanCovStore2[] = "__sanitizer_cov_store2" ; |
59 | const char SanCovStore4[] = "__sanitizer_cov_store4" ; |
60 | const char SanCovStore8[] = "__sanitizer_cov_store8" ; |
61 | const char SanCovStore16[] = "__sanitizer_cov_store16" ; |
62 | const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4" ; |
63 | const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8" ; |
64 | const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep" ; |
65 | const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch" ; |
66 | const char SanCovModuleCtorTracePcGuardName[] = |
67 | "sancov.module_ctor_trace_pc_guard" ; |
68 | const char SanCovModuleCtor8bitCountersName[] = |
69 | "sancov.module_ctor_8bit_counters" ; |
70 | const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag" ; |
71 | static const uint64_t SanCtorAndDtorPriority = 2; |
72 | |
73 | const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard" ; |
74 | const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init" ; |
75 | const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init" ; |
76 | const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init" ; |
77 | const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init" ; |
78 | const char SanCovCFsInitName[] = "__sanitizer_cov_cfs_init" ; |
79 | |
80 | const char SanCovGuardsSectionName[] = "sancov_guards" ; |
81 | const char [] = "sancov_cntrs" ; |
82 | const char SanCovBoolFlagSectionName[] = "sancov_bools" ; |
83 | const char SanCovPCsSectionName[] = "sancov_pcs" ; |
84 | const char SanCovCFsSectionName[] = "sancov_cfs" ; |
85 | |
86 | const char SanCovLowestStackName[] = "__sancov_lowest_stack" ; |
87 | |
88 | static cl::opt<int> ClCoverageLevel( |
89 | "sanitizer-coverage-level" , |
90 | cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, " |
91 | "3: all blocks and critical edges" ), |
92 | cl::Hidden); |
93 | |
94 | static cl::opt<bool> ClTracePC("sanitizer-coverage-trace-pc" , |
95 | cl::desc("Experimental pc tracing" ), cl::Hidden); |
96 | |
97 | static cl::opt<bool> ClTracePCGuard("sanitizer-coverage-trace-pc-guard" , |
98 | cl::desc("pc tracing with a guard" ), |
99 | cl::Hidden); |
100 | |
101 | // If true, we create a global variable that contains PCs of all instrumented |
102 | // BBs, put this global into a named section, and pass this section's bounds |
103 | // to __sanitizer_cov_pcs_init. |
104 | // This way the coverage instrumentation does not need to acquire the PCs |
105 | // at run-time. Works with trace-pc-guard, inline-8bit-counters, and |
106 | // inline-bool-flag. |
107 | static cl::opt<bool> ClCreatePCTable("sanitizer-coverage-pc-table" , |
108 | cl::desc("create a static PC table" ), |
109 | cl::Hidden); |
110 | |
111 | static cl::opt<bool> |
112 | ClInline8bitCounters("sanitizer-coverage-inline-8bit-counters" , |
113 | cl::desc("increments 8-bit counter for every edge" ), |
114 | cl::Hidden); |
115 | |
116 | static cl::opt<bool> |
117 | ClInlineBoolFlag("sanitizer-coverage-inline-bool-flag" , |
118 | cl::desc("sets a boolean flag for every edge" ), |
119 | cl::Hidden); |
120 | |
121 | static cl::opt<bool> |
122 | ClCMPTracing("sanitizer-coverage-trace-compares" , |
123 | cl::desc("Tracing of CMP and similar instructions" ), |
124 | cl::Hidden); |
125 | |
126 | static cl::opt<bool> ClDIVTracing("sanitizer-coverage-trace-divs" , |
127 | cl::desc("Tracing of DIV instructions" ), |
128 | cl::Hidden); |
129 | |
130 | static cl::opt<bool> ClLoadTracing("sanitizer-coverage-trace-loads" , |
131 | cl::desc("Tracing of load instructions" ), |
132 | cl::Hidden); |
133 | |
134 | static cl::opt<bool> ClStoreTracing("sanitizer-coverage-trace-stores" , |
135 | cl::desc("Tracing of store instructions" ), |
136 | cl::Hidden); |
137 | |
138 | static cl::opt<bool> ClGEPTracing("sanitizer-coverage-trace-geps" , |
139 | cl::desc("Tracing of GEP instructions" ), |
140 | cl::Hidden); |
141 | |
142 | static cl::opt<bool> |
143 | ClPruneBlocks("sanitizer-coverage-prune-blocks" , |
144 | cl::desc("Reduce the number of instrumented blocks" ), |
145 | cl::Hidden, cl::init(Val: true)); |
146 | |
147 | static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth" , |
148 | cl::desc("max stack depth tracing" ), |
149 | cl::Hidden); |
150 | |
151 | static cl::opt<bool> |
152 | ClCollectCF("sanitizer-coverage-control-flow" , |
153 | cl::desc("collect control flow for each function" ), cl::Hidden); |
154 | |
155 | namespace { |
156 | |
157 | SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) { |
158 | SanitizerCoverageOptions Res; |
159 | switch (LegacyCoverageLevel) { |
160 | case 0: |
161 | Res.CoverageType = SanitizerCoverageOptions::SCK_None; |
162 | break; |
163 | case 1: |
164 | Res.CoverageType = SanitizerCoverageOptions::SCK_Function; |
165 | break; |
166 | case 2: |
167 | Res.CoverageType = SanitizerCoverageOptions::SCK_BB; |
168 | break; |
169 | case 3: |
170 | Res.CoverageType = SanitizerCoverageOptions::SCK_Edge; |
171 | break; |
172 | case 4: |
173 | Res.CoverageType = SanitizerCoverageOptions::SCK_Edge; |
174 | Res.IndirectCalls = true; |
175 | break; |
176 | } |
177 | return Res; |
178 | } |
179 | |
180 | SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { |
181 | // Sets CoverageType and IndirectCalls. |
182 | SanitizerCoverageOptions CLOpts = getOptions(LegacyCoverageLevel: ClCoverageLevel); |
183 | Options.CoverageType = std::max(a: Options.CoverageType, b: CLOpts.CoverageType); |
184 | Options.IndirectCalls |= CLOpts.IndirectCalls; |
185 | Options.TraceCmp |= ClCMPTracing; |
186 | Options.TraceDiv |= ClDIVTracing; |
187 | Options.TraceGep |= ClGEPTracing; |
188 | Options.TracePC |= ClTracePC; |
189 | Options.TracePCGuard |= ClTracePCGuard; |
190 | Options.Inline8bitCounters |= ClInline8bitCounters; |
191 | Options.InlineBoolFlag |= ClInlineBoolFlag; |
192 | Options.PCTable |= ClCreatePCTable; |
193 | Options.NoPrune |= !ClPruneBlocks; |
194 | Options.StackDepth |= ClStackDepth; |
195 | Options.TraceLoads |= ClLoadTracing; |
196 | Options.TraceStores |= ClStoreTracing; |
197 | if (!Options.TracePCGuard && !Options.TracePC && |
198 | !Options.Inline8bitCounters && !Options.StackDepth && |
199 | !Options.InlineBoolFlag && !Options.TraceLoads && !Options.TraceStores) |
200 | Options.TracePCGuard = true; // TracePCGuard is default. |
201 | Options.CollectControlFlow |= ClCollectCF; |
202 | return Options; |
203 | } |
204 | |
205 | class ModuleSanitizerCoverage { |
206 | public: |
207 | using DomTreeCallback = function_ref<const DominatorTree &(Function &F)>; |
208 | using PostDomTreeCallback = |
209 | function_ref<const PostDominatorTree &(Function &F)>; |
210 | |
211 | ModuleSanitizerCoverage(Module &M, DomTreeCallback DTCallback, |
212 | PostDomTreeCallback PDTCallback, |
213 | const SanitizerCoverageOptions &Options, |
214 | const SpecialCaseList *Allowlist, |
215 | const SpecialCaseList *Blocklist) |
216 | : M(M), DTCallback(DTCallback), PDTCallback(PDTCallback), |
217 | Options(Options), Allowlist(Allowlist), Blocklist(Blocklist) {} |
218 | |
219 | bool instrumentModule(); |
220 | |
221 | private: |
222 | void createFunctionControlFlow(Function &F); |
223 | void instrumentFunction(Function &F); |
224 | void InjectCoverageForIndirectCalls(Function &F, |
225 | ArrayRef<Instruction *> IndirCalls); |
226 | void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets); |
227 | void InjectTraceForDiv(Function &F, |
228 | ArrayRef<BinaryOperator *> DivTraceTargets); |
229 | void InjectTraceForGep(Function &F, |
230 | ArrayRef<GetElementPtrInst *> GepTraceTargets); |
231 | void InjectTraceForLoadsAndStores(Function &F, ArrayRef<LoadInst *> Loads, |
232 | ArrayRef<StoreInst *> Stores); |
233 | void InjectTraceForSwitch(Function &F, |
234 | ArrayRef<Instruction *> SwitchTraceTargets); |
235 | bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks, |
236 | bool IsLeafFunc = true); |
237 | GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements, |
238 | Function &F, Type *Ty, |
239 | const char *Section); |
240 | GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks); |
241 | void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks); |
242 | void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, |
243 | bool IsLeafFunc = true); |
244 | Function *CreateInitCallsForSections(Module &M, const char *CtorName, |
245 | const char *InitFunctionName, Type *Ty, |
246 | const char *Section); |
247 | std::pair<Value *, Value *> CreateSecStartEnd(Module &M, const char *Section, |
248 | Type *Ty); |
249 | |
250 | std::string getSectionName(const std::string &Section) const; |
251 | std::string getSectionStart(const std::string &Section) const; |
252 | std::string getSectionEnd(const std::string &Section) const; |
253 | |
254 | Module &M; |
255 | DomTreeCallback DTCallback; |
256 | PostDomTreeCallback PDTCallback; |
257 | |
258 | FunctionCallee SanCovTracePCIndir; |
259 | FunctionCallee SanCovTracePC, SanCovTracePCGuard; |
260 | std::array<FunctionCallee, 4> SanCovTraceCmpFunction; |
261 | std::array<FunctionCallee, 4> SanCovTraceConstCmpFunction; |
262 | std::array<FunctionCallee, 5> SanCovLoadFunction; |
263 | std::array<FunctionCallee, 5> SanCovStoreFunction; |
264 | std::array<FunctionCallee, 2> SanCovTraceDivFunction; |
265 | FunctionCallee SanCovTraceGepFunction; |
266 | FunctionCallee SanCovTraceSwitchFunction; |
267 | GlobalVariable *SanCovLowestStack; |
268 | Type *PtrTy, *IntptrTy, *Int64Ty, *Int32Ty, *Int16Ty, *Int8Ty, *Int1Ty; |
269 | Module *CurModule; |
270 | std::string CurModuleUniqueId; |
271 | Triple TargetTriple; |
272 | LLVMContext *C; |
273 | const DataLayout *DL; |
274 | |
275 | GlobalVariable *FunctionGuardArray; // for trace-pc-guard. |
276 | GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters. |
277 | GlobalVariable *FunctionBoolArray; // for inline-bool-flag. |
278 | GlobalVariable *FunctionPCsArray; // for pc-table. |
279 | GlobalVariable *FunctionCFsArray; // for control flow table |
280 | SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed; |
281 | SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed; |
282 | |
283 | SanitizerCoverageOptions Options; |
284 | |
285 | const SpecialCaseList *Allowlist; |
286 | const SpecialCaseList *Blocklist; |
287 | }; |
288 | } // namespace |
289 | |
290 | PreservedAnalyses SanitizerCoveragePass::run(Module &M, |
291 | ModuleAnalysisManager &MAM) { |
292 | auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(IR&: M).getManager(); |
293 | auto DTCallback = [&FAM](Function &F) -> const DominatorTree & { |
294 | return FAM.getResult<DominatorTreeAnalysis>(IR&: F); |
295 | }; |
296 | auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree & { |
297 | return FAM.getResult<PostDominatorTreeAnalysis>(IR&: F); |
298 | }; |
299 | ModuleSanitizerCoverage ModuleSancov(M, DTCallback, PDTCallback, |
300 | OverrideFromCL(Options), Allowlist.get(), |
301 | Blocklist.get()); |
302 | if (!ModuleSancov.instrumentModule()) |
303 | return PreservedAnalyses::all(); |
304 | |
305 | PreservedAnalyses PA = PreservedAnalyses::none(); |
306 | // GlobalsAA is considered stateless and does not get invalidated unless |
307 | // explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers |
308 | // make changes that require GlobalsAA to be invalidated. |
309 | PA.abandon<GlobalsAA>(); |
310 | return PA; |
311 | } |
312 | |
313 | std::pair<Value *, Value *> |
314 | ModuleSanitizerCoverage::CreateSecStartEnd(Module &M, const char *Section, |
315 | Type *Ty) { |
316 | // Use ExternalWeak so that if all sections are discarded due to section |
317 | // garbage collection, the linker will not report undefined symbol errors. |
318 | // Windows defines the start/stop symbols in compiler-rt so no need for |
319 | // ExternalWeak. |
320 | GlobalValue::LinkageTypes Linkage = TargetTriple.isOSBinFormatCOFF() |
321 | ? GlobalVariable::ExternalLinkage |
322 | : GlobalVariable::ExternalWeakLinkage; |
323 | GlobalVariable *SecStart = |
324 | new GlobalVariable(M, Ty, false, Linkage, nullptr, |
325 | getSectionStart(Section)); |
326 | SecStart->setVisibility(GlobalValue::HiddenVisibility); |
327 | GlobalVariable *SecEnd = |
328 | new GlobalVariable(M, Ty, false, Linkage, nullptr, |
329 | getSectionEnd(Section)); |
330 | SecEnd->setVisibility(GlobalValue::HiddenVisibility); |
331 | IRBuilder<> IRB(M.getContext()); |
332 | if (!TargetTriple.isOSBinFormatCOFF()) |
333 | return std::make_pair(x&: SecStart, y&: SecEnd); |
334 | |
335 | // Account for the fact that on windows-msvc __start_* symbols actually |
336 | // point to a uint64_t before the start of the array. |
337 | auto GEP = |
338 | IRB.CreatePtrAdd(Ptr: SecStart, Offset: ConstantInt::get(Ty: IntptrTy, V: sizeof(uint64_t))); |
339 | return std::make_pair(x&: GEP, y&: SecEnd); |
340 | } |
341 | |
342 | Function *ModuleSanitizerCoverage::CreateInitCallsForSections( |
343 | Module &M, const char *CtorName, const char *InitFunctionName, Type *Ty, |
344 | const char *Section) { |
345 | auto SecStartEnd = CreateSecStartEnd(M, Section, Ty); |
346 | auto SecStart = SecStartEnd.first; |
347 | auto SecEnd = SecStartEnd.second; |
348 | Function *CtorFunc; |
349 | std::tie(args&: CtorFunc, args: std::ignore) = createSanitizerCtorAndInitFunctions( |
350 | M, CtorName, InitName: InitFunctionName, InitArgTypes: {PtrTy, PtrTy}, InitArgs: {SecStart, SecEnd}); |
351 | assert(CtorFunc->getName() == CtorName); |
352 | |
353 | if (TargetTriple.supportsCOMDAT()) { |
354 | // Use comdat to dedup CtorFunc. |
355 | CtorFunc->setComdat(M.getOrInsertComdat(Name: CtorName)); |
356 | appendToGlobalCtors(M, F: CtorFunc, Priority: SanCtorAndDtorPriority, Data: CtorFunc); |
357 | } else { |
358 | appendToGlobalCtors(M, F: CtorFunc, Priority: SanCtorAndDtorPriority); |
359 | } |
360 | |
361 | if (TargetTriple.isOSBinFormatCOFF()) { |
362 | // In COFF files, if the contructors are set as COMDAT (they are because |
363 | // COFF supports COMDAT) and the linker flag /OPT:REF (strip unreferenced |
364 | // functions and data) is used, the constructors get stripped. To prevent |
365 | // this, give the constructors weak ODR linkage and ensure the linker knows |
366 | // to include the sancov constructor. This way the linker can deduplicate |
367 | // the constructors but always leave one copy. |
368 | CtorFunc->setLinkage(GlobalValue::WeakODRLinkage); |
369 | } |
370 | return CtorFunc; |
371 | } |
372 | |
373 | bool ModuleSanitizerCoverage::instrumentModule() { |
374 | if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) |
375 | return false; |
376 | if (Allowlist && |
377 | !Allowlist->inSection(Section: "coverage" , Prefix: "src" , Query: M.getSourceFileName())) |
378 | return false; |
379 | if (Blocklist && |
380 | Blocklist->inSection(Section: "coverage" , Prefix: "src" , Query: M.getSourceFileName())) |
381 | return false; |
382 | C = &(M.getContext()); |
383 | DL = &M.getDataLayout(); |
384 | CurModule = &M; |
385 | CurModuleUniqueId = getUniqueModuleId(M: CurModule); |
386 | TargetTriple = Triple(M.getTargetTriple()); |
387 | FunctionGuardArray = nullptr; |
388 | Function8bitCounterArray = nullptr; |
389 | FunctionBoolArray = nullptr; |
390 | FunctionPCsArray = nullptr; |
391 | FunctionCFsArray = nullptr; |
392 | IntptrTy = Type::getIntNTy(C&: *C, N: DL->getPointerSizeInBits()); |
393 | PtrTy = PointerType::getUnqual(C&: *C); |
394 | Type *VoidTy = Type::getVoidTy(C&: *C); |
395 | IRBuilder<> IRB(*C); |
396 | Int64Ty = IRB.getInt64Ty(); |
397 | Int32Ty = IRB.getInt32Ty(); |
398 | Int16Ty = IRB.getInt16Ty(); |
399 | Int8Ty = IRB.getInt8Ty(); |
400 | Int1Ty = IRB.getInt1Ty(); |
401 | |
402 | SanCovTracePCIndir = |
403 | M.getOrInsertFunction(Name: SanCovTracePCIndirName, RetTy: VoidTy, Args: IntptrTy); |
404 | // Make sure smaller parameters are zero-extended to i64 if required by the |
405 | // target ABI. |
406 | AttributeList SanCovTraceCmpZeroExtAL; |
407 | SanCovTraceCmpZeroExtAL = |
408 | SanCovTraceCmpZeroExtAL.addParamAttribute(C&: *C, ArgNo: 0, Kind: Attribute::ZExt); |
409 | SanCovTraceCmpZeroExtAL = |
410 | SanCovTraceCmpZeroExtAL.addParamAttribute(C&: *C, ArgNo: 1, Kind: Attribute::ZExt); |
411 | |
412 | SanCovTraceCmpFunction[0] = |
413 | M.getOrInsertFunction(Name: SanCovTraceCmp1, AttributeList: SanCovTraceCmpZeroExtAL, RetTy: VoidTy, |
414 | Args: IRB.getInt8Ty(), Args: IRB.getInt8Ty()); |
415 | SanCovTraceCmpFunction[1] = |
416 | M.getOrInsertFunction(Name: SanCovTraceCmp2, AttributeList: SanCovTraceCmpZeroExtAL, RetTy: VoidTy, |
417 | Args: IRB.getInt16Ty(), Args: IRB.getInt16Ty()); |
418 | SanCovTraceCmpFunction[2] = |
419 | M.getOrInsertFunction(Name: SanCovTraceCmp4, AttributeList: SanCovTraceCmpZeroExtAL, RetTy: VoidTy, |
420 | Args: IRB.getInt32Ty(), Args: IRB.getInt32Ty()); |
421 | SanCovTraceCmpFunction[3] = |
422 | M.getOrInsertFunction(Name: SanCovTraceCmp8, RetTy: VoidTy, Args: Int64Ty, Args: Int64Ty); |
423 | |
424 | SanCovTraceConstCmpFunction[0] = M.getOrInsertFunction( |
425 | Name: SanCovTraceConstCmp1, AttributeList: SanCovTraceCmpZeroExtAL, RetTy: VoidTy, Args: Int8Ty, Args: Int8Ty); |
426 | SanCovTraceConstCmpFunction[1] = M.getOrInsertFunction( |
427 | Name: SanCovTraceConstCmp2, AttributeList: SanCovTraceCmpZeroExtAL, RetTy: VoidTy, Args: Int16Ty, Args: Int16Ty); |
428 | SanCovTraceConstCmpFunction[2] = M.getOrInsertFunction( |
429 | Name: SanCovTraceConstCmp4, AttributeList: SanCovTraceCmpZeroExtAL, RetTy: VoidTy, Args: Int32Ty, Args: Int32Ty); |
430 | SanCovTraceConstCmpFunction[3] = |
431 | M.getOrInsertFunction(Name: SanCovTraceConstCmp8, RetTy: VoidTy, Args: Int64Ty, Args: Int64Ty); |
432 | |
433 | // Loads. |
434 | SanCovLoadFunction[0] = M.getOrInsertFunction(Name: SanCovLoad1, RetTy: VoidTy, Args: PtrTy); |
435 | SanCovLoadFunction[1] = |
436 | M.getOrInsertFunction(Name: SanCovLoad2, RetTy: VoidTy, Args: PtrTy); |
437 | SanCovLoadFunction[2] = |
438 | M.getOrInsertFunction(Name: SanCovLoad4, RetTy: VoidTy, Args: PtrTy); |
439 | SanCovLoadFunction[3] = |
440 | M.getOrInsertFunction(Name: SanCovLoad8, RetTy: VoidTy, Args: PtrTy); |
441 | SanCovLoadFunction[4] = |
442 | M.getOrInsertFunction(Name: SanCovLoad16, RetTy: VoidTy, Args: PtrTy); |
443 | // Stores. |
444 | SanCovStoreFunction[0] = |
445 | M.getOrInsertFunction(Name: SanCovStore1, RetTy: VoidTy, Args: PtrTy); |
446 | SanCovStoreFunction[1] = |
447 | M.getOrInsertFunction(Name: SanCovStore2, RetTy: VoidTy, Args: PtrTy); |
448 | SanCovStoreFunction[2] = |
449 | M.getOrInsertFunction(Name: SanCovStore4, RetTy: VoidTy, Args: PtrTy); |
450 | SanCovStoreFunction[3] = |
451 | M.getOrInsertFunction(Name: SanCovStore8, RetTy: VoidTy, Args: PtrTy); |
452 | SanCovStoreFunction[4] = |
453 | M.getOrInsertFunction(Name: SanCovStore16, RetTy: VoidTy, Args: PtrTy); |
454 | |
455 | { |
456 | AttributeList AL; |
457 | AL = AL.addParamAttribute(C&: *C, ArgNo: 0, Kind: Attribute::ZExt); |
458 | SanCovTraceDivFunction[0] = |
459 | M.getOrInsertFunction(Name: SanCovTraceDiv4, AttributeList: AL, RetTy: VoidTy, Args: IRB.getInt32Ty()); |
460 | } |
461 | SanCovTraceDivFunction[1] = |
462 | M.getOrInsertFunction(Name: SanCovTraceDiv8, RetTy: VoidTy, Args: Int64Ty); |
463 | SanCovTraceGepFunction = |
464 | M.getOrInsertFunction(Name: SanCovTraceGep, RetTy: VoidTy, Args: IntptrTy); |
465 | SanCovTraceSwitchFunction = |
466 | M.getOrInsertFunction(Name: SanCovTraceSwitchName, RetTy: VoidTy, Args: Int64Ty, Args: PtrTy); |
467 | |
468 | Constant *SanCovLowestStackConstant = |
469 | M.getOrInsertGlobal(Name: SanCovLowestStackName, Ty: IntptrTy); |
470 | SanCovLowestStack = dyn_cast<GlobalVariable>(Val: SanCovLowestStackConstant); |
471 | if (!SanCovLowestStack || SanCovLowestStack->getValueType() != IntptrTy) { |
472 | C->emitError(ErrorStr: StringRef("'" ) + SanCovLowestStackName + |
473 | "' should not be declared by the user" ); |
474 | return true; |
475 | } |
476 | SanCovLowestStack->setThreadLocalMode( |
477 | GlobalValue::ThreadLocalMode::InitialExecTLSModel); |
478 | if (Options.StackDepth && !SanCovLowestStack->isDeclaration()) |
479 | SanCovLowestStack->setInitializer(Constant::getAllOnesValue(Ty: IntptrTy)); |
480 | |
481 | SanCovTracePC = M.getOrInsertFunction(Name: SanCovTracePCName, RetTy: VoidTy); |
482 | SanCovTracePCGuard = |
483 | M.getOrInsertFunction(Name: SanCovTracePCGuardName, RetTy: VoidTy, Args: PtrTy); |
484 | |
485 | for (auto &F : M) |
486 | instrumentFunction(F); |
487 | |
488 | Function *Ctor = nullptr; |
489 | |
490 | if (FunctionGuardArray) |
491 | Ctor = CreateInitCallsForSections(M, CtorName: SanCovModuleCtorTracePcGuardName, |
492 | InitFunctionName: SanCovTracePCGuardInitName, Ty: Int32Ty, |
493 | Section: SanCovGuardsSectionName); |
494 | if (Function8bitCounterArray) |
495 | Ctor = CreateInitCallsForSections(M, CtorName: SanCovModuleCtor8bitCountersName, |
496 | InitFunctionName: SanCov8bitCountersInitName, Ty: Int8Ty, |
497 | Section: SanCovCountersSectionName); |
498 | if (FunctionBoolArray) { |
499 | Ctor = CreateInitCallsForSections(M, CtorName: SanCovModuleCtorBoolFlagName, |
500 | InitFunctionName: SanCovBoolFlagInitName, Ty: Int1Ty, |
501 | Section: SanCovBoolFlagSectionName); |
502 | } |
503 | if (Ctor && Options.PCTable) { |
504 | auto SecStartEnd = CreateSecStartEnd(M, Section: SanCovPCsSectionName, Ty: IntptrTy); |
505 | FunctionCallee InitFunction = declareSanitizerInitFunction( |
506 | M, InitName: SanCovPCsInitName, InitArgTypes: {PtrTy, PtrTy}); |
507 | IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator()); |
508 | IRBCtor.CreateCall(Callee: InitFunction, Args: {SecStartEnd.first, SecStartEnd.second}); |
509 | } |
510 | |
511 | if (Ctor && Options.CollectControlFlow) { |
512 | auto SecStartEnd = CreateSecStartEnd(M, Section: SanCovCFsSectionName, Ty: IntptrTy); |
513 | FunctionCallee InitFunction = declareSanitizerInitFunction( |
514 | M, InitName: SanCovCFsInitName, InitArgTypes: {PtrTy, PtrTy}); |
515 | IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator()); |
516 | IRBCtor.CreateCall(Callee: InitFunction, Args: {SecStartEnd.first, SecStartEnd.second}); |
517 | } |
518 | |
519 | appendToUsed(M, Values: GlobalsToAppendToUsed); |
520 | appendToCompilerUsed(M, Values: GlobalsToAppendToCompilerUsed); |
521 | return true; |
522 | } |
523 | |
524 | // True if block has successors and it dominates all of them. |
525 | static bool isFullDominator(const BasicBlock *BB, const DominatorTree &DT) { |
526 | if (succ_empty(BB)) |
527 | return false; |
528 | |
529 | return llvm::all_of(Range: successors(BB), P: [&](const BasicBlock *SUCC) { |
530 | return DT.dominates(A: BB, B: SUCC); |
531 | }); |
532 | } |
533 | |
534 | // True if block has predecessors and it postdominates all of them. |
535 | static bool isFullPostDominator(const BasicBlock *BB, |
536 | const PostDominatorTree &PDT) { |
537 | if (pred_empty(BB)) |
538 | return false; |
539 | |
540 | return llvm::all_of(Range: predecessors(BB), P: [&](const BasicBlock *PRED) { |
541 | return PDT.dominates(A: BB, B: PRED); |
542 | }); |
543 | } |
544 | |
545 | static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, |
546 | const DominatorTree &DT, |
547 | const PostDominatorTree &PDT, |
548 | const SanitizerCoverageOptions &Options) { |
549 | // Don't insert coverage for blocks containing nothing but unreachable: we |
550 | // will never call __sanitizer_cov() for them, so counting them in |
551 | // NumberOfInstrumentedBlocks() might complicate calculation of code coverage |
552 | // percentage. Also, unreachable instructions frequently have no debug |
553 | // locations. |
554 | if (isa<UnreachableInst>(Val: BB->getFirstNonPHIOrDbgOrLifetime())) |
555 | return false; |
556 | |
557 | // Don't insert coverage into blocks without a valid insertion point |
558 | // (catchswitch blocks). |
559 | if (BB->getFirstInsertionPt() == BB->end()) |
560 | return false; |
561 | |
562 | if (Options.NoPrune || &F.getEntryBlock() == BB) |
563 | return true; |
564 | |
565 | if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function && |
566 | &F.getEntryBlock() != BB) |
567 | return false; |
568 | |
569 | // Do not instrument full dominators, or full post-dominators with multiple |
570 | // predecessors. |
571 | return !isFullDominator(BB, DT) |
572 | && !(isFullPostDominator(BB, PDT) && !BB->getSinglePredecessor()); |
573 | } |
574 | |
575 | // Returns true iff From->To is a backedge. |
576 | // A twist here is that we treat From->To as a backedge if |
577 | // * To dominates From or |
578 | // * To->UniqueSuccessor dominates From |
579 | static bool IsBackEdge(BasicBlock *From, BasicBlock *To, |
580 | const DominatorTree &DT) { |
581 | if (DT.dominates(A: To, B: From)) |
582 | return true; |
583 | if (auto Next = To->getUniqueSuccessor()) |
584 | if (DT.dominates(A: Next, B: From)) |
585 | return true; |
586 | return false; |
587 | } |
588 | |
589 | // Prunes uninteresting Cmp instrumentation: |
590 | // * CMP instructions that feed into loop backedge branch. |
591 | // |
592 | // Note that Cmp pruning is controlled by the same flag as the |
593 | // BB pruning. |
594 | static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree &DT, |
595 | const SanitizerCoverageOptions &Options) { |
596 | if (!Options.NoPrune) |
597 | if (CMP->hasOneUse()) |
598 | if (auto BR = dyn_cast<BranchInst>(Val: CMP->user_back())) |
599 | for (BasicBlock *B : BR->successors()) |
600 | if (IsBackEdge(From: BR->getParent(), To: B, DT)) |
601 | return false; |
602 | return true; |
603 | } |
604 | |
605 | void ModuleSanitizerCoverage::instrumentFunction(Function &F) { |
606 | if (F.empty()) |
607 | return; |
608 | if (F.getName().contains(Other: ".module_ctor" )) |
609 | return; // Should not instrument sanitizer init functions. |
610 | if (F.getName().starts_with(Prefix: "__sanitizer_" )) |
611 | return; // Don't instrument __sanitizer_* callbacks. |
612 | // Don't touch available_externally functions, their actual body is elewhere. |
613 | if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) |
614 | return; |
615 | // Don't instrument MSVC CRT configuration helpers. They may run before normal |
616 | // initialization. |
617 | if (F.getName() == "__local_stdio_printf_options" || |
618 | F.getName() == "__local_stdio_scanf_options" ) |
619 | return; |
620 | if (isa<UnreachableInst>(Val: F.getEntryBlock().getTerminator())) |
621 | return; |
622 | // Don't instrument functions using SEH for now. Splitting basic blocks like |
623 | // we do for coverage breaks WinEHPrepare. |
624 | // FIXME: Remove this when SEH no longer uses landingpad pattern matching. |
625 | if (F.hasPersonalityFn() && |
626 | isAsynchronousEHPersonality(Pers: classifyEHPersonality(Pers: F.getPersonalityFn()))) |
627 | return; |
628 | if (Allowlist && !Allowlist->inSection(Section: "coverage" , Prefix: "fun" , Query: F.getName())) |
629 | return; |
630 | if (Blocklist && Blocklist->inSection(Section: "coverage" , Prefix: "fun" , Query: F.getName())) |
631 | return; |
632 | if (F.hasFnAttribute(Kind: Attribute::NoSanitizeCoverage)) |
633 | return; |
634 | if (F.hasFnAttribute(Kind: Attribute::DisableSanitizerInstrumentation)) |
635 | return; |
636 | if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge) { |
637 | SplitAllCriticalEdges( |
638 | F, Options: CriticalEdgeSplittingOptions().setIgnoreUnreachableDests()); |
639 | } |
640 | SmallVector<Instruction *, 8> IndirCalls; |
641 | SmallVector<BasicBlock *, 16> BlocksToInstrument; |
642 | SmallVector<Instruction *, 8> CmpTraceTargets; |
643 | SmallVector<Instruction *, 8> SwitchTraceTargets; |
644 | SmallVector<BinaryOperator *, 8> DivTraceTargets; |
645 | SmallVector<GetElementPtrInst *, 8> GepTraceTargets; |
646 | SmallVector<LoadInst *, 8> Loads; |
647 | SmallVector<StoreInst *, 8> Stores; |
648 | |
649 | const DominatorTree &DT = DTCallback(F); |
650 | const PostDominatorTree &PDT = PDTCallback(F); |
651 | bool IsLeafFunc = true; |
652 | |
653 | for (auto &BB : F) { |
654 | if (shouldInstrumentBlock(F, BB: &BB, DT, PDT, Options)) |
655 | BlocksToInstrument.push_back(Elt: &BB); |
656 | for (auto &Inst : BB) { |
657 | if (Options.IndirectCalls) { |
658 | CallBase *CB = dyn_cast<CallBase>(Val: &Inst); |
659 | if (CB && CB->isIndirectCall()) |
660 | IndirCalls.push_back(Elt: &Inst); |
661 | } |
662 | if (Options.TraceCmp) { |
663 | if (ICmpInst *CMP = dyn_cast<ICmpInst>(Val: &Inst)) |
664 | if (IsInterestingCmp(CMP, DT, Options)) |
665 | CmpTraceTargets.push_back(Elt: &Inst); |
666 | if (isa<SwitchInst>(Val: &Inst)) |
667 | SwitchTraceTargets.push_back(Elt: &Inst); |
668 | } |
669 | if (Options.TraceDiv) |
670 | if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Val: &Inst)) |
671 | if (BO->getOpcode() == Instruction::SDiv || |
672 | BO->getOpcode() == Instruction::UDiv) |
673 | DivTraceTargets.push_back(Elt: BO); |
674 | if (Options.TraceGep) |
675 | if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Val: &Inst)) |
676 | GepTraceTargets.push_back(Elt: GEP); |
677 | if (Options.TraceLoads) |
678 | if (LoadInst *LI = dyn_cast<LoadInst>(Val: &Inst)) |
679 | Loads.push_back(Elt: LI); |
680 | if (Options.TraceStores) |
681 | if (StoreInst *SI = dyn_cast<StoreInst>(Val: &Inst)) |
682 | Stores.push_back(Elt: SI); |
683 | if (Options.StackDepth) |
684 | if (isa<InvokeInst>(Val: Inst) || |
685 | (isa<CallInst>(Val: Inst) && !isa<IntrinsicInst>(Val: Inst))) |
686 | IsLeafFunc = false; |
687 | } |
688 | } |
689 | |
690 | if (Options.CollectControlFlow) |
691 | createFunctionControlFlow(F); |
692 | |
693 | InjectCoverage(F, AllBlocks: BlocksToInstrument, IsLeafFunc); |
694 | InjectCoverageForIndirectCalls(F, IndirCalls); |
695 | InjectTraceForCmp(F, CmpTraceTargets); |
696 | InjectTraceForSwitch(F, SwitchTraceTargets); |
697 | InjectTraceForDiv(F, DivTraceTargets); |
698 | InjectTraceForGep(F, GepTraceTargets); |
699 | InjectTraceForLoadsAndStores(F, Loads, Stores); |
700 | } |
701 | |
702 | GlobalVariable *ModuleSanitizerCoverage::CreateFunctionLocalArrayInSection( |
703 | size_t NumElements, Function &F, Type *Ty, const char *Section) { |
704 | ArrayType *ArrayTy = ArrayType::get(ElementType: Ty, NumElements); |
705 | auto Array = new GlobalVariable( |
706 | *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, |
707 | Constant::getNullValue(Ty: ArrayTy), "__sancov_gen_" ); |
708 | |
709 | if (TargetTriple.supportsCOMDAT() && |
710 | (TargetTriple.isOSBinFormatELF() || !F.isInterposable())) |
711 | if (auto Comdat = getOrCreateFunctionComdat(F, T&: TargetTriple)) |
712 | Array->setComdat(Comdat); |
713 | Array->setSection(getSectionName(Section)); |
714 | Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue())); |
715 | |
716 | // sancov_pcs parallels the other metadata section(s). Optimizers (e.g. |
717 | // GlobalOpt/ConstantMerge) may not discard sancov_pcs and the other |
718 | // section(s) as a unit, so we conservatively retain all unconditionally in |
719 | // the compiler. |
720 | // |
721 | // With comdat (COFF/ELF), the linker can guarantee the associated sections |
722 | // will be retained or discarded as a unit, so llvm.compiler.used is |
723 | // sufficient. Otherwise, conservatively make all of them retained by the |
724 | // linker. |
725 | if (Array->hasComdat()) |
726 | GlobalsToAppendToCompilerUsed.push_back(Elt: Array); |
727 | else |
728 | GlobalsToAppendToUsed.push_back(Elt: Array); |
729 | |
730 | return Array; |
731 | } |
732 | |
733 | GlobalVariable * |
734 | ModuleSanitizerCoverage::CreatePCArray(Function &F, |
735 | ArrayRef<BasicBlock *> AllBlocks) { |
736 | size_t N = AllBlocks.size(); |
737 | assert(N); |
738 | SmallVector<Constant *, 32> PCs; |
739 | IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt()); |
740 | for (size_t i = 0; i < N; i++) { |
741 | if (&F.getEntryBlock() == AllBlocks[i]) { |
742 | PCs.push_back(Elt: (Constant *)IRB.CreatePointerCast(V: &F, DestTy: PtrTy)); |
743 | PCs.push_back(Elt: (Constant *)IRB.CreateIntToPtr( |
744 | V: ConstantInt::get(Ty: IntptrTy, V: 1), DestTy: PtrTy)); |
745 | } else { |
746 | PCs.push_back(Elt: (Constant *)IRB.CreatePointerCast( |
747 | V: BlockAddress::get(BB: AllBlocks[i]), DestTy: PtrTy)); |
748 | PCs.push_back(Elt: Constant::getNullValue(Ty: PtrTy)); |
749 | } |
750 | } |
751 | auto *PCArray = CreateFunctionLocalArrayInSection(NumElements: N * 2, F, Ty: PtrTy, |
752 | Section: SanCovPCsSectionName); |
753 | PCArray->setInitializer( |
754 | ConstantArray::get(T: ArrayType::get(ElementType: PtrTy, NumElements: N * 2), V: PCs)); |
755 | PCArray->setConstant(true); |
756 | |
757 | return PCArray; |
758 | } |
759 | |
760 | void ModuleSanitizerCoverage::CreateFunctionLocalArrays( |
761 | Function &F, ArrayRef<BasicBlock *> AllBlocks) { |
762 | if (Options.TracePCGuard) |
763 | FunctionGuardArray = CreateFunctionLocalArrayInSection( |
764 | NumElements: AllBlocks.size(), F, Ty: Int32Ty, Section: SanCovGuardsSectionName); |
765 | |
766 | if (Options.Inline8bitCounters) |
767 | Function8bitCounterArray = CreateFunctionLocalArrayInSection( |
768 | NumElements: AllBlocks.size(), F, Ty: Int8Ty, Section: SanCovCountersSectionName); |
769 | if (Options.InlineBoolFlag) |
770 | FunctionBoolArray = CreateFunctionLocalArrayInSection( |
771 | NumElements: AllBlocks.size(), F, Ty: Int1Ty, Section: SanCovBoolFlagSectionName); |
772 | |
773 | if (Options.PCTable) |
774 | FunctionPCsArray = CreatePCArray(F, AllBlocks); |
775 | } |
776 | |
777 | bool ModuleSanitizerCoverage::InjectCoverage(Function &F, |
778 | ArrayRef<BasicBlock *> AllBlocks, |
779 | bool IsLeafFunc) { |
780 | if (AllBlocks.empty()) return false; |
781 | CreateFunctionLocalArrays(F, AllBlocks); |
782 | for (size_t i = 0, N = AllBlocks.size(); i < N; i++) |
783 | InjectCoverageAtBlock(F, BB&: *AllBlocks[i], Idx: i, IsLeafFunc); |
784 | return true; |
785 | } |
786 | |
787 | // On every indirect call we call a run-time function |
788 | // __sanitizer_cov_indir_call* with two parameters: |
789 | // - callee address, |
790 | // - global cache array that contains CacheSize pointers (zero-initialized). |
791 | // The cache is used to speed up recording the caller-callee pairs. |
792 | // The address of the caller is passed implicitly via caller PC. |
793 | // CacheSize is encoded in the name of the run-time function. |
794 | void ModuleSanitizerCoverage::InjectCoverageForIndirectCalls( |
795 | Function &F, ArrayRef<Instruction *> IndirCalls) { |
796 | if (IndirCalls.empty()) |
797 | return; |
798 | assert(Options.TracePC || Options.TracePCGuard || |
799 | Options.Inline8bitCounters || Options.InlineBoolFlag); |
800 | for (auto *I : IndirCalls) { |
801 | InstrumentationIRBuilder IRB(I); |
802 | CallBase &CB = cast<CallBase>(Val&: *I); |
803 | Value *Callee = CB.getCalledOperand(); |
804 | if (isa<InlineAsm>(Val: Callee)) |
805 | continue; |
806 | IRB.CreateCall(Callee: SanCovTracePCIndir, Args: IRB.CreatePointerCast(V: Callee, DestTy: IntptrTy)); |
807 | } |
808 | } |
809 | |
810 | // For every switch statement we insert a call: |
811 | // __sanitizer_cov_trace_switch(CondValue, |
812 | // {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... }) |
813 | |
814 | void ModuleSanitizerCoverage::InjectTraceForSwitch( |
815 | Function &, ArrayRef<Instruction *> SwitchTraceTargets) { |
816 | for (auto *I : SwitchTraceTargets) { |
817 | if (SwitchInst *SI = dyn_cast<SwitchInst>(Val: I)) { |
818 | InstrumentationIRBuilder IRB(I); |
819 | SmallVector<Constant *, 16> Initializers; |
820 | Value *Cond = SI->getCondition(); |
821 | if (Cond->getType()->getScalarSizeInBits() > |
822 | Int64Ty->getScalarSizeInBits()) |
823 | continue; |
824 | Initializers.push_back(Elt: ConstantInt::get(Ty: Int64Ty, V: SI->getNumCases())); |
825 | Initializers.push_back( |
826 | Elt: ConstantInt::get(Ty: Int64Ty, V: Cond->getType()->getScalarSizeInBits())); |
827 | if (Cond->getType()->getScalarSizeInBits() < |
828 | Int64Ty->getScalarSizeInBits()) |
829 | Cond = IRB.CreateIntCast(V: Cond, DestTy: Int64Ty, isSigned: false); |
830 | for (auto It : SI->cases()) { |
831 | ConstantInt *C = It.getCaseValue(); |
832 | if (C->getType()->getScalarSizeInBits() < 64) |
833 | C = ConstantInt::get(Context&: C->getContext(), V: C->getValue().zext(width: 64)); |
834 | Initializers.push_back(Elt: C); |
835 | } |
836 | llvm::sort(C: drop_begin(RangeOrContainer&: Initializers, N: 2), |
837 | Comp: [](const Constant *A, const Constant *B) { |
838 | return cast<ConstantInt>(Val: A)->getLimitedValue() < |
839 | cast<ConstantInt>(Val: B)->getLimitedValue(); |
840 | }); |
841 | ArrayType *ArrayOfInt64Ty = ArrayType::get(ElementType: Int64Ty, NumElements: Initializers.size()); |
842 | GlobalVariable *GV = new GlobalVariable( |
843 | *CurModule, ArrayOfInt64Ty, false, GlobalVariable::InternalLinkage, |
844 | ConstantArray::get(T: ArrayOfInt64Ty, V: Initializers), |
845 | "__sancov_gen_cov_switch_values" ); |
846 | IRB.CreateCall(Callee: SanCovTraceSwitchFunction, Args: {Cond, GV}); |
847 | } |
848 | } |
849 | } |
850 | |
851 | void ModuleSanitizerCoverage::InjectTraceForDiv( |
852 | Function &, ArrayRef<BinaryOperator *> DivTraceTargets) { |
853 | for (auto *BO : DivTraceTargets) { |
854 | InstrumentationIRBuilder IRB(BO); |
855 | Value *A1 = BO->getOperand(i_nocapture: 1); |
856 | if (isa<ConstantInt>(Val: A1)) continue; |
857 | if (!A1->getType()->isIntegerTy()) |
858 | continue; |
859 | uint64_t TypeSize = DL->getTypeStoreSizeInBits(Ty: A1->getType()); |
860 | int CallbackIdx = TypeSize == 32 ? 0 : |
861 | TypeSize == 64 ? 1 : -1; |
862 | if (CallbackIdx < 0) continue; |
863 | auto Ty = Type::getIntNTy(C&: *C, N: TypeSize); |
864 | IRB.CreateCall(Callee: SanCovTraceDivFunction[CallbackIdx], |
865 | Args: {IRB.CreateIntCast(V: A1, DestTy: Ty, isSigned: true)}); |
866 | } |
867 | } |
868 | |
869 | void ModuleSanitizerCoverage::InjectTraceForGep( |
870 | Function &, ArrayRef<GetElementPtrInst *> GepTraceTargets) { |
871 | for (auto *GEP : GepTraceTargets) { |
872 | InstrumentationIRBuilder IRB(GEP); |
873 | for (Use &Idx : GEP->indices()) |
874 | if (!isa<ConstantInt>(Val: Idx) && Idx->getType()->isIntegerTy()) |
875 | IRB.CreateCall(Callee: SanCovTraceGepFunction, |
876 | Args: {IRB.CreateIntCast(V: Idx, DestTy: IntptrTy, isSigned: true)}); |
877 | } |
878 | } |
879 | |
880 | void ModuleSanitizerCoverage::InjectTraceForLoadsAndStores( |
881 | Function &, ArrayRef<LoadInst *> Loads, ArrayRef<StoreInst *> Stores) { |
882 | auto CallbackIdx = [&](Type *ElementTy) -> int { |
883 | uint64_t TypeSize = DL->getTypeStoreSizeInBits(Ty: ElementTy); |
884 | return TypeSize == 8 ? 0 |
885 | : TypeSize == 16 ? 1 |
886 | : TypeSize == 32 ? 2 |
887 | : TypeSize == 64 ? 3 |
888 | : TypeSize == 128 ? 4 |
889 | : -1; |
890 | }; |
891 | for (auto *LI : Loads) { |
892 | InstrumentationIRBuilder IRB(LI); |
893 | auto Ptr = LI->getPointerOperand(); |
894 | int Idx = CallbackIdx(LI->getType()); |
895 | if (Idx < 0) |
896 | continue; |
897 | IRB.CreateCall(Callee: SanCovLoadFunction[Idx], Args: Ptr); |
898 | } |
899 | for (auto *SI : Stores) { |
900 | InstrumentationIRBuilder IRB(SI); |
901 | auto Ptr = SI->getPointerOperand(); |
902 | int Idx = CallbackIdx(SI->getValueOperand()->getType()); |
903 | if (Idx < 0) |
904 | continue; |
905 | IRB.CreateCall(Callee: SanCovStoreFunction[Idx], Args: Ptr); |
906 | } |
907 | } |
908 | |
909 | void ModuleSanitizerCoverage::InjectTraceForCmp( |
910 | Function &, ArrayRef<Instruction *> CmpTraceTargets) { |
911 | for (auto *I : CmpTraceTargets) { |
912 | if (ICmpInst *ICMP = dyn_cast<ICmpInst>(Val: I)) { |
913 | InstrumentationIRBuilder IRB(ICMP); |
914 | Value *A0 = ICMP->getOperand(i_nocapture: 0); |
915 | Value *A1 = ICMP->getOperand(i_nocapture: 1); |
916 | if (!A0->getType()->isIntegerTy()) |
917 | continue; |
918 | uint64_t TypeSize = DL->getTypeStoreSizeInBits(Ty: A0->getType()); |
919 | int CallbackIdx = TypeSize == 8 ? 0 : |
920 | TypeSize == 16 ? 1 : |
921 | TypeSize == 32 ? 2 : |
922 | TypeSize == 64 ? 3 : -1; |
923 | if (CallbackIdx < 0) continue; |
924 | // __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1); |
925 | auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx]; |
926 | bool FirstIsConst = isa<ConstantInt>(Val: A0); |
927 | bool SecondIsConst = isa<ConstantInt>(Val: A1); |
928 | // If both are const, then we don't need such a comparison. |
929 | if (FirstIsConst && SecondIsConst) continue; |
930 | // If only one is const, then make it the first callback argument. |
931 | if (FirstIsConst || SecondIsConst) { |
932 | CallbackFunc = SanCovTraceConstCmpFunction[CallbackIdx]; |
933 | if (SecondIsConst) |
934 | std::swap(a&: A0, b&: A1); |
935 | } |
936 | |
937 | auto Ty = Type::getIntNTy(C&: *C, N: TypeSize); |
938 | IRB.CreateCall(Callee: CallbackFunc, Args: {IRB.CreateIntCast(V: A0, DestTy: Ty, isSigned: true), |
939 | IRB.CreateIntCast(V: A1, DestTy: Ty, isSigned: true)}); |
940 | } |
941 | } |
942 | } |
943 | |
944 | void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, |
945 | size_t Idx, |
946 | bool IsLeafFunc) { |
947 | BasicBlock::iterator IP = BB.getFirstInsertionPt(); |
948 | bool IsEntryBB = &BB == &F.getEntryBlock(); |
949 | DebugLoc EntryLoc; |
950 | if (IsEntryBB) { |
951 | if (auto SP = F.getSubprogram()) |
952 | EntryLoc = DILocation::get(Context&: SP->getContext(), Line: SP->getScopeLine(), Column: 0, Scope: SP); |
953 | // Keep static allocas and llvm.localescape calls in the entry block. Even |
954 | // if we aren't splitting the block, it's nice for allocas to be before |
955 | // calls. |
956 | IP = PrepareToSplitEntryBlock(BB, IP); |
957 | } |
958 | |
959 | InstrumentationIRBuilder IRB(&*IP); |
960 | if (EntryLoc) |
961 | IRB.SetCurrentDebugLocation(EntryLoc); |
962 | if (Options.TracePC) { |
963 | IRB.CreateCall(Callee: SanCovTracePC) |
964 | ->setCannotMerge(); // gets the PC using GET_CALLER_PC. |
965 | } |
966 | if (Options.TracePCGuard) { |
967 | auto GuardPtr = IRB.CreateIntToPtr( |
968 | V: IRB.CreateAdd(LHS: IRB.CreatePointerCast(V: FunctionGuardArray, DestTy: IntptrTy), |
969 | RHS: ConstantInt::get(Ty: IntptrTy, V: Idx * 4)), |
970 | DestTy: PtrTy); |
971 | IRB.CreateCall(Callee: SanCovTracePCGuard, Args: GuardPtr)->setCannotMerge(); |
972 | } |
973 | if (Options.Inline8bitCounters) { |
974 | auto CounterPtr = IRB.CreateGEP( |
975 | Ty: Function8bitCounterArray->getValueType(), Ptr: Function8bitCounterArray, |
976 | IdxList: {ConstantInt::get(Ty: IntptrTy, V: 0), ConstantInt::get(Ty: IntptrTy, V: Idx)}); |
977 | auto Load = IRB.CreateLoad(Ty: Int8Ty, Ptr: CounterPtr); |
978 | auto Inc = IRB.CreateAdd(LHS: Load, RHS: ConstantInt::get(Ty: Int8Ty, V: 1)); |
979 | auto Store = IRB.CreateStore(Val: Inc, Ptr: CounterPtr); |
980 | Load->setNoSanitizeMetadata(); |
981 | Store->setNoSanitizeMetadata(); |
982 | } |
983 | if (Options.InlineBoolFlag) { |
984 | auto FlagPtr = IRB.CreateGEP( |
985 | Ty: FunctionBoolArray->getValueType(), Ptr: FunctionBoolArray, |
986 | IdxList: {ConstantInt::get(Ty: IntptrTy, V: 0), ConstantInt::get(Ty: IntptrTy, V: Idx)}); |
987 | auto Load = IRB.CreateLoad(Ty: Int1Ty, Ptr: FlagPtr); |
988 | auto ThenTerm = SplitBlockAndInsertIfThen( |
989 | Cond: IRB.CreateIsNull(Arg: Load), SplitBefore: &*IP, Unreachable: false, |
990 | BranchWeights: MDBuilder(IRB.getContext()).createUnlikelyBranchWeights()); |
991 | IRBuilder<> ThenIRB(ThenTerm); |
992 | auto Store = ThenIRB.CreateStore(Val: ConstantInt::getTrue(Ty: Int1Ty), Ptr: FlagPtr); |
993 | Load->setNoSanitizeMetadata(); |
994 | Store->setNoSanitizeMetadata(); |
995 | } |
996 | if (Options.StackDepth && IsEntryBB && !IsLeafFunc) { |
997 | // Check stack depth. If it's the deepest so far, record it. |
998 | Module *M = F.getParent(); |
999 | Function *GetFrameAddr = Intrinsic::getDeclaration( |
1000 | M, id: Intrinsic::frameaddress, |
1001 | Tys: IRB.getPtrTy(AddrSpace: M->getDataLayout().getAllocaAddrSpace())); |
1002 | auto FrameAddrPtr = |
1003 | IRB.CreateCall(Callee: GetFrameAddr, Args: {Constant::getNullValue(Ty: Int32Ty)}); |
1004 | auto FrameAddrInt = IRB.CreatePtrToInt(V: FrameAddrPtr, DestTy: IntptrTy); |
1005 | auto LowestStack = IRB.CreateLoad(Ty: IntptrTy, Ptr: SanCovLowestStack); |
1006 | auto IsStackLower = IRB.CreateICmpULT(LHS: FrameAddrInt, RHS: LowestStack); |
1007 | auto ThenTerm = SplitBlockAndInsertIfThen( |
1008 | Cond: IsStackLower, SplitBefore: &*IP, Unreachable: false, |
1009 | BranchWeights: MDBuilder(IRB.getContext()).createUnlikelyBranchWeights()); |
1010 | IRBuilder<> ThenIRB(ThenTerm); |
1011 | auto Store = ThenIRB.CreateStore(Val: FrameAddrInt, Ptr: SanCovLowestStack); |
1012 | LowestStack->setNoSanitizeMetadata(); |
1013 | Store->setNoSanitizeMetadata(); |
1014 | } |
1015 | } |
1016 | |
1017 | std::string |
1018 | ModuleSanitizerCoverage::getSectionName(const std::string &Section) const { |
1019 | if (TargetTriple.isOSBinFormatCOFF()) { |
1020 | if (Section == SanCovCountersSectionName) |
1021 | return ".SCOV$CM" ; |
1022 | if (Section == SanCovBoolFlagSectionName) |
1023 | return ".SCOV$BM" ; |
1024 | if (Section == SanCovPCsSectionName) |
1025 | return ".SCOVP$M" ; |
1026 | return ".SCOV$GM" ; // For SanCovGuardsSectionName. |
1027 | } |
1028 | if (TargetTriple.isOSBinFormatMachO()) |
1029 | return "__DATA,__" + Section; |
1030 | return "__" + Section; |
1031 | } |
1032 | |
1033 | std::string |
1034 | ModuleSanitizerCoverage::getSectionStart(const std::string &Section) const { |
1035 | if (TargetTriple.isOSBinFormatMachO()) |
1036 | return "\1section$start$__DATA$__" + Section; |
1037 | return "__start___" + Section; |
1038 | } |
1039 | |
1040 | std::string |
1041 | ModuleSanitizerCoverage::getSectionEnd(const std::string &Section) const { |
1042 | if (TargetTriple.isOSBinFormatMachO()) |
1043 | return "\1section$end$__DATA$__" + Section; |
1044 | return "__stop___" + Section; |
1045 | } |
1046 | |
1047 | void ModuleSanitizerCoverage::createFunctionControlFlow(Function &F) { |
1048 | SmallVector<Constant *, 32> CFs; |
1049 | IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt()); |
1050 | |
1051 | for (auto &BB : F) { |
1052 | // blockaddress can not be used on function's entry block. |
1053 | if (&BB == &F.getEntryBlock()) |
1054 | CFs.push_back(Elt: (Constant *)IRB.CreatePointerCast(V: &F, DestTy: PtrTy)); |
1055 | else |
1056 | CFs.push_back(Elt: (Constant *)IRB.CreatePointerCast(V: BlockAddress::get(BB: &BB), |
1057 | DestTy: PtrTy)); |
1058 | |
1059 | for (auto SuccBB : successors(BB: &BB)) { |
1060 | assert(SuccBB != &F.getEntryBlock()); |
1061 | CFs.push_back(Elt: (Constant *)IRB.CreatePointerCast(V: BlockAddress::get(BB: SuccBB), |
1062 | DestTy: PtrTy)); |
1063 | } |
1064 | |
1065 | CFs.push_back(Elt: (Constant *)Constant::getNullValue(Ty: PtrTy)); |
1066 | |
1067 | for (auto &Inst : BB) { |
1068 | if (CallBase *CB = dyn_cast<CallBase>(Val: &Inst)) { |
1069 | if (CB->isIndirectCall()) { |
1070 | // TODO(navidem): handle indirect calls, for now mark its existence. |
1071 | CFs.push_back(Elt: (Constant *)IRB.CreateIntToPtr( |
1072 | V: ConstantInt::get(Ty: IntptrTy, V: -1), DestTy: PtrTy)); |
1073 | } else { |
1074 | auto CalledF = CB->getCalledFunction(); |
1075 | if (CalledF && !CalledF->isIntrinsic()) |
1076 | CFs.push_back( |
1077 | Elt: (Constant *)IRB.CreatePointerCast(V: CalledF, DestTy: PtrTy)); |
1078 | } |
1079 | } |
1080 | } |
1081 | |
1082 | CFs.push_back(Elt: (Constant *)Constant::getNullValue(Ty: PtrTy)); |
1083 | } |
1084 | |
1085 | FunctionCFsArray = CreateFunctionLocalArrayInSection( |
1086 | NumElements: CFs.size(), F, Ty: PtrTy, Section: SanCovCFsSectionName); |
1087 | FunctionCFsArray->setInitializer( |
1088 | ConstantArray::get(T: ArrayType::get(ElementType: PtrTy, NumElements: CFs.size()), V: CFs)); |
1089 | FunctionCFsArray->setConstant(true); |
1090 | } |
1091 | |