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