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 using namespace llvm; 42 43 WinException::WinException(AsmPrinter *A) : EHStreamer(A) { 44 // MSVC's EH tables are always composed of 32-bit words. All known 64-bit 45 // platforms use an imagerel32 relocation to refer to symbols. 46 useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64); 47 } 48 49 WinException::~WinException() {} 50 51 /// endModule - Emit all exception information that should come after the 52 /// content. 53 void WinException::endModule() { 54 auto &OS = *Asm->OutStreamer; 55 const Module *M = MMI->getModule(); 56 for (const Function &F : *M) 57 if (F.hasFnAttribute("safeseh")) 58 OS.EmitCOFFSafeSEH(Asm->getSymbol(&F)); 59 } 60 61 void WinException::beginFunction(const MachineFunction *MF) { 62 shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; 63 64 // If any landing pads survive, we need an EH table. 65 bool hasLandingPads = !MMI->getLandingPads().empty(); 66 bool hasEHFunclets = MMI->hasEHFunclets(); 67 68 const Function *F = MF->getFunction(); 69 const Function *ParentF = MMI->getWinEHParent(F); 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 // FIXME: If WinEHPrepare outlined something, we should emit the LSDA. Remove 94 // this once WinEHPrepare stops doing that. 95 if (!Asm->MAI->usesWindowsCFI()) { 96 shouldEmitLSDA = 97 hasEHFunclets || (F->hasFnAttribute("wineh-parent") && F == ParentF); 98 shouldEmitPersonality = false; 99 return; 100 } 101 102 beginFunclet(MF->front(), Asm->CurrentFnSym); 103 } 104 105 /// endFunction - Gather and emit post-function exception information. 106 /// 107 void WinException::endFunction(const MachineFunction *MF) { 108 if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA) 109 return; 110 111 const Function *F = MF->getFunction(); 112 EHPersonality Per = EHPersonality::Unknown; 113 if (F->hasPersonalityFn()) 114 Per = classifyEHPersonality(F->getPersonalityFn()); 115 116 // Get rid of any dead landing pads if we're not using a Windows EH scheme. In 117 // Windows EH schemes, the landing pad is not actually reachable. It only 118 // exists so that we can emit the right table data. 119 if (!isMSVCEHPersonality(Per)) 120 MMI->TidyLandingPads(); 121 122 endFunclet(); 123 124 // endFunclet will emit the necessary .xdata tables for x64 SEH. 125 if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets()) 126 return; 127 128 if (shouldEmitPersonality || shouldEmitLSDA) { 129 Asm->OutStreamer->PushSection(); 130 131 // Just switch sections to the right xdata section. This use of CurrentFnSym 132 // assumes that we only emit the LSDA when ending the parent function. 133 MCSection *XData = WinEH::UnwindEmitter::getXDataSection(Asm->CurrentFnSym, 134 Asm->OutContext); 135 Asm->OutStreamer->SwitchSection(XData); 136 137 // Emit the tables appropriate to the personality function in use. If we 138 // don't recognize the personality, assume it uses an Itanium-style LSDA. 139 if (Per == EHPersonality::MSVC_Win64SEH) 140 emitCSpecificHandlerTable(MF); 141 else if (Per == EHPersonality::MSVC_X86SEH) 142 emitExceptHandlerTable(MF); 143 else if (Per == EHPersonality::MSVC_CXX) 144 emitCXXFrameHandler3Table(MF); 145 else 146 emitExceptionTable(); 147 148 Asm->OutStreamer->PopSection(); 149 } 150 } 151 152 /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues 153 /// are used in the old WinEH scheme, and they will be removed eventually. 154 static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) { 155 if (!Handler) 156 return nullptr; 157 if (Handler.is<const MachineBasicBlock *>()) { 158 auto *MBB = Handler.get<const MachineBasicBlock *>(); 159 assert(MBB->isEHFuncletEntry()); 160 161 // Give catches and cleanups a name based off of their parent function and 162 // their funclet entry block's number. 163 const MachineFunction *MF = MBB->getParent(); 164 const Function *F = MF->getFunction(); 165 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 166 MCContext &Ctx = MF->getContext(); 167 StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch"; 168 return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" + 169 Twine(MBB->getNumber()) + "@?0?" + 170 FuncLinkageName + "@4HA"); 171 } 172 return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>())); 173 } 174 175 void WinException::beginFunclet(const MachineBasicBlock &MBB, 176 MCSymbol *Sym) { 177 CurrentFuncletEntry = &MBB; 178 179 const Function *F = Asm->MF->getFunction(); 180 // If a symbol was not provided for the funclet, invent one. 181 if (!Sym) { 182 Sym = getMCSymbolForMBBOrGV(Asm, &MBB); 183 184 // Describe our funclet symbol as a function with internal linkage. 185 Asm->OutStreamer->BeginCOFFSymbolDef(Sym); 186 Asm->OutStreamer->EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC); 187 Asm->OutStreamer->EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION 188 << COFF::SCT_COMPLEX_TYPE_SHIFT); 189 Asm->OutStreamer->EndCOFFSymbolDef(); 190 191 // We want our funclet's entry point to be aligned such that no nops will be 192 // present after the label. 193 Asm->EmitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()), 194 F); 195 196 // Now that we've emitted the alignment directive, point at our funclet. 197 Asm->OutStreamer->EmitLabel(Sym); 198 } 199 200 // Mark 'Sym' as starting our funclet. 201 if (shouldEmitMoves || shouldEmitPersonality) 202 Asm->OutStreamer->EmitWinCFIStartProc(Sym); 203 204 if (shouldEmitPersonality) { 205 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 206 const Function *PerFn = nullptr; 207 208 // Determine which personality routine we are using for this funclet. 209 if (F->hasPersonalityFn()) 210 PerFn = dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); 211 const MCSymbol *PersHandlerSym = 212 TLOF.getCFIPersonalitySymbol(PerFn, *Asm->Mang, Asm->TM, MMI); 213 214 // Classify the personality routine so that we may reason about it. 215 EHPersonality Per = EHPersonality::Unknown; 216 if (F->hasPersonalityFn()) 217 Per = classifyEHPersonality(F->getPersonalityFn()); 218 219 // Do not emit a .seh_handler directive if it is a C++ cleanup funclet. 220 if (Per != EHPersonality::MSVC_CXX || 221 !CurrentFuncletEntry->isCleanupFuncletEntry()) 222 Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true); 223 } 224 } 225 226 void WinException::endFunclet() { 227 // No funclet to process? Great, we have nothing to do. 228 if (!CurrentFuncletEntry) 229 return; 230 231 if (shouldEmitMoves || shouldEmitPersonality) { 232 const Function *F = Asm->MF->getFunction(); 233 EHPersonality Per = EHPersonality::Unknown; 234 if (F->hasPersonalityFn()) 235 Per = classifyEHPersonality(F->getPersonalityFn()); 236 237 // The .seh_handlerdata directive implicitly switches section, push the 238 // current section so that we may return to it. 239 Asm->OutStreamer->PushSection(); 240 241 // Emit an UNWIND_INFO struct describing the prologue. 242 Asm->OutStreamer->EmitWinEHHandlerData(); 243 244 if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality && 245 !CurrentFuncletEntry->isCleanupFuncletEntry()) { 246 // If this is a C++ catch funclet (or the parent function), 247 // emit a reference to the LSDA for the parent function. 248 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 249 MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol( 250 Twine("$cppxdata$", FuncLinkageName)); 251 Asm->OutStreamer->EmitValue(create32bitRef(FuncInfoXData), 4); 252 } else if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets() && 253 !CurrentFuncletEntry->isEHFuncletEntry()) { 254 // If this is the parent function in Win64 SEH, emit the LSDA immediately 255 // following .seh_handlerdata. 256 emitCSpecificHandlerTable(Asm->MF); 257 } 258 259 // Switch back to the previous section now that we are done writing to 260 // .xdata. 261 Asm->OutStreamer->PopSection(); 262 263 // Emit a .seh_endproc directive to mark the end of the function. 264 Asm->OutStreamer->EmitWinCFIEndProc(); 265 } 266 267 // Let's make sure we don't try to end the same funclet twice. 268 CurrentFuncletEntry = nullptr; 269 } 270 271 const MCExpr *WinException::create32bitRef(const MCSymbol *Value) { 272 if (!Value) 273 return MCConstantExpr::create(0, Asm->OutContext); 274 return MCSymbolRefExpr::create(Value, useImageRel32 275 ? MCSymbolRefExpr::VK_COFF_IMGREL32 276 : MCSymbolRefExpr::VK_None, 277 Asm->OutContext); 278 } 279 280 const MCExpr *WinException::create32bitRef(const Value *V) { 281 if (!V) 282 return MCConstantExpr::create(0, Asm->OutContext); 283 // FIXME: Delete the GlobalValue case once the new IR is fully functional. 284 if (const auto *GV = dyn_cast<GlobalValue>(V)) 285 return create32bitRef(Asm->getSymbol(GV)); 286 return create32bitRef(MMI->getAddrLabelSymbol(cast<BasicBlock>(V))); 287 } 288 289 const MCExpr *WinException::getLabelPlusOne(MCSymbol *Label) { 290 return MCBinaryExpr::createAdd(create32bitRef(Label), 291 MCConstantExpr::create(1, Asm->OutContext), 292 Asm->OutContext); 293 } 294 295 namespace { 296 /// Information describing an invoke range. 297 struct InvokeRange { 298 MCSymbol *BeginLabel = nullptr; 299 MCSymbol *EndLabel = nullptr; 300 int State = -1; 301 302 /// If we saw a potentially throwing call between this range and the last 303 /// range. 304 bool SawPotentiallyThrowing = false; 305 }; 306 307 /// Iterator over the begin/end label pairs of invokes within a basic block. 308 class InvokeLabelIterator { 309 public: 310 InvokeLabelIterator(WinEHFuncInfo &EHInfo, 311 MachineBasicBlock::const_iterator MBBI, 312 MachineBasicBlock::const_iterator MBBIEnd) 313 : EHInfo(EHInfo), MBBI(MBBI), MBBIEnd(MBBIEnd) { 314 scan(); 315 } 316 317 // Iterator methods. 318 bool operator==(const InvokeLabelIterator &o) const { return MBBI == o.MBBI; } 319 bool operator!=(const InvokeLabelIterator &o) const { return MBBI != o.MBBI; } 320 InvokeRange &operator*() { return CurRange; } 321 InvokeRange *operator->() { return &CurRange; } 322 InvokeLabelIterator &operator++() { return scan(); } 323 324 private: 325 // Scan forward to find the next invoke range, or hit the end iterator. 326 InvokeLabelIterator &scan(); 327 328 WinEHFuncInfo &EHInfo; 329 MachineBasicBlock::const_iterator MBBI; 330 MachineBasicBlock::const_iterator MBBIEnd; 331 InvokeRange CurRange; 332 }; 333 } // end anonymous namespace 334 335 /// Invoke label range iteration logic. Increment MBBI until we find the next 336 /// EH_LABEL pair, and then update MBBI to point after the end label. 337 InvokeLabelIterator &InvokeLabelIterator::scan() { 338 // Reset our state. 339 CurRange = InvokeRange{}; 340 341 for (const MachineInstr &MI : make_range(MBBI, MBBIEnd)) { 342 // Remember if we had to cross a potentially throwing call instruction that 343 // must unwind to caller. 344 if (MI.isCall()) { 345 CurRange.SawPotentiallyThrowing |= 346 !EHStreamer::callToNoUnwindFunction(&MI); 347 continue; 348 } 349 // Find the next EH_LABEL instruction. 350 if (!MI.isEHLabel()) 351 continue; 352 353 // If this is a begin label, break out with the state and end label. 354 // Otherwise this is probably a CFI EH_LABEL that we should continue past. 355 MCSymbol *Label = MI.getOperand(0).getMCSymbol(); 356 auto StateAndEnd = EHInfo.InvokeToStateMap.find(Label); 357 if (StateAndEnd == EHInfo.InvokeToStateMap.end()) 358 continue; 359 MBBI = MachineBasicBlock::const_iterator(&MI); 360 CurRange.BeginLabel = Label; 361 CurRange.EndLabel = StateAndEnd->second.second; 362 CurRange.State = StateAndEnd->second.first; 363 break; 364 } 365 366 // If we didn't find a begin label, we are done, return the end iterator. 367 if (!CurRange.BeginLabel) { 368 MBBI = MBBIEnd; 369 return *this; 370 } 371 372 // If this is a begin label, update MBBI to point past the end label. 373 for (; MBBI != MBBIEnd; ++MBBI) 374 if (MBBI->isEHLabel() && 375 MBBI->getOperand(0).getMCSymbol() == CurRange.EndLabel) 376 break; 377 return *this; 378 } 379 380 /// Utility for making a range for all the invoke ranges. 381 static iterator_range<InvokeLabelIterator> 382 invoke_ranges(WinEHFuncInfo &EHInfo, const MachineBasicBlock &MBB) { 383 return make_range(InvokeLabelIterator(EHInfo, MBB.begin(), MBB.end()), 384 InvokeLabelIterator(EHInfo, MBB.end(), MBB.end())); 385 } 386 387 /// Emit the language-specific data that __C_specific_handler expects. This 388 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning 389 /// up after faults with __try, __except, and __finally. The typeinfo values 390 /// are not really RTTI data, but pointers to filter functions that return an 391 /// integer (1, 0, or -1) indicating how to handle the exception. For __finally 392 /// blocks and other cleanups, the landing pad label is zero, and the filter 393 /// function is actually a cleanup handler with the same prototype. A catch-all 394 /// entry is modeled with a null filter function field and a non-zero landing 395 /// pad label. 396 /// 397 /// Possible filter function return values: 398 /// EXCEPTION_EXECUTE_HANDLER (1): 399 /// Jump to the landing pad label after cleanups. 400 /// EXCEPTION_CONTINUE_SEARCH (0): 401 /// Continue searching this table or continue unwinding. 402 /// EXCEPTION_CONTINUE_EXECUTION (-1): 403 /// Resume execution at the trapping PC. 404 /// 405 /// Inferred table structure: 406 /// struct Table { 407 /// int NumEntries; 408 /// struct Entry { 409 /// imagerel32 LabelStart; 410 /// imagerel32 LabelEnd; 411 /// imagerel32 FilterOrFinally; // One means catch-all. 412 /// imagerel32 LabelLPad; // Zero means __finally. 413 /// } Entries[NumEntries]; 414 /// }; 415 void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { 416 auto &OS = *Asm->OutStreamer; 417 MCContext &Ctx = Asm->OutContext; 418 419 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction()); 420 if (!FuncInfo.SEHUnwindMap.empty()) { 421 // Remember what state we were in the last time we found a begin try label. 422 // This allows us to coalesce many nearby invokes with the same state into 423 // one entry. 424 int LastEHState = -1; 425 MCSymbol *LastBeginLabel = nullptr; 426 MCSymbol *LastEndLabel = nullptr; 427 428 // Use the assembler to compute the number of table entries through label 429 // difference and division. 430 MCSymbol *TableBegin = 431 Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true); 432 MCSymbol *TableEnd = 433 Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true); 434 const MCExpr *LabelDiff = 435 MCBinaryExpr::createSub(MCSymbolRefExpr::create(TableEnd, Ctx), 436 MCSymbolRefExpr::create(TableBegin, Ctx), Ctx); 437 const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx); 438 const MCExpr *EntryCount = 439 MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx); 440 OS.EmitValue(EntryCount, 4); 441 442 OS.EmitLabel(TableBegin); 443 444 // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only 445 // models exceptions from invokes. LLVM also allows arbitrary reordering of 446 // the code, so our tables end up looking a bit different. Rather than 447 // trying to match MSVC's tables exactly, we emit a denormalized table. For 448 // each range of invokes in the same state, we emit table entries for all 449 // the actions that would be taken in that state. This means our tables are 450 // slightly bigger, which is OK. 451 for (const auto &MBB : *MF) { 452 for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) { 453 // If this invoke is in the same state as the last invoke and there were 454 // no non-throwing calls between it, extend the range to include both 455 // and continue. 456 if (!I.SawPotentiallyThrowing && I.State == LastEHState) { 457 LastEndLabel = I.EndLabel; 458 continue; 459 } 460 461 // If this invoke ends a previous one, emit all the actions for this 462 // state. 463 if (LastEHState != -1) { 464 assert(LastBeginLabel && LastEndLabel); 465 for (int State = LastEHState; State != -1;) { 466 SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State]; 467 const MCExpr *FilterOrFinally; 468 const MCExpr *ExceptOrNull; 469 auto *Handler = UME.Handler.get<MachineBasicBlock *>(); 470 if (UME.IsFinally) { 471 FilterOrFinally = create32bitRef(Handler->getSymbol()); 472 ExceptOrNull = MCConstantExpr::create(0, Ctx); 473 } else { 474 // For an except, the filter can be 1 (catch-all) or a function 475 // label. 476 FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter) 477 : MCConstantExpr::create(1, Ctx); 478 ExceptOrNull = create32bitRef(Handler->getSymbol()); 479 } 480 481 OS.EmitValue(getLabelPlusOne(LastBeginLabel), 4); 482 OS.EmitValue(getLabelPlusOne(LastEndLabel), 4); 483 OS.EmitValue(FilterOrFinally, 4); 484 OS.EmitValue(ExceptOrNull, 4); 485 486 State = UME.ToState; 487 } 488 } 489 490 LastBeginLabel = I.BeginLabel; 491 LastEndLabel = I.EndLabel; 492 LastEHState = I.State; 493 } 494 } 495 OS.EmitLabel(TableEnd); 496 return; 497 } 498 499 // Simplifying assumptions for first implementation: 500 // - Cleanups are not implemented. 501 // - Filters are not implemented. 502 503 // The Itanium LSDA table sorts similar landing pads together to simplify the 504 // actions table, but we don't need that. 505 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 506 SmallVector<const LandingPadInfo *, 64> LandingPads; 507 LandingPads.reserve(PadInfos.size()); 508 for (const auto &LP : PadInfos) 509 LandingPads.push_back(&LP); 510 511 // Compute label ranges for call sites as we would for the Itanium LSDA, but 512 // use an all zero action table because we aren't using these actions. 513 SmallVector<unsigned, 64> FirstActions; 514 FirstActions.resize(LandingPads.size()); 515 SmallVector<CallSiteEntry, 64> CallSites; 516 computeCallSiteTable(CallSites, LandingPads, FirstActions); 517 518 MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); 519 MCSymbol *EHFuncEndSym = Asm->getFunctionEnd(); 520 521 // Emit the number of table entries. 522 unsigned NumEntries = 0; 523 for (const CallSiteEntry &CSE : CallSites) { 524 if (!CSE.LPad) 525 continue; // Ignore gaps. 526 NumEntries += CSE.LPad->SEHHandlers.size(); 527 } 528 OS.EmitIntValue(NumEntries, 4); 529 530 // If there are no actions, we don't need to iterate again. 531 if (NumEntries == 0) 532 return; 533 534 // Emit the four-label records for each call site entry. The table has to be 535 // sorted in layout order, and the call sites should already be sorted. 536 for (const CallSiteEntry &CSE : CallSites) { 537 // Ignore gaps. Unlike the Itanium model, unwinding through a frame without 538 // an EH table entry will propagate the exception rather than terminating 539 // the program. 540 if (!CSE.LPad) 541 continue; 542 const LandingPadInfo *LPad = CSE.LPad; 543 544 // Compute the label range. We may reuse the function begin and end labels 545 // rather than forming new ones. 546 const MCExpr *Begin = 547 create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym); 548 const MCExpr *End; 549 if (CSE.EndLabel) { 550 // The interval is half-open, so we have to add one to include the return 551 // address of the last invoke in the range. 552 End = getLabelPlusOne(CSE.EndLabel); 553 } else { 554 End = create32bitRef(EHFuncEndSym); 555 } 556 557 // Emit an entry for each action. 558 for (SEHHandler Handler : LPad->SEHHandlers) { 559 OS.EmitValue(Begin, 4); 560 OS.EmitValue(End, 4); 561 562 // Emit the filter or finally function pointer, if present. Otherwise, 563 // emit '1' to indicate a catch-all. 564 const Function *F = Handler.FilterOrFinally; 565 if (F) 566 OS.EmitValue(create32bitRef(Asm->getSymbol(F)), 4); 567 else 568 OS.EmitIntValue(1, 4); 569 570 // Emit the recovery address, if present. Otherwise, this must be a 571 // finally. 572 const BlockAddress *BA = Handler.RecoverBA; 573 if (BA) 574 OS.EmitValue( 575 create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4); 576 else 577 OS.EmitIntValue(0, 4); 578 } 579 } 580 } 581 582 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { 583 const Function *F = MF->getFunction(); 584 auto &OS = *Asm->OutStreamer; 585 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F); 586 587 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 588 589 SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable; 590 MCSymbol *FuncInfoXData = nullptr; 591 if (shouldEmitPersonality) { 592 // If we're 64-bit, emit a pointer to the C++ EH data, and build a map from 593 // IPs to state numbers. 594 FuncInfoXData = 595 Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName)); 596 computeIP2StateTable(MF, FuncInfo, IPToStateTable); 597 } else { 598 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName); 599 emitEHRegistrationOffsetLabel(FuncInfo, FuncLinkageName); 600 } 601 602 MCSymbol *UnwindMapXData = nullptr; 603 MCSymbol *TryBlockMapXData = nullptr; 604 MCSymbol *IPToStateXData = nullptr; 605 if (!FuncInfo.UnwindMap.empty()) 606 UnwindMapXData = Asm->OutContext.getOrCreateSymbol( 607 Twine("$stateUnwindMap$", FuncLinkageName)); 608 if (!FuncInfo.TryBlockMap.empty()) 609 TryBlockMapXData = 610 Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName)); 611 if (!IPToStateTable.empty()) 612 IPToStateXData = 613 Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName)); 614 615 // FuncInfo { 616 // uint32_t MagicNumber 617 // int32_t MaxState; 618 // UnwindMapEntry *UnwindMap; 619 // uint32_t NumTryBlocks; 620 // TryBlockMapEntry *TryBlockMap; 621 // uint32_t IPMapEntries; // always 0 for x86 622 // IPToStateMapEntry *IPToStateMap; // always 0 for x86 623 // uint32_t UnwindHelp; // non-x86 only 624 // ESTypeList *ESTypeList; 625 // int32_t EHFlags; 626 // } 627 // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. 628 // EHFlags & 2 -> ??? 629 // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. 630 OS.EmitValueToAlignment(4); 631 OS.EmitLabel(FuncInfoXData); 632 OS.EmitIntValue(0x19930522, 4); // MagicNumber 633 OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState 634 OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap 635 OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks 636 OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap 637 OS.EmitIntValue(IPToStateTable.size(), 4); // IPMapEntries 638 OS.EmitValue(create32bitRef(IPToStateXData), 4); // IPToStateMap 639 if (Asm->MAI->usesWindowsCFI()) 640 OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp 641 OS.EmitIntValue(0, 4); // ESTypeList 642 OS.EmitIntValue(1, 4); // EHFlags 643 644 // UnwindMapEntry { 645 // int32_t ToState; 646 // void (*Action)(); 647 // }; 648 if (UnwindMapXData) { 649 OS.EmitLabel(UnwindMapXData); 650 for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { 651 MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup); 652 OS.EmitIntValue(UME.ToState, 4); // ToState 653 OS.EmitValue(create32bitRef(CleanupSym), 4); // Action 654 } 655 } 656 657 // TryBlockMap { 658 // int32_t TryLow; 659 // int32_t TryHigh; 660 // int32_t CatchHigh; 661 // int32_t NumCatches; 662 // HandlerType *HandlerArray; 663 // }; 664 if (TryBlockMapXData) { 665 OS.EmitLabel(TryBlockMapXData); 666 SmallVector<MCSymbol *, 1> HandlerMaps; 667 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 668 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 669 670 MCSymbol *HandlerMapXData = nullptr; 671 if (!TBME.HandlerArray.empty()) 672 HandlerMapXData = 673 Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") 674 .concat(Twine(I)) 675 .concat("$") 676 .concat(FuncLinkageName)); 677 HandlerMaps.push_back(HandlerMapXData); 678 679 // TBMEs should form intervals. 680 assert(0 <= TBME.TryLow && "bad trymap interval"); 681 assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval"); 682 assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval"); 683 assert(TBME.CatchHigh < int(FuncInfo.UnwindMap.size()) && 684 "bad trymap interval"); 685 686 OS.EmitIntValue(TBME.TryLow, 4); // TryLow 687 OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh 688 OS.EmitIntValue(TBME.CatchHigh, 4); // CatchHigh 689 OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches 690 OS.EmitValue(create32bitRef(HandlerMapXData), 4); // HandlerArray 691 } 692 693 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 694 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 695 MCSymbol *HandlerMapXData = HandlerMaps[I]; 696 if (!HandlerMapXData) 697 continue; 698 // HandlerType { 699 // int32_t Adjectives; 700 // TypeDescriptor *Type; 701 // int32_t CatchObjOffset; 702 // void (*Handler)(); 703 // int32_t ParentFrameOffset; // x64 only 704 // }; 705 OS.EmitLabel(HandlerMapXData); 706 for (const WinEHHandlerType &HT : TBME.HandlerArray) { 707 // Get the frame escape label with the offset of the catch object. If 708 // the index is -1, then there is no catch object, and we should emit an 709 // offset of zero, indicating that no copy will occur. 710 const MCExpr *FrameAllocOffsetRef = nullptr; 711 if (HT.CatchObjRecoverIdx >= 0) { 712 MCSymbol *FrameAllocOffset = 713 Asm->OutContext.getOrCreateFrameAllocSymbol( 714 FuncLinkageName, HT.CatchObjRecoverIdx); 715 FrameAllocOffsetRef = MCSymbolRefExpr::create( 716 FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); 717 } else if (HT.CatchObj.FrameOffset != INT_MAX) { 718 int Offset = HT.CatchObj.FrameOffset; 719 // For 32-bit, the catch object offset is relative to the end of the 720 // EH registration node. For 64-bit, it's relative to SP at the end of 721 // the prologue. 722 if (!shouldEmitPersonality) { 723 assert(FuncInfo.EHRegNodeEndOffset != INT_MAX); 724 Offset += FuncInfo.EHRegNodeEndOffset; 725 } 726 FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext); 727 } else { 728 FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext); 729 } 730 731 MCSymbol *HandlerSym = getMCSymbolForMBBOrGV(Asm, HT.Handler); 732 733 OS.EmitIntValue(HT.Adjectives, 4); // Adjectives 734 OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); // Type 735 OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset 736 OS.EmitValue(create32bitRef(HandlerSym), 4); // Handler 737 738 if (shouldEmitPersonality) { 739 // With the new IR, this is always 16 + 8 + getMaxCallFrameSize(). 740 // Keep this in sync with X86FrameLowering::emitPrologue. 741 int ParentFrameOffset = 742 16 + 8 + MF->getFrameInfo()->getMaxCallFrameSize(); 743 OS.EmitIntValue(ParentFrameOffset, 4); // ParentFrameOffset 744 } 745 } 746 } 747 } 748 749 // IPToStateMapEntry { 750 // void *IP; 751 // int32_t State; 752 // }; 753 if (IPToStateXData) { 754 OS.EmitLabel(IPToStateXData); 755 for (auto &IPStatePair : IPToStateTable) { 756 OS.EmitValue(IPStatePair.first, 4); // IP 757 OS.EmitIntValue(IPStatePair.second, 4); // State 758 } 759 } 760 } 761 762 void WinException::computeIP2StateTable( 763 const MachineFunction *MF, WinEHFuncInfo &FuncInfo, 764 SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) { 765 // Remember what state we were in the last time we found a begin try label. 766 // This allows us to coalesce many nearby invokes with the same state into one 767 // entry. 768 int LastEHState = -1; 769 MCSymbol *LastEndLabel = Asm->getFunctionBegin(); 770 assert(LastEndLabel && "need local function start label"); 771 772 // Indicate that all calls from the prologue to the first invoke unwind to 773 // caller. We handle this as a special case since other ranges starting at end 774 // labels need to use LtmpN+1. 775 IPToStateTable.push_back(std::make_pair(create32bitRef(LastEndLabel), -1)); 776 777 for (const auto &MBB : *MF) { 778 // FIXME: Do we need to emit entries for funclet base states? 779 780 for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) { 781 assert(I.BeginLabel && I.EndLabel); 782 // If there was a potentially throwing call between this begin label and 783 // the last end label, we need an extra base state entry to indicate that 784 // those calls unwind directly to the caller. 785 if (I.SawPotentiallyThrowing && LastEHState != -1) { 786 IPToStateTable.push_back( 787 std::make_pair(getLabelPlusOne(LastEndLabel), -1)); 788 LastEHState = -1; 789 } 790 791 // Emit an entry indicating that PCs after 'Label' have this EH state. 792 if (I.State != LastEHState) 793 IPToStateTable.push_back( 794 std::make_pair(create32bitRef(I.BeginLabel), I.State)); 795 LastEHState = I.State; 796 LastEndLabel = I.EndLabel; 797 } 798 } 799 800 if (LastEndLabel != Asm->getFunctionBegin()) { 801 // Indicate that all calls from the last invoke until the epilogue unwind to 802 // caller. This also ensures that we have at least one ip2state entry, if 803 // somehow all invokes were deleted during CodeGen. 804 IPToStateTable.push_back(std::make_pair(getLabelPlusOne(LastEndLabel), -1)); 805 } 806 } 807 808 void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, 809 StringRef FLinkageName) { 810 // Outlined helpers called by the EH runtime need to know the offset of the EH 811 // registration in order to recover the parent frame pointer. Now that we know 812 // we've code generated the parent, we can emit the label assignment that 813 // those helpers use to get the offset of the registration node. 814 assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX && 815 "no EH reg node localescape index"); 816 MCSymbol *ParentFrameOffset = 817 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName); 818 MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol( 819 FLinkageName, FuncInfo.EHRegNodeEscapeIndex); 820 const MCExpr *RegistrationOffsetSymRef = 821 MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext); 822 Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef); 823 } 824 825 /// Emit the language-specific data that _except_handler3 and 4 expect. This is 826 /// functionally equivalent to the __C_specific_handler table, except it is 827 /// indexed by state number instead of IP. 828 void WinException::emitExceptHandlerTable(const MachineFunction *MF) { 829 MCStreamer &OS = *Asm->OutStreamer; 830 const Function *F = MF->getFunction(); 831 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName()); 832 833 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F); 834 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName); 835 836 // Emit the __ehtable label that we use for llvm.x86.seh.lsda. 837 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); 838 OS.EmitValueToAlignment(4); 839 OS.EmitLabel(LSDALabel); 840 841 const Function *Per = 842 dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); 843 StringRef PerName = Per->getName(); 844 int BaseState = -1; 845 if (PerName == "_except_handler4") { 846 // The LSDA for _except_handler4 starts with this struct, followed by the 847 // scope table: 848 // 849 // struct EH4ScopeTable { 850 // int32_t GSCookieOffset; 851 // int32_t GSCookieXOROffset; 852 // int32_t EHCookieOffset; 853 // int32_t EHCookieXOROffset; 854 // ScopeTableEntry ScopeRecord[]; 855 // }; 856 // 857 // Only the EHCookieOffset field appears to vary, and it appears to be the 858 // offset from the final saved SP value to the retaddr. 859 OS.EmitIntValue(-2, 4); 860 OS.EmitIntValue(0, 4); 861 // FIXME: Calculate. 862 OS.EmitIntValue(9999, 4); 863 OS.EmitIntValue(0, 4); 864 BaseState = -2; 865 } 866 867 if (!FuncInfo.SEHUnwindMap.empty()) { 868 for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) { 869 MCSymbol *ExceptOrFinally = 870 UME.Handler.get<MachineBasicBlock *>()->getSymbol(); 871 OS.EmitIntValue(UME.ToState, 4); // ToState 872 OS.EmitValue(create32bitRef(UME.Filter), 4); // Filter 873 OS.EmitValue(create32bitRef(ExceptOrFinally), 4); // Except/Finally 874 } 875 return; 876 } 877 // FIXME: The following code is for the old landingpad-based SEH 878 // implementation. Remove it when possible. 879 880 // Build a list of pointers to LandingPadInfos and then sort by WinEHState. 881 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 882 SmallVector<const LandingPadInfo *, 4> LPads; 883 LPads.reserve((PadInfos.size())); 884 for (const LandingPadInfo &LPInfo : PadInfos) 885 LPads.push_back(&LPInfo); 886 std::sort(LPads.begin(), LPads.end(), 887 [](const LandingPadInfo *L, const LandingPadInfo *R) { 888 return L->WinEHState < R->WinEHState; 889 }); 890 891 // For each action in each lpad, emit one of these: 892 // struct ScopeTableEntry { 893 // int32_t EnclosingLevel; 894 // int32_t (__cdecl *Filter)(); 895 // void *HandlerOrFinally; 896 // }; 897 // 898 // The "outermost" action will use BaseState as its enclosing level. Each 899 // other action will refer to the previous state as its enclosing level. 900 int CurState = 0; 901 for (const LandingPadInfo *LPInfo : LPads) { 902 int EnclosingLevel = BaseState; 903 assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 == 904 LPInfo->WinEHState && 905 "gaps in the SEH scope table"); 906 for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend(); 907 I != E; ++I) { 908 const SEHHandler &Handler = *I; 909 const BlockAddress *BA = Handler.RecoverBA; 910 const Function *F = Handler.FilterOrFinally; 911 assert(F && "cannot catch all in 32-bit SEH without filter function"); 912 const MCExpr *FilterOrNull = 913 create32bitRef(BA ? Asm->getSymbol(F) : nullptr); 914 const MCExpr *ExceptOrFinally = create32bitRef( 915 BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F)); 916 917 OS.EmitIntValue(EnclosingLevel, 4); 918 OS.EmitValue(FilterOrNull, 4); 919 OS.EmitValue(ExceptOrFinally, 4); 920 921 // The next state unwinds to this state. 922 EnclosingLevel = CurState; 923 CurState++; 924 } 925 } 926 } 927