1 //===- EntryExitInstrumenter.cpp - Function Entry/Exit Instrumentation ----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" 11 #include "llvm/Analysis/GlobalsModRef.h" 12 #include "llvm/CodeGen/Passes.h" 13 #include "llvm/IR/Function.h" 14 #include "llvm/IR/Instructions.h" 15 #include "llvm/IR/Module.h" 16 #include "llvm/IR/Type.h" 17 #include "llvm/Pass.h" 18 #include "llvm/Transforms/Scalar.h" 19 using namespace llvm; 20 21 static void insertCall(Function &CurFn, StringRef Func, 22 Instruction *InsertionPt) { 23 Module &M = *InsertionPt->getParent()->getParent()->getParent(); 24 LLVMContext &C = InsertionPt->getParent()->getContext(); 25 26 if (Func == "mcount" || 27 Func == ".mcount" || 28 Func == "\01__gnu_mcount_nc" || 29 Func == "\01_mcount" || 30 Func == "\01mcount" || 31 Func == "__mcount" || 32 Func == "_mcount" || 33 Func == "__cyg_profile_func_enter_bare") { 34 Constant *Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C)); 35 CallInst::Create(Fn, "", InsertionPt); 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 Constant *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 50 Value *Args[] = {ConstantExpr::getBitCast(&CurFn, Type::getInt8PtrTy(C)), 51 RetAddr}; 52 53 CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt); 54 return; 55 } 56 57 // We only know how to call a fixed set of instrumentation functions, because 58 // they all expect different arguments, etc. 59 report_fatal_error(Twine("Unknown instrumentation function: '") + Func + "'"); 60 } 61 62 static bool runOnFunction(Function &F, bool PostInlining) { 63 StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined" 64 : "instrument-function-entry"; 65 66 StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined" 67 : "instrument-function-exit"; 68 69 StringRef EntryFunc = F.getFnAttribute(EntryAttr).getValueAsString(); 70 StringRef ExitFunc = F.getFnAttribute(ExitAttr).getValueAsString(); 71 72 bool Changed = false; 73 74 // If the attribute is specified, insert instrumentation and then "consume" 75 // the attribute so that it's not inserted again if the pass should happen to 76 // run later for some reason. 77 78 if (!EntryFunc.empty()) { 79 insertCall(F, EntryFunc, &*F.begin()->getFirstInsertionPt()); 80 Changed = true; 81 F.removeAttribute(AttributeList::FunctionIndex, EntryAttr); 82 } 83 84 if (!ExitFunc.empty()) { 85 for (BasicBlock &BB : F) { 86 TerminatorInst *T = BB.getTerminator(); 87 if (isa<ReturnInst>(T)) { 88 insertCall(F, ExitFunc, T); 89 Changed = true; 90 } 91 } 92 F.removeAttribute(AttributeList::FunctionIndex, ExitAttr); 93 } 94 95 return Changed; 96 } 97 98 namespace { 99 struct EntryExitInstrumenter : public FunctionPass { 100 static char ID; 101 EntryExitInstrumenter() : FunctionPass(ID) { 102 initializeEntryExitInstrumenterPass(*PassRegistry::getPassRegistry()); 103 } 104 void getAnalysisUsage(AnalysisUsage &AU) const override { 105 AU.addPreserved<GlobalsAAWrapperPass>(); 106 } 107 bool runOnFunction(Function &F) override { return ::runOnFunction(F, false); } 108 }; 109 char EntryExitInstrumenter::ID = 0; 110 111 struct PostInlineEntryExitInstrumenter : public FunctionPass { 112 static char ID; 113 PostInlineEntryExitInstrumenter() : FunctionPass(ID) { 114 initializePostInlineEntryExitInstrumenterPass( 115 *PassRegistry::getPassRegistry()); 116 } 117 void getAnalysisUsage(AnalysisUsage &AU) const override { 118 AU.addPreserved<GlobalsAAWrapperPass>(); 119 } 120 bool runOnFunction(Function &F) override { return ::runOnFunction(F, true); } 121 }; 122 char PostInlineEntryExitInstrumenter::ID = 0; 123 } 124 125 INITIALIZE_PASS( 126 EntryExitInstrumenter, "ee-instrument", 127 "Instrument function entry/exit with calls to e.g. mcount() (pre inlining)", 128 false, false) 129 INITIALIZE_PASS(PostInlineEntryExitInstrumenter, "post-inline-ee-instrument", 130 "Instrument function entry/exit with calls to e.g. mcount() " 131 "(post inlining)", 132 false, false) 133 134 FunctionPass *llvm::createEntryExitInstrumenterPass() { 135 return new EntryExitInstrumenter(); 136 } 137 138 FunctionPass *llvm::createPostInlineEntryExitInstrumenterPass() { 139 return new PostInlineEntryExitInstrumenter(); 140 } 141 142 PreservedAnalyses 143 llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) { 144 runOnFunction(F, PostInlining); 145 PreservedAnalyses PA; 146 PA.preserveSet<CFGAnalyses>(); 147 return PA; 148 } 149