xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Utils/SanitizerStats.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- SanitizerStats.cpp - Sanitizer statistics gathering ----------------===//
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 // Implements code generation for sanitizer statistics gathering.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/Transforms/Utils/SanitizerStats.h"
140b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
150b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
160b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h"
170b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
180b57cec5SDimitry Andric #include "llvm/IR/Module.h"
190b57cec5SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric SanitizerStatReport::SanitizerStatReport(Module *M) : M(M) {
24*5f757f3fSDimitry Andric   StatTy = ArrayType::get(PointerType::getUnqual(M->getContext()), 2);
250b57cec5SDimitry Andric   EmptyModuleStatsTy = makeModuleStatsTy();
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric   ModuleStatsGV = new GlobalVariable(*M, EmptyModuleStatsTy, false,
280b57cec5SDimitry Andric                                      GlobalValue::InternalLinkage, nullptr);
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric ArrayType *SanitizerStatReport::makeModuleStatsArrayTy() {
320b57cec5SDimitry Andric   return ArrayType::get(StatTy, Inits.size());
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric StructType *SanitizerStatReport::makeModuleStatsTy() {
36*5f757f3fSDimitry Andric   return StructType::get(M->getContext(),
37*5f757f3fSDimitry Andric                          {PointerType::getUnqual(M->getContext()),
380b57cec5SDimitry Andric                           Type::getInt32Ty(M->getContext()),
390b57cec5SDimitry Andric                           makeModuleStatsArrayTy()});
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric void SanitizerStatReport::create(IRBuilder<> &B, SanitizerStatKind SK) {
430b57cec5SDimitry Andric   Function *F = B.GetInsertBlock()->getParent();
440b57cec5SDimitry Andric   Module *M = F->getParent();
45*5f757f3fSDimitry Andric   PointerType *PtrTy = B.getPtrTy();
460b57cec5SDimitry Andric   IntegerType *IntPtrTy = B.getIntPtrTy(M->getDataLayout());
47*5f757f3fSDimitry Andric   ArrayType *StatTy = ArrayType::get(PtrTy, 2);
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   Inits.push_back(ConstantArray::get(
500b57cec5SDimitry Andric       StatTy,
51*5f757f3fSDimitry Andric       {Constant::getNullValue(PtrTy),
520b57cec5SDimitry Andric        ConstantExpr::getIntToPtr(
530b57cec5SDimitry Andric            ConstantInt::get(IntPtrTy, uint64_t(SK) << (IntPtrTy->getBitWidth() -
540b57cec5SDimitry Andric                                                        kSanitizerStatKindBits)),
55*5f757f3fSDimitry Andric            PtrTy)}));
560b57cec5SDimitry Andric 
57*5f757f3fSDimitry Andric   FunctionType *StatReportTy = FunctionType::get(B.getVoidTy(), PtrTy, false);
580b57cec5SDimitry Andric   FunctionCallee StatReport =
590b57cec5SDimitry Andric       M->getOrInsertFunction("__sanitizer_stat_report", StatReportTy);
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   auto InitAddr = ConstantExpr::getGetElementPtr(
620b57cec5SDimitry Andric       EmptyModuleStatsTy, ModuleStatsGV,
630b57cec5SDimitry Andric       ArrayRef<Constant *>{
640b57cec5SDimitry Andric           ConstantInt::get(IntPtrTy, 0), ConstantInt::get(B.getInt32Ty(), 2),
650b57cec5SDimitry Andric           ConstantInt::get(IntPtrTy, Inits.size() - 1),
660b57cec5SDimitry Andric       });
67*5f757f3fSDimitry Andric   B.CreateCall(StatReport, InitAddr);
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric void SanitizerStatReport::finish() {
710b57cec5SDimitry Andric   if (Inits.empty()) {
720b57cec5SDimitry Andric     ModuleStatsGV->eraseFromParent();
730b57cec5SDimitry Andric     return;
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
76*5f757f3fSDimitry Andric   PointerType *Int8PtrTy = PointerType::getUnqual(M->getContext());
770b57cec5SDimitry Andric   IntegerType *Int32Ty = Type::getInt32Ty(M->getContext());
780b57cec5SDimitry Andric   Type *VoidTy = Type::getVoidTy(M->getContext());
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   // Create a new ModuleStatsGV to replace the old one. We can't just set the
810b57cec5SDimitry Andric   // old one's initializer because its type is different.
820b57cec5SDimitry Andric   auto NewModuleStatsGV = new GlobalVariable(
830b57cec5SDimitry Andric       *M, makeModuleStatsTy(), false, GlobalValue::InternalLinkage,
840b57cec5SDimitry Andric       ConstantStruct::getAnon(
850b57cec5SDimitry Andric           {Constant::getNullValue(Int8PtrTy),
860b57cec5SDimitry Andric            ConstantInt::get(Int32Ty, Inits.size()),
870b57cec5SDimitry Andric            ConstantArray::get(makeModuleStatsArrayTy(), Inits)}));
88*5f757f3fSDimitry Andric   ModuleStatsGV->replaceAllUsesWith(NewModuleStatsGV);
890b57cec5SDimitry Andric   ModuleStatsGV->eraseFromParent();
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   // Create a global constructor to register NewModuleStatsGV.
920b57cec5SDimitry Andric   auto F = Function::Create(FunctionType::get(VoidTy, false),
930b57cec5SDimitry Andric                             GlobalValue::InternalLinkage, "", M);
940b57cec5SDimitry Andric   auto BB = BasicBlock::Create(M->getContext(), "", F);
950b57cec5SDimitry Andric   IRBuilder<> B(BB);
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   FunctionType *StatInitTy = FunctionType::get(VoidTy, Int8PtrTy, false);
980b57cec5SDimitry Andric   FunctionCallee StatInit =
990b57cec5SDimitry Andric       M->getOrInsertFunction("__sanitizer_stat_init", StatInitTy);
1000b57cec5SDimitry Andric 
101*5f757f3fSDimitry Andric   B.CreateCall(StatInit, NewModuleStatsGV);
1020b57cec5SDimitry Andric   B.CreateRetVoid();
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   appendToGlobalCtors(*M, F, 0);
1050b57cec5SDimitry Andric }
106