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