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