/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 | } |