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