1 //===- EntryExitInstrumenter.cpp - Function Entry/Exit Instrumentation ----===//
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
7 //===----------------------------------------------------------------------===//
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"
20 static void insertCall(Function
&CurFn
, StringRef Func
,
21 Instruction
*InsertionPt
, DebugLoc DL
) {
22 Module
&M
= *InsertionPt
->getParent()->getParent()->getParent();
23 LLVMContext
&C
= InsertionPt
->getParent()->getContext();
25 if (Func
== "mcount" ||
27 Func
== "llvm.arm.gnu.eabi.mcount" ||
28 Func
== "\01_mcount" ||
29 Func
== "\01mcount" ||
32 Func
== "__cyg_profile_func_enter_bare") {
33 FunctionCallee Fn
= M
.getOrInsertFunction(Func
, Type::getVoidTy(C
));
34 CallInst
*Call
= CallInst::Create(Fn
, "", InsertionPt
);
35 Call
->setDebugLoc(DL
);
39 if (Func
== "__cyg_profile_func_enter" || Func
== "__cyg_profile_func_exit") {
40 Type
*ArgTypes
[] = {Type::getInt8PtrTy(C
), Type::getInt8PtrTy(C
)};
42 FunctionCallee Fn
= M
.getOrInsertFunction(
43 Func
, FunctionType::get(Type::getVoidTy(C
), ArgTypes
, false));
45 Instruction
*RetAddr
= CallInst::Create(
46 Intrinsic::getDeclaration(&M
, Intrinsic::returnaddress
),
47 ArrayRef
<Value
*>(ConstantInt::get(Type::getInt32Ty(C
), 0)), "",
49 RetAddr
->setDebugLoc(DL
);
51 Value
*Args
[] = {ConstantExpr::getBitCast(&CurFn
, Type::getInt8PtrTy(C
)),
55 CallInst::Create(Fn
, ArrayRef
<Value
*>(Args
), "", InsertionPt
);
56 Call
->setDebugLoc(DL
);
60 // We only know how to call a fixed set of instrumentation functions, because
61 // they all expect different arguments, etc.
62 report_fatal_error(Twine("Unknown instrumentation function: '") + Func
+ "'");
65 static bool runOnFunction(Function
&F
, bool PostInlining
) {
66 StringRef EntryAttr
= PostInlining
? "instrument-function-entry-inlined"
67 : "instrument-function-entry";
69 StringRef ExitAttr
= PostInlining
? "instrument-function-exit-inlined"
70 : "instrument-function-exit";
72 StringRef EntryFunc
= F
.getFnAttribute(EntryAttr
).getValueAsString();
73 StringRef ExitFunc
= F
.getFnAttribute(ExitAttr
).getValueAsString();
77 // If the attribute is specified, insert instrumentation and then "consume"
78 // the attribute so that it's not inserted again if the pass should happen to
79 // run later for some reason.
81 if (!EntryFunc
.empty()) {
83 if (auto SP
= F
.getSubprogram())
84 DL
= DebugLoc::get(SP
->getScopeLine(), 0, SP
);
86 insertCall(F
, EntryFunc
, &*F
.begin()->getFirstInsertionPt(), DL
);
88 F
.removeAttribute(AttributeList::FunctionIndex
, EntryAttr
);
91 if (!ExitFunc
.empty()) {
92 for (BasicBlock
&BB
: F
) {
93 Instruction
*T
= BB
.getTerminator();
94 if (!isa
<ReturnInst
>(T
))
97 // If T is preceded by a musttail call, that's the real terminator.
98 Instruction
*Prev
= T
->getPrevNode();
99 if (BitCastInst
*BCI
= dyn_cast_or_null
<BitCastInst
>(Prev
))
100 Prev
= BCI
->getPrevNode();
101 if (CallInst
*CI
= dyn_cast_or_null
<CallInst
>(Prev
)) {
102 if (CI
->isMustTailCall())
107 if (DebugLoc TerminatorDL
= T
->getDebugLoc())
109 else if (auto SP
= F
.getSubprogram())
110 DL
= DebugLoc::get(0, 0, SP
);
112 insertCall(F
, ExitFunc
, T
, DL
);
115 F
.removeAttribute(AttributeList::FunctionIndex
, ExitAttr
);
122 struct EntryExitInstrumenter
: public FunctionPass
{
124 EntryExitInstrumenter() : FunctionPass(ID
) {
125 initializeEntryExitInstrumenterPass(*PassRegistry::getPassRegistry());
127 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
128 AU
.addPreserved
<GlobalsAAWrapperPass
>();
130 bool runOnFunction(Function
&F
) override
{ return ::runOnFunction(F
, false); }
132 char EntryExitInstrumenter::ID
= 0;
134 struct PostInlineEntryExitInstrumenter
: public FunctionPass
{
136 PostInlineEntryExitInstrumenter() : FunctionPass(ID
) {
137 initializePostInlineEntryExitInstrumenterPass(
138 *PassRegistry::getPassRegistry());
140 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
141 AU
.addPreserved
<GlobalsAAWrapperPass
>();
143 bool runOnFunction(Function
&F
) override
{ return ::runOnFunction(F
, true); }
145 char PostInlineEntryExitInstrumenter::ID
= 0;
149 EntryExitInstrumenter
, "ee-instrument",
150 "Instrument function entry/exit with calls to e.g. mcount() (pre inlining)",
152 INITIALIZE_PASS(PostInlineEntryExitInstrumenter
, "post-inline-ee-instrument",
153 "Instrument function entry/exit with calls to e.g. mcount() "
157 FunctionPass
*llvm::createEntryExitInstrumenterPass() {
158 return new EntryExitInstrumenter();
161 FunctionPass
*llvm::createPostInlineEntryExitInstrumenterPass() {
162 return new PostInlineEntryExitInstrumenter();
166 llvm::EntryExitInstrumenterPass::run(Function
&F
, FunctionAnalysisManager
&AM
) {
167 runOnFunction(F
, PostInlining
);
168 PreservedAnalyses PA
;
169 PA
.preserveSet
<CFGAnalyses
>();