/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Target/X86/X86WinEHState.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===// |
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 | | // All functions using an MSVC EH personality use an explicitly updated state |
11 | | // number stored in an exception registration stack object. The registration |
12 | | // object is linked into a thread-local chain of registrations stored at fs:00. |
13 | | // This pass adds the registration object and EH state updates. |
14 | | // |
15 | | //===----------------------------------------------------------------------===// |
16 | | |
17 | | #include "X86.h" |
18 | | #include "llvm/ADT/PostOrderIterator.h" |
19 | | #include "llvm/Analysis/CFG.h" |
20 | | #include "llvm/Analysis/EHPersonalities.h" |
21 | | #include "llvm/CodeGen/MachineModuleInfo.h" |
22 | | #include "llvm/CodeGen/WinEHFuncInfo.h" |
23 | | #include "llvm/IR/CallSite.h" |
24 | | #include "llvm/IR/Function.h" |
25 | | #include "llvm/IR/IRBuilder.h" |
26 | | #include "llvm/IR/Instructions.h" |
27 | | #include "llvm/IR/IntrinsicInst.h" |
28 | | #include "llvm/IR/Module.h" |
29 | | #include "llvm/Pass.h" |
30 | | #include "llvm/Support/Debug.h" |
31 | | #include <deque> |
32 | | |
33 | | using namespace llvm; |
34 | | |
35 | | #define DEBUG_TYPE "winehstate" |
36 | | |
37 | | namespace llvm { |
38 | | void initializeWinEHStatePassPass(PassRegistry &); |
39 | | } |
40 | | |
41 | | namespace { |
42 | | const int OverdefinedState = INT_MIN; |
43 | | |
44 | | class WinEHStatePass : public FunctionPass { |
45 | | public: |
46 | | static char ID; // Pass identification, replacement for typeid. |
47 | | |
48 | 238 | WinEHStatePass() : FunctionPass(ID) { |
49 | 238 | initializeWinEHStatePassPass(*PassRegistry::getPassRegistry()); |
50 | 238 | } |
51 | | |
52 | | bool runOnFunction(Function &Fn) override; |
53 | | |
54 | | bool doInitialization(Module &M) override; |
55 | | |
56 | | bool doFinalization(Module &M) override; |
57 | | |
58 | | void getAnalysisUsage(AnalysisUsage &AU) const override; |
59 | | |
60 | 0 | StringRef getPassName() const override { |
61 | 0 | return "Windows 32-bit x86 EH state insertion"; |
62 | 0 | } |
63 | | |
64 | | private: |
65 | | void emitExceptionRegistrationRecord(Function *F); |
66 | | |
67 | | void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler); |
68 | | void unlinkExceptionRegistration(IRBuilder<> &Builder); |
69 | | void addStateStores(Function &F, WinEHFuncInfo &FuncInfo); |
70 | | void insertStateNumberStore(Instruction *IP, int State); |
71 | | |
72 | | Value *emitEHLSDA(IRBuilder<> &Builder, Function *F); |
73 | | |
74 | | Function *generateLSDAInEAXThunk(Function *ParentFunc); |
75 | | |
76 | | bool isStateStoreNeeded(EHPersonality Personality, CallSite CS); |
77 | | void rewriteSetJmpCallSite(IRBuilder<> &Builder, Function &F, CallSite CS, |
78 | | Value *State); |
79 | | int getBaseStateForBB(DenseMap<BasicBlock *, ColorVector> &BlockColors, |
80 | | WinEHFuncInfo &FuncInfo, BasicBlock *BB); |
81 | | int getStateForCallSite(DenseMap<BasicBlock *, ColorVector> &BlockColors, |
82 | | WinEHFuncInfo &FuncInfo, CallSite CS); |
83 | | |
84 | | // Module-level type getters. |
85 | | Type *getEHLinkRegistrationType(); |
86 | | Type *getSEHRegistrationType(); |
87 | | Type *getCXXEHRegistrationType(); |
88 | | |
89 | | // Per-module data. |
90 | | Module *TheModule = nullptr; |
91 | | StructType *EHLinkRegistrationTy = nullptr; |
92 | | StructType *CXXEHRegistrationTy = nullptr; |
93 | | StructType *SEHRegistrationTy = nullptr; |
94 | | Constant *SetJmp3 = nullptr; |
95 | | Constant *CxxLongjmpUnwind = nullptr; |
96 | | |
97 | | // Per-function state |
98 | | EHPersonality Personality = EHPersonality::Unknown; |
99 | | Function *PersonalityFn = nullptr; |
100 | | bool UseStackGuard = false; |
101 | | int ParentBaseState; |
102 | | Constant *SehLongjmpUnwind = nullptr; |
103 | | Constant *Cookie = nullptr; |
104 | | |
105 | | /// The stack allocation containing all EH data, including the link in the |
106 | | /// fs:00 chain and the current state. |
107 | | AllocaInst *RegNode = nullptr; |
108 | | |
109 | | // The allocation containing the EH security guard. |
110 | | AllocaInst *EHGuardNode = nullptr; |
111 | | |
112 | | /// The index of the state field of RegNode. |
113 | | int StateFieldIndex = ~0U; |
114 | | |
115 | | /// The linked list node subobject inside of RegNode. |
116 | | Value *Link = nullptr; |
117 | | }; |
118 | | } |
119 | | |
120 | 234 | FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); } |
121 | | |
122 | | char WinEHStatePass::ID = 0; |
123 | | |
124 | | INITIALIZE_PASS(WinEHStatePass, "x86-winehstate", |
125 | | "Insert stores for EH state numbers", false, false) |
126 | | |
127 | 238 | bool WinEHStatePass::doInitialization(Module &M) { |
128 | 238 | TheModule = &M; |
129 | 238 | return false; |
130 | 238 | } |
131 | | |
132 | 236 | bool WinEHStatePass::doFinalization(Module &M) { |
133 | 236 | assert(TheModule == &M); |
134 | 236 | TheModule = nullptr; |
135 | 236 | EHLinkRegistrationTy = nullptr; |
136 | 236 | CXXEHRegistrationTy = nullptr; |
137 | 236 | SEHRegistrationTy = nullptr; |
138 | 236 | SetJmp3 = nullptr; |
139 | 236 | CxxLongjmpUnwind = nullptr; |
140 | 236 | SehLongjmpUnwind = nullptr; |
141 | 236 | Cookie = nullptr; |
142 | 236 | return false; |
143 | 236 | } |
144 | | |
145 | 238 | void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const { |
146 | 238 | // This pass should only insert a stack allocation, memory accesses, and |
147 | 238 | // localrecovers. |
148 | 238 | AU.setPreservesCFG(); |
149 | 238 | } |
150 | | |
151 | 912 | bool WinEHStatePass::runOnFunction(Function &F) { |
152 | 912 | // Check the personality. Do nothing if this personality doesn't use funclets. |
153 | 912 | if (!F.hasPersonalityFn()) |
154 | 855 | return false; |
155 | 57 | PersonalityFn = |
156 | 57 | dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts()); |
157 | 57 | if (!PersonalityFn) |
158 | 0 | return false; |
159 | 57 | Personality = classifyEHPersonality(PersonalityFn); |
160 | 57 | if (!isFuncletEHPersonality(Personality)) |
161 | 16 | return false; |
162 | 41 | |
163 | 41 | // Skip this function if there are no EH pads and we aren't using IR-level |
164 | 41 | // outlining. |
165 | 41 | bool HasPads = false; |
166 | 101 | for (BasicBlock &BB : F) { |
167 | 101 | if (BB.isEHPad()101 ) { |
168 | 39 | HasPads = true; |
169 | 39 | break; |
170 | 39 | } |
171 | 41 | } |
172 | 41 | if (!HasPads) |
173 | 2 | return false; |
174 | 39 | |
175 | 39 | Type *Int8PtrType = Type::getInt8PtrTy(TheModule->getContext()); |
176 | 39 | SetJmp3 = TheModule->getOrInsertFunction( |
177 | 39 | "_setjmp3", FunctionType::get( |
178 | 39 | Type::getInt32Ty(TheModule->getContext()), |
179 | 39 | {Int8PtrType, Type::getInt32Ty(TheModule->getContext())}, |
180 | 39 | /*isVarArg=*/true)); |
181 | 39 | |
182 | 39 | // Disable frame pointer elimination in this function. |
183 | 39 | // FIXME: Do the nested handlers need to keep the parent ebp in ebp, or can we |
184 | 39 | // use an arbitrary register? |
185 | 39 | F.addFnAttr("no-frame-pointer-elim", "true"); |
186 | 39 | |
187 | 39 | emitExceptionRegistrationRecord(&F); |
188 | 39 | |
189 | 39 | // The state numbers calculated here in IR must agree with what we calculate |
190 | 39 | // later on for the MachineFunction. In particular, if an IR pass deletes an |
191 | 39 | // unreachable EH pad after this point before machine CFG construction, we |
192 | 39 | // will be in trouble. If this assumption is ever broken, we should turn the |
193 | 39 | // numbers into an immutable analysis pass. |
194 | 39 | WinEHFuncInfo FuncInfo; |
195 | 39 | addStateStores(F, FuncInfo); |
196 | 39 | |
197 | 39 | // Reset per-function state. |
198 | 39 | PersonalityFn = nullptr; |
199 | 39 | Personality = EHPersonality::Unknown; |
200 | 39 | UseStackGuard = false; |
201 | 39 | RegNode = nullptr; |
202 | 39 | EHGuardNode = nullptr; |
203 | 39 | |
204 | 39 | return true; |
205 | 39 | } |
206 | | |
207 | | /// Get the common EH registration subobject: |
208 | | /// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)( |
209 | | /// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *); |
210 | | /// struct EHRegistrationNode { |
211 | | /// EHRegistrationNode *Next; |
212 | | /// PEXCEPTION_ROUTINE Handler; |
213 | | /// }; |
214 | 104 | Type *WinEHStatePass::getEHLinkRegistrationType() { |
215 | 104 | if (EHLinkRegistrationTy) |
216 | 80 | return EHLinkRegistrationTy; |
217 | 24 | LLVMContext &Context = TheModule->getContext(); |
218 | 24 | EHLinkRegistrationTy = StructType::create(Context, "EHRegistrationNode"); |
219 | 24 | Type *FieldTys[] = { |
220 | 24 | EHLinkRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next |
221 | 24 | Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...) |
222 | 24 | }; |
223 | 24 | EHLinkRegistrationTy->setBody(FieldTys, false); |
224 | 24 | return EHLinkRegistrationTy; |
225 | 24 | } |
226 | | |
227 | | /// The __CxxFrameHandler3 registration node: |
228 | | /// struct CXXExceptionRegistration { |
229 | | /// void *SavedESP; |
230 | | /// EHRegistrationNode SubRecord; |
231 | | /// int32_t TryLevel; |
232 | | /// }; |
233 | 23 | Type *WinEHStatePass::getCXXEHRegistrationType() { |
234 | 23 | if (CXXEHRegistrationTy) |
235 | 7 | return CXXEHRegistrationTy; |
236 | 16 | LLVMContext &Context = TheModule->getContext(); |
237 | 16 | Type *FieldTys[] = { |
238 | 16 | Type::getInt8PtrTy(Context), // void *SavedESP |
239 | 16 | getEHLinkRegistrationType(), // EHRegistrationNode SubRecord |
240 | 16 | Type::getInt32Ty(Context) // int32_t TryLevel |
241 | 16 | }; |
242 | 16 | CXXEHRegistrationTy = |
243 | 16 | StructType::create(FieldTys, "CXXExceptionRegistration"); |
244 | 16 | return CXXEHRegistrationTy; |
245 | 16 | } |
246 | | |
247 | | /// The _except_handler3/4 registration node: |
248 | | /// struct EH4ExceptionRegistration { |
249 | | /// void *SavedESP; |
250 | | /// _EXCEPTION_POINTERS *ExceptionPointers; |
251 | | /// EHRegistrationNode SubRecord; |
252 | | /// int32_t EncodedScopeTable; |
253 | | /// int32_t TryLevel; |
254 | | /// }; |
255 | 16 | Type *WinEHStatePass::getSEHRegistrationType() { |
256 | 16 | if (SEHRegistrationTy) |
257 | 5 | return SEHRegistrationTy; |
258 | 11 | LLVMContext &Context = TheModule->getContext(); |
259 | 11 | Type *FieldTys[] = { |
260 | 11 | Type::getInt8PtrTy(Context), // void *SavedESP |
261 | 11 | Type::getInt8PtrTy(Context), // void *ExceptionPointers |
262 | 11 | getEHLinkRegistrationType(), // EHRegistrationNode SubRecord |
263 | 11 | Type::getInt32Ty(Context), // int32_t EncodedScopeTable |
264 | 11 | Type::getInt32Ty(Context) // int32_t TryLevel |
265 | 11 | }; |
266 | 11 | SEHRegistrationTy = StructType::create(FieldTys, "SEHExceptionRegistration"); |
267 | 11 | return SEHRegistrationTy; |
268 | 11 | } |
269 | | |
270 | | // Emit an exception registration record. These are stack allocations with the |
271 | | // common subobject of two pointers: the previous registration record (the old |
272 | | // fs:00) and the personality function for the current frame. The data before |
273 | | // and after that is personality function specific. |
274 | 39 | void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { |
275 | 39 | assert(Personality == EHPersonality::MSVC_CXX || |
276 | 39 | Personality == EHPersonality::MSVC_X86SEH); |
277 | 39 | |
278 | 39 | // Struct type of RegNode. Used for GEPing. |
279 | 39 | Type *RegNodeTy; |
280 | 39 | |
281 | 39 | IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin()); |
282 | 39 | Type *Int8PtrType = Builder.getInt8PtrTy(); |
283 | 39 | Type *Int32Ty = Builder.getInt32Ty(); |
284 | 39 | Type *VoidTy = Builder.getVoidTy(); |
285 | 39 | |
286 | 39 | if (Personality == EHPersonality::MSVC_CXX39 ) { |
287 | 23 | RegNodeTy = getCXXEHRegistrationType(); |
288 | 23 | RegNode = Builder.CreateAlloca(RegNodeTy); |
289 | 23 | // SavedESP = llvm.stacksave() |
290 | 23 | Value *SP = Builder.CreateCall( |
291 | 23 | Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); |
292 | 23 | Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); |
293 | 23 | // TryLevel = -1 |
294 | 23 | StateFieldIndex = 2; |
295 | 23 | ParentBaseState = -1; |
296 | 23 | insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState); |
297 | 23 | // Handler = __ehhandler$F |
298 | 23 | Function *Trampoline = generateLSDAInEAXThunk(F); |
299 | 23 | Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1); |
300 | 23 | linkExceptionRegistration(Builder, Trampoline); |
301 | 23 | |
302 | 23 | CxxLongjmpUnwind = TheModule->getOrInsertFunction( |
303 | 23 | "__CxxLongjmpUnwind", |
304 | 23 | FunctionType::get(VoidTy, Int8PtrType, /*isVarArg=*/false)); |
305 | 23 | cast<Function>(CxxLongjmpUnwind->stripPointerCasts()) |
306 | 23 | ->setCallingConv(CallingConv::X86_StdCall); |
307 | 39 | } else if (16 Personality == EHPersonality::MSVC_X86SEH16 ) { |
308 | 16 | // If _except_handler4 is in use, some additional guard checks and prologue |
309 | 16 | // stuff is required. |
310 | 16 | StringRef PersonalityName = PersonalityFn->getName(); |
311 | 16 | UseStackGuard = (PersonalityName == "_except_handler4"); |
312 | 16 | |
313 | 16 | // Allocate local structures. |
314 | 16 | RegNodeTy = getSEHRegistrationType(); |
315 | 16 | RegNode = Builder.CreateAlloca(RegNodeTy); |
316 | 16 | if (UseStackGuard) |
317 | 2 | EHGuardNode = Builder.CreateAlloca(Int32Ty); |
318 | 16 | |
319 | 16 | // SavedESP = llvm.stacksave() |
320 | 16 | Value *SP = Builder.CreateCall( |
321 | 16 | Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); |
322 | 16 | Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); |
323 | 16 | // TryLevel = -2 / -1 |
324 | 16 | StateFieldIndex = 4; |
325 | 16 | ParentBaseState = UseStackGuard ? -22 : -114 ; |
326 | 16 | insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState); |
327 | 16 | // ScopeTable = llvm.x86.seh.lsda(F) |
328 | 16 | Value *LSDA = emitEHLSDA(Builder, F); |
329 | 16 | LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty); |
330 | 16 | // If using _except_handler4, xor the address of the table with |
331 | 16 | // __security_cookie. |
332 | 16 | if (UseStackGuard16 ) { |
333 | 2 | Cookie = TheModule->getOrInsertGlobal("__security_cookie", Int32Ty); |
334 | 2 | Value *Val = Builder.CreateLoad(Int32Ty, Cookie, "cookie"); |
335 | 2 | LSDA = Builder.CreateXor(LSDA, Val); |
336 | 2 | } |
337 | 16 | Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3)); |
338 | 16 | |
339 | 16 | // If using _except_handler4, the EHGuard contains: FramePtr xor Cookie. |
340 | 16 | if (UseStackGuard16 ) { |
341 | 2 | Value *Val = Builder.CreateLoad(Int32Ty, Cookie); |
342 | 2 | Value *FrameAddr = Builder.CreateCall( |
343 | 2 | Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress), |
344 | 2 | Builder.getInt32(0), "frameaddr"); |
345 | 2 | Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr, Int32Ty); |
346 | 2 | FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val); |
347 | 2 | Builder.CreateStore(FrameAddrI32, EHGuardNode); |
348 | 2 | } |
349 | 16 | |
350 | 16 | // Register the exception handler. |
351 | 16 | Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); |
352 | 16 | linkExceptionRegistration(Builder, PersonalityFn); |
353 | 16 | |
354 | 16 | SehLongjmpUnwind = TheModule->getOrInsertFunction( |
355 | 16 | UseStackGuard ? "_seh_longjmp_unwind4"2 : "_seh_longjmp_unwind"14 , |
356 | 16 | FunctionType::get(Type::getVoidTy(TheModule->getContext()), Int8PtrType, |
357 | 16 | /*isVarArg=*/false)); |
358 | 16 | cast<Function>(SehLongjmpUnwind->stripPointerCasts()) |
359 | 16 | ->setCallingConv(CallingConv::X86_StdCall); |
360 | 0 | } else { |
361 | 0 | llvm_unreachable("unexpected personality function"); |
362 | 16 | } |
363 | 39 | |
364 | 39 | // Insert an unlink before all returns. |
365 | 39 | for (BasicBlock &BB : *F) 39 { |
366 | 218 | TerminatorInst *T = BB.getTerminator(); |
367 | 218 | if (!isa<ReturnInst>(T)) |
368 | 180 | continue; |
369 | 38 | Builder.SetInsertPoint(T); |
370 | 38 | unlinkExceptionRegistration(Builder); |
371 | 38 | } |
372 | 39 | } |
373 | | |
374 | 42 | Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) { |
375 | 42 | Value *FI8 = Builder.CreateBitCast(F, Type::getInt8PtrTy(F->getContext())); |
376 | 42 | return Builder.CreateCall( |
377 | 42 | Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8); |
378 | 42 | } |
379 | | |
380 | | /// Generate a thunk that puts the LSDA of ParentFunc in EAX and then calls |
381 | | /// PersonalityFn, forwarding the parameters passed to PEXCEPTION_ROUTINE: |
382 | | /// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)( |
383 | | /// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *); |
384 | | /// We essentially want this code: |
385 | | /// movl $lsda, %eax |
386 | | /// jmpl ___CxxFrameHandler3 |
387 | 23 | Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) { |
388 | 23 | LLVMContext &Context = ParentFunc->getContext(); |
389 | 23 | Type *Int32Ty = Type::getInt32Ty(Context); |
390 | 23 | Type *Int8PtrType = Type::getInt8PtrTy(Context); |
391 | 23 | Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType, |
392 | 23 | Int8PtrType}; |
393 | 23 | FunctionType *TrampolineTy = |
394 | 23 | FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 4), |
395 | 23 | /*isVarArg=*/false); |
396 | 23 | FunctionType *TargetFuncTy = |
397 | 23 | FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 5), |
398 | 23 | /*isVarArg=*/false); |
399 | 23 | Function *Trampoline = |
400 | 23 | Function::Create(TrampolineTy, GlobalValue::InternalLinkage, |
401 | 23 | Twine("__ehhandler$") + GlobalValue::dropLLVMManglingEscape( |
402 | 23 | ParentFunc->getName()), |
403 | 23 | TheModule); |
404 | 23 | BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", Trampoline); |
405 | 23 | IRBuilder<> Builder(EntryBB); |
406 | 23 | Value *LSDA = emitEHLSDA(Builder, ParentFunc); |
407 | 23 | Value *CastPersonality = |
408 | 23 | Builder.CreateBitCast(PersonalityFn, TargetFuncTy->getPointerTo()); |
409 | 23 | auto AI = Trampoline->arg_begin(); |
410 | 23 | Value *Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++}; |
411 | 23 | CallInst *Call = Builder.CreateCall(CastPersonality, Args); |
412 | 23 | // Can't use musttail due to prototype mismatch, but we can use tail. |
413 | 23 | Call->setTailCall(true); |
414 | 23 | // Set inreg so we pass it in EAX. |
415 | 23 | Call->addParamAttr(0, Attribute::InReg); |
416 | 23 | Builder.CreateRet(Call); |
417 | 23 | return Trampoline; |
418 | 23 | } |
419 | | |
420 | | void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder, |
421 | 39 | Function *Handler) { |
422 | 39 | // Emit the .safeseh directive for this function. |
423 | 39 | Handler->addFnAttr("safeseh"); |
424 | 39 | |
425 | 39 | Type *LinkTy = getEHLinkRegistrationType(); |
426 | 39 | // Handler = Handler |
427 | 39 | Value *HandlerI8 = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy()); |
428 | 39 | Builder.CreateStore(HandlerI8, Builder.CreateStructGEP(LinkTy, Link, 1)); |
429 | 39 | // Next = [fs:00] |
430 | 39 | Constant *FSZero = |
431 | 39 | Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257)); |
432 | 39 | Value *Next = Builder.CreateLoad(FSZero); |
433 | 39 | Builder.CreateStore(Next, Builder.CreateStructGEP(LinkTy, Link, 0)); |
434 | 39 | // [fs:00] = Link |
435 | 39 | Builder.CreateStore(Link, FSZero); |
436 | 39 | } |
437 | | |
438 | 38 | void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) { |
439 | 38 | // Clone Link into the current BB for better address mode folding. |
440 | 38 | if (auto *GEP38 = dyn_cast<GetElementPtrInst>(Link)) { |
441 | 38 | GEP = cast<GetElementPtrInst>(GEP->clone()); |
442 | 38 | Builder.Insert(GEP); |
443 | 38 | Link = GEP; |
444 | 38 | } |
445 | 38 | Type *LinkTy = getEHLinkRegistrationType(); |
446 | 38 | // [fs:00] = Link->Next |
447 | 38 | Value *Next = |
448 | 38 | Builder.CreateLoad(Builder.CreateStructGEP(LinkTy, Link, 0)); |
449 | 38 | Constant *FSZero = |
450 | 38 | Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257)); |
451 | 38 | Builder.CreateStore(Next, FSZero); |
452 | 38 | } |
453 | | |
454 | | // Calls to setjmp(p) are lowered to _setjmp3(p, 0) by the frontend. |
455 | | // The idea behind _setjmp3 is that it takes an optional number of personality |
456 | | // specific parameters to indicate how to restore the personality-specific frame |
457 | | // state when longjmp is initiated. Typically, the current TryLevel is saved. |
458 | | void WinEHStatePass::rewriteSetJmpCallSite(IRBuilder<> &Builder, Function &F, |
459 | 5 | CallSite CS, Value *State) { |
460 | 5 | // Don't rewrite calls with a weird number of arguments. |
461 | 5 | if (CS.getNumArgOperands() != 2) |
462 | 0 | return; |
463 | 5 | |
464 | 5 | Instruction *Inst = CS.getInstruction(); |
465 | 5 | |
466 | 5 | SmallVector<OperandBundleDef, 1> OpBundles; |
467 | 5 | CS.getOperandBundlesAsDefs(OpBundles); |
468 | 5 | |
469 | 5 | SmallVector<Value *, 3> OptionalArgs; |
470 | 5 | if (Personality == EHPersonality::MSVC_CXX5 ) { |
471 | 3 | OptionalArgs.push_back(CxxLongjmpUnwind); |
472 | 3 | OptionalArgs.push_back(State); |
473 | 3 | OptionalArgs.push_back(emitEHLSDA(Builder, &F)); |
474 | 5 | } else if (2 Personality == EHPersonality::MSVC_X86SEH2 ) { |
475 | 2 | OptionalArgs.push_back(SehLongjmpUnwind); |
476 | 2 | OptionalArgs.push_back(State); |
477 | 2 | if (UseStackGuard) |
478 | 0 | OptionalArgs.push_back(Cookie); |
479 | 0 | } else { |
480 | 0 | llvm_unreachable("unhandled personality!"); |
481 | 2 | } |
482 | 5 | |
483 | 5 | SmallVector<Value *, 5> Args; |
484 | 5 | Args.push_back( |
485 | 5 | Builder.CreateBitCast(CS.getArgOperand(0), Builder.getInt8PtrTy())); |
486 | 5 | Args.push_back(Builder.getInt32(OptionalArgs.size())); |
487 | 5 | Args.append(OptionalArgs.begin(), OptionalArgs.end()); |
488 | 5 | |
489 | 5 | CallSite NewCS; |
490 | 5 | if (CS.isCall()5 ) { |
491 | 3 | auto *CI = cast<CallInst>(Inst); |
492 | 3 | CallInst *NewCI = Builder.CreateCall(SetJmp3, Args, OpBundles); |
493 | 3 | NewCI->setTailCallKind(CI->getTailCallKind()); |
494 | 3 | NewCS = NewCI; |
495 | 5 | } else { |
496 | 2 | auto *II = cast<InvokeInst>(Inst); |
497 | 2 | NewCS = Builder.CreateInvoke( |
498 | 2 | SetJmp3, II->getNormalDest(), II->getUnwindDest(), Args, OpBundles); |
499 | 2 | } |
500 | 5 | NewCS.setCallingConv(CS.getCallingConv()); |
501 | 5 | NewCS.setAttributes(CS.getAttributes()); |
502 | 5 | NewCS->setDebugLoc(CS->getDebugLoc()); |
503 | 5 | |
504 | 5 | Instruction *NewInst = NewCS.getInstruction(); |
505 | 5 | NewInst->takeName(Inst); |
506 | 5 | Inst->replaceAllUsesWith(NewInst); |
507 | 5 | Inst->eraseFromParent(); |
508 | 5 | } |
509 | | |
510 | | // Figure out what state we should assign calls in this block. |
511 | | int WinEHStatePass::getBaseStateForBB( |
512 | | DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo, |
513 | 184 | BasicBlock *BB) { |
514 | 184 | int BaseState = ParentBaseState; |
515 | 184 | auto &BBColors = BlockColors[BB]; |
516 | 184 | |
517 | 184 | assert(BBColors.size() == 1 && "multi-color BB not removed by preparation"); |
518 | 184 | BasicBlock *FuncletEntryBB = BBColors.front(); |
519 | 184 | if (auto *FuncletPad = |
520 | 48 | dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI())) { |
521 | 48 | auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); |
522 | 48 | if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) |
523 | 28 | BaseState = BaseStateI->second; |
524 | 48 | } |
525 | 184 | |
526 | 184 | return BaseState; |
527 | 184 | } |
528 | | |
529 | | // Calculate the state a call-site is in. |
530 | | int WinEHStatePass::getStateForCallSite( |
531 | | DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo, |
532 | 303 | CallSite CS) { |
533 | 303 | if (auto *II303 = dyn_cast<InvokeInst>(CS.getInstruction())) { |
534 | 119 | // Look up the state number of the EH pad this unwinds to. |
535 | 119 | assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!"); |
536 | 119 | return FuncInfo.InvokeStateMap[II]; |
537 | 119 | } |
538 | 184 | // Possibly throwing call instructions have no actions to take after |
539 | 184 | // an unwind. Ensure they are in the -1 state. |
540 | 184 | return getBaseStateForBB(BlockColors, FuncInfo, CS.getParent()); |
541 | 184 | } |
542 | | |
543 | | // Calculate the intersection of all the FinalStates for a BasicBlock's |
544 | | // predecessors. |
545 | | static int getPredState(DenseMap<BasicBlock *, int> &FinalStates, Function &F, |
546 | 321 | int ParentBaseState, BasicBlock *BB) { |
547 | 321 | // The entry block has no predecessors but we know that the prologue always |
548 | 321 | // sets us up with a fixed state. |
549 | 321 | if (&F.getEntryBlock() == BB) |
550 | 39 | return ParentBaseState; |
551 | 282 | |
552 | 282 | // This is an EH Pad, conservatively report this basic block as overdefined. |
553 | 282 | if (282 BB->isEHPad()282 ) |
554 | 164 | return OverdefinedState; |
555 | 118 | |
556 | 118 | int CommonState = OverdefinedState; |
557 | 125 | for (BasicBlock *PredBB : predecessors(BB)) { |
558 | 125 | // We didn't manage to get a state for one of these predecessors, |
559 | 125 | // conservatively report this basic block as overdefined. |
560 | 125 | auto PredEndState = FinalStates.find(PredBB); |
561 | 125 | if (PredEndState == FinalStates.end()) |
562 | 46 | return OverdefinedState; |
563 | 79 | |
564 | 79 | // This code is reachable via exceptional control flow, |
565 | 79 | // conservatively report this basic block as overdefined. |
566 | 79 | if (79 isa<CatchReturnInst>(PredBB->getTerminator())79 ) |
567 | 25 | return OverdefinedState; |
568 | 54 | |
569 | 54 | int PredState = PredEndState->second; |
570 | 54 | assert(PredState != OverdefinedState && |
571 | 54 | "overdefined BBs shouldn't be in FinalStates"); |
572 | 54 | if (CommonState == OverdefinedState) |
573 | 50 | CommonState = PredState; |
574 | 54 | |
575 | 54 | // At least two predecessors have different FinalStates, |
576 | 54 | // conservatively report this basic block as overdefined. |
577 | 54 | if (CommonState != PredState) |
578 | 3 | return OverdefinedState; |
579 | 44 | } |
580 | 44 | |
581 | 44 | return CommonState; |
582 | 44 | } |
583 | | |
584 | | // Calculate the intersection of all the InitialStates for a BasicBlock's |
585 | | // successors. |
586 | | static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F, |
587 | 218 | int ParentBaseState, BasicBlock *BB) { |
588 | 218 | // This block rejoins normal control flow, |
589 | 218 | // conservatively report this basic block as overdefined. |
590 | 218 | if (isa<CatchReturnInst>(BB->getTerminator())) |
591 | 42 | return OverdefinedState; |
592 | 176 | |
593 | 176 | int CommonState = OverdefinedState; |
594 | 154 | for (BasicBlock *SuccBB : successors(BB)) { |
595 | 154 | // We didn't manage to get a state for one of these predecessors, |
596 | 154 | // conservatively report this basic block as overdefined. |
597 | 154 | auto SuccStartState = InitialStates.find(SuccBB); |
598 | 154 | if (SuccStartState == InitialStates.end()) |
599 | 86 | return OverdefinedState; |
600 | 68 | |
601 | 68 | // This is an EH Pad, conservatively report this basic block as overdefined. |
602 | 68 | if (68 SuccBB->isEHPad()68 ) |
603 | 27 | return OverdefinedState; |
604 | 41 | |
605 | 41 | int SuccState = SuccStartState->second; |
606 | 41 | assert(SuccState != OverdefinedState && |
607 | 41 | "overdefined BBs shouldn't be in FinalStates"); |
608 | 41 | if (CommonState == OverdefinedState) |
609 | 39 | CommonState = SuccState; |
610 | 41 | |
611 | 41 | // At least two successors have different InitialStates, |
612 | 41 | // conservatively report this basic block as overdefined. |
613 | 41 | if (CommonState != SuccState) |
614 | 1 | return OverdefinedState; |
615 | 62 | } |
616 | 62 | |
617 | 62 | return CommonState; |
618 | 62 | } |
619 | | |
620 | | bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality, |
621 | 2.37k | CallSite CS) { |
622 | 2.37k | if (!CS) |
623 | 1.93k | return false; |
624 | 440 | |
625 | 440 | // If the function touches memory, it needs a state store. |
626 | 440 | if (440 isAsynchronousEHPersonality(Personality)440 ) |
627 | 191 | return !CS.doesNotAccessMemory(); |
628 | 249 | |
629 | 249 | // If the function throws, it needs a state store. |
630 | 249 | return !CS.doesNotThrow(); |
631 | 249 | } |
632 | | |
633 | 39 | void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) { |
634 | 39 | // Mark the registration node. The backend needs to know which alloca it is so |
635 | 39 | // that it can recover the original frame pointer. |
636 | 39 | IRBuilder<> Builder(RegNode->getNextNode()); |
637 | 39 | Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getInt8PtrTy()); |
638 | 39 | Builder.CreateCall( |
639 | 39 | Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehregnode), |
640 | 39 | {RegNodeI8}); |
641 | 39 | |
642 | 39 | if (EHGuardNode39 ) { |
643 | 2 | IRBuilder<> Builder(EHGuardNode->getNextNode()); |
644 | 2 | Value *EHGuardNodeI8 = |
645 | 2 | Builder.CreateBitCast(EHGuardNode, Builder.getInt8PtrTy()); |
646 | 2 | Builder.CreateCall( |
647 | 2 | Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehguard), |
648 | 2 | {EHGuardNodeI8}); |
649 | 2 | } |
650 | 39 | |
651 | 39 | // Calculate state numbers. |
652 | 39 | if (isAsynchronousEHPersonality(Personality)) |
653 | 16 | calculateSEHStateNumbers(&F, FuncInfo); |
654 | 39 | else |
655 | 23 | calculateWinCXXEHStateNumbers(&F, FuncInfo); |
656 | 39 | |
657 | 39 | // Iterate all the instructions and emit state number stores. |
658 | 39 | DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F); |
659 | 39 | ReversePostOrderTraversal<Function *> RPOT(&F); |
660 | 39 | |
661 | 39 | // InitialStates yields the state of the first call-site for a BasicBlock. |
662 | 39 | DenseMap<BasicBlock *, int> InitialStates; |
663 | 39 | // FinalStates yields the state of the last call-site for a BasicBlock. |
664 | 39 | DenseMap<BasicBlock *, int> FinalStates; |
665 | 39 | // Worklist used to revisit BasicBlocks with indeterminate |
666 | 39 | // Initial/Final-States. |
667 | 39 | std::deque<BasicBlock *> Worklist; |
668 | 39 | // Fill in InitialStates and FinalStates for BasicBlocks with call-sites. |
669 | 218 | for (BasicBlock *BB : RPOT) { |
670 | 218 | int InitialState = OverdefinedState; |
671 | 218 | int FinalState; |
672 | 218 | if (&F.getEntryBlock() == BB) |
673 | 39 | InitialState = FinalState = ParentBaseState; |
674 | 1.21k | for (Instruction &I : *BB) { |
675 | 1.21k | CallSite CS(&I); |
676 | 1.21k | if (!isStateStoreNeeded(Personality, CS)) |
677 | 1.06k | continue; |
678 | 156 | |
679 | 156 | int State = getStateForCallSite(BlockColors, FuncInfo, CS); |
680 | 156 | if (InitialState == OverdefinedState) |
681 | 56 | InitialState = State; |
682 | 1.21k | FinalState = State; |
683 | 1.21k | } |
684 | 218 | // No call-sites in this basic block? That's OK, we will come back to these |
685 | 218 | // in a later pass. |
686 | 218 | if (InitialState == OverdefinedState218 ) { |
687 | 123 | Worklist.push_back(BB); |
688 | 123 | continue; |
689 | 123 | } |
690 | 95 | DEBUG95 (dbgs() << "X86WinEHState: " << BB->getName() |
691 | 95 | << " InitialState=" << InitialState << '\n'); |
692 | 95 | DEBUG(dbgs() << "X86WinEHState: " << BB->getName() |
693 | 218 | << " FinalState=" << FinalState << '\n'); |
694 | 218 | InitialStates.insert({BB, InitialState}); |
695 | 218 | FinalStates.insert({BB, FinalState}); |
696 | 218 | } |
697 | 39 | |
698 | 39 | // Try to fill-in InitialStates and FinalStates which have no call-sites. |
699 | 168 | while (!Worklist.empty()168 ) { |
700 | 129 | BasicBlock *BB = Worklist.front(); |
701 | 129 | Worklist.pop_front(); |
702 | 129 | // This BasicBlock has already been figured out, nothing more we can do. |
703 | 129 | if (InitialStates.count(BB) != 0) |
704 | 2 | continue; |
705 | 127 | |
706 | 127 | int PredState = getPredState(FinalStates, F, ParentBaseState, BB); |
707 | 127 | if (PredState == OverdefinedState) |
708 | 111 | continue; |
709 | 16 | |
710 | 16 | // We successfully inferred this BasicBlock's state via it's predecessors; |
711 | 16 | // enqueue it's successors to see if we can infer their states. |
712 | 16 | InitialStates.insert({BB, PredState}); |
713 | 16 | FinalStates.insert({BB, PredState}); |
714 | 16 | for (BasicBlock *SuccBB : successors(BB)) |
715 | 6 | Worklist.push_back(SuccBB); |
716 | 129 | } |
717 | 39 | |
718 | 39 | // Try to hoist stores from successors. |
719 | 218 | for (BasicBlock *BB : RPOT) { |
720 | 218 | int SuccState = getSuccState(InitialStates, F, ParentBaseState, BB); |
721 | 218 | if (SuccState == OverdefinedState) |
722 | 215 | continue; |
723 | 3 | |
724 | 3 | // Update our FinalState to reflect the common InitialState of our |
725 | 3 | // successors. |
726 | 3 | FinalStates.insert({BB, SuccState}); |
727 | 3 | } |
728 | 39 | |
729 | 39 | // Finally, insert state stores before call-sites which transition us to a new |
730 | 39 | // state. |
731 | 218 | for (BasicBlock *BB : RPOT) { |
732 | 218 | auto &BBColors = BlockColors[BB]; |
733 | 218 | BasicBlock *FuncletEntryBB = BBColors.front(); |
734 | 218 | if (isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI())) |
735 | 24 | continue; |
736 | 194 | |
737 | 194 | int PrevState = getPredState(FinalStates, F, ParentBaseState, BB); |
738 | 194 | DEBUG(dbgs() << "X86WinEHState: " << BB->getName() |
739 | 194 | << " PrevState=" << PrevState << '\n'); |
740 | 194 | |
741 | 1.16k | for (Instruction &I : *BB) { |
742 | 1.16k | CallSite CS(&I); |
743 | 1.16k | if (!isStateStoreNeeded(Personality, CS)) |
744 | 1.01k | continue; |
745 | 143 | |
746 | 143 | int State = getStateForCallSite(BlockColors, FuncInfo, CS); |
747 | 143 | if (State != PrevState) |
748 | 80 | insertStateNumberStore(&I, State); |
749 | 1.16k | PrevState = State; |
750 | 1.16k | } |
751 | 194 | |
752 | 194 | // We might have hoisted a state store into this block, emit it now. |
753 | 194 | auto EndState = FinalStates.find(BB); |
754 | 194 | if (EndState != FinalStates.end()) |
755 | 97 | if (97 EndState->second != PrevState97 ) |
756 | 1 | insertStateNumberStore(BB->getTerminator(), EndState->second); |
757 | 218 | } |
758 | 39 | |
759 | 39 | SmallVector<CallSite, 1> SetJmp3CallSites; |
760 | 218 | for (BasicBlock *BB : RPOT) { |
761 | 1.37k | for (Instruction &I : *BB) { |
762 | 1.37k | CallSite CS(&I); |
763 | 1.37k | if (!CS) |
764 | 1.15k | continue; |
765 | 228 | if (228 CS.getCalledValue()->stripPointerCasts() != |
766 | 228 | SetJmp3->stripPointerCasts()) |
767 | 223 | continue; |
768 | 5 | |
769 | 5 | SetJmp3CallSites.push_back(CS); |
770 | 5 | } |
771 | 218 | } |
772 | 39 | |
773 | 5 | for (CallSite CS : SetJmp3CallSites) { |
774 | 5 | auto &BBColors = BlockColors[CS->getParent()]; |
775 | 5 | BasicBlock *FuncletEntryBB = BBColors.front(); |
776 | 5 | bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->getFirstNonPHI()); |
777 | 5 | |
778 | 5 | IRBuilder<> Builder(CS.getInstruction()); |
779 | 5 | Value *State; |
780 | 5 | if (InCleanup5 ) { |
781 | 1 | Value *StateField = |
782 | 1 | Builder.CreateStructGEP(nullptr, RegNode, StateFieldIndex); |
783 | 1 | State = Builder.CreateLoad(StateField); |
784 | 5 | } else { |
785 | 4 | State = Builder.getInt32(getStateForCallSite(BlockColors, FuncInfo, CS)); |
786 | 4 | } |
787 | 5 | rewriteSetJmpCallSite(Builder, F, CS, State); |
788 | 5 | } |
789 | 39 | } |
790 | | |
791 | 120 | void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) { |
792 | 120 | IRBuilder<> Builder(IP); |
793 | 120 | Value *StateField = |
794 | 120 | Builder.CreateStructGEP(nullptr, RegNode, StateFieldIndex); |
795 | 120 | Builder.CreateStore(Builder.getInt32(State), StateField); |
796 | 120 | } |