diff options
Diffstat (limited to 'contrib/llvm/lib/Transforms/Instrumentation/InstrOrderFile.cpp')
| -rw-r--r-- | contrib/llvm/lib/Transforms/Instrumentation/InstrOrderFile.cpp | 211 | 
1 files changed, 211 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Transforms/Instrumentation/InstrOrderFile.cpp b/contrib/llvm/lib/Transforms/Instrumentation/InstrOrderFile.cpp new file mode 100644 index 000000000000..a2c1ddfd279e --- /dev/null +++ b/contrib/llvm/lib/Transforms/Instrumentation/InstrOrderFile.cpp @@ -0,0 +1,211 @@ +//===- InstrOrderFile.cpp ---- Late IR instrumentation for order file ----===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Instrumentation/InstrOrderFile.h" +#include <fstream> +#include <map> +#include <mutex> +#include <set> +#include <sstream> + +using namespace llvm; +#define DEBUG_TYPE "instrorderfile" + +static cl::opt<std::string> ClOrderFileWriteMapping( +    "orderfile-write-mapping", cl::init(""), +    cl::desc( +        "Dump functions and their MD5 hash to deobfuscate profile data"), +    cl::Hidden); + +namespace { + +// We need a global bitmap to tell if a function is executed. We also +// need a global variable to save the order of functions. We can use a +// fixed-size buffer that saves the MD5 hash of the function. We need +// a global variable to save the index into the buffer. + +std::mutex MappingMutex; + +struct InstrOrderFile { +private: +  GlobalVariable *OrderFileBuffer; +  GlobalVariable *BufferIdx; +  GlobalVariable *BitMap; +  ArrayType *BufferTy; +  ArrayType *MapTy; + +public: +  InstrOrderFile() {} + +  void createOrderFileData(Module &M) { +    LLVMContext &Ctx = M.getContext(); +    int NumFunctions = 0; +    for (Function &F : M) { +      if (!F.isDeclaration()) +        NumFunctions++; +    } + +    BufferTy = +        ArrayType::get(Type::getInt64Ty(Ctx), INSTR_ORDER_FILE_BUFFER_SIZE); +    Type *IdxTy = Type::getInt32Ty(Ctx); +    MapTy = ArrayType::get(Type::getInt8Ty(Ctx), NumFunctions); + +    // Create the global variables. +    std::string SymbolName = INSTR_PROF_ORDERFILE_BUFFER_NAME_STR; +    OrderFileBuffer = new GlobalVariable(M, BufferTy, false, GlobalValue::LinkOnceODRLinkage, +                           Constant::getNullValue(BufferTy), SymbolName); +    Triple TT = Triple(M.getTargetTriple()); +    OrderFileBuffer->setSection( +        getInstrProfSectionName(IPSK_orderfile, TT.getObjectFormat())); + +    std::string IndexName = INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME_STR; +    BufferIdx = new GlobalVariable(M, IdxTy, false, GlobalValue::LinkOnceODRLinkage, +                           Constant::getNullValue(IdxTy), IndexName); + +    std::string BitMapName = "bitmap_0"; +    BitMap = new GlobalVariable(M, MapTy, false, GlobalValue::PrivateLinkage, +                                Constant::getNullValue(MapTy), BitMapName); +  } + +  // Generate the code sequence in the entry block of each function to +  // update the buffer. +  void generateCodeSequence(Module &M, Function &F, int FuncId) { +    if (!ClOrderFileWriteMapping.empty()) { +      std::lock_guard<std::mutex> LogLock(MappingMutex); +      std::error_code EC; +      llvm::raw_fd_ostream OS(ClOrderFileWriteMapping, EC, llvm::sys::fs::F_Append); +      if (EC) { +        report_fatal_error(Twine("Failed to open ") + ClOrderFileWriteMapping + +                           " to save mapping file for order file instrumentation\n"); +      } else { +        std::stringstream stream; +        stream << std::hex << MD5Hash(F.getName()); +        std::string singleLine = "MD5 " + stream.str() + " " + +                                 std::string(F.getName()) + '\n'; +        OS << singleLine; +      } +    } + +    BasicBlock *OrigEntry = &F.getEntryBlock(); + +    LLVMContext &Ctx = M.getContext(); +    IntegerType *Int32Ty = Type::getInt32Ty(Ctx); +    IntegerType *Int8Ty = Type::getInt8Ty(Ctx); + +    // Create a new entry block for instrumentation. We will check the bitmap +    // in this basic block. +    BasicBlock *NewEntry = +        BasicBlock::Create(M.getContext(), "order_file_entry", &F, OrigEntry); +    IRBuilder<> entryB(NewEntry); +    // Create a basic block for updating the circular buffer. +    BasicBlock *UpdateOrderFileBB = +        BasicBlock::Create(M.getContext(), "order_file_set", &F, OrigEntry); +    IRBuilder<> updateB(UpdateOrderFileBB); + +    // Check the bitmap, if it is already 1, do nothing. +    // Otherwise, set the bit, grab the index, update the buffer. +    Value *IdxFlags[] = {ConstantInt::get(Int32Ty, 0), +                         ConstantInt::get(Int32Ty, FuncId)}; +    Value *MapAddr = entryB.CreateGEP(MapTy, BitMap, IdxFlags, ""); +    LoadInst *loadBitMap = entryB.CreateLoad(Int8Ty, MapAddr, ""); +    entryB.CreateStore(ConstantInt::get(Int8Ty, 1), MapAddr); +    Value *IsNotExecuted = +        entryB.CreateICmpEQ(loadBitMap, ConstantInt::get(Int8Ty, 0)); +    entryB.CreateCondBr(IsNotExecuted, UpdateOrderFileBB, OrigEntry); + +    // Fill up UpdateOrderFileBB: grab the index, update the buffer! +    Value *IdxVal = updateB.CreateAtomicRMW( +        AtomicRMWInst::Add, BufferIdx, ConstantInt::get(Int32Ty, 1), +        AtomicOrdering::SequentiallyConsistent); +    // We need to wrap around the index to fit it inside the buffer. +    Value *WrappedIdx = updateB.CreateAnd( +        IdxVal, ConstantInt::get(Int32Ty, INSTR_ORDER_FILE_BUFFER_MASK)); +    Value *BufferGEPIdx[] = {ConstantInt::get(Int32Ty, 0), WrappedIdx}; +    Value *BufferAddr = +        updateB.CreateGEP(BufferTy, OrderFileBuffer, BufferGEPIdx, ""); +    updateB.CreateStore(ConstantInt::get(Type::getInt64Ty(Ctx), MD5Hash(F.getName())), +                        BufferAddr); +    updateB.CreateBr(OrigEntry); +  } + +  bool run(Module &M) { +    createOrderFileData(M); + +    int FuncId = 0; +    for (Function &F : M) { +      if (F.isDeclaration()) +        continue; +      generateCodeSequence(M, F, FuncId); +      ++FuncId; +    } + +    return true; +  } + +}; // End of InstrOrderFile struct + +class InstrOrderFileLegacyPass : public ModulePass { +public: +  static char ID; + +  InstrOrderFileLegacyPass() : ModulePass(ID) { +    initializeInstrOrderFileLegacyPassPass( +        *PassRegistry::getPassRegistry()); +  } + +  bool runOnModule(Module &M) override; +}; + +} // End anonymous namespace + +bool InstrOrderFileLegacyPass::runOnModule(Module &M) { +  if (skipModule(M)) +    return false; + +  return InstrOrderFile().run(M); +} + +PreservedAnalyses +InstrOrderFilePass::run(Module &M, ModuleAnalysisManager &AM) { +  if (InstrOrderFile().run(M)) +    return PreservedAnalyses::none(); +  return PreservedAnalyses::all(); +} + +INITIALIZE_PASS_BEGIN(InstrOrderFileLegacyPass, "instrorderfile", +                      "Instrumentation for Order File", false, false) +INITIALIZE_PASS_END(InstrOrderFileLegacyPass, "instrorderfile", +                    "Instrumentation for Order File", false, false) + +char InstrOrderFileLegacyPass::ID = 0; + +ModulePass *llvm::createInstrOrderFilePass() { +  return new InstrOrderFileLegacyPass(); +}  | 
