#include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/PassRegistry.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation.h"
#include <fstream>
#include <mutex>
#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 {
std::mutex MappingMutex;
struct InstrOrderFile {
private:
GlobalVariable *OrderFileBuffer;
GlobalVariable *BufferIdx;
GlobalVariable *BitMap;
ArrayType *BufferTy;
ArrayType *MapTy;
public:
InstrOrderFile() = default;
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);
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);
}
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::OF_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);
BasicBlock *NewEntry =
BasicBlock::Create(M.getContext(), "order_file_entry", &F, OrigEntry);
IRBuilder<> entryB(NewEntry);
BasicBlock *UpdateOrderFileBB =
BasicBlock::Create(M.getContext(), "order_file_set", &F, OrigEntry);
IRBuilder<> updateB(UpdateOrderFileBB);
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);
Value *IdxVal = updateB.CreateAtomicRMW(
AtomicRMWInst::Add, BufferIdx, ConstantInt::get(Int32Ty, 1),
MaybeAlign(), AtomicOrdering::SequentiallyConsistent);
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;
}
}; }
PreservedAnalyses
InstrOrderFilePass::run(Module &M, ModuleAnalysisManager &AM) {
if (InstrOrderFile().run(M))
return PreservedAnalyses::none();
return PreservedAnalyses::all();
}