1 //===- EntryExitInstrumenter.cpp - Function Entry/Exit Instrumentation ----===// 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 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" 10 #include "llvm/Analysis/GlobalsModRef.h" 11 #include "llvm/IR/DebugInfoMetadata.h" 12 #include "llvm/IR/Function.h" 13 #include "llvm/IR/Instructions.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/IR/Type.h" 16 #include "llvm/Pass.h" 17 #include "llvm/Transforms/Utils.h" 18 using namespace llvm; 19 20 static void insertCall(Function &CurFn, StringRef Func, 21 Instruction *InsertionPt, DebugLoc DL) { 22 Module &M = *InsertionPt->getParent()->getParent()->getParent(); 23 LLVMContext &C = InsertionPt->getParent()->getContext(); 24 25 if (Func == "mcount" || 26 Func == ".mcount" || 27 Func == "\01__gnu_mcount_nc" || 28 Func == "\01_mcount" || 29 Func == "\01mcount" || 30 Func == "__mcount" || 31 Func == "_mcount" || 32 Func == "__cyg_profile_func_enter_bare") { 33 FunctionCallee Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C)); 34 CallInst *Call = CallInst::Create(Fn, "", InsertionPt); 35 Call->setDebugLoc(DL); 36 return; 37 } 38 39 if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit") { 40 Type *ArgTypes[] = {Type::getInt8PtrTy(C), Type::getInt8PtrTy(C)}; 41 42 FunctionCallee Fn = M.getOrInsertFunction( 43 Func, FunctionType::get(Type::getVoidTy(C), ArgTypes, false)); 44 45 Instruction *RetAddr = CallInst::Create( 46 Intrinsic::getDeclaration(&M, Intrinsic::returnaddress), 47 ArrayRef<Value *>(ConstantInt::get(Type::getInt32Ty(C), 0)), "", 48 InsertionPt); 49 RetAddr->setDebugLoc(DL); 50 51 Value *Args[] = {ConstantExpr::getBitCast(&CurFn, Type::getInt8PtrTy(C)), 52 RetAddr}; 53 54 CallInst *Call = 55 CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt); 56 Call->setDebugLoc(DL); 57 return; 58 } 59 60 // We only know how to call a fixed set of instrumentation functions, because 61 // they all expect different arguments, etc. 62 report_fatal_error(Twine("Unknown instrumentation function: '") + Func + "'"); 63 } 64 65 static bool runOnFunction(Function &F, bool PostInlining) { 66 StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined" 67 : "instrument-function-entry"; 68 69 StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined" 70 : "instrument-function-exit"; 71 72 StringRef EntryFunc = F.getFnAttribute(EntryAttr).getValueAsString(); 73 StringRef ExitFunc = F.getFnAttribute(ExitAttr).getValueAsString(); 74 75 bool Changed = false; 76 77 // If the attribute is specified, insert instrumentation and then "consume" 78 // the attribute so that it's not inserted again if the pass should happen to 79 // run later for some reason. 80 81 if (!EntryFunc.empty()) { 82 DebugLoc DL; 83 if (auto SP = F.getSubprogram()) 84 DL = DebugLoc::get(SP->getScopeLine(), 0, SP); 85 86 insertCall(F, EntryFunc, &*F.begin()->getFirstInsertionPt(), DL); 87 Changed = true; 88 F.removeAttribute(AttributeList::FunctionIndex, EntryAttr); 89 } 90 91 if (!ExitFunc.empty()) { 92 for (BasicBlock &BB : F) { 93 Instruction *T = BB.getTerminator(); 94 if (!isa<ReturnInst>(T)) 95 continue; 96 97 // If T is preceded by a musttail call, that's the real terminator. 98 Instruction *Prev = T->getPrevNode(); 99 if (BitCastInst *BCI = dyn_cast_or_null<BitCastInst>(Prev)) 100 Prev = BCI->getPrevNode(); 101 if (CallInst *CI = dyn_cast_or_null<CallInst>(Prev)) { 102 if (CI->isMustTailCall()) 103 T = CI; 104 } 105 106 DebugLoc DL; 107 if (DebugLoc TerminatorDL = T->getDebugLoc()) 108 DL = TerminatorDL; 109 else if (auto SP = F.getSubprogram()) 110 DL = DebugLoc::get(0, 0, SP); 111 112 insertCall(F, ExitFunc, T, DL); 113 Changed = true; 114 } 115 F.removeAttribute(AttributeList::FunctionIndex, ExitAttr); 116 } 117 118 return Changed; 119 } 120 121 namespace { 122 struct EntryExitInstrumenter : public FunctionPass { 123 static char ID; 124 EntryExitInstrumenter() : FunctionPass(ID) { 125 initializeEntryExitInstrumenterPass(*PassRegistry::getPassRegistry()); 126 } 127 void getAnalysisUsage(AnalysisUsage &AU) const override { 128 AU.addPreserved<GlobalsAAWrapperPass>(); 129 } 130 bool runOnFunction(Function &F) override { return ::runOnFunction(F, false); } 131 }; 132 char EntryExitInstrumenter::ID = 0; 133 134 struct PostInlineEntryExitInstrumenter : public FunctionPass { 135 static char ID; 136 PostInlineEntryExitInstrumenter() : FunctionPass(ID) { 137 initializePostInlineEntryExitInstrumenterPass( 138 *PassRegistry::getPassRegistry()); 139 } 140 void getAnalysisUsage(AnalysisUsage &AU) const override { 141 AU.addPreserved<GlobalsAAWrapperPass>(); 142 } 143 bool runOnFunction(Function &F) override { return ::runOnFunction(F, true); } 144 }; 145 char PostInlineEntryExitInstrumenter::ID = 0; 146 } 147 148 INITIALIZE_PASS( 149 EntryExitInstrumenter, "ee-instrument", 150 "Instrument function entry/exit with calls to e.g. mcount() (pre inlining)", 151 false, false) 152 INITIALIZE_PASS(PostInlineEntryExitInstrumenter, "post-inline-ee-instrument", 153 "Instrument function entry/exit with calls to e.g. mcount() " 154 "(post inlining)", 155 false, false) 156 157 FunctionPass *llvm::createEntryExitInstrumenterPass() { 158 return new EntryExitInstrumenter(); 159 } 160 161 FunctionPass *llvm::createPostInlineEntryExitInstrumenterPass() { 162 return new PostInlineEntryExitInstrumenter(); 163 } 164 165 PreservedAnalyses 166 llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) { 167 runOnFunction(F, PostInlining); 168 PreservedAnalyses PA; 169 PA.preserveSet<CFGAnalyses>(); 170 return PA; 171 } 172