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