10b57cec5SDimitry Andric //===- InstrOrderFile.cpp ---- Late IR instrumentation for order file ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric //                     The LLVM Compiler Infrastructure
40b57cec5SDimitry Andric //
50b57cec5SDimitry Andric // This file is distributed under the University of Illinois Open Source
60b57cec5SDimitry Andric // License. See LICENSE.TXT for details.
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
90b57cec5SDimitry Andric //
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric 
12480093f4SDimitry Andric #include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
130b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
140b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
150b57cec5SDimitry Andric #include "llvm/IR/Function.h"
160b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h"
170b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
180b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
190b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
200b57cec5SDimitry Andric #include "llvm/IR/Metadata.h"
210b57cec5SDimitry Andric #include "llvm/IR/Module.h"
22480093f4SDimitry Andric #include "llvm/InitializePasses.h"
230b57cec5SDimitry Andric #include "llvm/Pass.h"
240b57cec5SDimitry Andric #include "llvm/PassRegistry.h"
250b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h"
260b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
270b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
280b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
290b57cec5SDimitry Andric #include "llvm/Support/Path.h"
300b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
310b57cec5SDimitry Andric #include "llvm/Transforms/Instrumentation.h"
320b57cec5SDimitry Andric #include <fstream>
330b57cec5SDimitry Andric #include <map>
340b57cec5SDimitry Andric #include <mutex>
350b57cec5SDimitry Andric #include <set>
360b57cec5SDimitry Andric #include <sstream>
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric using namespace llvm;
390b57cec5SDimitry Andric #define DEBUG_TYPE "instrorderfile"
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric static cl::opt<std::string> ClOrderFileWriteMapping(
420b57cec5SDimitry Andric     "orderfile-write-mapping", cl::init(""),
430b57cec5SDimitry Andric     cl::desc(
440b57cec5SDimitry Andric         "Dump functions and their MD5 hash to deobfuscate profile data"),
450b57cec5SDimitry Andric     cl::Hidden);
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric namespace {
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric // We need a global bitmap to tell if a function is executed. We also
500b57cec5SDimitry Andric // need a global variable to save the order of functions. We can use a
510b57cec5SDimitry Andric // fixed-size buffer that saves the MD5 hash of the function. We need
520b57cec5SDimitry Andric // a global variable to save the index into the buffer.
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric std::mutex MappingMutex;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric struct InstrOrderFile {
570b57cec5SDimitry Andric private:
580b57cec5SDimitry Andric   GlobalVariable *OrderFileBuffer;
590b57cec5SDimitry Andric   GlobalVariable *BufferIdx;
600b57cec5SDimitry Andric   GlobalVariable *BitMap;
610b57cec5SDimitry Andric   ArrayType *BufferTy;
620b57cec5SDimitry Andric   ArrayType *MapTy;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric public:
InstrOrderFile__anonf94012910111::InstrOrderFile650b57cec5SDimitry Andric   InstrOrderFile() {}
660b57cec5SDimitry Andric 
createOrderFileData__anonf94012910111::InstrOrderFile670b57cec5SDimitry Andric   void createOrderFileData(Module &M) {
680b57cec5SDimitry Andric     LLVMContext &Ctx = M.getContext();
690b57cec5SDimitry Andric     int NumFunctions = 0;
700b57cec5SDimitry Andric     for (Function &F : M) {
710b57cec5SDimitry Andric       if (!F.isDeclaration())
720b57cec5SDimitry Andric         NumFunctions++;
730b57cec5SDimitry Andric     }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric     BufferTy =
760b57cec5SDimitry Andric         ArrayType::get(Type::getInt64Ty(Ctx), INSTR_ORDER_FILE_BUFFER_SIZE);
770b57cec5SDimitry Andric     Type *IdxTy = Type::getInt32Ty(Ctx);
780b57cec5SDimitry Andric     MapTy = ArrayType::get(Type::getInt8Ty(Ctx), NumFunctions);
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric     // Create the global variables.
810b57cec5SDimitry Andric     std::string SymbolName = INSTR_PROF_ORDERFILE_BUFFER_NAME_STR;
820b57cec5SDimitry Andric     OrderFileBuffer = new GlobalVariable(M, BufferTy, false, GlobalValue::LinkOnceODRLinkage,
830b57cec5SDimitry Andric                            Constant::getNullValue(BufferTy), SymbolName);
840b57cec5SDimitry Andric     Triple TT = Triple(M.getTargetTriple());
850b57cec5SDimitry Andric     OrderFileBuffer->setSection(
860b57cec5SDimitry Andric         getInstrProfSectionName(IPSK_orderfile, TT.getObjectFormat()));
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric     std::string IndexName = INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME_STR;
890b57cec5SDimitry Andric     BufferIdx = new GlobalVariable(M, IdxTy, false, GlobalValue::LinkOnceODRLinkage,
900b57cec5SDimitry Andric                            Constant::getNullValue(IdxTy), IndexName);
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric     std::string BitMapName = "bitmap_0";
930b57cec5SDimitry Andric     BitMap = new GlobalVariable(M, MapTy, false, GlobalValue::PrivateLinkage,
940b57cec5SDimitry Andric                                 Constant::getNullValue(MapTy), BitMapName);
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   // Generate the code sequence in the entry block of each function to
980b57cec5SDimitry Andric   // update the buffer.
generateCodeSequence__anonf94012910111::InstrOrderFile990b57cec5SDimitry Andric   void generateCodeSequence(Module &M, Function &F, int FuncId) {
1000b57cec5SDimitry Andric     if (!ClOrderFileWriteMapping.empty()) {
1010b57cec5SDimitry Andric       std::lock_guard<std::mutex> LogLock(MappingMutex);
1020b57cec5SDimitry Andric       std::error_code EC;
1038bcb0991SDimitry Andric       llvm::raw_fd_ostream OS(ClOrderFileWriteMapping, EC,
1048bcb0991SDimitry Andric                               llvm::sys::fs::OF_Append);
1050b57cec5SDimitry Andric       if (EC) {
1060b57cec5SDimitry Andric         report_fatal_error(Twine("Failed to open ") + ClOrderFileWriteMapping +
1070b57cec5SDimitry Andric                            " to save mapping file for order file instrumentation\n");
1080b57cec5SDimitry Andric       } else {
1090b57cec5SDimitry Andric         std::stringstream stream;
1100b57cec5SDimitry Andric         stream << std::hex << MD5Hash(F.getName());
1110b57cec5SDimitry Andric         std::string singleLine = "MD5 " + stream.str() + " " +
1120b57cec5SDimitry Andric                                  std::string(F.getName()) + '\n';
1130b57cec5SDimitry Andric         OS << singleLine;
1140b57cec5SDimitry Andric       }
1150b57cec5SDimitry Andric     }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric     BasicBlock *OrigEntry = &F.getEntryBlock();
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric     LLVMContext &Ctx = M.getContext();
1200b57cec5SDimitry Andric     IntegerType *Int32Ty = Type::getInt32Ty(Ctx);
1210b57cec5SDimitry Andric     IntegerType *Int8Ty = Type::getInt8Ty(Ctx);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric     // Create a new entry block for instrumentation. We will check the bitmap
1240b57cec5SDimitry Andric     // in this basic block.
1250b57cec5SDimitry Andric     BasicBlock *NewEntry =
1260b57cec5SDimitry Andric         BasicBlock::Create(M.getContext(), "order_file_entry", &F, OrigEntry);
1270b57cec5SDimitry Andric     IRBuilder<> entryB(NewEntry);
1280b57cec5SDimitry Andric     // Create a basic block for updating the circular buffer.
1290b57cec5SDimitry Andric     BasicBlock *UpdateOrderFileBB =
1300b57cec5SDimitry Andric         BasicBlock::Create(M.getContext(), "order_file_set", &F, OrigEntry);
1310b57cec5SDimitry Andric     IRBuilder<> updateB(UpdateOrderFileBB);
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric     // Check the bitmap, if it is already 1, do nothing.
1340b57cec5SDimitry Andric     // Otherwise, set the bit, grab the index, update the buffer.
1350b57cec5SDimitry Andric     Value *IdxFlags[] = {ConstantInt::get(Int32Ty, 0),
1360b57cec5SDimitry Andric                          ConstantInt::get(Int32Ty, FuncId)};
1370b57cec5SDimitry Andric     Value *MapAddr = entryB.CreateGEP(MapTy, BitMap, IdxFlags, "");
1380b57cec5SDimitry Andric     LoadInst *loadBitMap = entryB.CreateLoad(Int8Ty, MapAddr, "");
1390b57cec5SDimitry Andric     entryB.CreateStore(ConstantInt::get(Int8Ty, 1), MapAddr);
1400b57cec5SDimitry Andric     Value *IsNotExecuted =
1410b57cec5SDimitry Andric         entryB.CreateICmpEQ(loadBitMap, ConstantInt::get(Int8Ty, 0));
1420b57cec5SDimitry Andric     entryB.CreateCondBr(IsNotExecuted, UpdateOrderFileBB, OrigEntry);
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric     // Fill up UpdateOrderFileBB: grab the index, update the buffer!
1450b57cec5SDimitry Andric     Value *IdxVal = updateB.CreateAtomicRMW(
1460b57cec5SDimitry Andric         AtomicRMWInst::Add, BufferIdx, ConstantInt::get(Int32Ty, 1),
147*5f7ddb14SDimitry Andric         MaybeAlign(), AtomicOrdering::SequentiallyConsistent);
1480b57cec5SDimitry Andric     // We need to wrap around the index to fit it inside the buffer.
1490b57cec5SDimitry Andric     Value *WrappedIdx = updateB.CreateAnd(
1500b57cec5SDimitry Andric         IdxVal, ConstantInt::get(Int32Ty, INSTR_ORDER_FILE_BUFFER_MASK));
1510b57cec5SDimitry Andric     Value *BufferGEPIdx[] = {ConstantInt::get(Int32Ty, 0), WrappedIdx};
1520b57cec5SDimitry Andric     Value *BufferAddr =
1530b57cec5SDimitry Andric         updateB.CreateGEP(BufferTy, OrderFileBuffer, BufferGEPIdx, "");
1540b57cec5SDimitry Andric     updateB.CreateStore(ConstantInt::get(Type::getInt64Ty(Ctx), MD5Hash(F.getName())),
1550b57cec5SDimitry Andric                         BufferAddr);
1560b57cec5SDimitry Andric     updateB.CreateBr(OrigEntry);
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric 
run__anonf94012910111::InstrOrderFile1590b57cec5SDimitry Andric   bool run(Module &M) {
1600b57cec5SDimitry Andric     createOrderFileData(M);
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric     int FuncId = 0;
1630b57cec5SDimitry Andric     for (Function &F : M) {
1640b57cec5SDimitry Andric       if (F.isDeclaration())
1650b57cec5SDimitry Andric         continue;
1660b57cec5SDimitry Andric       generateCodeSequence(M, F, FuncId);
1670b57cec5SDimitry Andric       ++FuncId;
1680b57cec5SDimitry Andric     }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric     return true;
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric }; // End of InstrOrderFile struct
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric class InstrOrderFileLegacyPass : public ModulePass {
1760b57cec5SDimitry Andric public:
1770b57cec5SDimitry Andric   static char ID;
1780b57cec5SDimitry Andric 
InstrOrderFileLegacyPass()1790b57cec5SDimitry Andric   InstrOrderFileLegacyPass() : ModulePass(ID) {
1800b57cec5SDimitry Andric     initializeInstrOrderFileLegacyPassPass(
1810b57cec5SDimitry Andric         *PassRegistry::getPassRegistry());
1820b57cec5SDimitry Andric   }
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   bool runOnModule(Module &M) override;
1850b57cec5SDimitry Andric };
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric } // End anonymous namespace
1880b57cec5SDimitry Andric 
runOnModule(Module & M)1890b57cec5SDimitry Andric bool InstrOrderFileLegacyPass::runOnModule(Module &M) {
1900b57cec5SDimitry Andric   if (skipModule(M))
1910b57cec5SDimitry Andric     return false;
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   return InstrOrderFile().run(M);
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric PreservedAnalyses
run(Module & M,ModuleAnalysisManager & AM)1970b57cec5SDimitry Andric InstrOrderFilePass::run(Module &M, ModuleAnalysisManager &AM) {
1980b57cec5SDimitry Andric   if (InstrOrderFile().run(M))
1990b57cec5SDimitry Andric     return PreservedAnalyses::none();
2000b57cec5SDimitry Andric   return PreservedAnalyses::all();
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(InstrOrderFileLegacyPass, "instrorderfile",
2040b57cec5SDimitry Andric                       "Instrumentation for Order File", false, false)
2050b57cec5SDimitry Andric INITIALIZE_PASS_END(InstrOrderFileLegacyPass, "instrorderfile",
2060b57cec5SDimitry Andric                     "Instrumentation for Order File", false, false)
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric char InstrOrderFileLegacyPass::ID = 0;
2090b57cec5SDimitry Andric 
createInstrOrderFilePass()2100b57cec5SDimitry Andric ModulePass *llvm::createInstrOrderFilePass() {
2110b57cec5SDimitry Andric   return new InstrOrderFileLegacyPass();
2120b57cec5SDimitry Andric }
213