blob: 7ef2832d41a3e498b1ac22a24357d7d962e95976 [file] [log] [blame]
Reid Kleckner60b640b2015-05-28 22:47:01 +00001//===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===//
Charles Davis91ed7992011-05-27 23:47:32 +00002//
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
Reid Kleckner60b640b2015-05-28 22:47:01 +000014#include "WinException.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000015#include "llvm/ADT/SmallString.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/ADT/Twine.h"
Charles Davis91ed7992011-05-27 23:47:32 +000018#include "llvm/CodeGen/AsmPrinter.h"
Charles Davis91ed7992011-05-27 23:47:32 +000019#include "llvm/CodeGen/MachineFrameInfo.h"
20#include "llvm/CodeGen/MachineFunction.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000021#include "llvm/CodeGen/MachineModuleInfo.h"
David Majnemercde33032015-03-30 22:58:10 +000022#include "llvm/CodeGen/WinEHFuncInfo.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000023#include "llvm/IR/DataLayout.h"
Rafael Espindola894843c2014-01-07 21:19:40 +000024#include "llvm/IR/Mangler.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000025#include "llvm/IR/Module.h"
Charles Davis91ed7992011-05-27 23:47:32 +000026#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"
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +000032#include "llvm/MC/MCWin64EH.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000033#include "llvm/Support/Dwarf.h"
34#include "llvm/Support/ErrorHandling.h"
35#include "llvm/Support/FormattedStream.h"
Charles Davis91ed7992011-05-27 23:47:32 +000036#include "llvm/Target/TargetFrameLowering.h"
37#include "llvm/Target/TargetLoweringObjectFile.h"
Charles Davis91ed7992011-05-27 23:47:32 +000038#include "llvm/Target/TargetOptions.h"
39#include "llvm/Target/TargetRegisterInfo.h"
Charles Davis91ed7992011-05-27 23:47:32 +000040using namespace llvm;
41
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +000042WinException::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}
Charles Davis91ed7992011-05-27 23:47:32 +000047
Reid Kleckner60b640b2015-05-28 22:47:01 +000048WinException::~WinException() {}
Charles Davis91ed7992011-05-27 23:47:32 +000049
Timur Iskhodzhanov119f3072013-11-26 13:34:55 +000050/// endModule - Emit all exception information that should come after the
Charles Davis91ed7992011-05-27 23:47:32 +000051/// content.
Reid Kleckner60b640b2015-05-28 22:47:01 +000052void WinException::endModule() {
Reid Kleckner2bc93ca2015-06-10 01:02:30 +000053 auto &OS = *Asm->OutStreamer;
54 const Module *M = MMI->getModule();
Reid Klecknerca6ef662015-06-10 01:13:44 +000055 for (const Function &F : *M)
56 if (F.hasFnAttribute("safeseh"))
Reid Kleckner2bc93ca2015-06-10 01:02:30 +000057 OS.EmitCOFFSafeSEH(Asm->getSymbol(&F));
Charles Davis91ed7992011-05-27 23:47:32 +000058}
59
Reid Kleckner60b640b2015-05-28 22:47:01 +000060void WinException::beginFunction(const MachineFunction *MF) {
Charles Davis5638b9f2011-05-28 04:21:04 +000061 shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;
62
63 // If any landing pads survive, we need an EH table.
64 bool hasLandingPads = !MMI->getLandingPads().empty();
65
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +000066 const Function *F = MF->getFunction();
67 const Function *ParentF = MMI->getWinEHParent(F);
68
Charles Davis5638b9f2011-05-28 04:21:04 +000069 shouldEmitMoves = Asm->needsSEHMoves();
70
71 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
72 unsigned PerEncoding = TLOF.getPersonalityEncoding();
Reid Kleckner9a1a9192015-07-13 20:41:46 +000073 const Function *Per = nullptr;
74 if (F->hasPersonalityFn())
75 Per = dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts());
Charles Davis5638b9f2011-05-28 04:21:04 +000076
77 shouldEmitPersonality = hasLandingPads &&
78 PerEncoding != dwarf::DW_EH_PE_omit && Per;
79
80 unsigned LSDAEncoding = TLOF.getLSDAEncoding();
81 shouldEmitLSDA = shouldEmitPersonality &&
82 LSDAEncoding != dwarf::DW_EH_PE_omit;
83
Reid Kleckner9a1a9192015-07-13 20:41:46 +000084 // If we're not using CFI, we don't want the CFI or the personality. If
85 // WinEHPrepare outlined something, we should emit the LSDA.
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +000086 if (!Asm->MAI->usesWindowsCFI()) {
Reid Kleckner9a1a9192015-07-13 20:41:46 +000087 bool HasOutlinedChildren =
88 F->hasFnAttribute("wineh-parent") && F == ParentF;
89 shouldEmitLSDA = HasOutlinedChildren;
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +000090 shouldEmitPersonality = false;
91 return;
92 }
David Majnemera225a192015-03-31 22:35:44 +000093
94 // If this was an outlined handler, we need to define the label corresponding
95 // to the offset of the parent frame relative to the stack pointer after the
96 // prologue.
David Majnemera225a192015-03-31 22:35:44 +000097 if (F != ParentF) {
98 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
99 auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F);
100 if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) {
101 MCSymbol *HandlerTypeParentFrameOffset =
102 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
103 GlobalValue::getRealLinkageName(F->getName()));
104
105 // Emit a symbol assignment.
Lang Hames9ff69c82015-04-24 19:11:51 +0000106 Asm->OutStreamer->EmitAssignment(
David Majnemera225a192015-03-31 22:35:44 +0000107 HandlerTypeParentFrameOffset,
Jim Grosbach13760bd2015-05-30 01:25:56 +0000108 MCConstantExpr::create(I->second, Asm->OutContext));
David Majnemera225a192015-03-31 22:35:44 +0000109 }
110 }
111
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000112 if (shouldEmitMoves || shouldEmitPersonality)
113 Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym);
Charles Davis5638b9f2011-05-28 04:21:04 +0000114
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000115 if (shouldEmitPersonality) {
116 const MCSymbol *PersHandlerSym =
117 TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);
118 Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true);
119 }
Charles Davis91ed7992011-05-27 23:47:32 +0000120}
121
Timur Iskhodzhanov119f3072013-11-26 13:34:55 +0000122/// endFunction - Gather and emit post-function exception information.
Charles Davis91ed7992011-05-27 23:47:32 +0000123///
Reid Kleckner60b640b2015-05-28 22:47:01 +0000124void WinException::endFunction(const MachineFunction *MF) {
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000125 if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA)
Charles Davis5638b9f2011-05-28 04:21:04 +0000126 return;
127
Reid Kleckner9a1a9192015-07-13 20:41:46 +0000128 const Function *F = MF->getFunction();
129 EHPersonality Per = EHPersonality::Unknown;
130 if (F->hasPersonalityFn())
131 Per = classifyEHPersonality(F->getPersonalityFn());
Reid Kleckner3e9fadf2015-04-15 18:48:15 +0000132
133 // Get rid of any dead landing pads if we're not using a Windows EH scheme. In
134 // Windows EH schemes, the landing pad is not actually reachable. It only
135 // exists so that we can emit the right table data.
136 if (!isMSVCEHPersonality(Per))
137 MMI->TidyLandingPads();
Charles Davisa5752262011-05-30 00:13:34 +0000138
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000139 if (shouldEmitPersonality || shouldEmitLSDA) {
Lang Hames9ff69c82015-04-24 19:11:51 +0000140 Asm->OutStreamer->PushSection();
Reid Kleckner0a57f652015-01-14 01:05:27 +0000141
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000142 if (shouldEmitMoves || shouldEmitPersonality) {
143 // Emit an UNWIND_INFO struct describing the prologue.
144 Asm->OutStreamer->EmitWinEHHandlerData();
145 } else {
146 // Just switch sections to the right xdata section. This use of
147 // CurrentFnSym assumes that we only emit the LSDA when ending the parent
148 // function.
149 MCSection *XData = WinEH::UnwindEmitter::getXDataSection(
150 Asm->CurrentFnSym, Asm->OutContext);
151 Asm->OutStreamer->SwitchSection(XData);
152 }
Reid Kleckner0a57f652015-01-14 01:05:27 +0000153
Reid Kleckner9b5eaf02015-01-14 18:50:10 +0000154 // Emit the tables appropriate to the personality function in use. If we
155 // don't recognize the personality, assume it uses an Itanium-style LSDA.
Reid Kleckner2d5fb682015-02-14 00:21:02 +0000156 if (Per == EHPersonality::MSVC_Win64SEH)
Reid Kleckner9b5eaf02015-01-14 18:50:10 +0000157 emitCSpecificHandlerTable();
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000158 else if (Per == EHPersonality::MSVC_X86SEH)
Reid Klecknerf12c0302015-06-09 21:42:19 +0000159 emitExceptHandlerTable(MF);
David Majnemercde33032015-03-30 22:58:10 +0000160 else if (Per == EHPersonality::MSVC_CXX)
161 emitCXXFrameHandler3Table(MF);
Reid Kleckner9b5eaf02015-01-14 18:50:10 +0000162 else
Reid Kleckner0a57f652015-01-14 01:05:27 +0000163 emitExceptionTable();
Reid Kleckner0a57f652015-01-14 01:05:27 +0000164
Lang Hames9ff69c82015-04-24 19:11:51 +0000165 Asm->OutStreamer->PopSection();
Charles Davisa5752262011-05-30 00:13:34 +0000166 }
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000167
168 if (shouldEmitMoves)
169 Asm->OutStreamer->EmitWinCFIEndProc();
Charles Davis91ed7992011-05-27 23:47:32 +0000170}
Reid Kleckner0a57f652015-01-14 01:05:27 +0000171
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000172const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {
David Majnemercde33032015-03-30 22:58:10 +0000173 if (!Value)
Jim Grosbach13760bd2015-05-30 01:25:56 +0000174 return MCConstantExpr::create(0, Asm->OutContext);
175 return MCSymbolRefExpr::create(Value, useImageRel32
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000176 ? MCSymbolRefExpr::VK_COFF_IMGREL32
177 : MCSymbolRefExpr::VK_None,
Reid Kleckner0a57f652015-01-14 01:05:27 +0000178 Asm->OutContext);
179}
180
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000181const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {
David Majnemercde33032015-03-30 22:58:10 +0000182 if (!GV)
Jim Grosbach13760bd2015-05-30 01:25:56 +0000183 return MCConstantExpr::create(0, Asm->OutContext);
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000184 return create32bitRef(Asm->getSymbol(GV));
David Majnemercde33032015-03-30 22:58:10 +0000185}
186
Reid Kleckner0a57f652015-01-14 01:05:27 +0000187/// Emit the language-specific data that __C_specific_handler expects. This
188/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
189/// up after faults with __try, __except, and __finally. The typeinfo values
190/// are not really RTTI data, but pointers to filter functions that return an
191/// integer (1, 0, or -1) indicating how to handle the exception. For __finally
192/// blocks and other cleanups, the landing pad label is zero, and the filter
193/// function is actually a cleanup handler with the same prototype. A catch-all
194/// entry is modeled with a null filter function field and a non-zero landing
195/// pad label.
196///
197/// Possible filter function return values:
198/// EXCEPTION_EXECUTE_HANDLER (1):
199/// Jump to the landing pad label after cleanups.
200/// EXCEPTION_CONTINUE_SEARCH (0):
201/// Continue searching this table or continue unwinding.
202/// EXCEPTION_CONTINUE_EXECUTION (-1):
203/// Resume execution at the trapping PC.
204///
205/// Inferred table structure:
206/// struct Table {
207/// int NumEntries;
208/// struct Entry {
209/// imagerel32 LabelStart;
210/// imagerel32 LabelEnd;
Reid Klecknerf690f502015-01-22 02:27:44 +0000211/// imagerel32 FilterOrFinally; // One means catch-all.
Reid Kleckner0a57f652015-01-14 01:05:27 +0000212/// imagerel32 LabelLPad; // Zero means __finally.
213/// } Entries[NumEntries];
214/// };
Reid Kleckner60b640b2015-05-28 22:47:01 +0000215void WinException::emitCSpecificHandlerTable() {
Reid Kleckner0a57f652015-01-14 01:05:27 +0000216 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
217
218 // Simplifying assumptions for first implementation:
219 // - Cleanups are not implemented.
220 // - Filters are not implemented.
221
222 // The Itanium LSDA table sorts similar landing pads together to simplify the
223 // actions table, but we don't need that.
224 SmallVector<const LandingPadInfo *, 64> LandingPads;
225 LandingPads.reserve(PadInfos.size());
226 for (const auto &LP : PadInfos)
227 LandingPads.push_back(&LP);
228
229 // Compute label ranges for call sites as we would for the Itanium LSDA, but
230 // use an all zero action table because we aren't using these actions.
231 SmallVector<unsigned, 64> FirstActions;
232 FirstActions.resize(LandingPads.size());
233 SmallVector<CallSiteEntry, 64> CallSites;
234 computeCallSiteTable(CallSites, LandingPads, FirstActions);
235
Rafael Espindola629cdba2015-02-27 18:18:39 +0000236 MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin();
237 MCSymbol *EHFuncEndSym = Asm->getFunctionEnd();
Reid Kleckner0a57f652015-01-14 01:05:27 +0000238
239 // Emit the number of table entries.
240 unsigned NumEntries = 0;
241 for (const CallSiteEntry &CSE : CallSites) {
242 if (!CSE.LPad)
243 continue; // Ignore gaps.
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000244 NumEntries += CSE.LPad->SEHHandlers.size();
Reid Kleckner0a57f652015-01-14 01:05:27 +0000245 }
Lang Hames9ff69c82015-04-24 19:11:51 +0000246 Asm->OutStreamer->EmitIntValue(NumEntries, 4);
Reid Kleckner0a57f652015-01-14 01:05:27 +0000247
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000248 // If there are no actions, we don't need to iterate again.
249 if (NumEntries == 0)
250 return;
251
Reid Kleckner0a57f652015-01-14 01:05:27 +0000252 // Emit the four-label records for each call site entry. The table has to be
253 // sorted in layout order, and the call sites should already be sorted.
254 for (const CallSiteEntry &CSE : CallSites) {
255 // Ignore gaps. Unlike the Itanium model, unwinding through a frame without
256 // an EH table entry will propagate the exception rather than terminating
257 // the program.
258 if (!CSE.LPad)
259 continue;
260 const LandingPadInfo *LPad = CSE.LPad;
261
262 // Compute the label range. We may reuse the function begin and end labels
263 // rather than forming new ones.
264 const MCExpr *Begin =
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000265 create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym);
Reid Kleckner0a57f652015-01-14 01:05:27 +0000266 const MCExpr *End;
267 if (CSE.EndLabel) {
268 // The interval is half-open, so we have to add one to include the return
269 // address of the last invoke in the range.
Jim Grosbach13760bd2015-05-30 01:25:56 +0000270 End = MCBinaryExpr::createAdd(create32bitRef(CSE.EndLabel),
271 MCConstantExpr::create(1, Asm->OutContext),
Reid Kleckner0a57f652015-01-14 01:05:27 +0000272 Asm->OutContext);
273 } else {
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000274 End = create32bitRef(EHFuncEndSym);
Reid Kleckner0a57f652015-01-14 01:05:27 +0000275 }
276
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000277 // Emit an entry for each action.
278 for (SEHHandler Handler : LPad->SEHHandlers) {
Lang Hames9ff69c82015-04-24 19:11:51 +0000279 Asm->OutStreamer->EmitValue(Begin, 4);
280 Asm->OutStreamer->EmitValue(End, 4);
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000281
282 // Emit the filter or finally function pointer, if present. Otherwise,
283 // emit '1' to indicate a catch-all.
284 const Function *F = Handler.FilterOrFinally;
285 if (F)
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000286 Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4);
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000287 else
Lang Hames9ff69c82015-04-24 19:11:51 +0000288 Asm->OutStreamer->EmitIntValue(1, 4);
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000289
290 // Emit the recovery address, if present. Otherwise, this must be a
291 // finally.
292 const BlockAddress *BA = Handler.RecoverBA;
293 if (BA)
Lang Hames9ff69c82015-04-24 19:11:51 +0000294 Asm->OutStreamer->EmitValue(
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000295 create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4);
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000296 else
Lang Hames9ff69c82015-04-24 19:11:51 +0000297 Asm->OutStreamer->EmitIntValue(0, 4);
Reid Klecknerd2a1a512015-04-21 18:23:57 +0000298 }
Reid Kleckner0a57f652015-01-14 01:05:27 +0000299 }
300}
David Majnemercde33032015-03-30 22:58:10 +0000301
Reid Kleckner60b640b2015-05-28 22:47:01 +0000302void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
David Majnemercde33032015-03-30 22:58:10 +0000303 const Function *F = MF->getFunction();
304 const Function *ParentF = MMI->getWinEHParent(F);
Lang Hames9ff69c82015-04-24 19:11:51 +0000305 auto &OS = *Asm->OutStreamer;
David Majnemera225a192015-03-31 22:35:44 +0000306 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
David Majnemercde33032015-03-30 22:58:10 +0000307
308 StringRef ParentLinkageName =
309 GlobalValue::getRealLinkageName(ParentF->getName());
310
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000311 MCSymbol *FuncInfoXData = nullptr;
312 if (shouldEmitPersonality) {
313 FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
314 Twine("$cppxdata$", ParentLinkageName));
315 OS.EmitValue(create32bitRef(FuncInfoXData), 4);
316
317 extendIP2StateTable(MF, ParentF, FuncInfo);
318
319 // Defer emission until we've visited the parent function and all the catch
320 // handlers. Cleanups don't contribute to the ip2state table, so don't count
321 // them.
322 if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F))
323 return;
324 ++FuncInfo.NumIPToStateFuncsVisited;
325 if (FuncInfo.NumIPToStateFuncsVisited != FuncInfo.CatchHandlerMaxState.size())
326 return;
327 } else {
328 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(ParentLinkageName);
Reid Kleckner399a2fe2015-06-30 22:46:59 +0000329 emitEHRegistrationOffsetLabel(FuncInfo, ParentLinkageName);
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000330 }
331
332 MCSymbol *UnwindMapXData = nullptr;
333 MCSymbol *TryBlockMapXData = nullptr;
334 MCSymbol *IPToStateXData = nullptr;
335 if (!FuncInfo.UnwindMap.empty())
336 UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
337 Twine("$stateUnwindMap$", ParentLinkageName));
338 if (!FuncInfo.TryBlockMap.empty())
339 TryBlockMapXData = Asm->OutContext.getOrCreateSymbol(
340 Twine("$tryMap$", ParentLinkageName));
341 if (!FuncInfo.IPToStateList.empty())
342 IPToStateXData = Asm->OutContext.getOrCreateSymbol(
343 Twine("$ip2state$", ParentLinkageName));
344
345 // FuncInfo {
346 // uint32_t MagicNumber
347 // int32_t MaxState;
348 // UnwindMapEntry *UnwindMap;
349 // uint32_t NumTryBlocks;
350 // TryBlockMapEntry *TryBlockMap;
351 // uint32_t IPMapEntries; // always 0 for x86
352 // IPToStateMapEntry *IPToStateMap; // always 0 for x86
353 // uint32_t UnwindHelp; // non-x86 only
354 // ESTypeList *ESTypeList;
355 // int32_t EHFlags;
356 // }
357 // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
358 // EHFlags & 2 -> ???
359 // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
Reid Kleckner85a24502015-07-10 00:08:49 +0000360 OS.EmitValueToAlignment(4);
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000361 OS.EmitLabel(FuncInfoXData);
362 OS.EmitIntValue(0x19930522, 4); // MagicNumber
363 OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState
364 OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap
365 OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks
366 OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap
367 OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries
368 OS.EmitValue(create32bitRef(IPToStateXData), 4); // IPToStateMap
369 if (Asm->MAI->usesWindowsCFI())
370 OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp
371 OS.EmitIntValue(0, 4); // ESTypeList
372 OS.EmitIntValue(1, 4); // EHFlags
373
374 // UnwindMapEntry {
375 // int32_t ToState;
376 // void (*Action)();
377 // };
378 if (UnwindMapXData) {
379 OS.EmitLabel(UnwindMapXData);
380 for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
381 OS.EmitIntValue(UME.ToState, 4); // ToState
382 OS.EmitValue(create32bitRef(UME.Cleanup), 4); // Action
383 }
384 }
385
386 // TryBlockMap {
387 // int32_t TryLow;
388 // int32_t TryHigh;
389 // int32_t CatchHigh;
390 // int32_t NumCatches;
391 // HandlerType *HandlerArray;
392 // };
393 if (TryBlockMapXData) {
394 OS.EmitLabel(TryBlockMapXData);
395 SmallVector<MCSymbol *, 1> HandlerMaps;
396 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
397 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
398 MCSymbol *HandlerMapXData = nullptr;
399
400 if (!TBME.HandlerArray.empty())
401 HandlerMapXData =
402 Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
403 .concat(Twine(I))
404 .concat("$")
405 .concat(ParentLinkageName));
406
407 HandlerMaps.push_back(HandlerMapXData);
408
409 int CatchHigh = -1;
410 for (WinEHHandlerType &HT : TBME.HandlerArray)
411 CatchHigh =
412 std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]);
413
414 assert(TBME.TryLow <= TBME.TryHigh);
415 OS.EmitIntValue(TBME.TryLow, 4); // TryLow
416 OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh
417 OS.EmitIntValue(CatchHigh, 4); // CatchHigh
418 OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches
419 OS.EmitValue(create32bitRef(HandlerMapXData), 4); // HandlerArray
420 }
421
422 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
423 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
424 MCSymbol *HandlerMapXData = HandlerMaps[I];
425 if (!HandlerMapXData)
426 continue;
427 // HandlerType {
428 // int32_t Adjectives;
429 // TypeDescriptor *Type;
430 // int32_t CatchObjOffset;
431 // void (*Handler)();
432 // int32_t ParentFrameOffset; // x64 only
433 // };
434 OS.EmitLabel(HandlerMapXData);
435 for (const WinEHHandlerType &HT : TBME.HandlerArray) {
436 // Get the frame escape label with the offset of the catch object. If
437 // the index is -1, then there is no catch object, and we should emit an
438 // offset of zero, indicating that no copy will occur.
439 const MCExpr *FrameAllocOffsetRef = nullptr;
440 if (HT.CatchObjRecoverIdx >= 0) {
441 MCSymbol *FrameAllocOffset =
442 Asm->OutContext.getOrCreateFrameAllocSymbol(
443 GlobalValue::getRealLinkageName(ParentF->getName()),
444 HT.CatchObjRecoverIdx);
Jim Grosbach13760bd2015-05-30 01:25:56 +0000445 FrameAllocOffsetRef = MCSymbolRefExpr::create(
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000446 FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
447 } else {
Jim Grosbach13760bd2015-05-30 01:25:56 +0000448 FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000449 }
450
451 OS.EmitIntValue(HT.Adjectives, 4); // Adjectives
452 OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); // Type
453 OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset
454 OS.EmitValue(create32bitRef(HT.Handler), 4); // Handler
455
456 if (shouldEmitPersonality) {
457 MCSymbol *ParentFrameOffset =
458 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
459 GlobalValue::getRealLinkageName(HT.Handler->getName()));
Jim Grosbach13760bd2015-05-30 01:25:56 +0000460 const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::create(
Reid Klecknera9d62532015-06-11 22:32:23 +0000461 ParentFrameOffset, Asm->OutContext);
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000462 OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
463 }
464 }
465 }
466 }
467
468 // IPToStateMapEntry {
469 // void *IP;
470 // int32_t State;
471 // };
472 if (IPToStateXData) {
473 OS.EmitLabel(IPToStateXData);
474 for (auto &IPStatePair : FuncInfo.IPToStateList) {
475 OS.EmitValue(create32bitRef(IPStatePair.first), 4); // IP
476 OS.EmitIntValue(IPStatePair.second, 4); // State
477 }
478 }
479}
480
481void WinException::extendIP2StateTable(const MachineFunction *MF,
482 const Function *ParentF,
483 WinEHFuncInfo &FuncInfo) {
484 const Function *F = MF->getFunction();
David Majnemercde33032015-03-30 22:58:10 +0000485
486 // The Itanium LSDA table sorts similar landing pads together to simplify the
487 // actions table, but we don't need that.
488 SmallVector<const LandingPadInfo *, 64> LandingPads;
489 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
490 LandingPads.reserve(PadInfos.size());
491 for (const auto &LP : PadInfos)
492 LandingPads.push_back(&LP);
493
494 RangeMapType PadMap;
495 computePadMap(LandingPads, PadMap);
496
497 // The end label of the previous invoke or nounwind try-range.
498 MCSymbol *LastLabel = Asm->getFunctionBegin();
499
500 // Whether there is a potentially throwing instruction (currently this means
501 // an ordinary call) between the end of the previous try-range and now.
502 bool SawPotentiallyThrowing = false;
503
David Majnemercde33032015-03-30 22:58:10 +0000504 int LastEHState = -2;
505
506 // The parent function and the catch handlers contribute to the 'ip2state'
507 // table.
Andrew Kaylor762a6be2015-05-11 19:41:19 +0000508
509 // Include ip2state entries for the beginning of the main function and
510 // for catch handler functions.
511 if (F == ParentF) {
512 FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
513 LastEHState = -1;
514 } else if (FuncInfo.HandlerBaseState.count(F)) {
Reid Kleckner1d3d4ad2015-05-29 17:00:57 +0000515 FuncInfo.IPToStateList.push_back(
516 std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F]));
Andrew Kaylor762a6be2015-05-11 19:41:19 +0000517 LastEHState = FuncInfo.HandlerBaseState[F];
518 }
David Majnemercde33032015-03-30 22:58:10 +0000519 for (const auto &MBB : *MF) {
520 for (const auto &MI : MBB) {
521 if (!MI.isEHLabel()) {
522 if (MI.isCall())
523 SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
524 continue;
525 }
526
527 // End of the previous try-range?
528 MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
529 if (BeginLabel == LastLabel)
530 SawPotentiallyThrowing = false;
531
532 // Beginning of a new try-range?
533 RangeMapType::const_iterator L = PadMap.find(BeginLabel);
534 if (L == PadMap.end())
535 // Nope, it was just some random label.
536 continue;
537
538 const PadRange &P = L->second;
539 const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
540 assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
541 "Inconsistent landing pad map!");
542
Andrew Kaylor762a6be2015-05-11 19:41:19 +0000543 // FIXME: Should this be using FuncInfo.HandlerBaseState?
544 if (SawPotentiallyThrowing && LastEHState != -1) {
David Majnemercde33032015-03-30 22:58:10 +0000545 FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
546 SawPotentiallyThrowing = false;
547 LastEHState = -1;
548 }
549
550 if (LandingPad->WinEHState != LastEHState)
551 FuncInfo.IPToStateList.push_back(
552 std::make_pair(BeginLabel, LandingPad->WinEHState));
553 LastEHState = LandingPad->WinEHState;
554 LastLabel = LandingPad->EndLabels[P.RangeIndex];
555 }
556 }
David Majnemercde33032015-03-30 22:58:10 +0000557}
Reid Klecknerf12c0302015-06-09 21:42:19 +0000558
Reid Kleckner399a2fe2015-06-30 22:46:59 +0000559void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
560 StringRef FLinkageName) {
561 // Outlined helpers called by the EH runtime need to know the offset of the EH
562 // registration in order to recover the parent frame pointer. Now that we know
563 // we've code generated the parent, we can emit the label assignment that
564 // those helpers use to get the offset of the registration node.
565 assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX &&
Reid Kleckner60381792015-07-07 22:25:32 +0000566 "no EH reg node localescape index");
Reid Kleckner399a2fe2015-06-30 22:46:59 +0000567 MCSymbol *ParentFrameOffset =
568 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName);
569 MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol(
570 FLinkageName, FuncInfo.EHRegNodeEscapeIndex);
571 const MCExpr *RegistrationOffsetSymRef =
572 MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext);
573 Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef);
574}
575
Reid Klecknerf12c0302015-06-09 21:42:19 +0000576/// Emit the language-specific data that _except_handler3 and 4 expect. This is
577/// functionally equivalent to the __C_specific_handler table, except it is
578/// indexed by state number instead of IP.
579void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
Reid Klecknera9d62532015-06-11 22:32:23 +0000580 MCStreamer &OS = *Asm->OutStreamer;
Reid Klecknera9d62532015-06-11 22:32:23 +0000581 const Function *F = MF->getFunction();
Reid Klecknera9d62532015-06-11 22:32:23 +0000582 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
Reid Kleckner399a2fe2015-06-30 22:46:59 +0000583
584 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F);
585 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
Reid Klecknerf12c0302015-06-09 21:42:19 +0000586
587 // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
Reid Klecknerf12c0302015-06-09 21:42:19 +0000588 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
Reid Kleckner85a24502015-07-10 00:08:49 +0000589 OS.EmitValueToAlignment(4);
Reid Klecknerf12c0302015-06-09 21:42:19 +0000590 OS.EmitLabel(LSDALabel);
591
Reid Kleckner9a1a9192015-07-13 20:41:46 +0000592 const Function *Per =
593 dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts());
Reid Klecknerf12c0302015-06-09 21:42:19 +0000594 StringRef PerName = Per->getName();
595 int BaseState = -1;
596 if (PerName == "_except_handler4") {
597 // The LSDA for _except_handler4 starts with this struct, followed by the
598 // scope table:
599 //
600 // struct EH4ScopeTable {
601 // int32_t GSCookieOffset;
602 // int32_t GSCookieXOROffset;
603 // int32_t EHCookieOffset;
604 // int32_t EHCookieXOROffset;
605 // ScopeTableEntry ScopeRecord[];
606 // };
607 //
608 // Only the EHCookieOffset field appears to vary, and it appears to be the
609 // offset from the final saved SP value to the retaddr.
610 OS.EmitIntValue(-2, 4);
611 OS.EmitIntValue(0, 4);
612 // FIXME: Calculate.
613 OS.EmitIntValue(9999, 4);
614 OS.EmitIntValue(0, 4);
615 BaseState = -2;
616 }
617
618 // Build a list of pointers to LandingPadInfos and then sort by WinEHState.
619 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
620 SmallVector<const LandingPadInfo *, 4> LPads;
621 LPads.reserve((PadInfos.size()));
622 for (const LandingPadInfo &LPInfo : PadInfos)
623 LPads.push_back(&LPInfo);
624 std::sort(LPads.begin(), LPads.end(),
625 [](const LandingPadInfo *L, const LandingPadInfo *R) {
626 return L->WinEHState < R->WinEHState;
627 });
628
629 // For each action in each lpad, emit one of these:
630 // struct ScopeTableEntry {
631 // int32_t EnclosingLevel;
Reid Kleckner81d1cc02015-06-11 23:37:18 +0000632 // int32_t (__cdecl *Filter)();
633 // void *HandlerOrFinally;
Reid Klecknerf12c0302015-06-09 21:42:19 +0000634 // };
635 //
636 // The "outermost" action will use BaseState as its enclosing level. Each
637 // other action will refer to the previous state as its enclosing level.
638 int CurState = 0;
639 for (const LandingPadInfo *LPInfo : LPads) {
640 int EnclosingLevel = BaseState;
Reid Kleckner7912d9b2015-06-10 00:04:53 +0000641 assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 ==
642 LPInfo->WinEHState &&
Reid Klecknerf12c0302015-06-09 21:42:19 +0000643 "gaps in the SEH scope table");
Reid Kleckner81d1cc02015-06-11 23:37:18 +0000644 for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend();
645 I != E; ++I) {
646 const SEHHandler &Handler = *I;
Reid Klecknerf12c0302015-06-09 21:42:19 +0000647 const BlockAddress *BA = Handler.RecoverBA;
Reid Kleckner81d1cc02015-06-11 23:37:18 +0000648 const Function *F = Handler.FilterOrFinally;
649 assert(F && "cannot catch all in 32-bit SEH without filter function");
650 const MCExpr *FilterOrNull =
651 create32bitRef(BA ? Asm->getSymbol(F) : nullptr);
652 const MCExpr *ExceptOrFinally = create32bitRef(
653 BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F));
Reid Klecknerf12c0302015-06-09 21:42:19 +0000654
655 OS.EmitIntValue(EnclosingLevel, 4);
Reid Kleckner81d1cc02015-06-11 23:37:18 +0000656 OS.EmitValue(FilterOrNull, 4);
657 OS.EmitValue(ExceptOrFinally, 4);
Reid Klecknerf12c0302015-06-09 21:42:19 +0000658
659 // The next state unwinds to this state.
660 EnclosingLevel = CurState;
661 CurState++;
662 }
663 }
664}