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