WinException.cpp revision 285181
1284184Sdim//===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===//
2284184Sdim//
3284184Sdim//                     The LLVM Compiler Infrastructure
4284184Sdim//
5284184Sdim// This file is distributed under the University of Illinois Open Source
6284184Sdim// License. See LICENSE.TXT for details.
7284184Sdim//
8284184Sdim//===----------------------------------------------------------------------===//
9284184Sdim//
10284184Sdim// This file contains support for writing Win64 exception info into asm files.
11284184Sdim//
12284184Sdim//===----------------------------------------------------------------------===//
13284184Sdim
14284184Sdim#include "WinException.h"
15284184Sdim#include "llvm/ADT/SmallString.h"
16284184Sdim#include "llvm/ADT/StringExtras.h"
17284184Sdim#include "llvm/ADT/Twine.h"
18284184Sdim#include "llvm/CodeGen/AsmPrinter.h"
19284184Sdim#include "llvm/CodeGen/MachineFrameInfo.h"
20284184Sdim#include "llvm/CodeGen/MachineFunction.h"
21284184Sdim#include "llvm/CodeGen/MachineModuleInfo.h"
22284184Sdim#include "llvm/CodeGen/WinEHFuncInfo.h"
23284184Sdim#include "llvm/IR/DataLayout.h"
24284184Sdim#include "llvm/IR/Mangler.h"
25284184Sdim#include "llvm/IR/Module.h"
26284184Sdim#include "llvm/MC/MCAsmInfo.h"
27284184Sdim#include "llvm/MC/MCContext.h"
28284184Sdim#include "llvm/MC/MCExpr.h"
29284184Sdim#include "llvm/MC/MCSection.h"
30284184Sdim#include "llvm/MC/MCStreamer.h"
31284184Sdim#include "llvm/MC/MCSymbol.h"
32284184Sdim#include "llvm/MC/MCWin64EH.h"
33284184Sdim#include "llvm/Support/Dwarf.h"
34284184Sdim#include "llvm/Support/ErrorHandling.h"
35284184Sdim#include "llvm/Support/FormattedStream.h"
36284184Sdim#include "llvm/Target/TargetFrameLowering.h"
37284184Sdim#include "llvm/Target/TargetLoweringObjectFile.h"
38284184Sdim#include "llvm/Target/TargetOptions.h"
39284184Sdim#include "llvm/Target/TargetRegisterInfo.h"
40284184Sdimusing namespace llvm;
41284184Sdim
42284184SdimWinException::WinException(AsmPrinter *A) : EHStreamer(A) {
43284184Sdim  // MSVC's EH tables are always composed of 32-bit words.  All known 64-bit
44284184Sdim  // platforms use an imagerel32 relocation to refer to symbols.
45284184Sdim  useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);
46284184Sdim}
47284184Sdim
48284184SdimWinException::~WinException() {}
49284184Sdim
50284184Sdim/// endModule - Emit all exception information that should come after the
51284184Sdim/// content.
52284184Sdimvoid WinException::endModule() {
53284734Sdim  auto &OS = *Asm->OutStreamer;
54284734Sdim  const Module *M = MMI->getModule();
55284734Sdim  for (const Function &F : *M)
56284734Sdim    if (F.hasFnAttribute("safeseh"))
57284734Sdim      OS.EmitCOFFSafeSEH(Asm->getSymbol(&F));
58284184Sdim}
59284184Sdim
60284184Sdimvoid WinException::beginFunction(const MachineFunction *MF) {
61284184Sdim  shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;
62284184Sdim
63284184Sdim  // If any landing pads survive, we need an EH table.
64284184Sdim  bool hasLandingPads = !MMI->getLandingPads().empty();
65284184Sdim
66284184Sdim  const Function *F = MF->getFunction();
67284184Sdim  const Function *ParentF = MMI->getWinEHParent(F);
68284184Sdim
69284184Sdim  shouldEmitMoves = Asm->needsSEHMoves();
70284184Sdim
71284184Sdim  const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
72284184Sdim  unsigned PerEncoding = TLOF.getPersonalityEncoding();
73284184Sdim  const Function *Per = MMI->getPersonality();
74284184Sdim
75284184Sdim  shouldEmitPersonality = hasLandingPads &&
76284184Sdim    PerEncoding != dwarf::DW_EH_PE_omit && Per;
77284184Sdim
78284184Sdim  unsigned LSDAEncoding = TLOF.getLSDAEncoding();
79284184Sdim  shouldEmitLSDA = shouldEmitPersonality &&
80284184Sdim    LSDAEncoding != dwarf::DW_EH_PE_omit;
81284184Sdim
82284184Sdim  // If we're not using CFI, we don't want the CFI or the personality. Emit the
83284184Sdim  // LSDA if this is the parent function.
84284184Sdim  if (!Asm->MAI->usesWindowsCFI()) {
85284184Sdim    shouldEmitLSDA = (hasLandingPads && F == ParentF);
86284184Sdim    shouldEmitPersonality = false;
87284184Sdim    return;
88284184Sdim  }
89284184Sdim
90284184Sdim  // If this was an outlined handler, we need to define the label corresponding
91284184Sdim  // to the offset of the parent frame relative to the stack pointer after the
92284184Sdim  // prologue.
93284184Sdim  if (F != ParentF) {
94284184Sdim    WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
95284184Sdim    auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F);
96284184Sdim    if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) {
97284184Sdim      MCSymbol *HandlerTypeParentFrameOffset =
98284184Sdim          Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
99284184Sdim              GlobalValue::getRealLinkageName(F->getName()));
100284184Sdim
101284184Sdim      // Emit a symbol assignment.
102284184Sdim      Asm->OutStreamer->EmitAssignment(
103284184Sdim          HandlerTypeParentFrameOffset,
104284184Sdim          MCConstantExpr::create(I->second, Asm->OutContext));
105284184Sdim    }
106284184Sdim  }
107284184Sdim
108284184Sdim  if (shouldEmitMoves || shouldEmitPersonality)
109284184Sdim    Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym);
110284184Sdim
111284184Sdim  if (shouldEmitPersonality) {
112284184Sdim    const MCSymbol *PersHandlerSym =
113284184Sdim        TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);
114284184Sdim    Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true);
115284184Sdim  }
116284184Sdim}
117284184Sdim
118284184Sdim/// endFunction - Gather and emit post-function exception information.
119284184Sdim///
120284184Sdimvoid WinException::endFunction(const MachineFunction *MF) {
121284184Sdim  if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA)
122284184Sdim    return;
123284184Sdim
124284184Sdim  EHPersonality Per = MMI->getPersonalityType();
125284184Sdim
126284184Sdim  // Get rid of any dead landing pads if we're not using a Windows EH scheme. In
127284184Sdim  // Windows EH schemes, the landing pad is not actually reachable. It only
128284184Sdim  // exists so that we can emit the right table data.
129284184Sdim  if (!isMSVCEHPersonality(Per))
130284184Sdim    MMI->TidyLandingPads();
131284184Sdim
132284184Sdim  if (shouldEmitPersonality || shouldEmitLSDA) {
133284184Sdim    Asm->OutStreamer->PushSection();
134284184Sdim
135284184Sdim    if (shouldEmitMoves || shouldEmitPersonality) {
136284184Sdim      // Emit an UNWIND_INFO struct describing the prologue.
137284184Sdim      Asm->OutStreamer->EmitWinEHHandlerData();
138284184Sdim    } else {
139284184Sdim      // Just switch sections to the right xdata section. This use of
140284184Sdim      // CurrentFnSym assumes that we only emit the LSDA when ending the parent
141284184Sdim      // function.
142284184Sdim      MCSection *XData = WinEH::UnwindEmitter::getXDataSection(
143284184Sdim          Asm->CurrentFnSym, Asm->OutContext);
144284184Sdim      Asm->OutStreamer->SwitchSection(XData);
145284184Sdim    }
146284184Sdim
147284184Sdim    // Emit the tables appropriate to the personality function in use. If we
148284184Sdim    // don't recognize the personality, assume it uses an Itanium-style LSDA.
149284184Sdim    if (Per == EHPersonality::MSVC_Win64SEH)
150284184Sdim      emitCSpecificHandlerTable();
151284184Sdim    else if (Per == EHPersonality::MSVC_X86SEH)
152284734Sdim      emitExceptHandlerTable(MF);
153284184Sdim    else if (Per == EHPersonality::MSVC_CXX)
154284184Sdim      emitCXXFrameHandler3Table(MF);
155284184Sdim    else
156284184Sdim      emitExceptionTable();
157284184Sdim
158284184Sdim    Asm->OutStreamer->PopSection();
159284184Sdim  }
160284184Sdim
161284184Sdim  if (shouldEmitMoves)
162284184Sdim    Asm->OutStreamer->EmitWinCFIEndProc();
163284184Sdim}
164284184Sdim
165284184Sdimconst MCExpr *WinException::create32bitRef(const MCSymbol *Value) {
166284184Sdim  if (!Value)
167284184Sdim    return MCConstantExpr::create(0, Asm->OutContext);
168284184Sdim  return MCSymbolRefExpr::create(Value, useImageRel32
169284184Sdim                                            ? MCSymbolRefExpr::VK_COFF_IMGREL32
170284184Sdim                                            : MCSymbolRefExpr::VK_None,
171284184Sdim                                 Asm->OutContext);
172284184Sdim}
173284184Sdim
174284184Sdimconst MCExpr *WinException::create32bitRef(const GlobalValue *GV) {
175284184Sdim  if (!GV)
176284184Sdim    return MCConstantExpr::create(0, Asm->OutContext);
177284184Sdim  return create32bitRef(Asm->getSymbol(GV));
178284184Sdim}
179284184Sdim
180284184Sdim/// Emit the language-specific data that __C_specific_handler expects.  This
181284184Sdim/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
182284184Sdim/// up after faults with __try, __except, and __finally.  The typeinfo values
183284184Sdim/// are not really RTTI data, but pointers to filter functions that return an
184284184Sdim/// integer (1, 0, or -1) indicating how to handle the exception. For __finally
185284184Sdim/// blocks and other cleanups, the landing pad label is zero, and the filter
186284184Sdim/// function is actually a cleanup handler with the same prototype.  A catch-all
187284184Sdim/// entry is modeled with a null filter function field and a non-zero landing
188284184Sdim/// pad label.
189284184Sdim///
190284184Sdim/// Possible filter function return values:
191284184Sdim///   EXCEPTION_EXECUTE_HANDLER (1):
192284184Sdim///     Jump to the landing pad label after cleanups.
193284184Sdim///   EXCEPTION_CONTINUE_SEARCH (0):
194284184Sdim///     Continue searching this table or continue unwinding.
195284184Sdim///   EXCEPTION_CONTINUE_EXECUTION (-1):
196284184Sdim///     Resume execution at the trapping PC.
197284184Sdim///
198284184Sdim/// Inferred table structure:
199284184Sdim///   struct Table {
200284184Sdim///     int NumEntries;
201284184Sdim///     struct Entry {
202284184Sdim///       imagerel32 LabelStart;
203284184Sdim///       imagerel32 LabelEnd;
204284184Sdim///       imagerel32 FilterOrFinally;  // One means catch-all.
205284184Sdim///       imagerel32 LabelLPad;        // Zero means __finally.
206284184Sdim///     } Entries[NumEntries];
207284184Sdim///   };
208284184Sdimvoid WinException::emitCSpecificHandlerTable() {
209284184Sdim  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
210284184Sdim
211284184Sdim  // Simplifying assumptions for first implementation:
212284184Sdim  // - Cleanups are not implemented.
213284184Sdim  // - Filters are not implemented.
214284184Sdim
215284184Sdim  // The Itanium LSDA table sorts similar landing pads together to simplify the
216284184Sdim  // actions table, but we don't need that.
217284184Sdim  SmallVector<const LandingPadInfo *, 64> LandingPads;
218284184Sdim  LandingPads.reserve(PadInfos.size());
219284184Sdim  for (const auto &LP : PadInfos)
220284184Sdim    LandingPads.push_back(&LP);
221284184Sdim
222284184Sdim  // Compute label ranges for call sites as we would for the Itanium LSDA, but
223284184Sdim  // use an all zero action table because we aren't using these actions.
224284184Sdim  SmallVector<unsigned, 64> FirstActions;
225284184Sdim  FirstActions.resize(LandingPads.size());
226284184Sdim  SmallVector<CallSiteEntry, 64> CallSites;
227284184Sdim  computeCallSiteTable(CallSites, LandingPads, FirstActions);
228284184Sdim
229284184Sdim  MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin();
230284184Sdim  MCSymbol *EHFuncEndSym = Asm->getFunctionEnd();
231284184Sdim
232284184Sdim  // Emit the number of table entries.
233284184Sdim  unsigned NumEntries = 0;
234284184Sdim  for (const CallSiteEntry &CSE : CallSites) {
235284184Sdim    if (!CSE.LPad)
236284184Sdim      continue; // Ignore gaps.
237284184Sdim    NumEntries += CSE.LPad->SEHHandlers.size();
238284184Sdim  }
239284184Sdim  Asm->OutStreamer->EmitIntValue(NumEntries, 4);
240284184Sdim
241284184Sdim  // If there are no actions, we don't need to iterate again.
242284184Sdim  if (NumEntries == 0)
243284184Sdim    return;
244284184Sdim
245284184Sdim  // Emit the four-label records for each call site entry. The table has to be
246284184Sdim  // sorted in layout order, and the call sites should already be sorted.
247284184Sdim  for (const CallSiteEntry &CSE : CallSites) {
248284184Sdim    // Ignore gaps. Unlike the Itanium model, unwinding through a frame without
249284184Sdim    // an EH table entry will propagate the exception rather than terminating
250284184Sdim    // the program.
251284184Sdim    if (!CSE.LPad)
252284184Sdim      continue;
253284184Sdim    const LandingPadInfo *LPad = CSE.LPad;
254284184Sdim
255284184Sdim    // Compute the label range. We may reuse the function begin and end labels
256284184Sdim    // rather than forming new ones.
257284184Sdim    const MCExpr *Begin =
258284184Sdim        create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym);
259284184Sdim    const MCExpr *End;
260284184Sdim    if (CSE.EndLabel) {
261284184Sdim      // The interval is half-open, so we have to add one to include the return
262284184Sdim      // address of the last invoke in the range.
263284184Sdim      End = MCBinaryExpr::createAdd(create32bitRef(CSE.EndLabel),
264284184Sdim                                    MCConstantExpr::create(1, Asm->OutContext),
265284184Sdim                                    Asm->OutContext);
266284184Sdim    } else {
267284184Sdim      End = create32bitRef(EHFuncEndSym);
268284184Sdim    }
269284184Sdim
270284184Sdim    // Emit an entry for each action.
271284184Sdim    for (SEHHandler Handler : LPad->SEHHandlers) {
272284184Sdim      Asm->OutStreamer->EmitValue(Begin, 4);
273284184Sdim      Asm->OutStreamer->EmitValue(End, 4);
274284184Sdim
275284184Sdim      // Emit the filter or finally function pointer, if present. Otherwise,
276284184Sdim      // emit '1' to indicate a catch-all.
277284184Sdim      const Function *F = Handler.FilterOrFinally;
278284184Sdim      if (F)
279284184Sdim        Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4);
280284184Sdim      else
281284184Sdim        Asm->OutStreamer->EmitIntValue(1, 4);
282284184Sdim
283284184Sdim      // Emit the recovery address, if present. Otherwise, this must be a
284284184Sdim      // finally.
285284184Sdim      const BlockAddress *BA = Handler.RecoverBA;
286284184Sdim      if (BA)
287284184Sdim        Asm->OutStreamer->EmitValue(
288284184Sdim            create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4);
289284184Sdim      else
290284184Sdim        Asm->OutStreamer->EmitIntValue(0, 4);
291284184Sdim    }
292284184Sdim  }
293284184Sdim}
294284184Sdim
295284184Sdimvoid WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
296284184Sdim  const Function *F = MF->getFunction();
297284184Sdim  const Function *ParentF = MMI->getWinEHParent(F);
298284184Sdim  auto &OS = *Asm->OutStreamer;
299284184Sdim  WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
300284184Sdim
301284184Sdim  StringRef ParentLinkageName =
302284184Sdim      GlobalValue::getRealLinkageName(ParentF->getName());
303284184Sdim
304284184Sdim  MCSymbol *FuncInfoXData = nullptr;
305284184Sdim  if (shouldEmitPersonality) {
306284184Sdim    FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
307284184Sdim        Twine("$cppxdata$", ParentLinkageName));
308284184Sdim    OS.EmitValue(create32bitRef(FuncInfoXData), 4);
309284184Sdim
310284184Sdim    extendIP2StateTable(MF, ParentF, FuncInfo);
311284184Sdim
312284184Sdim    // Defer emission until we've visited the parent function and all the catch
313284184Sdim    // handlers.  Cleanups don't contribute to the ip2state table, so don't count
314284184Sdim    // them.
315284184Sdim    if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F))
316284184Sdim      return;
317284184Sdim    ++FuncInfo.NumIPToStateFuncsVisited;
318284184Sdim    if (FuncInfo.NumIPToStateFuncsVisited != FuncInfo.CatchHandlerMaxState.size())
319284184Sdim      return;
320284184Sdim  } else {
321284184Sdim    FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(ParentLinkageName);
322285181Sdim    emitEHRegistrationOffsetLabel(FuncInfo, ParentLinkageName);
323284184Sdim  }
324284184Sdim
325284184Sdim  MCSymbol *UnwindMapXData = nullptr;
326284184Sdim  MCSymbol *TryBlockMapXData = nullptr;
327284184Sdim  MCSymbol *IPToStateXData = nullptr;
328284184Sdim  if (!FuncInfo.UnwindMap.empty())
329284184Sdim    UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
330284184Sdim        Twine("$stateUnwindMap$", ParentLinkageName));
331284184Sdim  if (!FuncInfo.TryBlockMap.empty())
332284184Sdim    TryBlockMapXData = Asm->OutContext.getOrCreateSymbol(
333284184Sdim        Twine("$tryMap$", ParentLinkageName));
334284184Sdim  if (!FuncInfo.IPToStateList.empty())
335284184Sdim    IPToStateXData = Asm->OutContext.getOrCreateSymbol(
336284184Sdim        Twine("$ip2state$", ParentLinkageName));
337284184Sdim
338284184Sdim  // FuncInfo {
339284184Sdim  //   uint32_t           MagicNumber
340284184Sdim  //   int32_t            MaxState;
341284184Sdim  //   UnwindMapEntry    *UnwindMap;
342284184Sdim  //   uint32_t           NumTryBlocks;
343284184Sdim  //   TryBlockMapEntry  *TryBlockMap;
344284184Sdim  //   uint32_t           IPMapEntries; // always 0 for x86
345284184Sdim  //   IPToStateMapEntry *IPToStateMap; // always 0 for x86
346284184Sdim  //   uint32_t           UnwindHelp;   // non-x86 only
347284184Sdim  //   ESTypeList        *ESTypeList;
348284184Sdim  //   int32_t            EHFlags;
349284184Sdim  // }
350284184Sdim  // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
351284184Sdim  // EHFlags & 2 -> ???
352284184Sdim  // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
353284184Sdim  OS.EmitLabel(FuncInfoXData);
354284184Sdim  OS.EmitIntValue(0x19930522, 4);                      // MagicNumber
355284184Sdim  OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4);       // MaxState
356284184Sdim  OS.EmitValue(create32bitRef(UnwindMapXData), 4);     // UnwindMap
357284184Sdim  OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4);     // NumTryBlocks
358284184Sdim  OS.EmitValue(create32bitRef(TryBlockMapXData), 4);   // TryBlockMap
359284184Sdim  OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4);   // IPMapEntries
360284184Sdim  OS.EmitValue(create32bitRef(IPToStateXData), 4);     // IPToStateMap
361284184Sdim  if (Asm->MAI->usesWindowsCFI())
362284184Sdim    OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp
363284184Sdim  OS.EmitIntValue(0, 4);                               // ESTypeList
364284184Sdim  OS.EmitIntValue(1, 4);                               // EHFlags
365284184Sdim
366284184Sdim  // UnwindMapEntry {
367284184Sdim  //   int32_t ToState;
368284184Sdim  //   void  (*Action)();
369284184Sdim  // };
370284184Sdim  if (UnwindMapXData) {
371284184Sdim    OS.EmitLabel(UnwindMapXData);
372284184Sdim    for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
373284184Sdim      OS.EmitIntValue(UME.ToState, 4);                // ToState
374284184Sdim      OS.EmitValue(create32bitRef(UME.Cleanup), 4);   // Action
375284184Sdim    }
376284184Sdim  }
377284184Sdim
378284184Sdim  // TryBlockMap {
379284184Sdim  //   int32_t      TryLow;
380284184Sdim  //   int32_t      TryHigh;
381284184Sdim  //   int32_t      CatchHigh;
382284184Sdim  //   int32_t      NumCatches;
383284184Sdim  //   HandlerType *HandlerArray;
384284184Sdim  // };
385284184Sdim  if (TryBlockMapXData) {
386284184Sdim    OS.EmitLabel(TryBlockMapXData);
387284184Sdim    SmallVector<MCSymbol *, 1> HandlerMaps;
388284184Sdim    for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
389284184Sdim      WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
390284184Sdim      MCSymbol *HandlerMapXData = nullptr;
391284184Sdim
392284184Sdim      if (!TBME.HandlerArray.empty())
393284184Sdim        HandlerMapXData =
394284184Sdim            Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
395284184Sdim                                                  .concat(Twine(I))
396284184Sdim                                                  .concat("$")
397284184Sdim                                                  .concat(ParentLinkageName));
398284184Sdim
399284184Sdim      HandlerMaps.push_back(HandlerMapXData);
400284184Sdim
401284184Sdim      int CatchHigh = -1;
402284184Sdim      for (WinEHHandlerType &HT : TBME.HandlerArray)
403284184Sdim        CatchHigh =
404284184Sdim            std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]);
405284184Sdim
406284184Sdim      assert(TBME.TryLow <= TBME.TryHigh);
407284184Sdim      OS.EmitIntValue(TBME.TryLow, 4);                    // TryLow
408284184Sdim      OS.EmitIntValue(TBME.TryHigh, 4);                   // TryHigh
409284184Sdim      OS.EmitIntValue(CatchHigh, 4);                      // CatchHigh
410284184Sdim      OS.EmitIntValue(TBME.HandlerArray.size(), 4);       // NumCatches
411284184Sdim      OS.EmitValue(create32bitRef(HandlerMapXData), 4);   // HandlerArray
412284184Sdim    }
413284184Sdim
414284184Sdim    for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
415284184Sdim      WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
416284184Sdim      MCSymbol *HandlerMapXData = HandlerMaps[I];
417284184Sdim      if (!HandlerMapXData)
418284184Sdim        continue;
419284184Sdim      // HandlerType {
420284184Sdim      //   int32_t         Adjectives;
421284184Sdim      //   TypeDescriptor *Type;
422284184Sdim      //   int32_t         CatchObjOffset;
423284184Sdim      //   void          (*Handler)();
424284184Sdim      //   int32_t         ParentFrameOffset; // x64 only
425284184Sdim      // };
426284184Sdim      OS.EmitLabel(HandlerMapXData);
427284184Sdim      for (const WinEHHandlerType &HT : TBME.HandlerArray) {
428284184Sdim        // Get the frame escape label with the offset of the catch object. If
429284184Sdim        // the index is -1, then there is no catch object, and we should emit an
430284184Sdim        // offset of zero, indicating that no copy will occur.
431284184Sdim        const MCExpr *FrameAllocOffsetRef = nullptr;
432284184Sdim        if (HT.CatchObjRecoverIdx >= 0) {
433284184Sdim          MCSymbol *FrameAllocOffset =
434284184Sdim              Asm->OutContext.getOrCreateFrameAllocSymbol(
435284184Sdim                  GlobalValue::getRealLinkageName(ParentF->getName()),
436284184Sdim                  HT.CatchObjRecoverIdx);
437284184Sdim          FrameAllocOffsetRef = MCSymbolRefExpr::create(
438284184Sdim              FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
439284184Sdim        } else {
440284184Sdim          FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
441284184Sdim        }
442284184Sdim
443284184Sdim        OS.EmitIntValue(HT.Adjectives, 4);                    // Adjectives
444284184Sdim        OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4);   // Type
445284184Sdim        OS.EmitValue(FrameAllocOffsetRef, 4);                 // CatchObjOffset
446284184Sdim        OS.EmitValue(create32bitRef(HT.Handler), 4);          // Handler
447284184Sdim
448284184Sdim        if (shouldEmitPersonality) {
449284184Sdim          MCSymbol *ParentFrameOffset =
450284184Sdim              Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
451284184Sdim                  GlobalValue::getRealLinkageName(HT.Handler->getName()));
452284184Sdim          const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::create(
453284734Sdim              ParentFrameOffset, Asm->OutContext);
454284184Sdim          OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
455284184Sdim        }
456284184Sdim      }
457284184Sdim    }
458284184Sdim  }
459284184Sdim
460284184Sdim  // IPToStateMapEntry {
461284184Sdim  //   void   *IP;
462284184Sdim  //   int32_t State;
463284184Sdim  // };
464284184Sdim  if (IPToStateXData) {
465284184Sdim    OS.EmitLabel(IPToStateXData);
466284184Sdim    for (auto &IPStatePair : FuncInfo.IPToStateList) {
467284184Sdim      OS.EmitValue(create32bitRef(IPStatePair.first), 4);   // IP
468284184Sdim      OS.EmitIntValue(IPStatePair.second, 4);               // State
469284184Sdim    }
470284184Sdim  }
471284184Sdim}
472284184Sdim
473284184Sdimvoid WinException::extendIP2StateTable(const MachineFunction *MF,
474284184Sdim                                       const Function *ParentF,
475284184Sdim                                       WinEHFuncInfo &FuncInfo) {
476284184Sdim  const Function *F = MF->getFunction();
477284184Sdim
478284184Sdim  // The Itanium LSDA table sorts similar landing pads together to simplify the
479284184Sdim  // actions table, but we don't need that.
480284184Sdim  SmallVector<const LandingPadInfo *, 64> LandingPads;
481284184Sdim  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
482284184Sdim  LandingPads.reserve(PadInfos.size());
483284184Sdim  for (const auto &LP : PadInfos)
484284184Sdim    LandingPads.push_back(&LP);
485284184Sdim
486284184Sdim  RangeMapType PadMap;
487284184Sdim  computePadMap(LandingPads, PadMap);
488284184Sdim
489284184Sdim  // The end label of the previous invoke or nounwind try-range.
490284184Sdim  MCSymbol *LastLabel = Asm->getFunctionBegin();
491284184Sdim
492284184Sdim  // Whether there is a potentially throwing instruction (currently this means
493284184Sdim  // an ordinary call) between the end of the previous try-range and now.
494284184Sdim  bool SawPotentiallyThrowing = false;
495284184Sdim
496284184Sdim  int LastEHState = -2;
497284184Sdim
498284184Sdim  // The parent function and the catch handlers contribute to the 'ip2state'
499284184Sdim  // table.
500284184Sdim
501284184Sdim  // Include ip2state entries for the beginning of the main function and
502284184Sdim  // for catch handler functions.
503284184Sdim  if (F == ParentF) {
504284184Sdim    FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
505284184Sdim    LastEHState = -1;
506284184Sdim  } else if (FuncInfo.HandlerBaseState.count(F)) {
507284184Sdim    FuncInfo.IPToStateList.push_back(
508284184Sdim        std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F]));
509284184Sdim    LastEHState = FuncInfo.HandlerBaseState[F];
510284184Sdim  }
511284184Sdim  for (const auto &MBB : *MF) {
512284184Sdim    for (const auto &MI : MBB) {
513284184Sdim      if (!MI.isEHLabel()) {
514284184Sdim        if (MI.isCall())
515284184Sdim          SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
516284184Sdim        continue;
517284184Sdim      }
518284184Sdim
519284184Sdim      // End of the previous try-range?
520284184Sdim      MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
521284184Sdim      if (BeginLabel == LastLabel)
522284184Sdim        SawPotentiallyThrowing = false;
523284184Sdim
524284184Sdim      // Beginning of a new try-range?
525284184Sdim      RangeMapType::const_iterator L = PadMap.find(BeginLabel);
526284184Sdim      if (L == PadMap.end())
527284184Sdim        // Nope, it was just some random label.
528284184Sdim        continue;
529284184Sdim
530284184Sdim      const PadRange &P = L->second;
531284184Sdim      const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
532284184Sdim      assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
533284184Sdim             "Inconsistent landing pad map!");
534284184Sdim
535284184Sdim      // FIXME: Should this be using FuncInfo.HandlerBaseState?
536284184Sdim      if (SawPotentiallyThrowing && LastEHState != -1) {
537284184Sdim        FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
538284184Sdim        SawPotentiallyThrowing = false;
539284184Sdim        LastEHState = -1;
540284184Sdim      }
541284184Sdim
542284184Sdim      if (LandingPad->WinEHState != LastEHState)
543284184Sdim        FuncInfo.IPToStateList.push_back(
544284184Sdim            std::make_pair(BeginLabel, LandingPad->WinEHState));
545284184Sdim      LastEHState = LandingPad->WinEHState;
546284184Sdim      LastLabel = LandingPad->EndLabels[P.RangeIndex];
547284184Sdim    }
548284184Sdim  }
549284184Sdim}
550284734Sdim
551285181Sdimvoid WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
552285181Sdim                                                 StringRef FLinkageName) {
553285181Sdim  // Outlined helpers called by the EH runtime need to know the offset of the EH
554285181Sdim  // registration in order to recover the parent frame pointer. Now that we know
555285181Sdim  // we've code generated the parent, we can emit the label assignment that
556285181Sdim  // those helpers use to get the offset of the registration node.
557285181Sdim  assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX &&
558285181Sdim         "no EH reg node frameescape index");
559285181Sdim  MCSymbol *ParentFrameOffset =
560285181Sdim      Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName);
561285181Sdim  MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol(
562285181Sdim      FLinkageName, FuncInfo.EHRegNodeEscapeIndex);
563285181Sdim  const MCExpr *RegistrationOffsetSymRef =
564285181Sdim      MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext);
565285181Sdim  Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef);
566285181Sdim}
567285181Sdim
568284734Sdim/// Emit the language-specific data that _except_handler3 and 4 expect. This is
569284734Sdim/// functionally equivalent to the __C_specific_handler table, except it is
570284734Sdim/// indexed by state number instead of IP.
571284734Sdimvoid WinException::emitExceptHandlerTable(const MachineFunction *MF) {
572284734Sdim  MCStreamer &OS = *Asm->OutStreamer;
573284734Sdim  const Function *F = MF->getFunction();
574284734Sdim  StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
575284734Sdim
576285181Sdim  WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F);
577285181Sdim  emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
578285181Sdim
579284734Sdim  // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
580284734Sdim  MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
581284734Sdim  OS.EmitLabel(LSDALabel);
582284734Sdim
583284734Sdim  const Function *Per = MMI->getPersonality();
584284734Sdim  StringRef PerName = Per->getName();
585284734Sdim  int BaseState = -1;
586284734Sdim  if (PerName == "_except_handler4") {
587284734Sdim    // The LSDA for _except_handler4 starts with this struct, followed by the
588284734Sdim    // scope table:
589284734Sdim    //
590284734Sdim    // struct EH4ScopeTable {
591284734Sdim    //   int32_t GSCookieOffset;
592284734Sdim    //   int32_t GSCookieXOROffset;
593284734Sdim    //   int32_t EHCookieOffset;
594284734Sdim    //   int32_t EHCookieXOROffset;
595284734Sdim    //   ScopeTableEntry ScopeRecord[];
596284734Sdim    // };
597284734Sdim    //
598284734Sdim    // Only the EHCookieOffset field appears to vary, and it appears to be the
599284734Sdim    // offset from the final saved SP value to the retaddr.
600284734Sdim    OS.EmitIntValue(-2, 4);
601284734Sdim    OS.EmitIntValue(0, 4);
602284734Sdim    // FIXME: Calculate.
603284734Sdim    OS.EmitIntValue(9999, 4);
604284734Sdim    OS.EmitIntValue(0, 4);
605284734Sdim    BaseState = -2;
606284734Sdim  }
607284734Sdim
608284734Sdim  // Build a list of pointers to LandingPadInfos and then sort by WinEHState.
609284734Sdim  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
610284734Sdim  SmallVector<const LandingPadInfo *, 4> LPads;
611284734Sdim  LPads.reserve((PadInfos.size()));
612284734Sdim  for (const LandingPadInfo &LPInfo : PadInfos)
613284734Sdim    LPads.push_back(&LPInfo);
614284734Sdim  std::sort(LPads.begin(), LPads.end(),
615284734Sdim            [](const LandingPadInfo *L, const LandingPadInfo *R) {
616284734Sdim              return L->WinEHState < R->WinEHState;
617284734Sdim            });
618284734Sdim
619284734Sdim  // For each action in each lpad, emit one of these:
620284734Sdim  // struct ScopeTableEntry {
621284734Sdim  //   int32_t EnclosingLevel;
622284734Sdim  //   int32_t (__cdecl *Filter)();
623284734Sdim  //   void *HandlerOrFinally;
624284734Sdim  // };
625284734Sdim  //
626284734Sdim  // The "outermost" action will use BaseState as its enclosing level. Each
627284734Sdim  // other action will refer to the previous state as its enclosing level.
628284734Sdim  int CurState = 0;
629284734Sdim  for (const LandingPadInfo *LPInfo : LPads) {
630284734Sdim    int EnclosingLevel = BaseState;
631284734Sdim    assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 ==
632284734Sdim               LPInfo->WinEHState &&
633284734Sdim           "gaps in the SEH scope table");
634284734Sdim    for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend();
635284734Sdim         I != E; ++I) {
636284734Sdim      const SEHHandler &Handler = *I;
637284734Sdim      const BlockAddress *BA = Handler.RecoverBA;
638284734Sdim      const Function *F = Handler.FilterOrFinally;
639284734Sdim      assert(F && "cannot catch all in 32-bit SEH without filter function");
640284734Sdim      const MCExpr *FilterOrNull =
641284734Sdim          create32bitRef(BA ? Asm->getSymbol(F) : nullptr);
642284734Sdim      const MCExpr *ExceptOrFinally = create32bitRef(
643284734Sdim          BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F));
644284734Sdim
645284734Sdim      OS.EmitIntValue(EnclosingLevel, 4);
646284734Sdim      OS.EmitValue(FilterOrNull, 4);
647284734Sdim      OS.EmitValue(ExceptOrFinally, 4);
648284734Sdim
649284734Sdim      // The next state unwinds to this state.
650284734Sdim      EnclosingLevel = CurState;
651284734Sdim      CurState++;
652284734Sdim    }
653284734Sdim  }
654284734Sdim}
655