1 //===- InstrOrderFile.cpp ---- Late IR instrumentation for order file ----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 //===----------------------------------------------------------------------===//
11 #include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
12 #include "llvm/ADT/Statistic.h"
13 #include "llvm/IR/Constants.h"
14 #include "llvm/IR/Function.h"
15 #include "llvm/IR/GlobalValue.h"
16 #include "llvm/IR/IRBuilder.h"
17 #include "llvm/IR/Instruction.h"
18 #include "llvm/IR/Instructions.h"
19 #include "llvm/IR/Metadata.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/InitializePasses.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"
38 #define DEBUG_TYPE "instrorderfile"
40 static cl::opt
<std::string
> ClOrderFileWriteMapping(
41 "orderfile-write-mapping", cl::init(""),
43 "Dump functions and their MD5 hash to deobfuscate profile data"),
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.
53 std::mutex MappingMutex
;
55 struct InstrOrderFile
{
57 GlobalVariable
*OrderFileBuffer
;
58 GlobalVariable
*BufferIdx
;
59 GlobalVariable
*BitMap
;
66 void createOrderFileData(Module
&M
) {
67 LLVMContext
&Ctx
= M
.getContext();
69 for (Function
&F
: M
) {
70 if (!F
.isDeclaration())
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
);
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()));
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
);
91 std::string BitMapName
= "bitmap_0";
92 BitMap
= new GlobalVariable(M
, MapTy
, false, GlobalValue::PrivateLinkage
,
93 Constant::getNullValue(MapTy
), BitMapName
);
96 // Generate the code sequence in the entry block of each function to
98 void generateCodeSequence(Module
&M
, Function
&F
, int FuncId
) {
99 if (!ClOrderFileWriteMapping
.empty()) {
100 std::lock_guard
<std::mutex
> LogLock(MappingMutex
);
102 llvm::raw_fd_ostream
OS(ClOrderFileWriteMapping
, EC
,
103 llvm::sys::fs::OF_Append
);
105 report_fatal_error(Twine("Failed to open ") + ClOrderFileWriteMapping
+
106 " to save mapping file for order file instrumentation\n");
108 std::stringstream stream
;
109 stream
<< std::hex
<< MD5Hash(F
.getName());
110 std::string singleLine
= "MD5 " + stream
.str() + " " +
111 std::string(F
.getName()) + '\n';
116 BasicBlock
*OrigEntry
= &F
.getEntryBlock();
118 LLVMContext
&Ctx
= M
.getContext();
119 IntegerType
*Int32Ty
= Type::getInt32Ty(Ctx
);
120 IntegerType
*Int8Ty
= Type::getInt8Ty(Ctx
);
122 // Create a new entry block for instrumentation. We will check the bitmap
123 // in this basic block.
124 BasicBlock
*NewEntry
=
125 BasicBlock::Create(M
.getContext(), "order_file_entry", &F
, OrigEntry
);
126 IRBuilder
<> entryB(NewEntry
);
127 // Create a basic block for updating the circular buffer.
128 BasicBlock
*UpdateOrderFileBB
=
129 BasicBlock::Create(M
.getContext(), "order_file_set", &F
, OrigEntry
);
130 IRBuilder
<> updateB(UpdateOrderFileBB
);
132 // Check the bitmap, if it is already 1, do nothing.
133 // Otherwise, set the bit, grab the index, update the buffer.
134 Value
*IdxFlags
[] = {ConstantInt::get(Int32Ty
, 0),
135 ConstantInt::get(Int32Ty
, FuncId
)};
136 Value
*MapAddr
= entryB
.CreateGEP(MapTy
, BitMap
, IdxFlags
, "");
137 LoadInst
*loadBitMap
= entryB
.CreateLoad(Int8Ty
, MapAddr
, "");
138 entryB
.CreateStore(ConstantInt::get(Int8Ty
, 1), MapAddr
);
139 Value
*IsNotExecuted
=
140 entryB
.CreateICmpEQ(loadBitMap
, ConstantInt::get(Int8Ty
, 0));
141 entryB
.CreateCondBr(IsNotExecuted
, UpdateOrderFileBB
, OrigEntry
);
143 // Fill up UpdateOrderFileBB: grab the index, update the buffer!
144 Value
*IdxVal
= updateB
.CreateAtomicRMW(
145 AtomicRMWInst::Add
, BufferIdx
, ConstantInt::get(Int32Ty
, 1),
146 MaybeAlign(), AtomicOrdering::SequentiallyConsistent
);
147 // We need to wrap around the index to fit it inside the buffer.
148 Value
*WrappedIdx
= updateB
.CreateAnd(
149 IdxVal
, ConstantInt::get(Int32Ty
, INSTR_ORDER_FILE_BUFFER_MASK
));
150 Value
*BufferGEPIdx
[] = {ConstantInt::get(Int32Ty
, 0), WrappedIdx
};
152 updateB
.CreateGEP(BufferTy
, OrderFileBuffer
, BufferGEPIdx
, "");
153 updateB
.CreateStore(ConstantInt::get(Type::getInt64Ty(Ctx
), MD5Hash(F
.getName())),
155 updateB
.CreateBr(OrigEntry
);
158 bool run(Module
&M
) {
159 createOrderFileData(M
);
162 for (Function
&F
: M
) {
163 if (F
.isDeclaration())
165 generateCodeSequence(M
, F
, FuncId
);
172 }; // End of InstrOrderFile struct
174 class InstrOrderFileLegacyPass
: public ModulePass
{
178 InstrOrderFileLegacyPass() : ModulePass(ID
) {
179 initializeInstrOrderFileLegacyPassPass(
180 *PassRegistry::getPassRegistry());
183 bool runOnModule(Module
&M
) override
;
186 } // End anonymous namespace
188 bool InstrOrderFileLegacyPass::runOnModule(Module
&M
) {
192 return InstrOrderFile().run(M
);
196 InstrOrderFilePass::run(Module
&M
, ModuleAnalysisManager
&AM
) {
197 if (InstrOrderFile().run(M
))
198 return PreservedAnalyses::none();
199 return PreservedAnalyses::all();
202 INITIALIZE_PASS_BEGIN(InstrOrderFileLegacyPass
, "instrorderfile",
203 "Instrumentation for Order File", false, false)
204 INITIALIZE_PASS_END(InstrOrderFileLegacyPass
, "instrorderfile",
205 "Instrumentation for Order File", false, false)
207 char InstrOrderFileLegacyPass::ID
= 0;
209 ModulePass
*llvm::createInstrOrderFilePass() {
210 return new InstrOrderFileLegacyPass();