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