Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp
35271 views
//===- EntryExitInstrumenter.cpp - Function Entry/Exit Instrumentation ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"9#include "llvm/Analysis/GlobalsModRef.h"10#include "llvm/IR/DebugInfoMetadata.h"11#include "llvm/IR/Dominators.h"12#include "llvm/IR/Function.h"13#include "llvm/IR/Instructions.h"14#include "llvm/IR/Intrinsics.h"15#include "llvm/IR/Module.h"16#include "llvm/IR/Type.h"17#include "llvm/InitializePasses.h"18#include "llvm/TargetParser/Triple.h"19#include "llvm/Pass.h"20#include "llvm/Transforms/Utils.h"2122using namespace llvm;2324static void insertCall(Function &CurFn, StringRef Func,25BasicBlock::iterator InsertionPt, DebugLoc DL) {26Module &M = *InsertionPt->getParent()->getParent()->getParent();27LLVMContext &C = InsertionPt->getParent()->getContext();2829if (Func == "mcount" ||30Func == ".mcount" ||31Func == "llvm.arm.gnu.eabi.mcount" ||32Func == "\01_mcount" ||33Func == "\01mcount" ||34Func == "__mcount" ||35Func == "_mcount" ||36Func == "__cyg_profile_func_enter_bare") {37Triple TargetTriple(M.getTargetTriple());38if (TargetTriple.isOSAIX() && Func == "__mcount") {39Type *SizeTy = M.getDataLayout().getIntPtrType(C);40Type *SizePtrTy = PointerType::getUnqual(C);41GlobalVariable *GV = new GlobalVariable(M, SizeTy, /*isConstant=*/false,42GlobalValue::InternalLinkage,43ConstantInt::get(SizeTy, 0));44CallInst *Call = CallInst::Create(45M.getOrInsertFunction(Func,46FunctionType::get(Type::getVoidTy(C), {SizePtrTy},47/*isVarArg=*/false)),48{GV}, "", InsertionPt);49Call->setDebugLoc(DL);50} else {51FunctionCallee Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C));52CallInst *Call = CallInst::Create(Fn, "", InsertionPt);53Call->setDebugLoc(DL);54}55return;56}5758if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit") {59Type *ArgTypes[] = {PointerType::getUnqual(C), PointerType::getUnqual(C)};6061FunctionCallee Fn = M.getOrInsertFunction(62Func, FunctionType::get(Type::getVoidTy(C), ArgTypes, false));6364Instruction *RetAddr = CallInst::Create(65Intrinsic::getDeclaration(&M, Intrinsic::returnaddress),66ArrayRef<Value *>(ConstantInt::get(Type::getInt32Ty(C), 0)), "",67InsertionPt);68RetAddr->setDebugLoc(DL);6970Value *Args[] = {&CurFn, RetAddr};71CallInst *Call =72CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt);73Call->setDebugLoc(DL);74return;75}7677// We only know how to call a fixed set of instrumentation functions, because78// they all expect different arguments, etc.79report_fatal_error(Twine("Unknown instrumentation function: '") + Func + "'");80}8182static bool runOnFunction(Function &F, bool PostInlining) {83// The asm in a naked function may reasonably expect the argument registers84// and the return address register (if present) to be live. An inserted85// function call will clobber these registers. Simply skip naked functions for86// all targets.87if (F.hasFnAttribute(Attribute::Naked))88return false;8990StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined"91: "instrument-function-entry";9293StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined"94: "instrument-function-exit";9596StringRef EntryFunc = F.getFnAttribute(EntryAttr).getValueAsString();97StringRef ExitFunc = F.getFnAttribute(ExitAttr).getValueAsString();9899bool Changed = false;100101// If the attribute is specified, insert instrumentation and then "consume"102// the attribute so that it's not inserted again if the pass should happen to103// run later for some reason.104105if (!EntryFunc.empty()) {106DebugLoc DL;107if (auto SP = F.getSubprogram())108DL = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);109110insertCall(F, EntryFunc, F.begin()->getFirstInsertionPt(), DL);111Changed = true;112F.removeFnAttr(EntryAttr);113}114115if (!ExitFunc.empty()) {116for (BasicBlock &BB : F) {117Instruction *T = BB.getTerminator();118if (!isa<ReturnInst>(T))119continue;120121// If T is preceded by a musttail call, that's the real terminator.122if (CallInst *CI = BB.getTerminatingMustTailCall())123T = CI;124125DebugLoc DL;126if (DebugLoc TerminatorDL = T->getDebugLoc())127DL = TerminatorDL;128else if (auto SP = F.getSubprogram())129DL = DILocation::get(SP->getContext(), 0, 0, SP);130131insertCall(F, ExitFunc, T->getIterator(), DL);132Changed = true;133}134F.removeFnAttr(ExitAttr);135}136137return Changed;138}139140namespace {141struct PostInlineEntryExitInstrumenter : public FunctionPass {142static char ID;143PostInlineEntryExitInstrumenter() : FunctionPass(ID) {144initializePostInlineEntryExitInstrumenterPass(145*PassRegistry::getPassRegistry());146}147void getAnalysisUsage(AnalysisUsage &AU) const override {148AU.addPreserved<GlobalsAAWrapperPass>();149AU.addPreserved<DominatorTreeWrapperPass>();150}151bool runOnFunction(Function &F) override { return ::runOnFunction(F, true); }152};153char PostInlineEntryExitInstrumenter::ID = 0;154}155156INITIALIZE_PASS_BEGIN(157PostInlineEntryExitInstrumenter, "post-inline-ee-instrument",158"Instrument function entry/exit with calls to e.g. mcount() "159"(post inlining)",160false, false)161INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)162INITIALIZE_PASS_END(163PostInlineEntryExitInstrumenter, "post-inline-ee-instrument",164"Instrument function entry/exit with calls to e.g. mcount() "165"(post inlining)",166false, false)167168FunctionPass *llvm::createPostInlineEntryExitInstrumenterPass() {169return new PostInlineEntryExitInstrumenter();170}171172PreservedAnalyses173llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) {174if (!runOnFunction(F, PostInlining))175return PreservedAnalyses::all();176PreservedAnalyses PA;177PA.preserveSet<CFGAnalyses>();178return PA;179}180181void llvm::EntryExitInstrumenterPass::printPipeline(182raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {183static_cast<PassInfoMixin<llvm::EntryExitInstrumenterPass> *>(this)184->printPipeline(OS, MapClassName2PassName);185OS << '<';186if (PostInlining)187OS << "post-inline";188OS << '>';189}190191192