Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/InstrOrderFile.cpp
35266 views
//===- InstrOrderFile.cpp ---- Late IR instrumentation for order file ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8//===----------------------------------------------------------------------===//910#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/ProfileData/InstrProf.h"18#include "llvm/Support/CommandLine.h"19#include "llvm/Support/FileSystem.h"20#include "llvm/Support/raw_ostream.h"21#include "llvm/Transforms/Instrumentation.h"22#include <fstream>23#include <mutex>24#include <sstream>2526using namespace llvm;27#define DEBUG_TYPE "instrorderfile"2829static cl::opt<std::string> ClOrderFileWriteMapping(30"orderfile-write-mapping", cl::init(""),31cl::desc(32"Dump functions and their MD5 hash to deobfuscate profile data"),33cl::Hidden);3435namespace {3637// We need a global bitmap to tell if a function is executed. We also38// need a global variable to save the order of functions. We can use a39// fixed-size buffer that saves the MD5 hash of the function. We need40// a global variable to save the index into the buffer.4142std::mutex MappingMutex;4344struct InstrOrderFile {45private:46GlobalVariable *OrderFileBuffer;47GlobalVariable *BufferIdx;48GlobalVariable *BitMap;49ArrayType *BufferTy;50ArrayType *MapTy;5152public:53InstrOrderFile() = default;5455void createOrderFileData(Module &M) {56LLVMContext &Ctx = M.getContext();57int NumFunctions = 0;58for (Function &F : M) {59if (!F.isDeclaration())60NumFunctions++;61}6263BufferTy =64ArrayType::get(Type::getInt64Ty(Ctx), INSTR_ORDER_FILE_BUFFER_SIZE);65Type *IdxTy = Type::getInt32Ty(Ctx);66MapTy = ArrayType::get(Type::getInt8Ty(Ctx), NumFunctions);6768// Create the global variables.69std::string SymbolName = INSTR_PROF_ORDERFILE_BUFFER_NAME_STR;70OrderFileBuffer = new GlobalVariable(M, BufferTy, false, GlobalValue::LinkOnceODRLinkage,71Constant::getNullValue(BufferTy), SymbolName);72Triple TT = Triple(M.getTargetTriple());73OrderFileBuffer->setSection(74getInstrProfSectionName(IPSK_orderfile, TT.getObjectFormat()));7576std::string IndexName = INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME_STR;77BufferIdx = new GlobalVariable(M, IdxTy, false, GlobalValue::LinkOnceODRLinkage,78Constant::getNullValue(IdxTy), IndexName);7980std::string BitMapName = "bitmap_0";81BitMap = new GlobalVariable(M, MapTy, false, GlobalValue::PrivateLinkage,82Constant::getNullValue(MapTy), BitMapName);83}8485// Generate the code sequence in the entry block of each function to86// update the buffer.87void generateCodeSequence(Module &M, Function &F, int FuncId) {88if (!ClOrderFileWriteMapping.empty()) {89std::lock_guard<std::mutex> LogLock(MappingMutex);90std::error_code EC;91llvm::raw_fd_ostream OS(ClOrderFileWriteMapping, EC,92llvm::sys::fs::OF_Append);93if (EC) {94report_fatal_error(Twine("Failed to open ") + ClOrderFileWriteMapping +95" to save mapping file for order file instrumentation\n");96} else {97std::stringstream stream;98stream << std::hex << MD5Hash(F.getName());99std::string singleLine = "MD5 " + stream.str() + " " +100std::string(F.getName()) + '\n';101OS << singleLine;102}103}104105BasicBlock *OrigEntry = &F.getEntryBlock();106107LLVMContext &Ctx = M.getContext();108IntegerType *Int32Ty = Type::getInt32Ty(Ctx);109IntegerType *Int8Ty = Type::getInt8Ty(Ctx);110111// Create a new entry block for instrumentation. We will check the bitmap112// in this basic block.113BasicBlock *NewEntry =114BasicBlock::Create(M.getContext(), "order_file_entry", &F, OrigEntry);115IRBuilder<> entryB(NewEntry);116// Create a basic block for updating the circular buffer.117BasicBlock *UpdateOrderFileBB =118BasicBlock::Create(M.getContext(), "order_file_set", &F, OrigEntry);119IRBuilder<> updateB(UpdateOrderFileBB);120121// Check the bitmap, if it is already 1, do nothing.122// Otherwise, set the bit, grab the index, update the buffer.123Value *IdxFlags[] = {ConstantInt::get(Int32Ty, 0),124ConstantInt::get(Int32Ty, FuncId)};125Value *MapAddr = entryB.CreateGEP(MapTy, BitMap, IdxFlags, "");126LoadInst *loadBitMap = entryB.CreateLoad(Int8Ty, MapAddr, "");127entryB.CreateStore(ConstantInt::get(Int8Ty, 1), MapAddr);128Value *IsNotExecuted =129entryB.CreateICmpEQ(loadBitMap, ConstantInt::get(Int8Ty, 0));130entryB.CreateCondBr(IsNotExecuted, UpdateOrderFileBB, OrigEntry);131132// Fill up UpdateOrderFileBB: grab the index, update the buffer!133Value *IdxVal = updateB.CreateAtomicRMW(134AtomicRMWInst::Add, BufferIdx, ConstantInt::get(Int32Ty, 1),135MaybeAlign(), AtomicOrdering::SequentiallyConsistent);136// We need to wrap around the index to fit it inside the buffer.137Value *WrappedIdx = updateB.CreateAnd(138IdxVal, ConstantInt::get(Int32Ty, INSTR_ORDER_FILE_BUFFER_MASK));139Value *BufferGEPIdx[] = {ConstantInt::get(Int32Ty, 0), WrappedIdx};140Value *BufferAddr =141updateB.CreateGEP(BufferTy, OrderFileBuffer, BufferGEPIdx, "");142updateB.CreateStore(ConstantInt::get(Type::getInt64Ty(Ctx), MD5Hash(F.getName())),143BufferAddr);144updateB.CreateBr(OrigEntry);145}146147bool run(Module &M) {148createOrderFileData(M);149150int FuncId = 0;151for (Function &F : M) {152if (F.isDeclaration())153continue;154generateCodeSequence(M, F, FuncId);155++FuncId;156}157158return true;159}160161}; // End of InstrOrderFile struct162} // End anonymous namespace163164PreservedAnalyses165InstrOrderFilePass::run(Module &M, ModuleAnalysisManager &AM) {166if (InstrOrderFile().run(M))167return PreservedAnalyses::none();168return PreservedAnalyses::all();169}170171172