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