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/Dominators.h" |
13 | #include "llvm/IR/Function.h" |
14 | #include "llvm/IR/Instructions.h" |
15 | #include "llvm/IR/Intrinsics.h" |
16 | #include "llvm/IR/Module.h" |
17 | #include "llvm/IR/Type.h" |
18 | #include "llvm/TargetParser/Triple.h" |
19 | |
20 | using namespace llvm; |
21 | |
22 | static void insertCall(Function &CurFn, StringRef Func, |
23 | BasicBlock::iterator InsertionPt, DebugLoc DL) { |
24 | Module &M = *InsertionPt->getParent()->getParent()->getParent(); |
25 | LLVMContext &C = InsertionPt->getParent()->getContext(); |
26 | |
27 | if (Func == "mcount" || |
28 | Func == ".mcount" || |
29 | Func == "llvm.arm.gnu.eabi.mcount" || |
30 | Func == "\01_mcount" || |
31 | Func == "\01mcount" || |
32 | Func == "__mcount" || |
33 | Func == "_mcount" || |
34 | Func == "__cyg_profile_func_enter_bare" ) { |
35 | Triple TargetTriple(M.getTargetTriple()); |
36 | if (TargetTriple.isOSAIX() && Func == "__mcount" ) { |
37 | Type *SizeTy = M.getDataLayout().getIntPtrType(C); |
38 | Type *SizePtrTy = PointerType::getUnqual(C); |
39 | GlobalVariable *GV = new GlobalVariable(M, SizeTy, /*isConstant=*/false, |
40 | GlobalValue::InternalLinkage, |
41 | ConstantInt::get(Ty: SizeTy, V: 0)); |
42 | CallInst *Call = CallInst::Create( |
43 | Func: M.getOrInsertFunction(Name: Func, |
44 | T: FunctionType::get(Result: Type::getVoidTy(C), Params: {SizePtrTy}, |
45 | /*isVarArg=*/false)), |
46 | Args: {GV}, NameStr: "" , InsertBefore: InsertionPt); |
47 | Call->setDebugLoc(DL); |
48 | } else { |
49 | FunctionCallee Fn = M.getOrInsertFunction(Name: Func, RetTy: Type::getVoidTy(C)); |
50 | CallInst *Call = CallInst::Create(Func: Fn, NameStr: "" , InsertBefore: InsertionPt); |
51 | Call->setDebugLoc(DL); |
52 | } |
53 | return; |
54 | } |
55 | |
56 | if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit" ) { |
57 | Type *ArgTypes[] = {PointerType::getUnqual(C), PointerType::getUnqual(C)}; |
58 | |
59 | FunctionCallee Fn = M.getOrInsertFunction( |
60 | Name: Func, T: FunctionType::get(Result: Type::getVoidTy(C), Params: ArgTypes, isVarArg: false)); |
61 | |
62 | Instruction *RetAddr = CallInst::Create( |
63 | Intrinsic::getDeclaration(M: &M, Intrinsic::id: returnaddress), |
64 | ArrayRef<Value *>(ConstantInt::get(Ty: Type::getInt32Ty(C), V: 0)), "" , |
65 | InsertionPt); |
66 | RetAddr->setDebugLoc(DL); |
67 | |
68 | Value *Args[] = {&CurFn, RetAddr}; |
69 | CallInst *Call = |
70 | CallInst::Create(Func: Fn, Args: ArrayRef<Value *>(Args), NameStr: "" , InsertBefore: InsertionPt); |
71 | Call->setDebugLoc(DL); |
72 | return; |
73 | } |
74 | |
75 | // We only know how to call a fixed set of instrumentation functions, because |
76 | // they all expect different arguments, etc. |
77 | report_fatal_error(reason: Twine("Unknown instrumentation function: '" ) + Func + "'" ); |
78 | } |
79 | |
80 | static bool runOnFunction(Function &F, bool PostInlining) { |
81 | // The asm in a naked function may reasonably expect the argument registers |
82 | // and the return address register (if present) to be live. An inserted |
83 | // function call will clobber these registers. Simply skip naked functions for |
84 | // all targets. |
85 | if (F.hasFnAttribute(Attribute::Naked)) |
86 | return false; |
87 | |
88 | StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined" |
89 | : "instrument-function-entry" ; |
90 | |
91 | StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined" |
92 | : "instrument-function-exit" ; |
93 | |
94 | StringRef EntryFunc = F.getFnAttribute(Kind: EntryAttr).getValueAsString(); |
95 | StringRef ExitFunc = F.getFnAttribute(Kind: ExitAttr).getValueAsString(); |
96 | |
97 | bool Changed = false; |
98 | |
99 | // If the attribute is specified, insert instrumentation and then "consume" |
100 | // the attribute so that it's not inserted again if the pass should happen to |
101 | // run later for some reason. |
102 | |
103 | if (!EntryFunc.empty()) { |
104 | DebugLoc DL; |
105 | if (auto SP = F.getSubprogram()) |
106 | DL = DILocation::get(Context&: SP->getContext(), Line: SP->getScopeLine(), Column: 0, Scope: SP); |
107 | |
108 | insertCall(CurFn&: F, Func: EntryFunc, InsertionPt: F.begin()->getFirstInsertionPt(), DL); |
109 | Changed = true; |
110 | F.removeFnAttr(Kind: EntryAttr); |
111 | } |
112 | |
113 | if (!ExitFunc.empty()) { |
114 | for (BasicBlock &BB : F) { |
115 | Instruction *T = BB.getTerminator(); |
116 | if (!isa<ReturnInst>(Val: T)) |
117 | continue; |
118 | |
119 | // If T is preceded by a musttail call, that's the real terminator. |
120 | if (CallInst *CI = BB.getTerminatingMustTailCall()) |
121 | T = CI; |
122 | |
123 | DebugLoc DL; |
124 | if (DebugLoc TerminatorDL = T->getDebugLoc()) |
125 | DL = TerminatorDL; |
126 | else if (auto SP = F.getSubprogram()) |
127 | DL = DILocation::get(Context&: SP->getContext(), Line: 0, Column: 0, Scope: SP); |
128 | |
129 | insertCall(CurFn&: F, Func: ExitFunc, InsertionPt: T->getIterator(), DL); |
130 | Changed = true; |
131 | } |
132 | F.removeFnAttr(Kind: ExitAttr); |
133 | } |
134 | |
135 | return Changed; |
136 | } |
137 | |
138 | PreservedAnalyses |
139 | llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) { |
140 | runOnFunction(F, PostInlining); |
141 | PreservedAnalyses PA; |
142 | PA.preserveSet<CFGAnalyses>(); |
143 | return PA; |
144 | } |
145 | |
146 | void llvm::EntryExitInstrumenterPass::printPipeline( |
147 | raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { |
148 | static_cast<PassInfoMixin<llvm::EntryExitInstrumenterPass> *>(this) |
149 | ->printPipeline(OS, MapClassName2PassName); |
150 | OS << '<'; |
151 | if (PostInlining) |
152 | OS << "post-inline" ; |
153 | OS << '>'; |
154 | } |
155 | |