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/Analysis/CFG.h"
19#include "llvm/Analysis/EHPersonalities.h"
20#include "llvm/CodeGen/MachineModuleInfo.h"
21#include "llvm/CodeGen/Passes.h"
22#include "llvm/CodeGen/WinEHFuncInfo.h"
23#include "llvm/IR/Dominators.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/IR/PatternMatch.h"
30#include "llvm/Pass.h"
31#include "llvm/Support/Debug.h"
32#include "llvm/Support/raw_ostream.h"
33#include "llvm/Transforms/Utils/BasicBlockUtils.h"
34#include "llvm/Transforms/Utils/Cloning.h"
35#include "llvm/Transforms/Utils/Local.h"
36
37using namespace llvm;
38using namespace llvm::PatternMatch;
39
40#define DEBUG_TYPE "winehstate"
41
42namespace llvm { void initializeWinEHStatePassPass(PassRegistry &); }
43
44namespace {
45class WinEHStatePass : public FunctionPass {
46public:
47  static char ID; // Pass identification, replacement for typeid.
48
49  WinEHStatePass() : FunctionPass(ID) {
50    initializeWinEHStatePassPass(*PassRegistry::getPassRegistry());
51  }
52
53  bool runOnFunction(Function &Fn) override;
54
55  bool doInitialization(Module &M) override;
56
57  bool doFinalization(Module &M) override;
58
59  void getAnalysisUsage(AnalysisUsage &AU) const override;
60
61  const char *getPassName() const override {
62    return "Windows 32-bit x86 EH state insertion";
63  }
64
65private:
66  void emitExceptionRegistrationRecord(Function *F);
67
68  void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler);
69  void unlinkExceptionRegistration(IRBuilder<> &Builder);
70  void addStateStores(Function &F, WinEHFuncInfo &FuncInfo);
71  void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
72
73  Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
74
75  Function *generateLSDAInEAXThunk(Function *ParentFunc);
76
77  // Module-level type getters.
78  Type *getEHLinkRegistrationType();
79  Type *getSEHRegistrationType();
80  Type *getCXXEHRegistrationType();
81
82  // Per-module data.
83  Module *TheModule = nullptr;
84  StructType *EHLinkRegistrationTy = nullptr;
85  StructType *CXXEHRegistrationTy = nullptr;
86  StructType *SEHRegistrationTy = nullptr;
87  Function *FrameRecover = nullptr;
88  Function *FrameAddress = nullptr;
89  Function *FrameEscape = nullptr;
90
91  // Per-function state
92  EHPersonality Personality = EHPersonality::Unknown;
93  Function *PersonalityFn = nullptr;
94
95  /// The stack allocation containing all EH data, including the link in the
96  /// fs:00 chain and the current state.
97  AllocaInst *RegNode = nullptr;
98
99  /// Struct type of RegNode. Used for GEPing.
100  Type *RegNodeTy = nullptr;
101
102  /// The index of the state field of RegNode.
103  int StateFieldIndex = ~0U;
104
105  /// The linked list node subobject inside of RegNode.
106  Value *Link = nullptr;
107};
108}
109
110FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); }
111
112char WinEHStatePass::ID = 0;
113
114INITIALIZE_PASS(WinEHStatePass, "x86-winehstate",
115                "Insert stores for EH state numbers", false, false)
116
117bool WinEHStatePass::doInitialization(Module &M) {
118  TheModule = &M;
119  FrameEscape = Intrinsic::getDeclaration(TheModule, Intrinsic::localescape);
120  FrameRecover = Intrinsic::getDeclaration(TheModule, Intrinsic::localrecover);
121  FrameAddress = Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress);
122  return false;
123}
124
125bool WinEHStatePass::doFinalization(Module &M) {
126  assert(TheModule == &M);
127  TheModule = nullptr;
128  EHLinkRegistrationTy = nullptr;
129  CXXEHRegistrationTy = nullptr;
130  SEHRegistrationTy = nullptr;
131  FrameEscape = nullptr;
132  FrameRecover = nullptr;
133  FrameAddress = nullptr;
134  return false;
135}
136
137void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const {
138  // This pass should only insert a stack allocation, memory accesses, and
139  // localrecovers.
140  AU.setPreservesCFG();
141}
142
143bool WinEHStatePass::runOnFunction(Function &F) {
144  // Check the personality. Do nothing if this personality doesn't use funclets.
145  if (!F.hasPersonalityFn())
146    return false;
147  PersonalityFn =
148      dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
149  if (!PersonalityFn)
150    return false;
151  Personality = classifyEHPersonality(PersonalityFn);
152  if (!isFuncletEHPersonality(Personality))
153    return false;
154
155  // Skip this function if there are no EH pads and we aren't using IR-level
156  // outlining.
157  bool HasPads = false;
158  for (BasicBlock &BB : F) {
159    if (BB.isEHPad()) {
160      HasPads = true;
161      break;
162    }
163  }
164  if (!HasPads)
165    return false;
166
167  // Disable frame pointer elimination in this function.
168  // FIXME: Do the nested handlers need to keep the parent ebp in ebp, or can we
169  // use an arbitrary register?
170  F.addFnAttr("no-frame-pointer-elim", "true");
171
172  emitExceptionRegistrationRecord(&F);
173
174  // The state numbers calculated here in IR must agree with what we calculate
175  // later on for the MachineFunction. In particular, if an IR pass deletes an
176  // unreachable EH pad after this point before machine CFG construction, we
177  // will be in trouble. If this assumption is ever broken, we should turn the
178  // numbers into an immutable analysis pass.
179  WinEHFuncInfo FuncInfo;
180  addStateStores(F, FuncInfo);
181
182  // Reset per-function state.
183  PersonalityFn = nullptr;
184  Personality = EHPersonality::Unknown;
185  return true;
186}
187
188/// Get the common EH registration subobject:
189///   typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(
190///       _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);
191///   struct EHRegistrationNode {
192///     EHRegistrationNode *Next;
193///     PEXCEPTION_ROUTINE Handler;
194///   };
195Type *WinEHStatePass::getEHLinkRegistrationType() {
196  if (EHLinkRegistrationTy)
197    return EHLinkRegistrationTy;
198  LLVMContext &Context = TheModule->getContext();
199  EHLinkRegistrationTy = StructType::create(Context, "EHRegistrationNode");
200  Type *FieldTys[] = {
201      EHLinkRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next
202      Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...)
203  };
204  EHLinkRegistrationTy->setBody(FieldTys, false);
205  return EHLinkRegistrationTy;
206}
207
208/// The __CxxFrameHandler3 registration node:
209///   struct CXXExceptionRegistration {
210///     void *SavedESP;
211///     EHRegistrationNode SubRecord;
212///     int32_t TryLevel;
213///   };
214Type *WinEHStatePass::getCXXEHRegistrationType() {
215  if (CXXEHRegistrationTy)
216    return CXXEHRegistrationTy;
217  LLVMContext &Context = TheModule->getContext();
218  Type *FieldTys[] = {
219      Type::getInt8PtrTy(Context), // void *SavedESP
220      getEHLinkRegistrationType(), // EHRegistrationNode SubRecord
221      Type::getInt32Ty(Context)    // int32_t TryLevel
222  };
223  CXXEHRegistrationTy =
224      StructType::create(FieldTys, "CXXExceptionRegistration");
225  return CXXEHRegistrationTy;
226}
227
228/// The _except_handler3/4 registration node:
229///   struct EH4ExceptionRegistration {
230///     void *SavedESP;
231///     _EXCEPTION_POINTERS *ExceptionPointers;
232///     EHRegistrationNode SubRecord;
233///     int32_t EncodedScopeTable;
234///     int32_t TryLevel;
235///   };
236Type *WinEHStatePass::getSEHRegistrationType() {
237  if (SEHRegistrationTy)
238    return SEHRegistrationTy;
239  LLVMContext &Context = TheModule->getContext();
240  Type *FieldTys[] = {
241      Type::getInt8PtrTy(Context), // void *SavedESP
242      Type::getInt8PtrTy(Context), // void *ExceptionPointers
243      getEHLinkRegistrationType(), // EHRegistrationNode SubRecord
244      Type::getInt32Ty(Context),   // int32_t EncodedScopeTable
245      Type::getInt32Ty(Context)    // int32_t TryLevel
246  };
247  SEHRegistrationTy = StructType::create(FieldTys, "SEHExceptionRegistration");
248  return SEHRegistrationTy;
249}
250
251// Emit an exception registration record. These are stack allocations with the
252// common subobject of two pointers: the previous registration record (the old
253// fs:00) and the personality function for the current frame. The data before
254// and after that is personality function specific.
255void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
256  assert(Personality == EHPersonality::MSVC_CXX ||
257         Personality == EHPersonality::MSVC_X86SEH);
258
259  StringRef PersonalityName = PersonalityFn->getName();
260  IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
261  Type *Int8PtrType = Builder.getInt8PtrTy();
262  if (Personality == EHPersonality::MSVC_CXX) {
263    RegNodeTy = getCXXEHRegistrationType();
264    RegNode = Builder.CreateAlloca(RegNodeTy);
265    // SavedESP = llvm.stacksave()
266    Value *SP = Builder.CreateCall(
267        Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {});
268    Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
269    // TryLevel = -1
270    StateFieldIndex = 2;
271    insertStateNumberStore(RegNode, &*Builder.GetInsertPoint(), -1);
272    // Handler = __ehhandler$F
273    Function *Trampoline = generateLSDAInEAXThunk(F);
274    Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
275    linkExceptionRegistration(Builder, Trampoline);
276  } else if (Personality == EHPersonality::MSVC_X86SEH) {
277    // If _except_handler4 is in use, some additional guard checks and prologue
278    // stuff is required.
279    bool UseStackGuard = (PersonalityName == "_except_handler4");
280    RegNodeTy = getSEHRegistrationType();
281    RegNode = Builder.CreateAlloca(RegNodeTy);
282    // SavedESP = llvm.stacksave()
283    Value *SP = Builder.CreateCall(
284        Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {});
285    Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
286    // TryLevel = -2 / -1
287    StateFieldIndex = 4;
288    insertStateNumberStore(RegNode, &*Builder.GetInsertPoint(),
289                           UseStackGuard ? -2 : -1);
290    // ScopeTable = llvm.x86.seh.lsda(F)
291    Value *FI8 = Builder.CreateBitCast(F, Int8PtrType);
292    Value *LSDA = Builder.CreateCall(
293        Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8);
294    Type *Int32Ty = Type::getInt32Ty(TheModule->getContext());
295    LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty);
296    // If using _except_handler4, xor the address of the table with
297    // __security_cookie.
298    if (UseStackGuard) {
299      Value *Cookie =
300          TheModule->getOrInsertGlobal("__security_cookie", Int32Ty);
301      Value *Val = Builder.CreateLoad(Int32Ty, Cookie);
302      LSDA = Builder.CreateXor(LSDA, Val);
303    }
304    Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
305    Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
306    linkExceptionRegistration(Builder, PersonalityFn);
307  } else {
308    llvm_unreachable("unexpected personality function");
309  }
310
311  // Insert an unlink before all returns.
312  for (BasicBlock &BB : *F) {
313    TerminatorInst *T = BB.getTerminator();
314    if (!isa<ReturnInst>(T))
315      continue;
316    Builder.SetInsertPoint(T);
317    unlinkExceptionRegistration(Builder);
318  }
319}
320
321Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) {
322  Value *FI8 = Builder.CreateBitCast(F, Type::getInt8PtrTy(F->getContext()));
323  return Builder.CreateCall(
324      Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8);
325}
326
327/// Generate a thunk that puts the LSDA of ParentFunc in EAX and then calls
328/// PersonalityFn, forwarding the parameters passed to PEXCEPTION_ROUTINE:
329///   typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(
330///       _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);
331/// We essentially want this code:
332///   movl $lsda, %eax
333///   jmpl ___CxxFrameHandler3
334Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) {
335  LLVMContext &Context = ParentFunc->getContext();
336  Type *Int32Ty = Type::getInt32Ty(Context);
337  Type *Int8PtrType = Type::getInt8PtrTy(Context);
338  Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
339                     Int8PtrType};
340  FunctionType *TrampolineTy =
341      FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 4),
342                        /*isVarArg=*/false);
343  FunctionType *TargetFuncTy =
344      FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 5),
345                        /*isVarArg=*/false);
346  Function *Trampoline =
347      Function::Create(TrampolineTy, GlobalValue::InternalLinkage,
348                       Twine("__ehhandler$") + GlobalValue::getRealLinkageName(
349                                                   ParentFunc->getName()),
350                       TheModule);
351  BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", Trampoline);
352  IRBuilder<> Builder(EntryBB);
353  Value *LSDA = emitEHLSDA(Builder, ParentFunc);
354  Value *CastPersonality =
355      Builder.CreateBitCast(PersonalityFn, TargetFuncTy->getPointerTo());
356  auto AI = Trampoline->arg_begin();
357  Value *Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
358  CallInst *Call = Builder.CreateCall(CastPersonality, Args);
359  // Can't use musttail due to prototype mismatch, but we can use tail.
360  Call->setTailCall(true);
361  // Set inreg so we pass it in EAX.
362  Call->addAttribute(1, Attribute::InReg);
363  Builder.CreateRet(Call);
364  return Trampoline;
365}
366
367void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,
368                                               Function *Handler) {
369  // Emit the .safeseh directive for this function.
370  Handler->addFnAttr("safeseh");
371
372  Type *LinkTy = getEHLinkRegistrationType();
373  // Handler = Handler
374  Value *HandlerI8 = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy());
375  Builder.CreateStore(HandlerI8, Builder.CreateStructGEP(LinkTy, Link, 1));
376  // Next = [fs:00]
377  Constant *FSZero =
378      Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257));
379  Value *Next = Builder.CreateLoad(FSZero);
380  Builder.CreateStore(Next, Builder.CreateStructGEP(LinkTy, Link, 0));
381  // [fs:00] = Link
382  Builder.CreateStore(Link, FSZero);
383}
384
385void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) {
386  // Clone Link into the current BB for better address mode folding.
387  if (auto *GEP = dyn_cast<GetElementPtrInst>(Link)) {
388    GEP = cast<GetElementPtrInst>(GEP->clone());
389    Builder.Insert(GEP);
390    Link = GEP;
391  }
392  Type *LinkTy = getEHLinkRegistrationType();
393  // [fs:00] = Link->Next
394  Value *Next =
395      Builder.CreateLoad(Builder.CreateStructGEP(LinkTy, Link, 0));
396  Constant *FSZero =
397      Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257));
398  Builder.CreateStore(Next, FSZero);
399}
400
401void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
402  // Mark the registration node. The backend needs to know which alloca it is so
403  // that it can recover the original frame pointer.
404  IRBuilder<> Builder(RegNode->getParent(), std::next(RegNode->getIterator()));
405  Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getInt8PtrTy());
406  Builder.CreateCall(
407      Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehregnode),
408      {RegNodeI8});
409
410  // Calculate state numbers.
411  if (isAsynchronousEHPersonality(Personality))
412    calculateSEHStateNumbers(&F, FuncInfo);
413  else
414    calculateWinCXXEHStateNumbers(&F, FuncInfo);
415
416  // Iterate all the instructions and emit state number stores.
417  DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F);
418  for (BasicBlock &BB : F) {
419    // Figure out what state we should assign calls in this block.
420    int BaseState = -1;
421    auto &BBColors = BlockColors[&BB];
422
423    assert(BBColors.size() == 1 &&
424           "multi-color BB not removed by preparation");
425    BasicBlock *FuncletEntryBB = BBColors.front();
426    if (auto *FuncletPad =
427            dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI())) {
428      auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad);
429      if (BaseStateI != FuncInfo.FuncletBaseStateMap.end())
430        BaseState = BaseStateI->second;
431    }
432
433    for (Instruction &I : BB) {
434      if (auto *CI = dyn_cast<CallInst>(&I)) {
435        // Possibly throwing call instructions have no actions to take after
436        // an unwind. Ensure they are in the -1 state.
437        if (CI->doesNotThrow())
438          continue;
439        insertStateNumberStore(RegNode, CI, BaseState);
440      } else if (auto *II = dyn_cast<InvokeInst>(&I)) {
441        // Look up the state number of the landingpad this unwinds to.
442        assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!");
443        int State = FuncInfo.InvokeStateMap[II];
444        insertStateNumberStore(RegNode, II, State);
445      }
446    }
447  }
448}
449
450void WinEHStatePass::insertStateNumberStore(Value *ParentRegNode,
451                                            Instruction *IP, int State) {
452  IRBuilder<> Builder(IP);
453  Value *StateField =
454      Builder.CreateStructGEP(RegNodeTy, ParentRegNode, StateFieldIndex);
455  Builder.CreateStore(Builder.getInt32(State), StateField);
456}
457