InstrOrderFile.cpp 7.2 KB

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