EntryExitInstrumenter.cpp 6.5 KB

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