OLD | NEW |
1 //===- subzero/src/IceASanInstrumentation.cpp - ASan ------------*- C++ -*-===// | 1 //===- subzero/src/IceASanInstrumentation.cpp - ASan ------------*- C++ -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
11 /// \brief Implements the AddressSanitizer instrumentation class. | 11 /// \brief Implements the AddressSanitizer instrumentation class. |
12 /// | 12 /// |
13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
14 | 14 |
15 #include "IceASanInstrumentation.h" | 15 #include "IceASanInstrumentation.h" |
16 | 16 |
17 #include "IceBuildDefs.h" | 17 #include "IceBuildDefs.h" |
18 #include "IceCfg.h" | 18 #include "IceCfg.h" |
19 #include "IceCfgNode.h" | 19 #include "IceCfgNode.h" |
20 #include "IceGlobalInits.h" | 20 #include "IceGlobalInits.h" |
21 #include "IceInst.h" | 21 #include "IceInst.h" |
22 #include "IceTargetLowering.h" | 22 #include "IceTargetLowering.h" |
23 #include "IceTypes.h" | 23 #include "IceTypes.h" |
24 | 24 |
25 #include <sstream> | 25 #include <sstream> |
26 #include <unordered_map> | 26 #include <unordered_map> |
| 27 #include <vector> |
27 | 28 |
28 namespace Ice { | 29 namespace Ice { |
29 | 30 |
30 namespace { | 31 namespace { |
| 32 |
31 constexpr SizeT RzSize = 32; | 33 constexpr SizeT RzSize = 32; |
32 const std::string RzPrefix = "__$rz"; | 34 const std::string RzPrefix = "__$rz"; |
33 const llvm::NaClBitcodeRecord::RecordVector RzContents = | 35 const llvm::NaClBitcodeRecord::RecordVector RzContents = |
34 llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R'); | 36 llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R'); |
35 | 37 |
36 // TODO(tlively): Handle all allocation functions | 38 // TODO(tlively): Handle all allocation functions |
37 // In order to instrument the code correctly, the .pexe must not have had its | 39 // In order to instrument the code correctly, the .pexe must not have had its |
38 // symbols stripped. | 40 // symbols stripped. |
39 using string_map = std::unordered_map<std::string, std::string>; | 41 using string_map = std::unordered_map<std::string, std::string>; |
40 const string_map FuncSubstitutions = {{"malloc", "__asan_malloc"}, | 42 const string_map FuncSubstitutions = {{"malloc", "__asan_malloc"}, |
41 {"free", "__asan_free"}}; | 43 {"free", "__asan_free"}}; |
42 | 44 |
43 } // end of anonymous namespace | 45 } // end of anonymous namespace |
44 | 46 |
| 47 ICE_TLS_DEFINE_FIELD(std::vector<InstCall *> *, ASanInstrumentation, |
| 48 LocalDtors); |
| 49 |
45 // Create redzones around all global variables, ensuring that the initializer | 50 // Create redzones around all global variables, ensuring that the initializer |
46 // types of the redzones and their associated globals match so that they are | 51 // types of the redzones and their associated globals match so that they are |
47 // laid out together in memory. | 52 // laid out together in memory. |
48 void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) { | 53 void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) { |
49 if (DidInsertRedZones) | 54 if (DidInsertRedZones) |
50 return; | 55 return; |
51 | 56 |
52 VariableDeclarationList NewGlobals; | 57 VariableDeclarationList NewGlobals; |
53 // Global holding pointers to all redzones | 58 // Global holding pointers to all redzones |
54 auto *RzArray = VariableDeclaration::create(&NewGlobals); | 59 auto *RzArray = VariableDeclaration::create(&NewGlobals); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 Rz->setIsConstant(Global->getIsConstant()); | 124 Rz->setIsConstant(Global->getIsConstant()); |
120 RzArray->addInitializer(VariableDeclaration::RelocInitializer::create( | 125 RzArray->addInitializer(VariableDeclaration::RelocInitializer::create( |
121 List, Rz, RelocOffsetArray(0))); | 126 List, Rz, RelocOffsetArray(0))); |
122 ++RzArraySize; | 127 ++RzArraySize; |
123 return Rz; | 128 return Rz; |
124 } | 129 } |
125 | 130 |
126 // Check for an alloca signaling the presence of local variables and add a | 131 // Check for an alloca signaling the presence of local variables and add a |
127 // redzone if it is found | 132 // redzone if it is found |
128 void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) { | 133 void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) { |
129 auto *FirstAlloca = llvm::dyn_cast<InstAlloca>(Context.getCur()); | 134 if (ICE_TLS_GET_FIELD(LocalDtors) == nullptr) |
130 if (FirstAlloca == nullptr) | 135 ICE_TLS_SET_FIELD(LocalDtors, new std::vector<InstCall *>()); |
131 return; | |
132 | 136 |
133 constexpr SizeT Alignment = 4; | 137 Cfg *Func = Context.getNode()->getCfg(); |
134 InstAlloca *RzAlloca = createLocalRz(Context, RzSize, Alignment); | 138 bool HasLocals = false; |
| 139 LoweringContext C; |
| 140 C.init(Context.getNode()); |
| 141 std::vector<Inst *> Initializations; |
| 142 Constant *InitFunc = |
| 143 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_poison")); |
| 144 Constant *DestroyFunc = |
| 145 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_unpoison")); |
135 | 146 |
136 // insert before the current instruction | 147 InstAlloca *Cur; |
137 InstList::iterator Next = Context.getNext(); | 148 ConstantInteger32 *VarSizeOp; |
138 Context.setInsertPoint(Context.getCur()); | 149 while ( |
139 Context.insert(RzAlloca); | 150 (Cur = llvm::dyn_cast<InstAlloca>(iteratorToInst(C.getCur()))) && |
140 Context.setNext(Next); | 151 (VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Cur->getSizeInBytes()))) { |
141 } | 152 HasLocals = true; |
142 | 153 |
143 void ASanInstrumentation::instrumentAlloca(LoweringContext &Context, | 154 // create the new alloca that includes a redzone |
144 InstAlloca *Instr) { | 155 SizeT VarSize = VarSizeOp->getValue(); |
145 auto *VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Instr->getSizeInBytes()); | 156 Variable *Dest = Cur->getDest(); |
146 SizeT VarSize = (VarSizeOp == nullptr) ? RzSize : VarSizeOp->getValue(); | 157 SizeT RzPadding = RzSize + Utils::OffsetToAlignment(VarSize, RzSize); |
147 SizeT Padding = Utils::OffsetToAlignment(VarSize, RzSize); | 158 auto *ByteCount = |
148 constexpr SizeT Alignment = 1; | 159 ConstantInteger32::create(Ctx, IceType_i32, VarSize + RzPadding); |
149 InstAlloca *Rz = createLocalRz(Context, RzSize + Padding, Alignment); | 160 constexpr SizeT Alignment = 8; |
150 Context.insert(Rz); | 161 auto *NewVar = InstAlloca::create(Func, Dest, ByteCount, Alignment); |
151 } | |
152 | 162 |
153 InstAlloca *ASanInstrumentation::createLocalRz(LoweringContext &Context, | 163 // calculate the redzone offset |
154 SizeT Size, SizeT Alignment) { | 164 Variable *RzLocVar = Func->makeVariable(IceType_i32); |
155 Cfg *Func = Context.getNode()->getCfg(); | 165 RzLocVar->setName(Func, nextRzName()); |
156 Variable *Rz = Func->makeVariable(IceType_i32); | 166 auto *Offset = ConstantInteger32::create(Ctx, IceType_i32, VarSize); |
157 Rz->setName(Func, nextRzName()); | 167 auto *RzLoc = InstArithmetic::create(Func, InstArithmetic::Add, RzLocVar, |
158 auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, Size); | 168 Dest, Offset); |
159 auto *RzAlloca = InstAlloca::create(Func, Rz, ByteCount, Alignment); | 169 |
160 return RzAlloca; | 170 // instructions to poison and unpoison the redzone |
| 171 constexpr SizeT NumArgs = 2; |
| 172 constexpr Variable *Void = nullptr; |
| 173 constexpr bool NoTailcall = false; |
| 174 auto *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall); |
| 175 auto *Destroy = |
| 176 InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall); |
| 177 Init->addArg(RzLocVar); |
| 178 Destroy->addArg(RzLocVar); |
| 179 auto *RzSizeConst = ConstantInteger32::create(Ctx, IceType_i32, RzPadding); |
| 180 Init->addArg(RzSizeConst); |
| 181 Destroy->addArg(RzSizeConst); |
| 182 |
| 183 Cur->setDeleted(); |
| 184 C.insert(NewVar); |
| 185 ICE_TLS_GET_FIELD(LocalDtors)->emplace_back(Destroy); |
| 186 Initializations.emplace_back(RzLoc); |
| 187 Initializations.emplace_back(Init); |
| 188 |
| 189 C.advanceCur(); |
| 190 C.advanceNext(); |
| 191 } |
| 192 |
| 193 C.setInsertPoint(C.getCur()); |
| 194 |
| 195 // add the leftmost redzone |
| 196 if (HasLocals) { |
| 197 Variable *LastRz = Func->makeVariable(IceType_i32); |
| 198 LastRz->setName(Func, nextRzName()); |
| 199 auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, RzSize); |
| 200 constexpr SizeT Alignment = 8; |
| 201 auto *RzAlloca = InstAlloca::create(Func, LastRz, ByteCount, Alignment); |
| 202 |
| 203 constexpr SizeT NumArgs = 2; |
| 204 constexpr Variable *Void = nullptr; |
| 205 constexpr bool NoTailcall = false; |
| 206 auto *Init = InstCall::create(Func, NumArgs, Void, InitFunc, NoTailcall); |
| 207 auto *Destroy = |
| 208 InstCall::create(Func, NumArgs, Void, DestroyFunc, NoTailcall); |
| 209 Init->addArg(LastRz); |
| 210 Destroy->addArg(LastRz); |
| 211 Init->addArg(RzAlloca->getSizeInBytes()); |
| 212 Destroy->addArg(RzAlloca->getSizeInBytes()); |
| 213 |
| 214 ICE_TLS_GET_FIELD(LocalDtors)->emplace_back(Destroy); |
| 215 C.insert(RzAlloca); |
| 216 C.insert(Init); |
| 217 } |
| 218 |
| 219 // insert initializers for the redzones |
| 220 for (Inst *Init : Initializations) { |
| 221 C.insert(Init); |
| 222 } |
161 } | 223 } |
162 | 224 |
163 void ASanInstrumentation::instrumentCall(LoweringContext &Context, | 225 void ASanInstrumentation::instrumentCall(LoweringContext &Context, |
164 InstCall *Instr) { | 226 InstCall *Instr) { |
165 auto *CallTarget = | 227 auto *CallTarget = |
166 llvm::dyn_cast<ConstantRelocatable>(Instr->getCallTarget()); | 228 llvm::dyn_cast<ConstantRelocatable>(Instr->getCallTarget()); |
167 if (CallTarget == nullptr) | 229 if (CallTarget == nullptr) |
168 return; | 230 return; |
169 | 231 |
170 std::string TargetName = CallTarget->getName().toStringOrEmpty(); | 232 std::string TargetName = CallTarget->getName().toStringOrEmpty(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 AccessCheck, NoTailCall); | 269 AccessCheck, NoTailCall); |
208 Call->addArg(Op); | 270 Call->addArg(Op); |
209 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, Size)); | 271 Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, Size)); |
210 // play games to insert the call before the access instruction | 272 // play games to insert the call before the access instruction |
211 InstList::iterator Next = Context.getNext(); | 273 InstList::iterator Next = Context.getNext(); |
212 Context.setInsertPoint(Context.getCur()); | 274 Context.setInsertPoint(Context.getCur()); |
213 Context.insert(Call); | 275 Context.insert(Call); |
214 Context.setNext(Next); | 276 Context.setNext(Next); |
215 } | 277 } |
216 | 278 |
| 279 void ASanInstrumentation::instrumentRet(LoweringContext &Context, InstRet *) { |
| 280 InstList::iterator Next = Context.getNext(); |
| 281 Context.setInsertPoint(Context.getCur()); |
| 282 for (InstCall *RzUnpoison : *ICE_TLS_GET_FIELD(LocalDtors)) { |
| 283 Context.insert(RzUnpoison); |
| 284 } |
| 285 Context.setNext(Next); |
| 286 } |
| 287 |
217 void ASanInstrumentation::instrumentStart(Cfg *Func) { | 288 void ASanInstrumentation::instrumentStart(Cfg *Func) { |
218 Constant *ShadowMemInit = | 289 Constant *ShadowMemInit = |
219 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_init")); | 290 Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_init")); |
220 constexpr SizeT NumArgs = 0; | 291 constexpr SizeT NumArgs = 0; |
221 constexpr Variable *Void = nullptr; | 292 constexpr Variable *Void = nullptr; |
222 constexpr bool NoTailCall = false; | 293 constexpr bool NoTailCall = false; |
223 auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall); | 294 auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall); |
224 Func->getEntryNode()->getInsts().push_front(Call); | 295 Func->getEntryNode()->getInsts().push_front(Call); |
225 } | 296 } |
226 | 297 |
| 298 // TODO(tlively): make this more efficient with swap idiom |
| 299 void ASanInstrumentation::finishFunc(Cfg *Func) { |
| 300 (void)Func; |
| 301 ICE_TLS_GET_FIELD(LocalDtors)->clear(); |
| 302 } |
| 303 |
227 } // end of namespace Ice | 304 } // end of namespace Ice |
OLD | NEW |