/src/llvm-project/llvm/lib/Transforms/Utils/SanitizerStats.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- SanitizerStats.cpp - Sanitizer statistics gathering ----------------===// |
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 | | // Implements code generation for sanitizer statistics gathering. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "llvm/Transforms/Utils/SanitizerStats.h" |
14 | | #include "llvm/IR/Constants.h" |
15 | | #include "llvm/IR/DerivedTypes.h" |
16 | | #include "llvm/IR/GlobalVariable.h" |
17 | | #include "llvm/IR/IRBuilder.h" |
18 | | #include "llvm/IR/Module.h" |
19 | | #include "llvm/Transforms/Utils/ModuleUtils.h" |
20 | | |
21 | | using namespace llvm; |
22 | | |
23 | 0 | SanitizerStatReport::SanitizerStatReport(Module *M) : M(M) { |
24 | 0 | StatTy = ArrayType::get(PointerType::getUnqual(M->getContext()), 2); |
25 | 0 | EmptyModuleStatsTy = makeModuleStatsTy(); |
26 | |
|
27 | 0 | ModuleStatsGV = new GlobalVariable(*M, EmptyModuleStatsTy, false, |
28 | 0 | GlobalValue::InternalLinkage, nullptr); |
29 | 0 | } |
30 | | |
31 | 0 | ArrayType *SanitizerStatReport::makeModuleStatsArrayTy() { |
32 | 0 | return ArrayType::get(StatTy, Inits.size()); |
33 | 0 | } |
34 | | |
35 | 0 | StructType *SanitizerStatReport::makeModuleStatsTy() { |
36 | 0 | return StructType::get(M->getContext(), |
37 | 0 | {PointerType::getUnqual(M->getContext()), |
38 | 0 | Type::getInt32Ty(M->getContext()), |
39 | 0 | makeModuleStatsArrayTy()}); |
40 | 0 | } |
41 | | |
42 | 0 | void SanitizerStatReport::create(IRBuilder<> &B, SanitizerStatKind SK) { |
43 | 0 | Function *F = B.GetInsertBlock()->getParent(); |
44 | 0 | Module *M = F->getParent(); |
45 | 0 | PointerType *PtrTy = B.getPtrTy(); |
46 | 0 | IntegerType *IntPtrTy = B.getIntPtrTy(M->getDataLayout()); |
47 | 0 | ArrayType *StatTy = ArrayType::get(PtrTy, 2); |
48 | |
|
49 | 0 | Inits.push_back(ConstantArray::get( |
50 | 0 | StatTy, |
51 | 0 | {Constant::getNullValue(PtrTy), |
52 | 0 | ConstantExpr::getIntToPtr( |
53 | 0 | ConstantInt::get(IntPtrTy, uint64_t(SK) << (IntPtrTy->getBitWidth() - |
54 | 0 | kSanitizerStatKindBits)), |
55 | 0 | PtrTy)})); |
56 | |
|
57 | 0 | FunctionType *StatReportTy = FunctionType::get(B.getVoidTy(), PtrTy, false); |
58 | 0 | FunctionCallee StatReport = |
59 | 0 | M->getOrInsertFunction("__sanitizer_stat_report", StatReportTy); |
60 | |
|
61 | 0 | auto InitAddr = ConstantExpr::getGetElementPtr( |
62 | 0 | EmptyModuleStatsTy, ModuleStatsGV, |
63 | 0 | ArrayRef<Constant *>{ |
64 | 0 | ConstantInt::get(IntPtrTy, 0), ConstantInt::get(B.getInt32Ty(), 2), |
65 | 0 | ConstantInt::get(IntPtrTy, Inits.size() - 1), |
66 | 0 | }); |
67 | 0 | B.CreateCall(StatReport, InitAddr); |
68 | 0 | } |
69 | | |
70 | 0 | void SanitizerStatReport::finish() { |
71 | 0 | if (Inits.empty()) { |
72 | 0 | ModuleStatsGV->eraseFromParent(); |
73 | 0 | return; |
74 | 0 | } |
75 | | |
76 | 0 | PointerType *Int8PtrTy = PointerType::getUnqual(M->getContext()); |
77 | 0 | IntegerType *Int32Ty = Type::getInt32Ty(M->getContext()); |
78 | 0 | Type *VoidTy = Type::getVoidTy(M->getContext()); |
79 | | |
80 | | // Create a new ModuleStatsGV to replace the old one. We can't just set the |
81 | | // old one's initializer because its type is different. |
82 | 0 | auto NewModuleStatsGV = new GlobalVariable( |
83 | 0 | *M, makeModuleStatsTy(), false, GlobalValue::InternalLinkage, |
84 | 0 | ConstantStruct::getAnon( |
85 | 0 | {Constant::getNullValue(Int8PtrTy), |
86 | 0 | ConstantInt::get(Int32Ty, Inits.size()), |
87 | 0 | ConstantArray::get(makeModuleStatsArrayTy(), Inits)})); |
88 | 0 | ModuleStatsGV->replaceAllUsesWith(NewModuleStatsGV); |
89 | 0 | ModuleStatsGV->eraseFromParent(); |
90 | | |
91 | | // Create a global constructor to register NewModuleStatsGV. |
92 | 0 | auto F = Function::Create(FunctionType::get(VoidTy, false), |
93 | 0 | GlobalValue::InternalLinkage, "", M); |
94 | 0 | auto BB = BasicBlock::Create(M->getContext(), "", F); |
95 | 0 | IRBuilder<> B(BB); |
96 | |
|
97 | 0 | FunctionType *StatInitTy = FunctionType::get(VoidTy, Int8PtrTy, false); |
98 | 0 | FunctionCallee StatInit = |
99 | 0 | M->getOrInsertFunction("__sanitizer_stat_init", StatInitTy); |
100 | |
|
101 | 0 | B.CreateCall(StatInit, NewModuleStatsGV); |
102 | 0 | B.CreateRetVoid(); |
103 | |
|
104 | 0 | appendToGlobalCtors(*M, F, 0); |
105 | 0 | } |