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/StringExtras.h" 16 #include "llvm/ADT/Twine.h" 17 #include "llvm/CodeGen/AsmPrinter.h" 18 #include "llvm/CodeGen/MachineFrameInfo.h" 19 #include "llvm/CodeGen/MachineFunction.h" 20 #include "llvm/CodeGen/MachineModuleInfo.h" 21 #include "llvm/CodeGen/WinEHFuncInfo.h" 22 #include "llvm/IR/DataLayout.h" 23 #include "llvm/IR/Mangler.h" 24 #include "llvm/IR/Module.h" 25 #include "llvm/MC/MCAsmInfo.h" 26 #include "llvm/MC/MCContext.h" 27 #include "llvm/MC/MCExpr.h" 28 #include "llvm/MC/MCSection.h" 29 #include "llvm/MC/MCStreamer.h" 30 #include "llvm/MC/MCSymbol.h" 31 #include "llvm/MC/MCWin64EH.h" 32 #include "llvm/Support/COFF.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 #include "llvm/Target/TargetSubtargetInfo.h" 41 using namespace llvm; 42 43 WinException::WinException(AsmPrinter *A) : EHStreamer(A) { 44 // MSVC's EH tables are always composed of 32-bit words. All known 64-bit 45 // platforms use an imagerel32 relocation to refer to symbols. 46 useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64); 47 } 48 49 WinException::~WinException() {} 50 51 /// endModule - Emit all exception information that should come after the 52 /// content. 53 void WinException::endModule() { 54 auto &OS = *Asm->OutStreamer; 55 const Module *M = MMI->getModule(); 56 for (const Function &F : *M) 57 if (F.hasFnAttribute("safeseh")) 58 OS.EmitCOFFSafeSEH(Asm->getSymbol(&F)); 59 } 60 61 void WinException::beginFunction(const MachineFunction *MF) { 62 shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; 63 64 // If any landing pads survive, we need an EH table. 65 bool hasLandingPads = !MMI->getLandingPads().empty(); 66 bool hasEHFunclets = MMI->hasEHFunclets(); 67 68 const Function *F = MF->getFunction(); 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 if (!Asm->MAI->usesWindowsCFI()) { 93 shouldEmitLSDA = hasEHFunclets; 94 shouldEmitPersonality = false; 95 return; 96 } 97 98 beginFunclet(MF->front(), Asm->CurrentFnSym); 99 } 100 101 /// endFunction - Gather and emit post-function exception information. 102 /// 103 void WinException::endFunction(const MachineFunction *MF) { 104 if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA) 105 return; 106 107 const Function *F = MF->getFunction(); 108 EHPersonality Per = EHPersonality::Unknown; 109 if (F->hasPersonalityFn()) 110 Per = classifyEHPersonality(F->getPersonalityFn()); 111 112 // Get rid of any dead landing pads if we're not using funclets. In funclet 113 // schemes, the landing pad is not actually reachable. It only exists so 114 // that we can emit the right table data. 115 if (!isFuncletEHPersonality(Per)) 116 MMI->TidyLandingPads(); 117 118 endFunclet(); 119 120 // endFunclet will emit the necessary .xdata tables for x64 SEH. 121 if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets()) 122 return; 123 124 if (shouldEmitPersonality || shouldEmitLSDA) { 125 Asm->OutStreamer->PushSection(); 126 127 // Just switch sections to the right xdata section. This use of CurrentFnSym 128 // assumes that we only emit the LSDA when ending the parent function. 129 MCSection *XData = WinEH::UnwindEmitter::getXDataSection(Asm->CurrentFnSym, 130 Asm->OutContext); 131 Asm->OutStreamer->SwitchSection(XData); 132 133 // Emit the tables appropriate to the personality function in use. If we 134 // don't recognize the personality, assume it uses an Itanium-style LSDA. 135 if (Per == EHPersonality::MSVC_Win64SEH) 136 emitCSpecificHandlerTable(MF); 137 else if (Per == EHPersonality::MSVC_X86SEH) 138 emitExceptHandlerTable(MF); 139 else if (Per == EHPersonality::MSVC_CXX) 140 emitCXXFrameHandler3Table(MF); 141 else if (Per == EHPersonality::CoreCLR) 142 emitCLRExceptionTable(MF); 143 else 144 emitExceptionTable(); 145 146 Asm->OutStreamer->PopSection(); 147 } 148 } 149 150 /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. 151 static MCSymbol *getMCSymbolForMBB(AsmPrinter *Asm, 152 const MachineBasicBlock *MBB) { 153 if (!MBB) 154 return nullptr; 155 156 assert(MBB->isEHFuncletEntry()); 157 158 // Give catches and cleanups a name based off of their parent function and 159 // their funclet entry block's number. 160 const MachineFunction *MF = MBB->getParent(); 161 const Function *F = MF->getFunction(); 162 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 163 MCContext &Ctx = MF->getContext(); 164 StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch"; 165 return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" + 166 Twine(MBB->getNumber()) + "@?0?" + 167 FuncLinkageName + "@4HA"); 168 } 169 170 void WinException::beginFunclet(const MachineBasicBlock &MBB, 171 MCSymbol *Sym) { 172 CurrentFuncletEntry = &MBB; 173 174 const Function *F = Asm->MF->getFunction(); 175 // If a symbol was not provided for the funclet, invent one. 176 if (!Sym) { 177 Sym = getMCSymbolForMBB(Asm, &MBB); 178 179 // Describe our funclet symbol as a function with internal linkage. 180 Asm->OutStreamer->BeginCOFFSymbolDef(Sym); 181 Asm->OutStreamer->EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC); 182 Asm->OutStreamer->EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION 183 << COFF::SCT_COMPLEX_TYPE_SHIFT); 184 Asm->OutStreamer->EndCOFFSymbolDef(); 185 186 // We want our funclet's entry point to be aligned such that no nops will be 187 // present after the label. 188 Asm->EmitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()), 189 F); 190 191 // Now that we've emitted the alignment directive, point at our funclet. 192 Asm->OutStreamer->EmitLabel(Sym); 193 } 194 195 // Mark 'Sym' as starting our funclet. 196 if (shouldEmitMoves || shouldEmitPersonality) 197 Asm->OutStreamer->EmitWinCFIStartProc(Sym); 198 199 if (shouldEmitPersonality) { 200 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 201 const Function *PerFn = nullptr; 202 203 // Determine which personality routine we are using for this funclet. 204 if (F->hasPersonalityFn()) 205 PerFn = dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); 206 const MCSymbol *PersHandlerSym = 207 TLOF.getCFIPersonalitySymbol(PerFn, *Asm->Mang, Asm->TM, MMI); 208 209 // Classify the personality routine so that we may reason about it. 210 EHPersonality Per = EHPersonality::Unknown; 211 if (F->hasPersonalityFn()) 212 Per = classifyEHPersonality(F->getPersonalityFn()); 213 214 // Do not emit a .seh_handler directive if it is a C++ cleanup funclet. 215 if (Per != EHPersonality::MSVC_CXX || 216 !CurrentFuncletEntry->isCleanupFuncletEntry()) 217 Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true); 218 } 219 } 220 221 void WinException::endFunclet() { 222 // No funclet to process? Great, we have nothing to do. 223 if (!CurrentFuncletEntry) 224 return; 225 226 if (shouldEmitMoves || shouldEmitPersonality) { 227 const Function *F = Asm->MF->getFunction(); 228 EHPersonality Per = EHPersonality::Unknown; 229 if (F->hasPersonalityFn()) 230 Per = classifyEHPersonality(F->getPersonalityFn()); 231 232 // The .seh_handlerdata directive implicitly switches section, push the 233 // current section so that we may return to it. 234 Asm->OutStreamer->PushSection(); 235 236 // Emit an UNWIND_INFO struct describing the prologue. 237 Asm->OutStreamer->EmitWinEHHandlerData(); 238 239 if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality && 240 !CurrentFuncletEntry->isCleanupFuncletEntry()) { 241 // If this is a C++ catch funclet (or the parent function), 242 // emit a reference to the LSDA for the parent function. 243 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 244 MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol( 245 Twine("$cppxdata$", FuncLinkageName)); 246 Asm->OutStreamer->EmitValue(create32bitRef(FuncInfoXData), 4); 247 } else if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets() && 248 !CurrentFuncletEntry->isEHFuncletEntry()) { 249 // If this is the parent function in Win64 SEH, emit the LSDA immediately 250 // following .seh_handlerdata. 251 emitCSpecificHandlerTable(Asm->MF); 252 } 253 254 // Switch back to the previous section now that we are done writing to 255 // .xdata. 256 Asm->OutStreamer->PopSection(); 257 258 // Emit a .seh_endproc directive to mark the end of the function. 259 Asm->OutStreamer->EmitWinCFIEndProc(); 260 } 261 262 // Let's make sure we don't try to end the same funclet twice. 263 CurrentFuncletEntry = nullptr; 264 } 265 266 const MCExpr *WinException::create32bitRef(const MCSymbol *Value) { 267 if (!Value) 268 return MCConstantExpr::create(0, Asm->OutContext); 269 return MCSymbolRefExpr::create(Value, useImageRel32 270 ? MCSymbolRefExpr::VK_COFF_IMGREL32 271 : MCSymbolRefExpr::VK_None, 272 Asm->OutContext); 273 } 274 275 const MCExpr *WinException::create32bitRef(const GlobalValue *GV) { 276 if (!GV) 277 return MCConstantExpr::create(0, Asm->OutContext); 278 return create32bitRef(Asm->getSymbol(GV)); 279 } 280 281 const MCExpr *WinException::getLabelPlusOne(const MCSymbol *Label) { 282 return MCBinaryExpr::createAdd(create32bitRef(Label), 283 MCConstantExpr::create(1, Asm->OutContext), 284 Asm->OutContext); 285 } 286 287 const MCExpr *WinException::getOffset(const MCSymbol *OffsetOf, 288 const MCSymbol *OffsetFrom) { 289 return MCBinaryExpr::createSub( 290 MCSymbolRefExpr::create(OffsetOf, Asm->OutContext), 291 MCSymbolRefExpr::create(OffsetFrom, Asm->OutContext), Asm->OutContext); 292 } 293 294 const MCExpr *WinException::getOffsetPlusOne(const MCSymbol *OffsetOf, 295 const MCSymbol *OffsetFrom) { 296 return MCBinaryExpr::createAdd(getOffset(OffsetOf, OffsetFrom), 297 MCConstantExpr::create(1, Asm->OutContext), 298 Asm->OutContext); 299 } 300 301 int WinException::getFrameIndexOffset(int FrameIndex, 302 const WinEHFuncInfo &FuncInfo) { 303 const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering(); 304 unsigned UnusedReg; 305 if (Asm->MAI->usesWindowsCFI()) 306 return TFI.getFrameIndexReferenceFromSP(*Asm->MF, FrameIndex, UnusedReg); 307 // For 32-bit, offsets should be relative to the end of the EH registration 308 // node. For 64-bit, it's relative to SP at the end of the prologue. 309 assert(FuncInfo.EHRegNodeEndOffset != INT_MAX); 310 int Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg); 311 Offset += FuncInfo.EHRegNodeEndOffset; 312 return Offset; 313 } 314 315 namespace { 316 317 /// Top-level state used to represent unwind to caller 318 const int NullState = -1; 319 320 struct InvokeStateChange { 321 /// EH Label immediately after the last invoke in the previous state, or 322 /// nullptr if the previous state was the null state. 323 const MCSymbol *PreviousEndLabel; 324 325 /// EH label immediately before the first invoke in the new state, or nullptr 326 /// if the new state is the null state. 327 const MCSymbol *NewStartLabel; 328 329 /// State of the invoke following NewStartLabel, or NullState to indicate 330 /// the presence of calls which may unwind to caller. 331 int NewState; 332 }; 333 334 /// Iterator that reports all the invoke state changes in a range of machine 335 /// basic blocks. Changes to the null state are reported whenever a call that 336 /// may unwind to caller is encountered. The MBB range is expected to be an 337 /// entire function or funclet, and the start and end of the range are treated 338 /// as being in the NullState even if there's not an unwind-to-caller call 339 /// before the first invoke or after the last one (i.e., the first state change 340 /// reported is the first change to something other than NullState, and a 341 /// change back to NullState is always reported at the end of iteration). 342 class InvokeStateChangeIterator { 343 InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo, 344 MachineFunction::const_iterator MFI, 345 MachineFunction::const_iterator MFE, 346 MachineBasicBlock::const_iterator MBBI, 347 int BaseState) 348 : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) { 349 LastStateChange.PreviousEndLabel = nullptr; 350 LastStateChange.NewStartLabel = nullptr; 351 LastStateChange.NewState = BaseState; 352 scan(); 353 } 354 355 public: 356 static iterator_range<InvokeStateChangeIterator> 357 range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin, 358 MachineFunction::const_iterator End, int BaseState = NullState) { 359 // Reject empty ranges to simplify bookkeeping by ensuring that we can get 360 // the end of the last block. 361 assert(Begin != End); 362 auto BlockBegin = Begin->begin(); 363 auto BlockEnd = std::prev(End)->end(); 364 return make_range( 365 InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState), 366 InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState)); 367 } 368 369 // Iterator methods. 370 bool operator==(const InvokeStateChangeIterator &O) const { 371 assert(BaseState == O.BaseState); 372 // Must be visiting same block. 373 if (MFI != O.MFI) 374 return false; 375 // Must be visiting same isntr. 376 if (MBBI != O.MBBI) 377 return false; 378 // At end of block/instr iteration, we can still have two distinct states: 379 // one to report the final EndLabel, and another indicating the end of the 380 // state change iteration. Check for CurrentEndLabel equality to 381 // distinguish these. 382 return CurrentEndLabel == O.CurrentEndLabel; 383 } 384 385 bool operator!=(const InvokeStateChangeIterator &O) const { 386 return !operator==(O); 387 } 388 InvokeStateChange &operator*() { return LastStateChange; } 389 InvokeStateChange *operator->() { return &LastStateChange; } 390 InvokeStateChangeIterator &operator++() { return scan(); } 391 392 private: 393 InvokeStateChangeIterator &scan(); 394 395 const WinEHFuncInfo &EHInfo; 396 const MCSymbol *CurrentEndLabel = nullptr; 397 MachineFunction::const_iterator MFI; 398 MachineFunction::const_iterator MFE; 399 MachineBasicBlock::const_iterator MBBI; 400 InvokeStateChange LastStateChange; 401 bool VisitingInvoke = false; 402 int BaseState; 403 }; 404 405 } // end anonymous namespace 406 407 InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { 408 bool IsNewBlock = false; 409 for (; MFI != MFE; ++MFI, IsNewBlock = true) { 410 if (IsNewBlock) 411 MBBI = MFI->begin(); 412 for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) { 413 const MachineInstr &MI = *MBBI; 414 if (!VisitingInvoke && LastStateChange.NewState != BaseState && 415 MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) { 416 // Indicate a change of state to the null state. We don't have 417 // start/end EH labels handy but the caller won't expect them for 418 // null state regions. 419 LastStateChange.PreviousEndLabel = CurrentEndLabel; 420 LastStateChange.NewStartLabel = nullptr; 421 LastStateChange.NewState = BaseState; 422 CurrentEndLabel = nullptr; 423 // Don't re-visit this instr on the next scan 424 ++MBBI; 425 return *this; 426 } 427 428 // All other state changes are at EH labels before/after invokes. 429 if (!MI.isEHLabel()) 430 continue; 431 MCSymbol *Label = MI.getOperand(0).getMCSymbol(); 432 if (Label == CurrentEndLabel) { 433 VisitingInvoke = false; 434 continue; 435 } 436 auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label); 437 // Ignore EH labels that aren't the ones inserted before an invoke 438 if (InvokeMapIter == EHInfo.LabelToStateMap.end()) 439 continue; 440 auto &StateAndEnd = InvokeMapIter->second; 441 int NewState = StateAndEnd.first; 442 // Keep track of the fact that we're between EH start/end labels so 443 // we know not to treat the inoke we'll see as unwinding to caller. 444 VisitingInvoke = true; 445 if (NewState == LastStateChange.NewState) { 446 // The state isn't actually changing here. Record the new end and 447 // keep going. 448 CurrentEndLabel = StateAndEnd.second; 449 continue; 450 } 451 // Found a state change to report 452 LastStateChange.PreviousEndLabel = CurrentEndLabel; 453 LastStateChange.NewStartLabel = Label; 454 LastStateChange.NewState = NewState; 455 // Start keeping track of the new current end 456 CurrentEndLabel = StateAndEnd.second; 457 // Don't re-visit this instr on the next scan 458 ++MBBI; 459 return *this; 460 } 461 } 462 // Iteration hit the end of the block range. 463 if (LastStateChange.NewState != BaseState) { 464 // Report the end of the last new state 465 LastStateChange.PreviousEndLabel = CurrentEndLabel; 466 LastStateChange.NewStartLabel = nullptr; 467 LastStateChange.NewState = BaseState; 468 // Leave CurrentEndLabel non-null to distinguish this state from end. 469 assert(CurrentEndLabel != nullptr); 470 return *this; 471 } 472 // We've reported all state changes and hit the end state. 473 CurrentEndLabel = nullptr; 474 return *this; 475 } 476 477 /// Emit the language-specific data that __C_specific_handler expects. This 478 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning 479 /// up after faults with __try, __except, and __finally. The typeinfo values 480 /// are not really RTTI data, but pointers to filter functions that return an 481 /// integer (1, 0, or -1) indicating how to handle the exception. For __finally 482 /// blocks and other cleanups, the landing pad label is zero, and the filter 483 /// function is actually a cleanup handler with the same prototype. A catch-all 484 /// entry is modeled with a null filter function field and a non-zero landing 485 /// pad label. 486 /// 487 /// Possible filter function return values: 488 /// EXCEPTION_EXECUTE_HANDLER (1): 489 /// Jump to the landing pad label after cleanups. 490 /// EXCEPTION_CONTINUE_SEARCH (0): 491 /// Continue searching this table or continue unwinding. 492 /// EXCEPTION_CONTINUE_EXECUTION (-1): 493 /// Resume execution at the trapping PC. 494 /// 495 /// Inferred table structure: 496 /// struct Table { 497 /// int NumEntries; 498 /// struct Entry { 499 /// imagerel32 LabelStart; 500 /// imagerel32 LabelEnd; 501 /// imagerel32 FilterOrFinally; // One means catch-all. 502 /// imagerel32 LabelLPad; // Zero means __finally. 503 /// } Entries[NumEntries]; 504 /// }; 505 void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { 506 auto &OS = *Asm->OutStreamer; 507 MCContext &Ctx = Asm->OutContext; 508 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 509 510 bool VerboseAsm = OS.isVerboseAsm(); 511 auto AddComment = [&](const Twine &Comment) { 512 if (VerboseAsm) 513 OS.AddComment(Comment); 514 }; 515 516 // Emit a label assignment with the SEH frame offset so we can use it for 517 // llvm.x86.seh.recoverfp. 518 StringRef FLinkageName = 519 GlobalValue::getRealLinkageName(MF->getFunction()->getName()); 520 MCSymbol *ParentFrameOffset = 521 Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName); 522 const MCExpr *MCOffset = 523 MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx); 524 Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset); 525 526 // Use the assembler to compute the number of table entries through label 527 // difference and division. 528 MCSymbol *TableBegin = 529 Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true); 530 MCSymbol *TableEnd = 531 Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true); 532 const MCExpr *LabelDiff = getOffset(TableEnd, TableBegin); 533 const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx); 534 const MCExpr *EntryCount = MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx); 535 AddComment("Number of call sites"); 536 OS.EmitValue(EntryCount, 4); 537 538 OS.EmitLabel(TableBegin); 539 540 // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only 541 // models exceptions from invokes. LLVM also allows arbitrary reordering of 542 // the code, so our tables end up looking a bit different. Rather than 543 // trying to match MSVC's tables exactly, we emit a denormalized table. For 544 // each range of invokes in the same state, we emit table entries for all 545 // the actions that would be taken in that state. This means our tables are 546 // slightly bigger, which is OK. 547 const MCSymbol *LastStartLabel = nullptr; 548 int LastEHState = -1; 549 // Break out before we enter into a finally funclet. 550 // FIXME: We need to emit separate EH tables for cleanups. 551 MachineFunction::const_iterator End = MF->end(); 552 MachineFunction::const_iterator Stop = std::next(MF->begin()); 553 while (Stop != End && !Stop->isEHFuncletEntry()) 554 ++Stop; 555 for (const auto &StateChange : 556 InvokeStateChangeIterator::range(FuncInfo, MF->begin(), Stop)) { 557 // Emit all the actions for the state we just transitioned out of 558 // if it was not the null state 559 if (LastEHState != -1) 560 emitSEHActionsForRange(FuncInfo, LastStartLabel, 561 StateChange.PreviousEndLabel, LastEHState); 562 LastStartLabel = StateChange.NewStartLabel; 563 LastEHState = StateChange.NewState; 564 } 565 566 OS.EmitLabel(TableEnd); 567 } 568 569 void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo, 570 const MCSymbol *BeginLabel, 571 const MCSymbol *EndLabel, int State) { 572 auto &OS = *Asm->OutStreamer; 573 MCContext &Ctx = Asm->OutContext; 574 575 bool VerboseAsm = OS.isVerboseAsm(); 576 auto AddComment = [&](const Twine &Comment) { 577 if (VerboseAsm) 578 OS.AddComment(Comment); 579 }; 580 581 assert(BeginLabel && EndLabel); 582 while (State != -1) { 583 const SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State]; 584 const MCExpr *FilterOrFinally; 585 const MCExpr *ExceptOrNull; 586 auto *Handler = UME.Handler.get<MachineBasicBlock *>(); 587 if (UME.IsFinally) { 588 FilterOrFinally = create32bitRef(getMCSymbolForMBB(Asm, Handler)); 589 ExceptOrNull = MCConstantExpr::create(0, Ctx); 590 } else { 591 // For an except, the filter can be 1 (catch-all) or a function 592 // label. 593 FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter) 594 : MCConstantExpr::create(1, Ctx); 595 ExceptOrNull = create32bitRef(Handler->getSymbol()); 596 } 597 598 AddComment("LabelStart"); 599 OS.EmitValue(getLabelPlusOne(BeginLabel), 4); 600 AddComment("LabelEnd"); 601 OS.EmitValue(getLabelPlusOne(EndLabel), 4); 602 AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction" 603 : "CatchAll"); 604 OS.EmitValue(FilterOrFinally, 4); 605 AddComment(UME.IsFinally ? "Null" : "ExceptionHandler"); 606 OS.EmitValue(ExceptOrNull, 4); 607 608 assert(UME.ToState < State && "states should decrease"); 609 State = UME.ToState; 610 } 611 } 612 613 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { 614 const Function *F = MF->getFunction(); 615 auto &OS = *Asm->OutStreamer; 616 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 617 618 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 619 620 SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable; 621 MCSymbol *FuncInfoXData = nullptr; 622 if (shouldEmitPersonality) { 623 // If we're 64-bit, emit a pointer to the C++ EH data, and build a map from 624 // IPs to state numbers. 625 FuncInfoXData = 626 Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName)); 627 computeIP2StateTable(MF, FuncInfo, IPToStateTable); 628 } else { 629 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName); 630 } 631 632 int UnwindHelpOffset = 0; 633 if (Asm->MAI->usesWindowsCFI()) 634 UnwindHelpOffset = 635 getFrameIndexOffset(FuncInfo.UnwindHelpFrameIdx, FuncInfo); 636 637 MCSymbol *UnwindMapXData = nullptr; 638 MCSymbol *TryBlockMapXData = nullptr; 639 MCSymbol *IPToStateXData = nullptr; 640 if (!FuncInfo.CxxUnwindMap.empty()) 641 UnwindMapXData = Asm->OutContext.getOrCreateSymbol( 642 Twine("$stateUnwindMap$", FuncLinkageName)); 643 if (!FuncInfo.TryBlockMap.empty()) 644 TryBlockMapXData = 645 Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName)); 646 if (!IPToStateTable.empty()) 647 IPToStateXData = 648 Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName)); 649 650 bool VerboseAsm = OS.isVerboseAsm(); 651 auto AddComment = [&](const Twine &Comment) { 652 if (VerboseAsm) 653 OS.AddComment(Comment); 654 }; 655 656 // FuncInfo { 657 // uint32_t MagicNumber 658 // int32_t MaxState; 659 // UnwindMapEntry *UnwindMap; 660 // uint32_t NumTryBlocks; 661 // TryBlockMapEntry *TryBlockMap; 662 // uint32_t IPMapEntries; // always 0 for x86 663 // IPToStateMapEntry *IPToStateMap; // always 0 for x86 664 // uint32_t UnwindHelp; // non-x86 only 665 // ESTypeList *ESTypeList; 666 // int32_t EHFlags; 667 // } 668 // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. 669 // EHFlags & 2 -> ??? 670 // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. 671 OS.EmitValueToAlignment(4); 672 OS.EmitLabel(FuncInfoXData); 673 674 AddComment("MagicNumber"); 675 OS.EmitIntValue(0x19930522, 4); 676 677 AddComment("MaxState"); 678 OS.EmitIntValue(FuncInfo.CxxUnwindMap.size(), 4); 679 680 AddComment("UnwindMap"); 681 OS.EmitValue(create32bitRef(UnwindMapXData), 4); 682 683 AddComment("NumTryBlocks"); 684 OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); 685 686 AddComment("TryBlockMap"); 687 OS.EmitValue(create32bitRef(TryBlockMapXData), 4); 688 689 AddComment("IPMapEntries"); 690 OS.EmitIntValue(IPToStateTable.size(), 4); 691 692 AddComment("IPToStateXData"); 693 OS.EmitValue(create32bitRef(IPToStateXData), 4); 694 695 if (Asm->MAI->usesWindowsCFI()) { 696 AddComment("UnwindHelp"); 697 OS.EmitIntValue(UnwindHelpOffset, 4); 698 } 699 700 AddComment("ESTypeList"); 701 OS.EmitIntValue(0, 4); 702 703 AddComment("EHFlags"); 704 OS.EmitIntValue(1, 4); 705 706 // UnwindMapEntry { 707 // int32_t ToState; 708 // void (*Action)(); 709 // }; 710 if (UnwindMapXData) { 711 OS.EmitLabel(UnwindMapXData); 712 for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) { 713 MCSymbol *CleanupSym = 714 getMCSymbolForMBB(Asm, UME.Cleanup.dyn_cast<MachineBasicBlock *>()); 715 AddComment("ToState"); 716 OS.EmitIntValue(UME.ToState, 4); 717 718 AddComment("Action"); 719 OS.EmitValue(create32bitRef(CleanupSym), 4); 720 } 721 } 722 723 // TryBlockMap { 724 // int32_t TryLow; 725 // int32_t TryHigh; 726 // int32_t CatchHigh; 727 // int32_t NumCatches; 728 // HandlerType *HandlerArray; 729 // }; 730 if (TryBlockMapXData) { 731 OS.EmitLabel(TryBlockMapXData); 732 SmallVector<MCSymbol *, 1> HandlerMaps; 733 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 734 const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 735 736 MCSymbol *HandlerMapXData = nullptr; 737 if (!TBME.HandlerArray.empty()) 738 HandlerMapXData = 739 Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") 740 .concat(Twine(I)) 741 .concat("$") 742 .concat(FuncLinkageName)); 743 HandlerMaps.push_back(HandlerMapXData); 744 745 // TBMEs should form intervals. 746 assert(0 <= TBME.TryLow && "bad trymap interval"); 747 assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval"); 748 assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval"); 749 assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) && 750 "bad trymap interval"); 751 752 AddComment("TryLow"); 753 OS.EmitIntValue(TBME.TryLow, 4); 754 755 AddComment("TryHigh"); 756 OS.EmitIntValue(TBME.TryHigh, 4); 757 758 AddComment("CatchHigh"); 759 OS.EmitIntValue(TBME.CatchHigh, 4); 760 761 AddComment("NumCatches"); 762 OS.EmitIntValue(TBME.HandlerArray.size(), 4); 763 764 AddComment("HandlerArray"); 765 OS.EmitValue(create32bitRef(HandlerMapXData), 4); 766 } 767 768 // All funclets use the same parent frame offset currently. 769 unsigned ParentFrameOffset = 0; 770 if (shouldEmitPersonality) { 771 const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); 772 ParentFrameOffset = TFI->getWinEHParentFrameOffset(*MF); 773 } 774 775 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 776 const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 777 MCSymbol *HandlerMapXData = HandlerMaps[I]; 778 if (!HandlerMapXData) 779 continue; 780 // HandlerType { 781 // int32_t Adjectives; 782 // TypeDescriptor *Type; 783 // int32_t CatchObjOffset; 784 // void (*Handler)(); 785 // int32_t ParentFrameOffset; // x64 only 786 // }; 787 OS.EmitLabel(HandlerMapXData); 788 for (const WinEHHandlerType &HT : TBME.HandlerArray) { 789 // Get the frame escape label with the offset of the catch object. If 790 // the index is INT_MAX, then there is no catch object, and we should 791 // emit an offset of zero, indicating that no copy will occur. 792 const MCExpr *FrameAllocOffsetRef = nullptr; 793 if (HT.CatchObj.FrameIndex != INT_MAX) { 794 int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex, FuncInfo); 795 assert(Offset != 0 && "Illegal offset for catch object!"); 796 FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext); 797 } else { 798 FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext); 799 } 800 801 MCSymbol *HandlerSym = 802 getMCSymbolForMBB(Asm, HT.Handler.dyn_cast<MachineBasicBlock *>()); 803 804 AddComment("Adjectives"); 805 OS.EmitIntValue(HT.Adjectives, 4); 806 807 AddComment("Type"); 808 OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); 809 810 AddComment("CatchObjOffset"); 811 OS.EmitValue(FrameAllocOffsetRef, 4); 812 813 AddComment("Handler"); 814 OS.EmitValue(create32bitRef(HandlerSym), 4); 815 816 if (shouldEmitPersonality) { 817 AddComment("ParentFrameOffset"); 818 OS.EmitIntValue(ParentFrameOffset, 4); 819 } 820 } 821 } 822 } 823 824 // IPToStateMapEntry { 825 // void *IP; 826 // int32_t State; 827 // }; 828 if (IPToStateXData) { 829 OS.EmitLabel(IPToStateXData); 830 for (auto &IPStatePair : IPToStateTable) { 831 AddComment("IP"); 832 OS.EmitValue(IPStatePair.first, 4); 833 AddComment("ToState"); 834 OS.EmitIntValue(IPStatePair.second, 4); 835 } 836 } 837 } 838 839 void WinException::computeIP2StateTable( 840 const MachineFunction *MF, const WinEHFuncInfo &FuncInfo, 841 SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) { 842 843 for (MachineFunction::const_iterator FuncletStart = MF->begin(), 844 FuncletEnd = MF->begin(), 845 End = MF->end(); 846 FuncletStart != End; FuncletStart = FuncletEnd) { 847 // Find the end of the funclet 848 while (++FuncletEnd != End) { 849 if (FuncletEnd->isEHFuncletEntry()) { 850 break; 851 } 852 } 853 854 // Don't emit ip2state entries for cleanup funclets. Any interesting 855 // exceptional actions in cleanups must be handled in a separate IR 856 // function. 857 if (FuncletStart->isCleanupFuncletEntry()) 858 continue; 859 860 MCSymbol *StartLabel; 861 int BaseState; 862 if (FuncletStart == MF->begin()) { 863 BaseState = NullState; 864 StartLabel = Asm->getFunctionBegin(); 865 } else { 866 auto *FuncletPad = 867 cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI()); 868 assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0); 869 BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second; 870 StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart); 871 } 872 assert(StartLabel && "need local function start label"); 873 IPToStateTable.push_back( 874 std::make_pair(create32bitRef(StartLabel), BaseState)); 875 876 for (const auto &StateChange : InvokeStateChangeIterator::range( 877 FuncInfo, FuncletStart, FuncletEnd, BaseState)) { 878 // Compute the label to report as the start of this entry; use the EH 879 // start label for the invoke if we have one, otherwise (this is a call 880 // which may unwind to our caller and does not have an EH start label, so) 881 // use the previous end label. 882 const MCSymbol *ChangeLabel = StateChange.NewStartLabel; 883 if (!ChangeLabel) 884 ChangeLabel = StateChange.PreviousEndLabel; 885 // Emit an entry indicating that PCs after 'Label' have this EH state. 886 IPToStateTable.push_back( 887 std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState)); 888 // FIXME: assert that NewState is between CatchLow and CatchHigh. 889 } 890 } 891 } 892 893 void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, 894 StringRef FLinkageName) { 895 // Outlined helpers called by the EH runtime need to know the offset of the EH 896 // registration in order to recover the parent frame pointer. Now that we know 897 // we've code generated the parent, we can emit the label assignment that 898 // those helpers use to get the offset of the registration node. 899 MCContext &Ctx = Asm->OutContext; 900 MCSymbol *ParentFrameOffset = 901 Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName); 902 unsigned UnusedReg; 903 const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); 904 int64_t Offset = TFI->getFrameIndexReference( 905 *Asm->MF, FuncInfo.EHRegNodeFrameIndex, UnusedReg); 906 const MCExpr *MCOffset = MCConstantExpr::create(Offset, Ctx); 907 Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset); 908 } 909 910 /// Emit the language-specific data that _except_handler3 and 4 expect. This is 911 /// functionally equivalent to the __C_specific_handler table, except it is 912 /// indexed by state number instead of IP. 913 void WinException::emitExceptHandlerTable(const MachineFunction *MF) { 914 MCStreamer &OS = *Asm->OutStreamer; 915 const Function *F = MF->getFunction(); 916 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName()); 917 918 bool VerboseAsm = OS.isVerboseAsm(); 919 auto AddComment = [&](const Twine &Comment) { 920 if (VerboseAsm) 921 OS.AddComment(Comment); 922 }; 923 924 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 925 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName); 926 927 // Emit the __ehtable label that we use for llvm.x86.seh.lsda. 928 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); 929 OS.EmitValueToAlignment(4); 930 OS.EmitLabel(LSDALabel); 931 932 const Function *Per = 933 dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); 934 StringRef PerName = Per->getName(); 935 int BaseState = -1; 936 if (PerName == "_except_handler4") { 937 // The LSDA for _except_handler4 starts with this struct, followed by the 938 // scope table: 939 // 940 // struct EH4ScopeTable { 941 // int32_t GSCookieOffset; 942 // int32_t GSCookieXOROffset; 943 // int32_t EHCookieOffset; 944 // int32_t EHCookieXOROffset; 945 // ScopeTableEntry ScopeRecord[]; 946 // }; 947 // 948 // Only the EHCookieOffset field appears to vary, and it appears to be the 949 // offset from the final saved SP value to the retaddr. 950 AddComment("GSCookieOffset"); 951 OS.EmitIntValue(-2, 4); 952 AddComment("GSCookieXOROffset"); 953 OS.EmitIntValue(0, 4); 954 // FIXME: Calculate. 955 AddComment("EHCookieOffset"); 956 OS.EmitIntValue(9999, 4); 957 AddComment("EHCookieXOROffset"); 958 OS.EmitIntValue(0, 4); 959 BaseState = -2; 960 } 961 962 assert(!FuncInfo.SEHUnwindMap.empty()); 963 for (const SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) { 964 auto *Handler = UME.Handler.get<MachineBasicBlock *>(); 965 const MCSymbol *ExceptOrFinally = 966 UME.IsFinally ? getMCSymbolForMBB(Asm, Handler) : Handler->getSymbol(); 967 // -1 is usually the base state for "unwind to caller", but for 968 // _except_handler4 it's -2. Do that replacement here if necessary. 969 int ToState = UME.ToState == -1 ? BaseState : UME.ToState; 970 AddComment("ToState"); 971 OS.EmitIntValue(ToState, 4); 972 AddComment(UME.IsFinally ? "Null" : "FilterFunction"); 973 OS.EmitValue(create32bitRef(UME.Filter), 4); 974 AddComment(UME.IsFinally ? "FinallyFunclet" : "ExceptionHandler"); 975 OS.EmitValue(create32bitRef(ExceptOrFinally), 4); 976 } 977 } 978 979 static int getTryRank(const WinEHFuncInfo &FuncInfo, int State) { 980 int Rank = 0; 981 while (State != -1) { 982 ++Rank; 983 State = FuncInfo.ClrEHUnwindMap[State].TryParentState; 984 } 985 return Rank; 986 } 987 988 static int getTryAncestor(const WinEHFuncInfo &FuncInfo, int Left, int Right) { 989 int LeftRank = getTryRank(FuncInfo, Left); 990 int RightRank = getTryRank(FuncInfo, Right); 991 992 while (LeftRank < RightRank) { 993 Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState; 994 --RightRank; 995 } 996 997 while (RightRank < LeftRank) { 998 Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState; 999 --LeftRank; 1000 } 1001 1002 while (Left != Right) { 1003 Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState; 1004 Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState; 1005 } 1006 1007 return Left; 1008 } 1009 1010 void WinException::emitCLRExceptionTable(const MachineFunction *MF) { 1011 // CLR EH "states" are really just IDs that identify handlers/funclets; 1012 // states, handlers, and funclets all have 1:1 mappings between them, and a 1013 // handler/funclet's "state" is its index in the ClrEHUnwindMap. 1014 MCStreamer &OS = *Asm->OutStreamer; 1015 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 1016 MCSymbol *FuncBeginSym = Asm->getFunctionBegin(); 1017 MCSymbol *FuncEndSym = Asm->getFunctionEnd(); 1018 1019 // A ClrClause describes a protected region. 1020 struct ClrClause { 1021 const MCSymbol *StartLabel; // Start of protected region 1022 const MCSymbol *EndLabel; // End of protected region 1023 int State; // Index of handler protecting the protected region 1024 int EnclosingState; // Index of funclet enclosing the protected region 1025 }; 1026 SmallVector<ClrClause, 8> Clauses; 1027 1028 // Build a map from handler MBBs to their corresponding states (i.e. their 1029 // indices in the ClrEHUnwindMap). 1030 int NumStates = FuncInfo.ClrEHUnwindMap.size(); 1031 assert(NumStates > 0 && "Don't need exception table!"); 1032 DenseMap<const MachineBasicBlock *, int> HandlerStates; 1033 for (int State = 0; State < NumStates; ++State) { 1034 MachineBasicBlock *HandlerBlock = 1035 FuncInfo.ClrEHUnwindMap[State].Handler.get<MachineBasicBlock *>(); 1036 HandlerStates[HandlerBlock] = State; 1037 // Use this loop through all handlers to verify our assumption (used in 1038 // the MinEnclosingState computation) that enclosing funclets have lower 1039 // state numbers than their enclosed funclets. 1040 assert(FuncInfo.ClrEHUnwindMap[State].HandlerParentState < State && 1041 "ill-formed state numbering"); 1042 } 1043 // Map the main function to the NullState. 1044 HandlerStates[&MF->front()] = NullState; 1045 1046 // Write out a sentinel indicating the end of the standard (Windows) xdata 1047 // and the start of the additional (CLR) info. 1048 OS.EmitIntValue(0xffffffff, 4); 1049 // Write out the number of funclets 1050 OS.EmitIntValue(NumStates, 4); 1051 1052 // Walk the machine blocks/instrs, computing and emitting a few things: 1053 // 1. Emit a list of the offsets to each handler entry, in lexical order. 1054 // 2. Compute a map (EndSymbolMap) from each funclet to the symbol at its end. 1055 // 3. Compute the list of ClrClauses, in the required order (inner before 1056 // outer, earlier before later; the order by which a forward scan with 1057 // early termination will find the innermost enclosing clause covering 1058 // a given address). 1059 // 4. A map (MinClauseMap) from each handler index to the index of the 1060 // outermost funclet/function which contains a try clause targeting the 1061 // key handler. This will be used to determine IsDuplicate-ness when 1062 // emitting ClrClauses. The NullState value is used to indicate that the 1063 // top-level function contains a try clause targeting the key handler. 1064 // HandlerStack is a stack of (PendingStartLabel, PendingState) pairs for 1065 // try regions we entered before entering the PendingState try but which 1066 // we haven't yet exited. 1067 SmallVector<std::pair<const MCSymbol *, int>, 4> HandlerStack; 1068 // EndSymbolMap and MinClauseMap are maps described above. 1069 std::unique_ptr<MCSymbol *[]> EndSymbolMap(new MCSymbol *[NumStates]); 1070 SmallVector<int, 4> MinClauseMap((size_t)NumStates, NumStates); 1071 1072 // Visit the root function and each funclet. 1073 for (MachineFunction::const_iterator FuncletStart = MF->begin(), 1074 FuncletEnd = MF->begin(), 1075 End = MF->end(); 1076 FuncletStart != End; FuncletStart = FuncletEnd) { 1077 int FuncletState = HandlerStates[&*FuncletStart]; 1078 // Find the end of the funclet 1079 MCSymbol *EndSymbol = FuncEndSym; 1080 while (++FuncletEnd != End) { 1081 if (FuncletEnd->isEHFuncletEntry()) { 1082 EndSymbol = getMCSymbolForMBB(Asm, &*FuncletEnd); 1083 break; 1084 } 1085 } 1086 // Emit the function/funclet end and, if this is a funclet (and not the 1087 // root function), record it in the EndSymbolMap. 1088 OS.EmitValue(getOffset(EndSymbol, FuncBeginSym), 4); 1089 if (FuncletState != NullState) { 1090 // Record the end of the handler. 1091 EndSymbolMap[FuncletState] = EndSymbol; 1092 } 1093 1094 // Walk the state changes in this function/funclet and compute its clauses. 1095 // Funclets always start in the null state. 1096 const MCSymbol *CurrentStartLabel = nullptr; 1097 int CurrentState = NullState; 1098 assert(HandlerStack.empty()); 1099 for (const auto &StateChange : 1100 InvokeStateChangeIterator::range(FuncInfo, FuncletStart, FuncletEnd)) { 1101 // Close any try regions we're not still under 1102 int StillPendingState = 1103 getTryAncestor(FuncInfo, CurrentState, StateChange.NewState); 1104 while (CurrentState != StillPendingState) { 1105 assert(CurrentState != NullState && 1106 "Failed to find still-pending state!"); 1107 // Close the pending clause 1108 Clauses.push_back({CurrentStartLabel, StateChange.PreviousEndLabel, 1109 CurrentState, FuncletState}); 1110 // Now the next-outer try region is current 1111 CurrentState = FuncInfo.ClrEHUnwindMap[CurrentState].TryParentState; 1112 // Pop the new start label from the handler stack if we've exited all 1113 // inner try regions of the corresponding try region. 1114 if (HandlerStack.back().second == CurrentState) 1115 CurrentStartLabel = HandlerStack.pop_back_val().first; 1116 } 1117 1118 if (StateChange.NewState != CurrentState) { 1119 // For each clause we're starting, update the MinClauseMap so we can 1120 // know which is the topmost funclet containing a clause targeting 1121 // it. 1122 for (int EnteredState = StateChange.NewState; 1123 EnteredState != CurrentState; 1124 EnteredState = 1125 FuncInfo.ClrEHUnwindMap[EnteredState].TryParentState) { 1126 int &MinEnclosingState = MinClauseMap[EnteredState]; 1127 if (FuncletState < MinEnclosingState) 1128 MinEnclosingState = FuncletState; 1129 } 1130 // Save the previous current start/label on the stack and update to 1131 // the newly-current start/state. 1132 HandlerStack.emplace_back(CurrentStartLabel, CurrentState); 1133 CurrentStartLabel = StateChange.NewStartLabel; 1134 CurrentState = StateChange.NewState; 1135 } 1136 } 1137 assert(HandlerStack.empty()); 1138 } 1139 1140 // Now emit the clause info, starting with the number of clauses. 1141 OS.EmitIntValue(Clauses.size(), 4); 1142 for (ClrClause &Clause : Clauses) { 1143 // Emit a CORINFO_EH_CLAUSE : 1144 /* 1145 struct CORINFO_EH_CLAUSE 1146 { 1147 CORINFO_EH_CLAUSE_FLAGS Flags; // actually a CorExceptionFlag 1148 DWORD TryOffset; 1149 DWORD TryLength; // actually TryEndOffset 1150 DWORD HandlerOffset; 1151 DWORD HandlerLength; // actually HandlerEndOffset 1152 union 1153 { 1154 DWORD ClassToken; // use for catch clauses 1155 DWORD FilterOffset; // use for filter clauses 1156 }; 1157 }; 1158 1159 enum CORINFO_EH_CLAUSE_FLAGS 1160 { 1161 CORINFO_EH_CLAUSE_NONE = 0, 1162 CORINFO_EH_CLAUSE_FILTER = 0x0001, // This clause is for a filter 1163 CORINFO_EH_CLAUSE_FINALLY = 0x0002, // This clause is a finally clause 1164 CORINFO_EH_CLAUSE_FAULT = 0x0004, // This clause is a fault clause 1165 }; 1166 typedef enum CorExceptionFlag 1167 { 1168 COR_ILEXCEPTION_CLAUSE_NONE, 1169 COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001, // This is a filter clause 1170 COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002, // This is a finally clause 1171 COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004, // This is a fault clause 1172 COR_ILEXCEPTION_CLAUSE_DUPLICATED = 0x0008, // duplicated clause. This 1173 // clause was duplicated 1174 // to a funclet which was 1175 // pulled out of line 1176 } CorExceptionFlag; 1177 */ 1178 // Add 1 to the start/end of the EH clause; the IP associated with a 1179 // call when the runtime does its scan is the IP of the next instruction 1180 // (the one to which control will return after the call), so we need 1181 // to add 1 to the end of the clause to cover that offset. We also add 1182 // 1 to the start of the clause to make sure that the ranges reported 1183 // for all clauses are disjoint. Note that we'll need some additional 1184 // logic when machine traps are supported, since in that case the IP 1185 // that the runtime uses is the offset of the faulting instruction 1186 // itself; if such an instruction immediately follows a call but the 1187 // two belong to different clauses, we'll need to insert a nop between 1188 // them so the runtime can distinguish the point to which the call will 1189 // return from the point at which the fault occurs. 1190 1191 const MCExpr *ClauseBegin = 1192 getOffsetPlusOne(Clause.StartLabel, FuncBeginSym); 1193 const MCExpr *ClauseEnd = getOffsetPlusOne(Clause.EndLabel, FuncBeginSym); 1194 1195 const ClrEHUnwindMapEntry &Entry = FuncInfo.ClrEHUnwindMap[Clause.State]; 1196 MachineBasicBlock *HandlerBlock = Entry.Handler.get<MachineBasicBlock *>(); 1197 MCSymbol *BeginSym = getMCSymbolForMBB(Asm, HandlerBlock); 1198 const MCExpr *HandlerBegin = getOffset(BeginSym, FuncBeginSym); 1199 MCSymbol *EndSym = EndSymbolMap[Clause.State]; 1200 const MCExpr *HandlerEnd = getOffset(EndSym, FuncBeginSym); 1201 1202 uint32_t Flags = 0; 1203 switch (Entry.HandlerType) { 1204 case ClrHandlerType::Catch: 1205 // Leaving bits 0-2 clear indicates catch. 1206 break; 1207 case ClrHandlerType::Filter: 1208 Flags |= 1; 1209 break; 1210 case ClrHandlerType::Finally: 1211 Flags |= 2; 1212 break; 1213 case ClrHandlerType::Fault: 1214 Flags |= 4; 1215 break; 1216 } 1217 if (Clause.EnclosingState != MinClauseMap[Clause.State]) { 1218 // This is a "duplicate" clause; the handler needs to be entered from a 1219 // frame above the one holding the invoke. 1220 assert(Clause.EnclosingState > MinClauseMap[Clause.State]); 1221 Flags |= 8; 1222 } 1223 OS.EmitIntValue(Flags, 4); 1224 1225 // Write the clause start/end 1226 OS.EmitValue(ClauseBegin, 4); 1227 OS.EmitValue(ClauseEnd, 4); 1228 1229 // Write out the handler start/end 1230 OS.EmitValue(HandlerBegin, 4); 1231 OS.EmitValue(HandlerEnd, 4); 1232 1233 // Write out the type token or filter offset 1234 assert(Entry.HandlerType != ClrHandlerType::Filter && "NYI: filters"); 1235 OS.EmitIntValue(Entry.TypeToken, 4); 1236 } 1237 } 1238