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