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