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