EntryExitInstrumenter.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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/ADT/Triple.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/InitializePasses.h"
  19. #include "llvm/Pass.h"
  20. #include "llvm/Transforms/Utils.h"
  21. using namespace llvm;
  22. static void insertCall(Function &CurFn, StringRef Func,
  23. Instruction *InsertionPt, DebugLoc DL) {
  24. Module &M = *InsertionPt->getParent()->getParent()->getParent();
  25. LLVMContext &C = InsertionPt->getParent()->getContext();
  26. if (Func == "mcount" ||
  27. Func == ".mcount" ||
  28. Func == "llvm.arm.gnu.eabi.mcount" ||
  29. Func == "\01_mcount" ||
  30. Func == "\01mcount" ||
  31. Func == "__mcount" ||
  32. Func == "_mcount" ||
  33. Func == "__cyg_profile_func_enter_bare") {
  34. Triple TargetTriple(M.getTargetTriple());
  35. if (TargetTriple.isOSAIX() && Func == "__mcount") {
  36. Type *SizeTy = M.getDataLayout().getIntPtrType(C);
  37. Type *SizePtrTy = SizeTy->getPointerTo();
  38. GlobalVariable *GV = new GlobalVariable(M, SizeTy, /*isConstant=*/false,
  39. GlobalValue::InternalLinkage,
  40. ConstantInt::get(SizeTy, 0));
  41. CallInst *Call = CallInst::Create(
  42. M.getOrInsertFunction(Func,
  43. FunctionType::get(Type::getVoidTy(C), {SizePtrTy},
  44. /*isVarArg=*/false)),
  45. {GV}, "", InsertionPt);
  46. Call->setDebugLoc(DL);
  47. } else {
  48. FunctionCallee Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C));
  49. CallInst *Call = CallInst::Create(Fn, "", InsertionPt);
  50. Call->setDebugLoc(DL);
  51. }
  52. return;
  53. }
  54. if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit") {
  55. Type *ArgTypes[] = {Type::getInt8PtrTy(C), Type::getInt8PtrTy(C)};
  56. FunctionCallee Fn = M.getOrInsertFunction(
  57. Func, FunctionType::get(Type::getVoidTy(C), ArgTypes, false));
  58. Instruction *RetAddr = CallInst::Create(
  59. Intrinsic::getDeclaration(&M, Intrinsic::returnaddress),
  60. ArrayRef<Value *>(ConstantInt::get(Type::getInt32Ty(C), 0)), "",
  61. InsertionPt);
  62. RetAddr->setDebugLoc(DL);
  63. Value *Args[] = {ConstantExpr::getBitCast(&CurFn, Type::getInt8PtrTy(C)),
  64. RetAddr};
  65. CallInst *Call =
  66. CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt);
  67. Call->setDebugLoc(DL);
  68. return;
  69. }
  70. // We only know how to call a fixed set of instrumentation functions, because
  71. // they all expect different arguments, etc.
  72. report_fatal_error(Twine("Unknown instrumentation function: '") + Func + "'");
  73. }
  74. static bool runOnFunction(Function &F, bool PostInlining) {
  75. StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined"
  76. : "instrument-function-entry";
  77. StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined"
  78. : "instrument-function-exit";
  79. StringRef EntryFunc = F.getFnAttribute(EntryAttr).getValueAsString();
  80. StringRef ExitFunc = F.getFnAttribute(ExitAttr).getValueAsString();
  81. bool Changed = false;
  82. // If the attribute is specified, insert instrumentation and then "consume"
  83. // the attribute so that it's not inserted again if the pass should happen to
  84. // run later for some reason.
  85. if (!EntryFunc.empty()) {
  86. DebugLoc DL;
  87. if (auto SP = F.getSubprogram())
  88. DL = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
  89. insertCall(F, EntryFunc, &*F.begin()->getFirstInsertionPt(), DL);
  90. Changed = true;
  91. F.removeFnAttr(EntryAttr);
  92. }
  93. if (!ExitFunc.empty()) {
  94. for (BasicBlock &BB : F) {
  95. Instruction *T = BB.getTerminator();
  96. if (!isa<ReturnInst>(T))
  97. continue;
  98. // If T is preceded by a musttail call, that's the real terminator.
  99. if (CallInst *CI = BB.getTerminatingMustTailCall())
  100. T = CI;
  101. DebugLoc DL;
  102. if (DebugLoc TerminatorDL = T->getDebugLoc())
  103. DL = TerminatorDL;
  104. else if (auto SP = F.getSubprogram())
  105. DL = DILocation::get(SP->getContext(), 0, 0, SP);
  106. insertCall(F, ExitFunc, T, DL);
  107. Changed = true;
  108. }
  109. F.removeFnAttr(ExitAttr);
  110. }
  111. return Changed;
  112. }
  113. PreservedAnalyses
  114. llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) {
  115. runOnFunction(F, PostInlining);
  116. PreservedAnalyses PA;
  117. PA.preserveSet<CFGAnalyses>();
  118. return PA;
  119. }
  120. void llvm::EntryExitInstrumenterPass::printPipeline(
  121. raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
  122. static_cast<PassInfoMixin<llvm::EntryExitInstrumenterPass> *>(this)
  123. ->printPipeline(OS, MapClassName2PassName);
  124. OS << "<";
  125. if (PostInlining)
  126. OS << "post-inline";
  127. OS << ">";
  128. }