[WinEH] Make sure LSDA tables are 4 byte aligned
[oota-llvm.git] / lib / CodeGen / AsmPrinter / WinException.cpp
1 //===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===//
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 // This file contains support for writing Win64 exception info into asm files.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "WinException.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/Twine.h"
18 #include "llvm/CodeGen/AsmPrinter.h"
19 #include "llvm/CodeGen/MachineFrameInfo.h"
20 #include "llvm/CodeGen/MachineFunction.h"
21 #include "llvm/CodeGen/MachineModuleInfo.h"
22 #include "llvm/CodeGen/WinEHFuncInfo.h"
23 #include "llvm/IR/DataLayout.h"
24 #include "llvm/IR/Mangler.h"
25 #include "llvm/IR/Module.h"
26 #include "llvm/MC/MCAsmInfo.h"
27 #include "llvm/MC/MCContext.h"
28 #include "llvm/MC/MCExpr.h"
29 #include "llvm/MC/MCSection.h"
30 #include "llvm/MC/MCStreamer.h"
31 #include "llvm/MC/MCSymbol.h"
32 #include "llvm/MC/MCWin64EH.h"
33 #include "llvm/Support/Dwarf.h"
34 #include "llvm/Support/ErrorHandling.h"
35 #include "llvm/Support/FormattedStream.h"
36 #include "llvm/Target/TargetFrameLowering.h"
37 #include "llvm/Target/TargetLoweringObjectFile.h"
38 #include "llvm/Target/TargetOptions.h"
39 #include "llvm/Target/TargetRegisterInfo.h"
40 using namespace llvm;
41
42 WinException::WinException(AsmPrinter *A) : EHStreamer(A) {
43   // MSVC's EH tables are always composed of 32-bit words.  All known 64-bit
44   // platforms use an imagerel32 relocation to refer to symbols.
45   useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);
46 }
47
48 WinException::~WinException() {}
49
50 /// endModule - Emit all exception information that should come after the
51 /// content.
52 void WinException::endModule() {
53   auto &OS = *Asm->OutStreamer;
54   const Module *M = MMI->getModule();
55   for (const Function &F : *M)
56     if (F.hasFnAttribute("safeseh"))
57       OS.EmitCOFFSafeSEH(Asm->getSymbol(&F));
58 }
59
60 void WinException::beginFunction(const MachineFunction *MF) {
61   shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;
62
63   // If any landing pads survive, we need an EH table.
64   bool hasLandingPads = !MMI->getLandingPads().empty();
65
66   const Function *F = MF->getFunction();
67   const Function *ParentF = MMI->getWinEHParent(F);
68
69   shouldEmitMoves = Asm->needsSEHMoves();
70
71   const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
72   unsigned PerEncoding = TLOF.getPersonalityEncoding();
73   const Function *Per = MMI->getPersonality();
74
75   shouldEmitPersonality = hasLandingPads &&
76     PerEncoding != dwarf::DW_EH_PE_omit && Per;
77
78   unsigned LSDAEncoding = TLOF.getLSDAEncoding();
79   shouldEmitLSDA = shouldEmitPersonality &&
80     LSDAEncoding != dwarf::DW_EH_PE_omit;
81
82   // If we're not using CFI, we don't want the CFI or the personality. Emit the
83   // LSDA if this is the parent function.
84   if (!Asm->MAI->usesWindowsCFI()) {
85     shouldEmitLSDA = (hasLandingPads && F == ParentF);
86     shouldEmitPersonality = false;
87     return;
88   }
89
90   // If this was an outlined handler, we need to define the label corresponding
91   // to the offset of the parent frame relative to the stack pointer after the
92   // prologue.
93   if (F != ParentF) {
94     WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
95     auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F);
96     if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) {
97       MCSymbol *HandlerTypeParentFrameOffset =
98           Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
99               GlobalValue::getRealLinkageName(F->getName()));
100
101       // Emit a symbol assignment.
102       Asm->OutStreamer->EmitAssignment(
103           HandlerTypeParentFrameOffset,
104           MCConstantExpr::create(I->second, Asm->OutContext));
105     }
106   }
107
108   if (shouldEmitMoves || shouldEmitPersonality)
109     Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym);
110
111   if (shouldEmitPersonality) {
112     const MCSymbol *PersHandlerSym =
113         TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);
114     Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true);
115   }
116 }
117
118 /// endFunction - Gather and emit post-function exception information.
119 ///
120 void WinException::endFunction(const MachineFunction *MF) {
121   if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA)
122     return;
123
124   EHPersonality Per = MMI->getPersonalityType();
125
126   // Get rid of any dead landing pads if we're not using a Windows EH scheme. In
127   // Windows EH schemes, the landing pad is not actually reachable. It only
128   // exists so that we can emit the right table data.
129   if (!isMSVCEHPersonality(Per))
130     MMI->TidyLandingPads();
131
132   if (shouldEmitPersonality || shouldEmitLSDA) {
133     Asm->OutStreamer->PushSection();
134
135     if (shouldEmitMoves || shouldEmitPersonality) {
136       // Emit an UNWIND_INFO struct describing the prologue.
137       Asm->OutStreamer->EmitWinEHHandlerData();
138     } else {
139       // Just switch sections to the right xdata section. This use of
140       // CurrentFnSym assumes that we only emit the LSDA when ending the parent
141       // function.
142       MCSection *XData = WinEH::UnwindEmitter::getXDataSection(
143           Asm->CurrentFnSym, Asm->OutContext);
144       Asm->OutStreamer->SwitchSection(XData);
145     }
146
147     // Emit the tables appropriate to the personality function in use. If we
148     // don't recognize the personality, assume it uses an Itanium-style LSDA.
149     if (Per == EHPersonality::MSVC_Win64SEH)
150       emitCSpecificHandlerTable();
151     else if (Per == EHPersonality::MSVC_X86SEH)
152       emitExceptHandlerTable(MF);
153     else if (Per == EHPersonality::MSVC_CXX)
154       emitCXXFrameHandler3Table(MF);
155     else
156       emitExceptionTable();
157
158     Asm->OutStreamer->PopSection();
159   }
160
161   if (shouldEmitMoves)
162     Asm->OutStreamer->EmitWinCFIEndProc();
163 }
164
165 const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {
166   if (!Value)
167     return MCConstantExpr::create(0, Asm->OutContext);
168   return MCSymbolRefExpr::create(Value, useImageRel32
169                                             ? MCSymbolRefExpr::VK_COFF_IMGREL32
170                                             : MCSymbolRefExpr::VK_None,
171                                  Asm->OutContext);
172 }
173
174 const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {
175   if (!GV)
176     return MCConstantExpr::create(0, Asm->OutContext);
177   return create32bitRef(Asm->getSymbol(GV));
178 }
179
180 /// Emit the language-specific data that __C_specific_handler expects.  This
181 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
182 /// up after faults with __try, __except, and __finally.  The typeinfo values
183 /// are not really RTTI data, but pointers to filter functions that return an
184 /// integer (1, 0, or -1) indicating how to handle the exception. For __finally
185 /// blocks and other cleanups, the landing pad label is zero, and the filter
186 /// function is actually a cleanup handler with the same prototype.  A catch-all
187 /// entry is modeled with a null filter function field and a non-zero landing
188 /// pad label.
189 ///
190 /// Possible filter function return values:
191 ///   EXCEPTION_EXECUTE_HANDLER (1):
192 ///     Jump to the landing pad label after cleanups.
193 ///   EXCEPTION_CONTINUE_SEARCH (0):
194 ///     Continue searching this table or continue unwinding.
195 ///   EXCEPTION_CONTINUE_EXECUTION (-1):
196 ///     Resume execution at the trapping PC.
197 ///
198 /// Inferred table structure:
199 ///   struct Table {
200 ///     int NumEntries;
201 ///     struct Entry {
202 ///       imagerel32 LabelStart;
203 ///       imagerel32 LabelEnd;
204 ///       imagerel32 FilterOrFinally;  // One means catch-all.
205 ///       imagerel32 LabelLPad;        // Zero means __finally.
206 ///     } Entries[NumEntries];
207 ///   };
208 void WinException::emitCSpecificHandlerTable() {
209   const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
210
211   // Simplifying assumptions for first implementation:
212   // - Cleanups are not implemented.
213   // - Filters are not implemented.
214
215   // The Itanium LSDA table sorts similar landing pads together to simplify the
216   // actions table, but we don't need that.
217   SmallVector<const LandingPadInfo *, 64> LandingPads;
218   LandingPads.reserve(PadInfos.size());
219   for (const auto &LP : PadInfos)
220     LandingPads.push_back(&LP);
221
222   // Compute label ranges for call sites as we would for the Itanium LSDA, but
223   // use an all zero action table because we aren't using these actions.
224   SmallVector<unsigned, 64> FirstActions;
225   FirstActions.resize(LandingPads.size());
226   SmallVector<CallSiteEntry, 64> CallSites;
227   computeCallSiteTable(CallSites, LandingPads, FirstActions);
228
229   MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin();
230   MCSymbol *EHFuncEndSym = Asm->getFunctionEnd();
231
232   // Emit the number of table entries.
233   unsigned NumEntries = 0;
234   for (const CallSiteEntry &CSE : CallSites) {
235     if (!CSE.LPad)
236       continue; // Ignore gaps.
237     NumEntries += CSE.LPad->SEHHandlers.size();
238   }
239   Asm->OutStreamer->EmitIntValue(NumEntries, 4);
240
241   // If there are no actions, we don't need to iterate again.
242   if (NumEntries == 0)
243     return;
244
245   // Emit the four-label records for each call site entry. The table has to be
246   // sorted in layout order, and the call sites should already be sorted.
247   for (const CallSiteEntry &CSE : CallSites) {
248     // Ignore gaps. Unlike the Itanium model, unwinding through a frame without
249     // an EH table entry will propagate the exception rather than terminating
250     // the program.
251     if (!CSE.LPad)
252       continue;
253     const LandingPadInfo *LPad = CSE.LPad;
254
255     // Compute the label range. We may reuse the function begin and end labels
256     // rather than forming new ones.
257     const MCExpr *Begin =
258         create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym);
259     const MCExpr *End;
260     if (CSE.EndLabel) {
261       // The interval is half-open, so we have to add one to include the return
262       // address of the last invoke in the range.
263       End = MCBinaryExpr::createAdd(create32bitRef(CSE.EndLabel),
264                                     MCConstantExpr::create(1, Asm->OutContext),
265                                     Asm->OutContext);
266     } else {
267       End = create32bitRef(EHFuncEndSym);
268     }
269
270     // Emit an entry for each action.
271     for (SEHHandler Handler : LPad->SEHHandlers) {
272       Asm->OutStreamer->EmitValue(Begin, 4);
273       Asm->OutStreamer->EmitValue(End, 4);
274
275       // Emit the filter or finally function pointer, if present. Otherwise,
276       // emit '1' to indicate a catch-all.
277       const Function *F = Handler.FilterOrFinally;
278       if (F)
279         Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4);
280       else
281         Asm->OutStreamer->EmitIntValue(1, 4);
282
283       // Emit the recovery address, if present. Otherwise, this must be a
284       // finally.
285       const BlockAddress *BA = Handler.RecoverBA;
286       if (BA)
287         Asm->OutStreamer->EmitValue(
288             create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4);
289       else
290         Asm->OutStreamer->EmitIntValue(0, 4);
291     }
292   }
293 }
294
295 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
296   const Function *F = MF->getFunction();
297   const Function *ParentF = MMI->getWinEHParent(F);
298   auto &OS = *Asm->OutStreamer;
299   WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
300
301   StringRef ParentLinkageName =
302       GlobalValue::getRealLinkageName(ParentF->getName());
303
304   MCSymbol *FuncInfoXData = nullptr;
305   if (shouldEmitPersonality) {
306     FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
307         Twine("$cppxdata$", ParentLinkageName));
308     OS.EmitValue(create32bitRef(FuncInfoXData), 4);
309
310     extendIP2StateTable(MF, ParentF, FuncInfo);
311
312     // Defer emission until we've visited the parent function and all the catch
313     // handlers.  Cleanups don't contribute to the ip2state table, so don't count
314     // them.
315     if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F))
316       return;
317     ++FuncInfo.NumIPToStateFuncsVisited;
318     if (FuncInfo.NumIPToStateFuncsVisited != FuncInfo.CatchHandlerMaxState.size())
319       return;
320   } else {
321     FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(ParentLinkageName);
322     emitEHRegistrationOffsetLabel(FuncInfo, ParentLinkageName);
323   }
324
325   MCSymbol *UnwindMapXData = nullptr;
326   MCSymbol *TryBlockMapXData = nullptr;
327   MCSymbol *IPToStateXData = nullptr;
328   if (!FuncInfo.UnwindMap.empty())
329     UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
330         Twine("$stateUnwindMap$", ParentLinkageName));
331   if (!FuncInfo.TryBlockMap.empty())
332     TryBlockMapXData = Asm->OutContext.getOrCreateSymbol(
333         Twine("$tryMap$", ParentLinkageName));
334   if (!FuncInfo.IPToStateList.empty())
335     IPToStateXData = Asm->OutContext.getOrCreateSymbol(
336         Twine("$ip2state$", ParentLinkageName));
337
338   // FuncInfo {
339   //   uint32_t           MagicNumber
340   //   int32_t            MaxState;
341   //   UnwindMapEntry    *UnwindMap;
342   //   uint32_t           NumTryBlocks;
343   //   TryBlockMapEntry  *TryBlockMap;
344   //   uint32_t           IPMapEntries; // always 0 for x86
345   //   IPToStateMapEntry *IPToStateMap; // always 0 for x86
346   //   uint32_t           UnwindHelp;   // non-x86 only
347   //   ESTypeList        *ESTypeList;
348   //   int32_t            EHFlags;
349   // }
350   // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
351   // EHFlags & 2 -> ???
352   // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
353   OS.EmitValueToAlignment(4);
354   OS.EmitLabel(FuncInfoXData);
355   OS.EmitIntValue(0x19930522, 4);                      // MagicNumber
356   OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4);       // MaxState
357   OS.EmitValue(create32bitRef(UnwindMapXData), 4);     // UnwindMap
358   OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4);     // NumTryBlocks
359   OS.EmitValue(create32bitRef(TryBlockMapXData), 4);   // TryBlockMap
360   OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4);   // IPMapEntries
361   OS.EmitValue(create32bitRef(IPToStateXData), 4);     // IPToStateMap
362   if (Asm->MAI->usesWindowsCFI())
363     OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp
364   OS.EmitIntValue(0, 4);                               // ESTypeList
365   OS.EmitIntValue(1, 4);                               // EHFlags
366
367   // UnwindMapEntry {
368   //   int32_t ToState;
369   //   void  (*Action)();
370   // };
371   if (UnwindMapXData) {
372     OS.EmitLabel(UnwindMapXData);
373     for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
374       OS.EmitIntValue(UME.ToState, 4);                // ToState
375       OS.EmitValue(create32bitRef(UME.Cleanup), 4);   // Action
376     }
377   }
378
379   // TryBlockMap {
380   //   int32_t      TryLow;
381   //   int32_t      TryHigh;
382   //   int32_t      CatchHigh;
383   //   int32_t      NumCatches;
384   //   HandlerType *HandlerArray;
385   // };
386   if (TryBlockMapXData) {
387     OS.EmitLabel(TryBlockMapXData);
388     SmallVector<MCSymbol *, 1> HandlerMaps;
389     for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
390       WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
391       MCSymbol *HandlerMapXData = nullptr;
392
393       if (!TBME.HandlerArray.empty())
394         HandlerMapXData =
395             Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
396                                                   .concat(Twine(I))
397                                                   .concat("$")
398                                                   .concat(ParentLinkageName));
399
400       HandlerMaps.push_back(HandlerMapXData);
401
402       int CatchHigh = -1;
403       for (WinEHHandlerType &HT : TBME.HandlerArray)
404         CatchHigh =
405             std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]);
406
407       assert(TBME.TryLow <= TBME.TryHigh);
408       OS.EmitIntValue(TBME.TryLow, 4);                    // TryLow
409       OS.EmitIntValue(TBME.TryHigh, 4);                   // TryHigh
410       OS.EmitIntValue(CatchHigh, 4);                      // CatchHigh
411       OS.EmitIntValue(TBME.HandlerArray.size(), 4);       // NumCatches
412       OS.EmitValue(create32bitRef(HandlerMapXData), 4);   // HandlerArray
413     }
414
415     for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
416       WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
417       MCSymbol *HandlerMapXData = HandlerMaps[I];
418       if (!HandlerMapXData)
419         continue;
420       // HandlerType {
421       //   int32_t         Adjectives;
422       //   TypeDescriptor *Type;
423       //   int32_t         CatchObjOffset;
424       //   void          (*Handler)();
425       //   int32_t         ParentFrameOffset; // x64 only
426       // };
427       OS.EmitLabel(HandlerMapXData);
428       for (const WinEHHandlerType &HT : TBME.HandlerArray) {
429         // Get the frame escape label with the offset of the catch object. If
430         // the index is -1, then there is no catch object, and we should emit an
431         // offset of zero, indicating that no copy will occur.
432         const MCExpr *FrameAllocOffsetRef = nullptr;
433         if (HT.CatchObjRecoverIdx >= 0) {
434           MCSymbol *FrameAllocOffset =
435               Asm->OutContext.getOrCreateFrameAllocSymbol(
436                   GlobalValue::getRealLinkageName(ParentF->getName()),
437                   HT.CatchObjRecoverIdx);
438           FrameAllocOffsetRef = MCSymbolRefExpr::create(
439               FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
440         } else {
441           FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
442         }
443
444         OS.EmitIntValue(HT.Adjectives, 4);                    // Adjectives
445         OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4);   // Type
446         OS.EmitValue(FrameAllocOffsetRef, 4);                 // CatchObjOffset
447         OS.EmitValue(create32bitRef(HT.Handler), 4);          // Handler
448
449         if (shouldEmitPersonality) {
450           MCSymbol *ParentFrameOffset =
451               Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
452                   GlobalValue::getRealLinkageName(HT.Handler->getName()));
453           const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::create(
454               ParentFrameOffset, Asm->OutContext);
455           OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
456         }
457       }
458     }
459   }
460
461   // IPToStateMapEntry {
462   //   void   *IP;
463   //   int32_t State;
464   // };
465   if (IPToStateXData) {
466     OS.EmitLabel(IPToStateXData);
467     for (auto &IPStatePair : FuncInfo.IPToStateList) {
468       OS.EmitValue(create32bitRef(IPStatePair.first), 4);   // IP
469       OS.EmitIntValue(IPStatePair.second, 4);               // State
470     }
471   }
472 }
473
474 void WinException::extendIP2StateTable(const MachineFunction *MF,
475                                        const Function *ParentF,
476                                        WinEHFuncInfo &FuncInfo) {
477   const Function *F = MF->getFunction();
478
479   // The Itanium LSDA table sorts similar landing pads together to simplify the
480   // actions table, but we don't need that.
481   SmallVector<const LandingPadInfo *, 64> LandingPads;
482   const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
483   LandingPads.reserve(PadInfos.size());
484   for (const auto &LP : PadInfos)
485     LandingPads.push_back(&LP);
486
487   RangeMapType PadMap;
488   computePadMap(LandingPads, PadMap);
489
490   // The end label of the previous invoke or nounwind try-range.
491   MCSymbol *LastLabel = Asm->getFunctionBegin();
492
493   // Whether there is a potentially throwing instruction (currently this means
494   // an ordinary call) between the end of the previous try-range and now.
495   bool SawPotentiallyThrowing = false;
496
497   int LastEHState = -2;
498
499   // The parent function and the catch handlers contribute to the 'ip2state'
500   // table.
501
502   // Include ip2state entries for the beginning of the main function and
503   // for catch handler functions.
504   if (F == ParentF) {
505     FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
506     LastEHState = -1;
507   } else if (FuncInfo.HandlerBaseState.count(F)) {
508     FuncInfo.IPToStateList.push_back(
509         std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F]));
510     LastEHState = FuncInfo.HandlerBaseState[F];
511   }
512   for (const auto &MBB : *MF) {
513     for (const auto &MI : MBB) {
514       if (!MI.isEHLabel()) {
515         if (MI.isCall())
516           SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
517         continue;
518       }
519
520       // End of the previous try-range?
521       MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
522       if (BeginLabel == LastLabel)
523         SawPotentiallyThrowing = false;
524
525       // Beginning of a new try-range?
526       RangeMapType::const_iterator L = PadMap.find(BeginLabel);
527       if (L == PadMap.end())
528         // Nope, it was just some random label.
529         continue;
530
531       const PadRange &P = L->second;
532       const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
533       assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
534              "Inconsistent landing pad map!");
535
536       // FIXME: Should this be using FuncInfo.HandlerBaseState?
537       if (SawPotentiallyThrowing && LastEHState != -1) {
538         FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
539         SawPotentiallyThrowing = false;
540         LastEHState = -1;
541       }
542
543       if (LandingPad->WinEHState != LastEHState)
544         FuncInfo.IPToStateList.push_back(
545             std::make_pair(BeginLabel, LandingPad->WinEHState));
546       LastEHState = LandingPad->WinEHState;
547       LastLabel = LandingPad->EndLabels[P.RangeIndex];
548     }
549   }
550 }
551
552 void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
553                                                  StringRef FLinkageName) {
554   // Outlined helpers called by the EH runtime need to know the offset of the EH
555   // registration in order to recover the parent frame pointer. Now that we know
556   // we've code generated the parent, we can emit the label assignment that
557   // those helpers use to get the offset of the registration node.
558   assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX &&
559          "no EH reg node localescape index");
560   MCSymbol *ParentFrameOffset =
561       Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName);
562   MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol(
563       FLinkageName, FuncInfo.EHRegNodeEscapeIndex);
564   const MCExpr *RegistrationOffsetSymRef =
565       MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext);
566   Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef);
567 }
568
569 /// Emit the language-specific data that _except_handler3 and 4 expect. This is
570 /// functionally equivalent to the __C_specific_handler table, except it is
571 /// indexed by state number instead of IP.
572 void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
573   MCStreamer &OS = *Asm->OutStreamer;
574   const Function *F = MF->getFunction();
575   StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
576
577   WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F);
578   emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
579
580   // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
581   MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
582   OS.EmitValueToAlignment(4);
583   OS.EmitLabel(LSDALabel);
584
585   const Function *Per = MMI->getPersonality();
586   StringRef PerName = Per->getName();
587   int BaseState = -1;
588   if (PerName == "_except_handler4") {
589     // The LSDA for _except_handler4 starts with this struct, followed by the
590     // scope table:
591     //
592     // struct EH4ScopeTable {
593     //   int32_t GSCookieOffset;
594     //   int32_t GSCookieXOROffset;
595     //   int32_t EHCookieOffset;
596     //   int32_t EHCookieXOROffset;
597     //   ScopeTableEntry ScopeRecord[];
598     // };
599     //
600     // Only the EHCookieOffset field appears to vary, and it appears to be the
601     // offset from the final saved SP value to the retaddr.
602     OS.EmitIntValue(-2, 4);
603     OS.EmitIntValue(0, 4);
604     // FIXME: Calculate.
605     OS.EmitIntValue(9999, 4);
606     OS.EmitIntValue(0, 4);
607     BaseState = -2;
608   }
609
610   // Build a list of pointers to LandingPadInfos and then sort by WinEHState.
611   const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
612   SmallVector<const LandingPadInfo *, 4> LPads;
613   LPads.reserve((PadInfos.size()));
614   for (const LandingPadInfo &LPInfo : PadInfos)
615     LPads.push_back(&LPInfo);
616   std::sort(LPads.begin(), LPads.end(),
617             [](const LandingPadInfo *L, const LandingPadInfo *R) {
618               return L->WinEHState < R->WinEHState;
619             });
620
621   // For each action in each lpad, emit one of these:
622   // struct ScopeTableEntry {
623   //   int32_t EnclosingLevel;
624   //   int32_t (__cdecl *Filter)();
625   //   void *HandlerOrFinally;
626   // };
627   //
628   // The "outermost" action will use BaseState as its enclosing level. Each
629   // other action will refer to the previous state as its enclosing level.
630   int CurState = 0;
631   for (const LandingPadInfo *LPInfo : LPads) {
632     int EnclosingLevel = BaseState;
633     assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 ==
634                LPInfo->WinEHState &&
635            "gaps in the SEH scope table");
636     for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend();
637          I != E; ++I) {
638       const SEHHandler &Handler = *I;
639       const BlockAddress *BA = Handler.RecoverBA;
640       const Function *F = Handler.FilterOrFinally;
641       assert(F && "cannot catch all in 32-bit SEH without filter function");
642       const MCExpr *FilterOrNull =
643           create32bitRef(BA ? Asm->getSymbol(F) : nullptr);
644       const MCExpr *ExceptOrFinally = create32bitRef(
645           BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F));
646
647       OS.EmitIntValue(EnclosingLevel, 4);
648       OS.EmitValue(FilterOrNull, 4);
649       OS.EmitValue(ExceptOrFinally, 4);
650
651       // The next state unwinds to this state.
652       EnclosingLevel = CurState;
653       CurState++;
654     }
655   }
656 }