WinException.cpp revision 284734
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"
40using namespace llvm;
41
42WinException::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
48WinException::~WinException() {}
49
50/// endModule - Emit all exception information that should come after the
51/// content.
52void 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
60void 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///
120void 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
165const 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
174const 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///   };
208void 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
295void 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  }
323
324  MCSymbol *UnwindMapXData = nullptr;
325  MCSymbol *TryBlockMapXData = nullptr;
326  MCSymbol *IPToStateXData = nullptr;
327  if (!FuncInfo.UnwindMap.empty())
328    UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
329        Twine("$stateUnwindMap$", ParentLinkageName));
330  if (!FuncInfo.TryBlockMap.empty())
331    TryBlockMapXData = Asm->OutContext.getOrCreateSymbol(
332        Twine("$tryMap$", ParentLinkageName));
333  if (!FuncInfo.IPToStateList.empty())
334    IPToStateXData = Asm->OutContext.getOrCreateSymbol(
335        Twine("$ip2state$", ParentLinkageName));
336
337  // FuncInfo {
338  //   uint32_t           MagicNumber
339  //   int32_t            MaxState;
340  //   UnwindMapEntry    *UnwindMap;
341  //   uint32_t           NumTryBlocks;
342  //   TryBlockMapEntry  *TryBlockMap;
343  //   uint32_t           IPMapEntries; // always 0 for x86
344  //   IPToStateMapEntry *IPToStateMap; // always 0 for x86
345  //   uint32_t           UnwindHelp;   // non-x86 only
346  //   ESTypeList        *ESTypeList;
347  //   int32_t            EHFlags;
348  // }
349  // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
350  // EHFlags & 2 -> ???
351  // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
352  OS.EmitLabel(FuncInfoXData);
353  OS.EmitIntValue(0x19930522, 4);                      // MagicNumber
354  OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4);       // MaxState
355  OS.EmitValue(create32bitRef(UnwindMapXData), 4);     // UnwindMap
356  OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4);     // NumTryBlocks
357  OS.EmitValue(create32bitRef(TryBlockMapXData), 4);   // TryBlockMap
358  OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4);   // IPMapEntries
359  OS.EmitValue(create32bitRef(IPToStateXData), 4);     // IPToStateMap
360  if (Asm->MAI->usesWindowsCFI())
361    OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp
362  OS.EmitIntValue(0, 4);                               // ESTypeList
363  OS.EmitIntValue(1, 4);                               // EHFlags
364
365  // UnwindMapEntry {
366  //   int32_t ToState;
367  //   void  (*Action)();
368  // };
369  if (UnwindMapXData) {
370    OS.EmitLabel(UnwindMapXData);
371    for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
372      OS.EmitIntValue(UME.ToState, 4);                // ToState
373      OS.EmitValue(create32bitRef(UME.Cleanup), 4);   // Action
374    }
375  }
376
377  // TryBlockMap {
378  //   int32_t      TryLow;
379  //   int32_t      TryHigh;
380  //   int32_t      CatchHigh;
381  //   int32_t      NumCatches;
382  //   HandlerType *HandlerArray;
383  // };
384  if (TryBlockMapXData) {
385    OS.EmitLabel(TryBlockMapXData);
386    SmallVector<MCSymbol *, 1> HandlerMaps;
387    for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
388      WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
389      MCSymbol *HandlerMapXData = nullptr;
390
391      if (!TBME.HandlerArray.empty())
392        HandlerMapXData =
393            Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
394                                                  .concat(Twine(I))
395                                                  .concat("$")
396                                                  .concat(ParentLinkageName));
397
398      HandlerMaps.push_back(HandlerMapXData);
399
400      int CatchHigh = -1;
401      for (WinEHHandlerType &HT : TBME.HandlerArray)
402        CatchHigh =
403            std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]);
404
405      assert(TBME.TryLow <= TBME.TryHigh);
406      OS.EmitIntValue(TBME.TryLow, 4);                    // TryLow
407      OS.EmitIntValue(TBME.TryHigh, 4);                   // TryHigh
408      OS.EmitIntValue(CatchHigh, 4);                      // CatchHigh
409      OS.EmitIntValue(TBME.HandlerArray.size(), 4);       // NumCatches
410      OS.EmitValue(create32bitRef(HandlerMapXData), 4);   // HandlerArray
411    }
412
413    for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
414      WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
415      MCSymbol *HandlerMapXData = HandlerMaps[I];
416      if (!HandlerMapXData)
417        continue;
418      // HandlerType {
419      //   int32_t         Adjectives;
420      //   TypeDescriptor *Type;
421      //   int32_t         CatchObjOffset;
422      //   void          (*Handler)();
423      //   int32_t         ParentFrameOffset; // x64 only
424      // };
425      OS.EmitLabel(HandlerMapXData);
426      for (const WinEHHandlerType &HT : TBME.HandlerArray) {
427        // Get the frame escape label with the offset of the catch object. If
428        // the index is -1, then there is no catch object, and we should emit an
429        // offset of zero, indicating that no copy will occur.
430        const MCExpr *FrameAllocOffsetRef = nullptr;
431        if (HT.CatchObjRecoverIdx >= 0) {
432          MCSymbol *FrameAllocOffset =
433              Asm->OutContext.getOrCreateFrameAllocSymbol(
434                  GlobalValue::getRealLinkageName(ParentF->getName()),
435                  HT.CatchObjRecoverIdx);
436          FrameAllocOffsetRef = MCSymbolRefExpr::create(
437              FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
438        } else {
439          FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
440        }
441
442        OS.EmitIntValue(HT.Adjectives, 4);                    // Adjectives
443        OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4);   // Type
444        OS.EmitValue(FrameAllocOffsetRef, 4);                 // CatchObjOffset
445        OS.EmitValue(create32bitRef(HT.Handler), 4);          // Handler
446
447        if (shouldEmitPersonality) {
448          MCSymbol *ParentFrameOffset =
449              Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
450                  GlobalValue::getRealLinkageName(HT.Handler->getName()));
451          const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::create(
452              ParentFrameOffset, Asm->OutContext);
453          OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
454        }
455      }
456    }
457  }
458
459  // IPToStateMapEntry {
460  //   void   *IP;
461  //   int32_t State;
462  // };
463  if (IPToStateXData) {
464    OS.EmitLabel(IPToStateXData);
465    for (auto &IPStatePair : FuncInfo.IPToStateList) {
466      OS.EmitValue(create32bitRef(IPStatePair.first), 4);   // IP
467      OS.EmitIntValue(IPStatePair.second, 4);               // State
468    }
469  }
470}
471
472void WinException::extendIP2StateTable(const MachineFunction *MF,
473                                       const Function *ParentF,
474                                       WinEHFuncInfo &FuncInfo) {
475  const Function *F = MF->getFunction();
476
477  // The Itanium LSDA table sorts similar landing pads together to simplify the
478  // actions table, but we don't need that.
479  SmallVector<const LandingPadInfo *, 64> LandingPads;
480  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
481  LandingPads.reserve(PadInfos.size());
482  for (const auto &LP : PadInfos)
483    LandingPads.push_back(&LP);
484
485  RangeMapType PadMap;
486  computePadMap(LandingPads, PadMap);
487
488  // The end label of the previous invoke or nounwind try-range.
489  MCSymbol *LastLabel = Asm->getFunctionBegin();
490
491  // Whether there is a potentially throwing instruction (currently this means
492  // an ordinary call) between the end of the previous try-range and now.
493  bool SawPotentiallyThrowing = false;
494
495  int LastEHState = -2;
496
497  // The parent function and the catch handlers contribute to the 'ip2state'
498  // table.
499
500  // Include ip2state entries for the beginning of the main function and
501  // for catch handler functions.
502  if (F == ParentF) {
503    FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
504    LastEHState = -1;
505  } else if (FuncInfo.HandlerBaseState.count(F)) {
506    FuncInfo.IPToStateList.push_back(
507        std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F]));
508    LastEHState = FuncInfo.HandlerBaseState[F];
509  }
510  for (const auto &MBB : *MF) {
511    for (const auto &MI : MBB) {
512      if (!MI.isEHLabel()) {
513        if (MI.isCall())
514          SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
515        continue;
516      }
517
518      // End of the previous try-range?
519      MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
520      if (BeginLabel == LastLabel)
521        SawPotentiallyThrowing = false;
522
523      // Beginning of a new try-range?
524      RangeMapType::const_iterator L = PadMap.find(BeginLabel);
525      if (L == PadMap.end())
526        // Nope, it was just some random label.
527        continue;
528
529      const PadRange &P = L->second;
530      const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
531      assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
532             "Inconsistent landing pad map!");
533
534      // FIXME: Should this be using FuncInfo.HandlerBaseState?
535      if (SawPotentiallyThrowing && LastEHState != -1) {
536        FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
537        SawPotentiallyThrowing = false;
538        LastEHState = -1;
539      }
540
541      if (LandingPad->WinEHState != LastEHState)
542        FuncInfo.IPToStateList.push_back(
543            std::make_pair(BeginLabel, LandingPad->WinEHState));
544      LastEHState = LandingPad->WinEHState;
545      LastLabel = LandingPad->EndLabels[P.RangeIndex];
546    }
547  }
548}
549
550/// Emit the language-specific data that _except_handler3 and 4 expect. This is
551/// functionally equivalent to the __C_specific_handler table, except it is
552/// indexed by state number instead of IP.
553void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
554  MCStreamer &OS = *Asm->OutStreamer;
555
556  // Define the EH registration node offset label in terms of its frameescape
557  // label. The WinEHStatePass ensures that the registration node is passed to
558  // frameescape. This allows SEH filter functions to access the
559  // EXCEPTION_POINTERS field, which is filled in by the _except_handlerN.
560  const Function *F = MF->getFunction();
561  WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F);
562  assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX &&
563         "no EH reg node frameescape index");
564  StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
565  MCSymbol *ParentFrameOffset =
566      Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName);
567  MCSymbol *FrameAllocSym = Asm->OutContext.getOrCreateFrameAllocSymbol(
568      FLinkageName, FuncInfo.EHRegNodeEscapeIndex);
569  const MCSymbolRefExpr *FrameAllocSymRef =
570      MCSymbolRefExpr::create(FrameAllocSym, Asm->OutContext);
571  OS.EmitAssignment(ParentFrameOffset, FrameAllocSymRef);
572
573  // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
574  MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
575  OS.EmitLabel(LSDALabel);
576
577  const Function *Per = MMI->getPersonality();
578  StringRef PerName = Per->getName();
579  int BaseState = -1;
580  if (PerName == "_except_handler4") {
581    // The LSDA for _except_handler4 starts with this struct, followed by the
582    // scope table:
583    //
584    // struct EH4ScopeTable {
585    //   int32_t GSCookieOffset;
586    //   int32_t GSCookieXOROffset;
587    //   int32_t EHCookieOffset;
588    //   int32_t EHCookieXOROffset;
589    //   ScopeTableEntry ScopeRecord[];
590    // };
591    //
592    // Only the EHCookieOffset field appears to vary, and it appears to be the
593    // offset from the final saved SP value to the retaddr.
594    OS.EmitIntValue(-2, 4);
595    OS.EmitIntValue(0, 4);
596    // FIXME: Calculate.
597    OS.EmitIntValue(9999, 4);
598    OS.EmitIntValue(0, 4);
599    BaseState = -2;
600  }
601
602  // Build a list of pointers to LandingPadInfos and then sort by WinEHState.
603  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
604  SmallVector<const LandingPadInfo *, 4> LPads;
605  LPads.reserve((PadInfos.size()));
606  for (const LandingPadInfo &LPInfo : PadInfos)
607    LPads.push_back(&LPInfo);
608  std::sort(LPads.begin(), LPads.end(),
609            [](const LandingPadInfo *L, const LandingPadInfo *R) {
610              return L->WinEHState < R->WinEHState;
611            });
612
613  // For each action in each lpad, emit one of these:
614  // struct ScopeTableEntry {
615  //   int32_t EnclosingLevel;
616  //   int32_t (__cdecl *Filter)();
617  //   void *HandlerOrFinally;
618  // };
619  //
620  // The "outermost" action will use BaseState as its enclosing level. Each
621  // other action will refer to the previous state as its enclosing level.
622  int CurState = 0;
623  for (const LandingPadInfo *LPInfo : LPads) {
624    int EnclosingLevel = BaseState;
625    assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 ==
626               LPInfo->WinEHState &&
627           "gaps in the SEH scope table");
628    for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend();
629         I != E; ++I) {
630      const SEHHandler &Handler = *I;
631      const BlockAddress *BA = Handler.RecoverBA;
632      const Function *F = Handler.FilterOrFinally;
633      assert(F && "cannot catch all in 32-bit SEH without filter function");
634      const MCExpr *FilterOrNull =
635          create32bitRef(BA ? Asm->getSymbol(F) : nullptr);
636      const MCExpr *ExceptOrFinally = create32bitRef(
637          BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F));
638
639      OS.EmitIntValue(EnclosingLevel, 4);
640      OS.EmitValue(FilterOrNull, 4);
641      OS.EmitValue(ExceptOrFinally, 4);
642
643      // The next state unwinds to this state.
644      EnclosingLevel = CurState;
645      CurState++;
646    }
647  }
648}
649