blob: a23b9ef4a3d785bd8751b82931e1204ca12329c1 [file] [log] [blame]
Manman Ren18295122019-02-28 20:13:38 +00001//===- InstrOrderFile.cpp ---- Late IR instrumentation for order file ----===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//===----------------------------------------------------------------------===//
11
12#include "llvm/ADT/Statistic.h"
13#include "llvm/IR/CallSite.h"
14#include "llvm/IR/Constants.h"
15#include "llvm/IR/Function.h"
16#include "llvm/IR/GlobalValue.h"
17#include "llvm/IR/IRBuilder.h"
18#include "llvm/IR/Instruction.h"
19#include "llvm/IR/Instructions.h"
20#include "llvm/IR/Metadata.h"
21#include "llvm/IR/Module.h"
22#include "llvm/Pass.h"
23#include "llvm/PassRegistry.h"
24#include "llvm/ProfileData/InstrProf.h"
25#include "llvm/Support/CommandLine.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/FileSystem.h"
28#include "llvm/Support/Path.h"
29#include "llvm/Support/raw_ostream.h"
30#include "llvm/Transforms/Instrumentation.h"
31#include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
32#include <fstream>
33#include <map>
34#include <set>
35#include <sstream>
36
37using namespace llvm;
38#define DEBUG_TYPE "instrorderfile"
39
40static cl::opt<std::string> ClOrderFileWriteMapping(
41 "orderfile-write-mapping", cl::init(""),
42 cl::desc(
43 "Dump functions and their MD5 hash to deobfuscate profile data"),
44 cl::Hidden);
45
46namespace {
47
48// We need a global bitmap to tell if a function is executed. We also
49// need a global variable to save the order of functions. We can use a
50// fixed-size buffer that saves the MD5 hash of the function. We need
51// a global variable to save the index into the buffer.
52
53std::mutex MappingMutex;
54
55struct InstrOrderFile {
56private:
57 GlobalVariable *OrderFileBuffer;
58 GlobalVariable *BufferIdx;
59 GlobalVariable *BitMap;
60 ArrayType *BufferTy;
61 ArrayType *MapTy;
62
63public:
64 InstrOrderFile() {}
65
66 void createOrderFileData(Module &M) {
67 LLVMContext &Ctx = M.getContext();
68 int NumFunctions = 0;
69 for (Function &F : M) {
70 if (!F.isDeclaration())
71 NumFunctions++;
72 }
73
74 BufferTy =
75 ArrayType::get(Type::getInt64Ty(Ctx), INSTR_ORDER_FILE_BUFFER_SIZE);
76 Type *IdxTy = Type::getInt32Ty(Ctx);
77 MapTy = ArrayType::get(Type::getInt8Ty(Ctx), NumFunctions);
78
79 // Create the global variables.
80 std::string SymbolName = INSTR_PROF_ORDERFILE_BUFFER_NAME_STR;
81 OrderFileBuffer = new GlobalVariable(M, BufferTy, false, GlobalValue::LinkOnceODRLinkage,
82 Constant::getNullValue(BufferTy), SymbolName);
83 Triple TT = Triple(M.getTargetTriple());
84 OrderFileBuffer->setSection(
85 getInstrProfSectionName(IPSK_orderfile, TT.getObjectFormat()));
86
87 std::string IndexName = INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME_STR;
88 BufferIdx = new GlobalVariable(M, IdxTy, false, GlobalValue::LinkOnceODRLinkage,
89 Constant::getNullValue(IdxTy), IndexName);
90
91 std::string BitMapName = "bitmap_0";
92 BitMap = new GlobalVariable(M, MapTy, false, GlobalValue::PrivateLinkage,
93 Constant::getNullValue(MapTy), BitMapName);
94 }
95
96 // Generate the code sequence in the entry block of each function to
97 // update the buffer.
98 void generateCodeSequence(Module &M, Function &F, int FuncId) {
99 if (!ClOrderFileWriteMapping.empty()) {
100 std::lock_guard<std::mutex> LogLock(MappingMutex);
101 std::error_code EC;
102 llvm::raw_fd_ostream OS(ClOrderFileWriteMapping, EC, llvm::sys::fs::F_Append);
103 if (EC) {
104 report_fatal_error(Twine("Failed to open ") + ClOrderFileWriteMapping +
105 " to save mapping file for order file instrumentation\n");
106 } else {
107 std::stringstream stream;
108 stream << std::hex << MD5Hash(F.getName());
109 std::string singleLine = "MD5 " + stream.str() + " " +
110 std::string(F.getName()) + '\n';
111 OS << singleLine;
112 }
113 }
114
115 BasicBlock *OrigEntry = &F.getEntryBlock();
116
117 LLVMContext &Ctx = M.getContext();
118 IntegerType *Int32Ty = Type::getInt32Ty(Ctx);
119 IntegerType *Int8Ty = Type::getInt8Ty(Ctx);
120
121 // Create a new entry block for instrumentation. We will check the bitmap
122 // in this basic block.
123 BasicBlock *NewEntry =
124 BasicBlock::Create(M.getContext(), "order_file_entry", &F, OrigEntry);
125 IRBuilder<> entryB(NewEntry);
126 // Create a basic block for updating the circular buffer.
127 BasicBlock *UpdateOrderFileBB =
128 BasicBlock::Create(M.getContext(), "order_file_set", &F, OrigEntry);
129 IRBuilder<> updateB(UpdateOrderFileBB);
130
131 // Check the bitmap, if it is already 1, do nothing.
132 // Otherwise, set the bit, grab the index, update the buffer.
133 Value *IdxFlags[] = {ConstantInt::get(Int32Ty, 0),
134 ConstantInt::get(Int32Ty, FuncId)};
135 Value *MapAddr = entryB.CreateGEP(MapTy, BitMap, IdxFlags, "");
136 LoadInst *loadBitMap = entryB.CreateLoad(Int8Ty, MapAddr, "");
137 entryB.CreateStore(ConstantInt::get(Int8Ty, 1), MapAddr);
138 Value *IsNotExecuted =
139 entryB.CreateICmpEQ(loadBitMap, ConstantInt::get(Int8Ty, 0));
140 entryB.CreateCondBr(IsNotExecuted, UpdateOrderFileBB, OrigEntry);
141
142 // Fill up UpdateOrderFileBB: grab the index, update the buffer!
143 Value *IdxVal = updateB.CreateAtomicRMW(
144 AtomicRMWInst::Add, BufferIdx, ConstantInt::get(Int32Ty, 1),
145 AtomicOrdering::SequentiallyConsistent);
146 // We need to wrap around the index to fit it inside the buffer.
147 Value *WrappedIdx = updateB.CreateAnd(
148 IdxVal, ConstantInt::get(Int32Ty, INSTR_ORDER_FILE_BUFFER_MASK));
149 Value *BufferGEPIdx[] = {ConstantInt::get(Int32Ty, 0), WrappedIdx};
150 Value *BufferAddr =
151 updateB.CreateGEP(BufferTy, OrderFileBuffer, BufferGEPIdx, "");
152 updateB.CreateStore(ConstantInt::get(Type::getInt64Ty(Ctx), MD5Hash(F.getName())),
153 BufferAddr);
154 updateB.CreateBr(OrigEntry);
155 }
156
157 bool run(Module &M) {
158 createOrderFileData(M);
159
160 int FuncId = 0;
161 for (Function &F : M) {
162 if (F.isDeclaration())
163 continue;
164 generateCodeSequence(M, F, FuncId);
165 ++FuncId;
166 }
167
168 return true;
169 }
170
171}; // End of InstrOrderFile struct
172
173class InstrOrderFileLegacyPass : public ModulePass {
174public:
175 static char ID;
176
177 InstrOrderFileLegacyPass() : ModulePass(ID) {
178 initializeInstrOrderFileLegacyPassPass(
179 *PassRegistry::getPassRegistry());
180 }
181
182 bool runOnModule(Module &M) override;
183};
184
185} // End anonymous namespace
186
187bool InstrOrderFileLegacyPass::runOnModule(Module &M) {
188 if (skipModule(M))
189 return false;
190
191 return InstrOrderFile().run(M);
192}
193
194PreservedAnalyses
195InstrOrderFilePass::run(Module &M, ModuleAnalysisManager &AM) {
196 if (InstrOrderFile().run(M))
197 return PreservedAnalyses::none();
198 return PreservedAnalyses::all();
199}
200
201INITIALIZE_PASS_BEGIN(InstrOrderFileLegacyPass, "instrorderfile",
202 "Instrumentation for Order File", false, false)
203INITIALIZE_PASS_END(InstrOrderFileLegacyPass, "instrorderfile",
204 "Instrumentation for Order File", false, false)
205
206char InstrOrderFileLegacyPass::ID = 0;
207
208ModulePass *llvm::createInstrOrderFilePass() {
209 return new InstrOrderFileLegacyPass();
210}