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 | SanitizerStatReport::SanitizerStatReport(Module *M) : M(M) { |
24 | StatTy = ArrayType::get(ElementType: PointerType::getUnqual(C&: M->getContext()), NumElements: 2); |
25 | EmptyModuleStatsTy = makeModuleStatsTy(); |
26 | |
27 | ModuleStatsGV = new GlobalVariable(*M, EmptyModuleStatsTy, false, |
28 | GlobalValue::InternalLinkage, nullptr); |
29 | } |
30 | |
31 | ArrayType *SanitizerStatReport::makeModuleStatsArrayTy() { |
32 | return ArrayType::get(ElementType: StatTy, NumElements: Inits.size()); |
33 | } |
34 | |
35 | StructType *SanitizerStatReport::makeModuleStatsTy() { |
36 | return StructType::get(Context&: M->getContext(), |
37 | Elements: {PointerType::getUnqual(C&: M->getContext()), |
38 | Type::getInt32Ty(C&: M->getContext()), |
39 | makeModuleStatsArrayTy()}); |
40 | } |
41 | |
42 | void SanitizerStatReport::create(IRBuilder<> &B, SanitizerStatKind SK) { |
43 | Function *F = B.GetInsertBlock()->getParent(); |
44 | Module *M = F->getParent(); |
45 | PointerType *PtrTy = B.getPtrTy(); |
46 | IntegerType *IntPtrTy = B.getIntPtrTy(DL: M->getDataLayout()); |
47 | ArrayType *StatTy = ArrayType::get(ElementType: PtrTy, NumElements: 2); |
48 | |
49 | Inits.push_back(x: ConstantArray::get( |
50 | T: StatTy, |
51 | V: {Constant::getNullValue(Ty: PtrTy), |
52 | ConstantExpr::getIntToPtr( |
53 | C: ConstantInt::get(Ty: IntPtrTy, V: uint64_t(SK) << (IntPtrTy->getBitWidth() - |
54 | kSanitizerStatKindBits)), |
55 | Ty: PtrTy)})); |
56 | |
57 | FunctionType *StatReportTy = FunctionType::get(Result: B.getVoidTy(), Params: PtrTy, isVarArg: false); |
58 | FunctionCallee StatReport = |
59 | M->getOrInsertFunction(Name: "__sanitizer_stat_report" , T: StatReportTy); |
60 | |
61 | auto InitAddr = ConstantExpr::getGetElementPtr( |
62 | Ty: EmptyModuleStatsTy, C: ModuleStatsGV, |
63 | IdxList: ArrayRef<Constant *>{ |
64 | ConstantInt::get(Ty: IntPtrTy, V: 0), ConstantInt::get(Ty: B.getInt32Ty(), V: 2), |
65 | ConstantInt::get(Ty: IntPtrTy, V: Inits.size() - 1), |
66 | }); |
67 | B.CreateCall(Callee: StatReport, Args: InitAddr); |
68 | } |
69 | |
70 | void SanitizerStatReport::finish() { |
71 | if (Inits.empty()) { |
72 | ModuleStatsGV->eraseFromParent(); |
73 | return; |
74 | } |
75 | |
76 | PointerType *Int8PtrTy = PointerType::getUnqual(C&: M->getContext()); |
77 | IntegerType *Int32Ty = Type::getInt32Ty(C&: M->getContext()); |
78 | Type *VoidTy = Type::getVoidTy(C&: 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 | auto NewModuleStatsGV = new GlobalVariable( |
83 | *M, makeModuleStatsTy(), false, GlobalValue::InternalLinkage, |
84 | ConstantStruct::getAnon( |
85 | V: {Constant::getNullValue(Ty: Int8PtrTy), |
86 | ConstantInt::get(Ty: Int32Ty, V: Inits.size()), |
87 | ConstantArray::get(T: makeModuleStatsArrayTy(), V: Inits)})); |
88 | ModuleStatsGV->replaceAllUsesWith(V: NewModuleStatsGV); |
89 | ModuleStatsGV->eraseFromParent(); |
90 | |
91 | // Create a global constructor to register NewModuleStatsGV. |
92 | auto F = Function::Create(Ty: FunctionType::get(Result: VoidTy, isVarArg: false), |
93 | Linkage: GlobalValue::InternalLinkage, N: "" , M); |
94 | auto BB = BasicBlock::Create(Context&: M->getContext(), Name: "" , Parent: F); |
95 | IRBuilder<> B(BB); |
96 | |
97 | FunctionType *StatInitTy = FunctionType::get(Result: VoidTy, Params: Int8PtrTy, isVarArg: false); |
98 | FunctionCallee StatInit = |
99 | M->getOrInsertFunction(Name: "__sanitizer_stat_init" , T: StatInitTy); |
100 | |
101 | B.CreateCall(Callee: StatInit, Args: NewModuleStatsGV); |
102 | B.CreateRetVoid(); |
103 | |
104 | appendToGlobalCtors(M&: *M, F, Priority: 0); |
105 | } |
106 | |