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