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