Coverage Report

Created: 2019-07-24 05:18

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