InstrOrderFile.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //===- InstrOrderFile.cpp ---- Late IR instrumentation for order file ----===//
  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. //===----------------------------------------------------------------------===//
  10. #include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
  11. #include "llvm/IR/Constants.h"
  12. #include "llvm/IR/Function.h"
  13. #include "llvm/IR/GlobalValue.h"
  14. #include "llvm/IR/IRBuilder.h"
  15. #include "llvm/IR/Instructions.h"
  16. #include "llvm/IR/Module.h"
  17. #include "llvm/InitializePasses.h"
  18. #include "llvm/Pass.h"
  19. #include "llvm/PassRegistry.h"
  20. #include "llvm/ProfileData/InstrProf.h"
  21. #include "llvm/Support/CommandLine.h"
  22. #include "llvm/Support/FileSystem.h"
  23. #include "llvm/Support/raw_ostream.h"
  24. #include "llvm/Transforms/Instrumentation.h"
  25. #include <fstream>
  26. #include <mutex>
  27. #include <sstream>
  28. using namespace llvm;
  29. #define DEBUG_TYPE "instrorderfile"
  30. static cl::opt<std::string> ClOrderFileWriteMapping(
  31. "orderfile-write-mapping", cl::init(""),
  32. cl::desc(
  33. "Dump functions and their MD5 hash to deobfuscate profile data"),
  34. cl::Hidden);
  35. namespace {
  36. // We need a global bitmap to tell if a function is executed. We also
  37. // need a global variable to save the order of functions. We can use a
  38. // fixed-size buffer that saves the MD5 hash of the function. We need
  39. // a global variable to save the index into the buffer.
  40. std::mutex MappingMutex;
  41. struct InstrOrderFile {
  42. private:
  43. GlobalVariable *OrderFileBuffer;
  44. GlobalVariable *BufferIdx;
  45. GlobalVariable *BitMap;
  46. ArrayType *BufferTy;
  47. ArrayType *MapTy;
  48. public:
  49. InstrOrderFile() = default;
  50. void createOrderFileData(Module &M) {
  51. LLVMContext &Ctx = M.getContext();
  52. int NumFunctions = 0;
  53. for (Function &F : M) {
  54. if (!F.isDeclaration())
  55. NumFunctions++;
  56. }
  57. BufferTy =
  58. ArrayType::get(Type::getInt64Ty(Ctx), INSTR_ORDER_FILE_BUFFER_SIZE);
  59. Type *IdxTy = Type::getInt32Ty(Ctx);
  60. MapTy = ArrayType::get(Type::getInt8Ty(Ctx), NumFunctions);
  61. // Create the global variables.
  62. std::string SymbolName = INSTR_PROF_ORDERFILE_BUFFER_NAME_STR;
  63. OrderFileBuffer = new GlobalVariable(M, BufferTy, false, GlobalValue::LinkOnceODRLinkage,
  64. Constant::getNullValue(BufferTy), SymbolName);
  65. Triple TT = Triple(M.getTargetTriple());
  66. OrderFileBuffer->setSection(
  67. getInstrProfSectionName(IPSK_orderfile, TT.getObjectFormat()));
  68. std::string IndexName = INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME_STR;
  69. BufferIdx = new GlobalVariable(M, IdxTy, false, GlobalValue::LinkOnceODRLinkage,
  70. Constant::getNullValue(IdxTy), IndexName);
  71. std::string BitMapName = "bitmap_0";
  72. BitMap = new GlobalVariable(M, MapTy, false, GlobalValue::PrivateLinkage,
  73. Constant::getNullValue(MapTy), BitMapName);
  74. }
  75. // Generate the code sequence in the entry block of each function to
  76. // update the buffer.
  77. void generateCodeSequence(Module &M, Function &F, int FuncId) {
  78. if (!ClOrderFileWriteMapping.empty()) {
  79. std::lock_guard<std::mutex> LogLock(MappingMutex);
  80. std::error_code EC;
  81. llvm::raw_fd_ostream OS(ClOrderFileWriteMapping, EC,
  82. llvm::sys::fs::OF_Append);
  83. if (EC) {
  84. report_fatal_error(Twine("Failed to open ") + ClOrderFileWriteMapping +
  85. " to save mapping file for order file instrumentation\n");
  86. } else {
  87. std::stringstream stream;
  88. stream << std::hex << MD5Hash(F.getName());
  89. std::string singleLine = "MD5 " + stream.str() + " " +
  90. std::string(F.getName()) + '\n';
  91. OS << singleLine;
  92. }
  93. }
  94. BasicBlock *OrigEntry = &F.getEntryBlock();
  95. LLVMContext &Ctx = M.getContext();
  96. IntegerType *Int32Ty = Type::getInt32Ty(Ctx);
  97. IntegerType *Int8Ty = Type::getInt8Ty(Ctx);
  98. // Create a new entry block for instrumentation. We will check the bitmap
  99. // in this basic block.
  100. BasicBlock *NewEntry =
  101. BasicBlock::Create(M.getContext(), "order_file_entry", &F, OrigEntry);
  102. IRBuilder<> entryB(NewEntry);
  103. // Create a basic block for updating the circular buffer.
  104. BasicBlock *UpdateOrderFileBB =
  105. BasicBlock::Create(M.getContext(), "order_file_set", &F, OrigEntry);
  106. IRBuilder<> updateB(UpdateOrderFileBB);
  107. // Check the bitmap, if it is already 1, do nothing.
  108. // Otherwise, set the bit, grab the index, update the buffer.
  109. Value *IdxFlags[] = {ConstantInt::get(Int32Ty, 0),
  110. ConstantInt::get(Int32Ty, FuncId)};
  111. Value *MapAddr = entryB.CreateGEP(MapTy, BitMap, IdxFlags, "");
  112. LoadInst *loadBitMap = entryB.CreateLoad(Int8Ty, MapAddr, "");
  113. entryB.CreateStore(ConstantInt::get(Int8Ty, 1), MapAddr);
  114. Value *IsNotExecuted =
  115. entryB.CreateICmpEQ(loadBitMap, ConstantInt::get(Int8Ty, 0));
  116. entryB.CreateCondBr(IsNotExecuted, UpdateOrderFileBB, OrigEntry);
  117. // Fill up UpdateOrderFileBB: grab the index, update the buffer!
  118. Value *IdxVal = updateB.CreateAtomicRMW(
  119. AtomicRMWInst::Add, BufferIdx, ConstantInt::get(Int32Ty, 1),
  120. MaybeAlign(), AtomicOrdering::SequentiallyConsistent);
  121. // We need to wrap around the index to fit it inside the buffer.
  122. Value *WrappedIdx = updateB.CreateAnd(
  123. IdxVal, ConstantInt::get(Int32Ty, INSTR_ORDER_FILE_BUFFER_MASK));
  124. Value *BufferGEPIdx[] = {ConstantInt::get(Int32Ty, 0), WrappedIdx};
  125. Value *BufferAddr =
  126. updateB.CreateGEP(BufferTy, OrderFileBuffer, BufferGEPIdx, "");
  127. updateB.CreateStore(ConstantInt::get(Type::getInt64Ty(Ctx), MD5Hash(F.getName())),
  128. BufferAddr);
  129. updateB.CreateBr(OrigEntry);
  130. }
  131. bool run(Module &M) {
  132. createOrderFileData(M);
  133. int FuncId = 0;
  134. for (Function &F : M) {
  135. if (F.isDeclaration())
  136. continue;
  137. generateCodeSequence(M, F, FuncId);
  138. ++FuncId;
  139. }
  140. return true;
  141. }
  142. }; // End of InstrOrderFile struct
  143. } // End anonymous namespace
  144. PreservedAnalyses
  145. InstrOrderFilePass::run(Module &M, ModuleAnalysisManager &AM) {
  146. if (InstrOrderFile().run(M))
  147. return PreservedAnalyses::none();
  148. return PreservedAnalyses::all();
  149. }