InstrOrderFile.cpp 7.2 KB

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