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