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