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