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