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