blob: ba6f67e15cae54ad84590583769d5d75ee0138e6 [file] [log] [blame]
Hans Wennborge1ecd612017-11-14 21:09:45 +00001//===- 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"
19using namespace llvm;
20
21static 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
61static 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
97namespace {
98struct 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};
108char EntryExitInstrumenter::ID = 0;
109
110struct 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};
121char PostInlineEntryExitInstrumenter::ID = 0;
122}
123
124INITIALIZE_PASS(
125 EntryExitInstrumenter, "ee-instrument",
126 "Instrument function entry/exit with calls to e.g. mcount() (pre inlining)",
127 false, false);
128
129INITIALIZE_PASS(PostInlineEntryExitInstrumenter, "post-inline-ee-instrument",
130 "Instrument function entry/exit with calls to e.g. mcount() "
131 "(post inlining)",
132 false, false);
133
134FunctionPass *llvm::createEntryExitInstrumenterPass() {
135 return new EntryExitInstrumenter();
136}
137
138FunctionPass *llvm::createPostInlineEntryExitInstrumenterPass() {
139 return new PostInlineEntryExitInstrumenter();
140}
141
142PreservedAnalyses
143llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) {
144 runOnFunction(F, PostInlining);
145 PreservedAnalyses PA;
146 PA.preserveSet<CFGAnalyses>();
147 return PA;
148}