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