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 Constant *Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C)); 34 CallInst::Create(Fn, "", InsertionPt); 35 return; 36 } 37 38 if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit") { 39 Type *ArgTypes[] = {Type::getInt8PtrTy(C), Type::getInt8PtrTy(C)}; 40 41 Constant *Fn = M.getOrInsertFunction( 42 Func, FunctionType::get(Type::getVoidTy(C), ArgTypes, false)); 43 44 Instruction *RetAddr = CallInst::Create( 45 Intrinsic::getDeclaration(&M, Intrinsic::returnaddress), 46 ArrayRef<Value *>(ConstantInt::get(Type::getInt32Ty(C), 0)), "", 47 InsertionPt); 48 49 Value *Args[] = {ConstantExpr::getBitCast(&CurFn, Type::getInt8PtrTy(C)), 50 RetAddr}; 51 52 CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt); 53 return; 54 } 55 56 // We only know how to call a fixed set of instrumentation functions, because 57 // they all expect different arguments, etc. 58 report_fatal_error(Twine("Unknown instrumentation function: '") + Func + "'"); 59 } 60 61 static bool runOnFunction(Function &F, bool PostInlining) { 62 StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined" 63 : "instrument-function-entry"; 64 65 StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined" 66 : "instrument-function-exit"; 67 68 StringRef EntryFunc = F.getFnAttribute(EntryAttr).getValueAsString(); 69 StringRef ExitFunc = F.getFnAttribute(ExitAttr).getValueAsString(); 70 71 bool Changed = false; 72 73 // If the attribute is specified, insert instrumentation and then "consume" 74 // the attribute so that it's not inserted again if the pass should happen to 75 // run later for some reason. 76 77 if (!EntryFunc.empty()) { 78 insertCall(F, EntryFunc, &*F.begin()->getFirstInsertionPt()); 79 Changed = true; 80 F.removeAttribute(AttributeList::FunctionIndex, EntryAttr); 81 } 82 83 if (!ExitFunc.empty()) { 84 for (BasicBlock &BB : F) { 85 TerminatorInst *T = BB.getTerminator(); 86 if (isa<ReturnInst>(T)) { 87 insertCall(F, ExitFunc, T); 88 Changed = true; 89 } 90 } 91 F.removeAttribute(AttributeList::FunctionIndex, ExitAttr); 92 } 93 94 return Changed; 95 } 96 97 namespace { 98 struct EntryExitInstrumenter : public FunctionPass { 99 static char ID; 100 EntryExitInstrumenter() : FunctionPass(ID) { 101 initializeEntryExitInstrumenterPass(*PassRegistry::getPassRegistry()); 102 } 103 void getAnalysisUsage(AnalysisUsage &AU) const override { 104 AU.addPreserved<GlobalsAAWrapperPass>(); 105 } 106 bool runOnFunction(Function &F) override { return ::runOnFunction(F, false); } 107 }; 108 char EntryExitInstrumenter::ID = 0; 109 110 struct PostInlineEntryExitInstrumenter : public FunctionPass { 111 static char ID; 112 PostInlineEntryExitInstrumenter() : FunctionPass(ID) { 113 initializePostInlineEntryExitInstrumenterPass( 114 *PassRegistry::getPassRegistry()); 115 } 116 void getAnalysisUsage(AnalysisUsage &AU) const override { 117 AU.addPreserved<GlobalsAAWrapperPass>(); 118 } 119 bool runOnFunction(Function &F) override { return ::runOnFunction(F, true); } 120 }; 121 char PostInlineEntryExitInstrumenter::ID = 0; 122 } 123 124 INITIALIZE_PASS( 125 EntryExitInstrumenter, "ee-instrument", 126 "Instrument function entry/exit with calls to e.g. mcount() (pre inlining)", 127 false, false) 128 INITIALIZE_PASS(PostInlineEntryExitInstrumenter, "post-inline-ee-instrument", 129 "Instrument function entry/exit with calls to e.g. mcount() " 130 "(post inlining)", 131 false, false) 132 133 FunctionPass *llvm::createEntryExitInstrumenterPass() { 134 return new EntryExitInstrumenter(); 135 } 136 137 FunctionPass *llvm::createPostInlineEntryExitInstrumenterPass() { 138 return new PostInlineEntryExitInstrumenter(); 139 } 140 141 PreservedAnalyses 142 llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) { 143 runOnFunction(F, PostInlining); 144 PreservedAnalyses PA; 145 PA.preserveSet<CFGAnalyses>(); 146 return PA; 147 } 148