106f32e7eSjoerg //===- InstrOrderFile.cpp ---- Late IR instrumentation for order file ----===//
206f32e7eSjoerg //
306f32e7eSjoerg //                     The LLVM Compiler Infrastructure
406f32e7eSjoerg //
506f32e7eSjoerg // This file is distributed under the University of Illinois Open Source
606f32e7eSjoerg // License. See LICENSE.TXT for details.
706f32e7eSjoerg //
806f32e7eSjoerg //===----------------------------------------------------------------------===//
906f32e7eSjoerg //
1006f32e7eSjoerg //===----------------------------------------------------------------------===//
1106f32e7eSjoerg 
12*da58b97aSjoerg #include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
1306f32e7eSjoerg #include "llvm/ADT/Statistic.h"
1406f32e7eSjoerg #include "llvm/IR/Constants.h"
1506f32e7eSjoerg #include "llvm/IR/Function.h"
1606f32e7eSjoerg #include "llvm/IR/GlobalValue.h"
1706f32e7eSjoerg #include "llvm/IR/IRBuilder.h"
1806f32e7eSjoerg #include "llvm/IR/Instruction.h"
1906f32e7eSjoerg #include "llvm/IR/Instructions.h"
2006f32e7eSjoerg #include "llvm/IR/Metadata.h"
2106f32e7eSjoerg #include "llvm/IR/Module.h"
22*da58b97aSjoerg #include "llvm/InitializePasses.h"
2306f32e7eSjoerg #include "llvm/Pass.h"
2406f32e7eSjoerg #include "llvm/PassRegistry.h"
2506f32e7eSjoerg #include "llvm/ProfileData/InstrProf.h"
2606f32e7eSjoerg #include "llvm/Support/CommandLine.h"
2706f32e7eSjoerg #include "llvm/Support/Debug.h"
2806f32e7eSjoerg #include "llvm/Support/FileSystem.h"
2906f32e7eSjoerg #include "llvm/Support/Path.h"
3006f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
3106f32e7eSjoerg #include "llvm/Transforms/Instrumentation.h"
3206f32e7eSjoerg #include <fstream>
3306f32e7eSjoerg #include <map>
3406f32e7eSjoerg #include <mutex>
3506f32e7eSjoerg #include <set>
3606f32e7eSjoerg #include <sstream>
3706f32e7eSjoerg 
3806f32e7eSjoerg using namespace llvm;
3906f32e7eSjoerg #define DEBUG_TYPE "instrorderfile"
4006f32e7eSjoerg 
4106f32e7eSjoerg static cl::opt<std::string> ClOrderFileWriteMapping(
4206f32e7eSjoerg     "orderfile-write-mapping", cl::init(""),
4306f32e7eSjoerg     cl::desc(
4406f32e7eSjoerg         "Dump functions and their MD5 hash to deobfuscate profile data"),
4506f32e7eSjoerg     cl::Hidden);
4606f32e7eSjoerg 
4706f32e7eSjoerg namespace {
4806f32e7eSjoerg 
4906f32e7eSjoerg // We need a global bitmap to tell if a function is executed. We also
5006f32e7eSjoerg // need a global variable to save the order of functions. We can use a
5106f32e7eSjoerg // fixed-size buffer that saves the MD5 hash of the function. We need
5206f32e7eSjoerg // a global variable to save the index into the buffer.
5306f32e7eSjoerg 
5406f32e7eSjoerg std::mutex MappingMutex;
5506f32e7eSjoerg 
5606f32e7eSjoerg struct InstrOrderFile {
5706f32e7eSjoerg private:
5806f32e7eSjoerg   GlobalVariable *OrderFileBuffer;
5906f32e7eSjoerg   GlobalVariable *BufferIdx;
6006f32e7eSjoerg   GlobalVariable *BitMap;
6106f32e7eSjoerg   ArrayType *BufferTy;
6206f32e7eSjoerg   ArrayType *MapTy;
6306f32e7eSjoerg 
6406f32e7eSjoerg public:
InstrOrderFile__anon7a59e55e0111::InstrOrderFile6506f32e7eSjoerg   InstrOrderFile() {}
6606f32e7eSjoerg 
createOrderFileData__anon7a59e55e0111::InstrOrderFile6706f32e7eSjoerg   void createOrderFileData(Module &M) {
6806f32e7eSjoerg     LLVMContext &Ctx = M.getContext();
6906f32e7eSjoerg     int NumFunctions = 0;
7006f32e7eSjoerg     for (Function &F : M) {
7106f32e7eSjoerg       if (!F.isDeclaration())
7206f32e7eSjoerg         NumFunctions++;
7306f32e7eSjoerg     }
7406f32e7eSjoerg 
7506f32e7eSjoerg     BufferTy =
7606f32e7eSjoerg         ArrayType::get(Type::getInt64Ty(Ctx), INSTR_ORDER_FILE_BUFFER_SIZE);
7706f32e7eSjoerg     Type *IdxTy = Type::getInt32Ty(Ctx);
7806f32e7eSjoerg     MapTy = ArrayType::get(Type::getInt8Ty(Ctx), NumFunctions);
7906f32e7eSjoerg 
8006f32e7eSjoerg     // Create the global variables.
8106f32e7eSjoerg     std::string SymbolName = INSTR_PROF_ORDERFILE_BUFFER_NAME_STR;
8206f32e7eSjoerg     OrderFileBuffer = new GlobalVariable(M, BufferTy, false, GlobalValue::LinkOnceODRLinkage,
8306f32e7eSjoerg                            Constant::getNullValue(BufferTy), SymbolName);
8406f32e7eSjoerg     Triple TT = Triple(M.getTargetTriple());
8506f32e7eSjoerg     OrderFileBuffer->setSection(
8606f32e7eSjoerg         getInstrProfSectionName(IPSK_orderfile, TT.getObjectFormat()));
8706f32e7eSjoerg 
8806f32e7eSjoerg     std::string IndexName = INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME_STR;
8906f32e7eSjoerg     BufferIdx = new GlobalVariable(M, IdxTy, false, GlobalValue::LinkOnceODRLinkage,
9006f32e7eSjoerg                            Constant::getNullValue(IdxTy), IndexName);
9106f32e7eSjoerg 
9206f32e7eSjoerg     std::string BitMapName = "bitmap_0";
9306f32e7eSjoerg     BitMap = new GlobalVariable(M, MapTy, false, GlobalValue::PrivateLinkage,
9406f32e7eSjoerg                                 Constant::getNullValue(MapTy), BitMapName);
9506f32e7eSjoerg   }
9606f32e7eSjoerg 
9706f32e7eSjoerg   // Generate the code sequence in the entry block of each function to
9806f32e7eSjoerg   // update the buffer.
generateCodeSequence__anon7a59e55e0111::InstrOrderFile9906f32e7eSjoerg   void generateCodeSequence(Module &M, Function &F, int FuncId) {
10006f32e7eSjoerg     if (!ClOrderFileWriteMapping.empty()) {
10106f32e7eSjoerg       std::lock_guard<std::mutex> LogLock(MappingMutex);
10206f32e7eSjoerg       std::error_code EC;
10306f32e7eSjoerg       llvm::raw_fd_ostream OS(ClOrderFileWriteMapping, EC,
10406f32e7eSjoerg                               llvm::sys::fs::OF_Append);
10506f32e7eSjoerg       if (EC) {
10606f32e7eSjoerg         report_fatal_error(Twine("Failed to open ") + ClOrderFileWriteMapping +
10706f32e7eSjoerg                            " to save mapping file for order file instrumentation\n");
10806f32e7eSjoerg       } else {
10906f32e7eSjoerg         std::stringstream stream;
11006f32e7eSjoerg         stream << std::hex << MD5Hash(F.getName());
11106f32e7eSjoerg         std::string singleLine = "MD5 " + stream.str() + " " +
11206f32e7eSjoerg                                  std::string(F.getName()) + '\n';
11306f32e7eSjoerg         OS << singleLine;
11406f32e7eSjoerg       }
11506f32e7eSjoerg     }
11606f32e7eSjoerg 
11706f32e7eSjoerg     BasicBlock *OrigEntry = &F.getEntryBlock();
11806f32e7eSjoerg 
11906f32e7eSjoerg     LLVMContext &Ctx = M.getContext();
12006f32e7eSjoerg     IntegerType *Int32Ty = Type::getInt32Ty(Ctx);
12106f32e7eSjoerg     IntegerType *Int8Ty = Type::getInt8Ty(Ctx);
12206f32e7eSjoerg 
12306f32e7eSjoerg     // Create a new entry block for instrumentation. We will check the bitmap
12406f32e7eSjoerg     // in this basic block.
12506f32e7eSjoerg     BasicBlock *NewEntry =
12606f32e7eSjoerg         BasicBlock::Create(M.getContext(), "order_file_entry", &F, OrigEntry);
12706f32e7eSjoerg     IRBuilder<> entryB(NewEntry);
12806f32e7eSjoerg     // Create a basic block for updating the circular buffer.
12906f32e7eSjoerg     BasicBlock *UpdateOrderFileBB =
13006f32e7eSjoerg         BasicBlock::Create(M.getContext(), "order_file_set", &F, OrigEntry);
13106f32e7eSjoerg     IRBuilder<> updateB(UpdateOrderFileBB);
13206f32e7eSjoerg 
13306f32e7eSjoerg     // Check the bitmap, if it is already 1, do nothing.
13406f32e7eSjoerg     // Otherwise, set the bit, grab the index, update the buffer.
13506f32e7eSjoerg     Value *IdxFlags[] = {ConstantInt::get(Int32Ty, 0),
13606f32e7eSjoerg                          ConstantInt::get(Int32Ty, FuncId)};
13706f32e7eSjoerg     Value *MapAddr = entryB.CreateGEP(MapTy, BitMap, IdxFlags, "");
13806f32e7eSjoerg     LoadInst *loadBitMap = entryB.CreateLoad(Int8Ty, MapAddr, "");
13906f32e7eSjoerg     entryB.CreateStore(ConstantInt::get(Int8Ty, 1), MapAddr);
14006f32e7eSjoerg     Value *IsNotExecuted =
14106f32e7eSjoerg         entryB.CreateICmpEQ(loadBitMap, ConstantInt::get(Int8Ty, 0));
14206f32e7eSjoerg     entryB.CreateCondBr(IsNotExecuted, UpdateOrderFileBB, OrigEntry);
14306f32e7eSjoerg 
14406f32e7eSjoerg     // Fill up UpdateOrderFileBB: grab the index, update the buffer!
14506f32e7eSjoerg     Value *IdxVal = updateB.CreateAtomicRMW(
14606f32e7eSjoerg         AtomicRMWInst::Add, BufferIdx, ConstantInt::get(Int32Ty, 1),
147*da58b97aSjoerg         MaybeAlign(), AtomicOrdering::SequentiallyConsistent);
14806f32e7eSjoerg     // We need to wrap around the index to fit it inside the buffer.
14906f32e7eSjoerg     Value *WrappedIdx = updateB.CreateAnd(
15006f32e7eSjoerg         IdxVal, ConstantInt::get(Int32Ty, INSTR_ORDER_FILE_BUFFER_MASK));
15106f32e7eSjoerg     Value *BufferGEPIdx[] = {ConstantInt::get(Int32Ty, 0), WrappedIdx};
15206f32e7eSjoerg     Value *BufferAddr =
15306f32e7eSjoerg         updateB.CreateGEP(BufferTy, OrderFileBuffer, BufferGEPIdx, "");
15406f32e7eSjoerg     updateB.CreateStore(ConstantInt::get(Type::getInt64Ty(Ctx), MD5Hash(F.getName())),
15506f32e7eSjoerg                         BufferAddr);
15606f32e7eSjoerg     updateB.CreateBr(OrigEntry);
15706f32e7eSjoerg   }
15806f32e7eSjoerg 
run__anon7a59e55e0111::InstrOrderFile15906f32e7eSjoerg   bool run(Module &M) {
16006f32e7eSjoerg     createOrderFileData(M);
16106f32e7eSjoerg 
16206f32e7eSjoerg     int FuncId = 0;
16306f32e7eSjoerg     for (Function &F : M) {
16406f32e7eSjoerg       if (F.isDeclaration())
16506f32e7eSjoerg         continue;
16606f32e7eSjoerg       generateCodeSequence(M, F, FuncId);
16706f32e7eSjoerg       ++FuncId;
16806f32e7eSjoerg     }
16906f32e7eSjoerg 
17006f32e7eSjoerg     return true;
17106f32e7eSjoerg   }
17206f32e7eSjoerg 
17306f32e7eSjoerg }; // End of InstrOrderFile struct
17406f32e7eSjoerg 
17506f32e7eSjoerg class InstrOrderFileLegacyPass : public ModulePass {
17606f32e7eSjoerg public:
17706f32e7eSjoerg   static char ID;
17806f32e7eSjoerg 
InstrOrderFileLegacyPass()17906f32e7eSjoerg   InstrOrderFileLegacyPass() : ModulePass(ID) {
18006f32e7eSjoerg     initializeInstrOrderFileLegacyPassPass(
18106f32e7eSjoerg         *PassRegistry::getPassRegistry());
18206f32e7eSjoerg   }
18306f32e7eSjoerg 
18406f32e7eSjoerg   bool runOnModule(Module &M) override;
18506f32e7eSjoerg };
18606f32e7eSjoerg 
18706f32e7eSjoerg } // End anonymous namespace
18806f32e7eSjoerg 
runOnModule(Module & M)18906f32e7eSjoerg bool InstrOrderFileLegacyPass::runOnModule(Module &M) {
19006f32e7eSjoerg   if (skipModule(M))
19106f32e7eSjoerg     return false;
19206f32e7eSjoerg 
19306f32e7eSjoerg   return InstrOrderFile().run(M);
19406f32e7eSjoerg }
19506f32e7eSjoerg 
19606f32e7eSjoerg PreservedAnalyses
run(Module & M,ModuleAnalysisManager & AM)19706f32e7eSjoerg InstrOrderFilePass::run(Module &M, ModuleAnalysisManager &AM) {
19806f32e7eSjoerg   if (InstrOrderFile().run(M))
19906f32e7eSjoerg     return PreservedAnalyses::none();
20006f32e7eSjoerg   return PreservedAnalyses::all();
20106f32e7eSjoerg }
20206f32e7eSjoerg 
20306f32e7eSjoerg INITIALIZE_PASS_BEGIN(InstrOrderFileLegacyPass, "instrorderfile",
20406f32e7eSjoerg                       "Instrumentation for Order File", false, false)
20506f32e7eSjoerg INITIALIZE_PASS_END(InstrOrderFileLegacyPass, "instrorderfile",
20606f32e7eSjoerg                     "Instrumentation for Order File", false, false)
20706f32e7eSjoerg 
20806f32e7eSjoerg char InstrOrderFileLegacyPass::ID = 0;
20906f32e7eSjoerg 
createInstrOrderFilePass()21006f32e7eSjoerg ModulePass *llvm::createInstrOrderFilePass() {
21106f32e7eSjoerg   return new InstrOrderFileLegacyPass();
21206f32e7eSjoerg }
213