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