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