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 if (shouldEmitPersonality || shouldEmitLSDA) { 125 Asm->OutStreamer->PushSection(); 126 127 // Just switch sections to the right xdata section. This use of CurrentFnSym 128 // assumes that we only emit the LSDA when ending the parent function. 129 MCSection *XData = WinEH::UnwindEmitter::getXDataSection(Asm->CurrentFnSym, 130 Asm->OutContext); 131 Asm->OutStreamer->SwitchSection(XData); 132 133 // Emit the tables appropriate to the personality function in use. If we 134 // don't recognize the personality, assume it uses an Itanium-style LSDA. 135 if (Per == EHPersonality::MSVC_Win64SEH) 136 emitCSpecificHandlerTable(MF); 137 else if (Per == EHPersonality::MSVC_X86SEH) 138 emitExceptHandlerTable(MF); 139 else if (Per == EHPersonality::MSVC_CXX) 140 emitCXXFrameHandler3Table(MF); 141 else 142 emitExceptionTable(); 143 144 Asm->OutStreamer->PopSection(); 145 } 146 } 147 148 /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues 149 /// are used in the old WinEH scheme, and they will be removed eventually. 150 static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) { 151 if (!Handler) 152 return nullptr; 153 if (Handler.is<const MachineBasicBlock *>()) { 154 auto *MBB = Handler.get<const MachineBasicBlock *>(); 155 assert(MBB->isEHFuncletEntry()); 156 157 // Give catches and cleanups a name based off of their parent function and 158 // their funclet entry block's number. 159 const MachineFunction *MF = MBB->getParent(); 160 const Function *F = MF->getFunction(); 161 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 162 MCContext &Ctx = MF->getContext(); 163 StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch"; 164 return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" + 165 Twine(MBB->getNumber()) + "@?0?" + 166 FuncLinkageName + "@4HA"); 167 } 168 return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>())); 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 = getMCSymbolForMBBOrGV(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 this is a C++ catch funclet (or the parent function), 241 // emit a reference to the LSDA for the parent function. 242 if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality && 243 !CurrentFuncletEntry->isCleanupFuncletEntry()) { 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 } 249 250 // Switch back to the previous section now that we are done writing to 251 // .xdata. 252 Asm->OutStreamer->PopSection(); 253 254 // Emit a .seh_endproc directive to mark the end of the function. 255 Asm->OutStreamer->EmitWinCFIEndProc(); 256 } 257 258 // Let's make sure we don't try to end the same funclet twice. 259 CurrentFuncletEntry = nullptr; 260 } 261 262 const MCExpr *WinException::create32bitRef(const MCSymbol *Value) { 263 if (!Value) 264 return MCConstantExpr::create(0, Asm->OutContext); 265 return MCSymbolRefExpr::create(Value, useImageRel32 266 ? MCSymbolRefExpr::VK_COFF_IMGREL32 267 : MCSymbolRefExpr::VK_None, 268 Asm->OutContext); 269 } 270 271 const MCExpr *WinException::create32bitRef(const Value *V) { 272 if (!V) 273 return MCConstantExpr::create(0, Asm->OutContext); 274 // FIXME: Delete the GlobalValue case once the new IR is fully functional. 275 if (const auto *GV = dyn_cast<GlobalValue>(V)) 276 return create32bitRef(Asm->getSymbol(GV)); 277 return create32bitRef(MMI->getAddrLabelSymbol(cast<BasicBlock>(V))); 278 } 279 280 const MCExpr *WinException::getLabelPlusOne(MCSymbol *Label) { 281 return MCBinaryExpr::createAdd(create32bitRef(Label), 282 MCConstantExpr::create(1, Asm->OutContext), 283 Asm->OutContext); 284 } 285 286 /// Emit the language-specific data that __C_specific_handler expects. This 287 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning 288 /// up after faults with __try, __except, and __finally. The typeinfo values 289 /// are not really RTTI data, but pointers to filter functions that return an 290 /// integer (1, 0, or -1) indicating how to handle the exception. For __finally 291 /// blocks and other cleanups, the landing pad label is zero, and the filter 292 /// function is actually a cleanup handler with the same prototype. A catch-all 293 /// entry is modeled with a null filter function field and a non-zero landing 294 /// pad label. 295 /// 296 /// Possible filter function return values: 297 /// EXCEPTION_EXECUTE_HANDLER (1): 298 /// Jump to the landing pad label after cleanups. 299 /// EXCEPTION_CONTINUE_SEARCH (0): 300 /// Continue searching this table or continue unwinding. 301 /// EXCEPTION_CONTINUE_EXECUTION (-1): 302 /// Resume execution at the trapping PC. 303 /// 304 /// Inferred table structure: 305 /// struct Table { 306 /// int NumEntries; 307 /// struct Entry { 308 /// imagerel32 LabelStart; 309 /// imagerel32 LabelEnd; 310 /// imagerel32 FilterOrFinally; // One means catch-all. 311 /// imagerel32 LabelLPad; // Zero means __finally. 312 /// } Entries[NumEntries]; 313 /// }; 314 void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { 315 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 316 317 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction()); 318 if (!FuncInfo.SEHUnwindMap.empty()) 319 report_fatal_error("x64 SEH tables not yet implemented"); 320 321 // Simplifying assumptions for first implementation: 322 // - Cleanups are not implemented. 323 // - Filters are not implemented. 324 325 // The Itanium LSDA table sorts similar landing pads together to simplify the 326 // actions table, but we don't need that. 327 SmallVector<const LandingPadInfo *, 64> LandingPads; 328 LandingPads.reserve(PadInfos.size()); 329 for (const auto &LP : PadInfos) 330 LandingPads.push_back(&LP); 331 332 // Compute label ranges for call sites as we would for the Itanium LSDA, but 333 // use an all zero action table because we aren't using these actions. 334 SmallVector<unsigned, 64> FirstActions; 335 FirstActions.resize(LandingPads.size()); 336 SmallVector<CallSiteEntry, 64> CallSites; 337 computeCallSiteTable(CallSites, LandingPads, FirstActions); 338 339 MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); 340 MCSymbol *EHFuncEndSym = Asm->getFunctionEnd(); 341 342 // Emit the number of table entries. 343 unsigned NumEntries = 0; 344 for (const CallSiteEntry &CSE : CallSites) { 345 if (!CSE.LPad) 346 continue; // Ignore gaps. 347 NumEntries += CSE.LPad->SEHHandlers.size(); 348 } 349 Asm->OutStreamer->EmitIntValue(NumEntries, 4); 350 351 // If there are no actions, we don't need to iterate again. 352 if (NumEntries == 0) 353 return; 354 355 // Emit the four-label records for each call site entry. The table has to be 356 // sorted in layout order, and the call sites should already be sorted. 357 for (const CallSiteEntry &CSE : CallSites) { 358 // Ignore gaps. Unlike the Itanium model, unwinding through a frame without 359 // an EH table entry will propagate the exception rather than terminating 360 // the program. 361 if (!CSE.LPad) 362 continue; 363 const LandingPadInfo *LPad = CSE.LPad; 364 365 // Compute the label range. We may reuse the function begin and end labels 366 // rather than forming new ones. 367 const MCExpr *Begin = 368 create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym); 369 const MCExpr *End; 370 if (CSE.EndLabel) { 371 // The interval is half-open, so we have to add one to include the return 372 // address of the last invoke in the range. 373 End = getLabelPlusOne(CSE.EndLabel); 374 } else { 375 End = create32bitRef(EHFuncEndSym); 376 } 377 378 // Emit an entry for each action. 379 for (SEHHandler Handler : LPad->SEHHandlers) { 380 Asm->OutStreamer->EmitValue(Begin, 4); 381 Asm->OutStreamer->EmitValue(End, 4); 382 383 // Emit the filter or finally function pointer, if present. Otherwise, 384 // emit '1' to indicate a catch-all. 385 const Function *F = Handler.FilterOrFinally; 386 if (F) 387 Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4); 388 else 389 Asm->OutStreamer->EmitIntValue(1, 4); 390 391 // Emit the recovery address, if present. Otherwise, this must be a 392 // finally. 393 const BlockAddress *BA = Handler.RecoverBA; 394 if (BA) 395 Asm->OutStreamer->EmitValue( 396 create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4); 397 else 398 Asm->OutStreamer->EmitIntValue(0, 4); 399 } 400 } 401 } 402 403 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { 404 const Function *F = MF->getFunction(); 405 auto &OS = *Asm->OutStreamer; 406 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F); 407 408 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName()); 409 410 SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable; 411 MCSymbol *FuncInfoXData = nullptr; 412 if (shouldEmitPersonality) { 413 // If we're 64-bit, emit a pointer to the C++ EH data, and build a map from 414 // IPs to state numbers. 415 FuncInfoXData = 416 Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName)); 417 computeIP2StateTable(MF, FuncInfo, IPToStateTable); 418 } else { 419 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName); 420 emitEHRegistrationOffsetLabel(FuncInfo, FuncLinkageName); 421 } 422 423 MCSymbol *UnwindMapXData = nullptr; 424 MCSymbol *TryBlockMapXData = nullptr; 425 MCSymbol *IPToStateXData = nullptr; 426 if (!FuncInfo.UnwindMap.empty()) 427 UnwindMapXData = Asm->OutContext.getOrCreateSymbol( 428 Twine("$stateUnwindMap$", FuncLinkageName)); 429 if (!FuncInfo.TryBlockMap.empty()) 430 TryBlockMapXData = 431 Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName)); 432 if (!IPToStateTable.empty()) 433 IPToStateXData = 434 Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName)); 435 436 // FuncInfo { 437 // uint32_t MagicNumber 438 // int32_t MaxState; 439 // UnwindMapEntry *UnwindMap; 440 // uint32_t NumTryBlocks; 441 // TryBlockMapEntry *TryBlockMap; 442 // uint32_t IPMapEntries; // always 0 for x86 443 // IPToStateMapEntry *IPToStateMap; // always 0 for x86 444 // uint32_t UnwindHelp; // non-x86 only 445 // ESTypeList *ESTypeList; 446 // int32_t EHFlags; 447 // } 448 // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. 449 // EHFlags & 2 -> ??? 450 // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. 451 OS.EmitValueToAlignment(4); 452 OS.EmitLabel(FuncInfoXData); 453 OS.EmitIntValue(0x19930522, 4); // MagicNumber 454 OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState 455 OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap 456 OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks 457 OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap 458 OS.EmitIntValue(IPToStateTable.size(), 4); // IPMapEntries 459 OS.EmitValue(create32bitRef(IPToStateXData), 4); // IPToStateMap 460 if (Asm->MAI->usesWindowsCFI()) 461 OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp 462 OS.EmitIntValue(0, 4); // ESTypeList 463 OS.EmitIntValue(1, 4); // EHFlags 464 465 // UnwindMapEntry { 466 // int32_t ToState; 467 // void (*Action)(); 468 // }; 469 if (UnwindMapXData) { 470 OS.EmitLabel(UnwindMapXData); 471 for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { 472 MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup); 473 OS.EmitIntValue(UME.ToState, 4); // ToState 474 OS.EmitValue(create32bitRef(CleanupSym), 4); // Action 475 } 476 } 477 478 // TryBlockMap { 479 // int32_t TryLow; 480 // int32_t TryHigh; 481 // int32_t CatchHigh; 482 // int32_t NumCatches; 483 // HandlerType *HandlerArray; 484 // }; 485 if (TryBlockMapXData) { 486 OS.EmitLabel(TryBlockMapXData); 487 SmallVector<MCSymbol *, 1> HandlerMaps; 488 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 489 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 490 491 MCSymbol *HandlerMapXData = nullptr; 492 if (!TBME.HandlerArray.empty()) 493 HandlerMapXData = 494 Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") 495 .concat(Twine(I)) 496 .concat("$") 497 .concat(FuncLinkageName)); 498 HandlerMaps.push_back(HandlerMapXData); 499 500 // TBMEs should form intervals. 501 assert(0 <= TBME.TryLow && "bad trymap interval"); 502 assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval"); 503 assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval"); 504 assert(TBME.CatchHigh < int(FuncInfo.UnwindMap.size()) && 505 "bad trymap interval"); 506 507 OS.EmitIntValue(TBME.TryLow, 4); // TryLow 508 OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh 509 OS.EmitIntValue(TBME.CatchHigh, 4); // CatchHigh 510 OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches 511 OS.EmitValue(create32bitRef(HandlerMapXData), 4); // HandlerArray 512 } 513 514 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 515 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 516 MCSymbol *HandlerMapXData = HandlerMaps[I]; 517 if (!HandlerMapXData) 518 continue; 519 // HandlerType { 520 // int32_t Adjectives; 521 // TypeDescriptor *Type; 522 // int32_t CatchObjOffset; 523 // void (*Handler)(); 524 // int32_t ParentFrameOffset; // x64 only 525 // }; 526 OS.EmitLabel(HandlerMapXData); 527 for (const WinEHHandlerType &HT : TBME.HandlerArray) { 528 // Get the frame escape label with the offset of the catch object. If 529 // the index is -1, then there is no catch object, and we should emit an 530 // offset of zero, indicating that no copy will occur. 531 const MCExpr *FrameAllocOffsetRef = nullptr; 532 if (HT.CatchObjRecoverIdx >= 0) { 533 MCSymbol *FrameAllocOffset = 534 Asm->OutContext.getOrCreateFrameAllocSymbol( 535 FuncLinkageName, HT.CatchObjRecoverIdx); 536 FrameAllocOffsetRef = MCSymbolRefExpr::create( 537 FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); 538 } else if (HT.CatchObj.FrameOffset != INT_MAX) { 539 int Offset = HT.CatchObj.FrameOffset; 540 // For 32-bit, the catch object offset is relative to the end of the 541 // EH registration node. For 64-bit, it's relative to SP at the end of 542 // the prologue. 543 if (!shouldEmitPersonality) { 544 assert(FuncInfo.EHRegNodeEndOffset != INT_MAX); 545 Offset += FuncInfo.EHRegNodeEndOffset; 546 } 547 FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext); 548 } else { 549 FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext); 550 } 551 552 MCSymbol *HandlerSym = getMCSymbolForMBBOrGV(Asm, HT.Handler); 553 554 OS.EmitIntValue(HT.Adjectives, 4); // Adjectives 555 OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); // Type 556 OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset 557 OS.EmitValue(create32bitRef(HandlerSym), 4); // Handler 558 559 if (shouldEmitPersonality) { 560 // With the new IR, this is always 16 + 8 + getMaxCallFrameSize(). 561 // Keep this in sync with X86FrameLowering::emitPrologue. 562 int ParentFrameOffset = 563 16 + 8 + MF->getFrameInfo()->getMaxCallFrameSize(); 564 OS.EmitIntValue(ParentFrameOffset, 4); // ParentFrameOffset 565 } 566 } 567 } 568 } 569 570 // IPToStateMapEntry { 571 // void *IP; 572 // int32_t State; 573 // }; 574 if (IPToStateXData) { 575 OS.EmitLabel(IPToStateXData); 576 for (auto &IPStatePair : IPToStateTable) { 577 OS.EmitValue(IPStatePair.first, 4); // IP 578 OS.EmitIntValue(IPStatePair.second, 4); // State 579 } 580 } 581 } 582 583 void WinException::computeIP2StateTable( 584 const MachineFunction *MF, WinEHFuncInfo &FuncInfo, 585 SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) { 586 // Whether there is a potentially throwing instruction (currently this means 587 // an ordinary call) between the end of the previous try-range and now. 588 bool SawPotentiallyThrowing = true; 589 590 // Remember what state we were in the last time we found a begin try label. 591 // This allows us to coalesce many nearby invokes with the same state into one 592 // entry. 593 int LastEHState = -1; 594 MCSymbol *LastEndLabel = Asm->getFunctionBegin(); 595 assert(LastEndLabel && "need local function start label"); 596 597 // Indicate that all calls from the prologue to the first invoke unwind to 598 // caller. We handle this as a special case since other ranges starting at end 599 // labels need to use LtmpN+1. 600 IPToStateTable.push_back(std::make_pair(create32bitRef(LastEndLabel), -1)); 601 602 for (const auto &MBB : *MF) { 603 // FIXME: Do we need to emit entries for funclet base states? 604 605 for (const auto &MI : MBB) { 606 // Find all the EH_LABEL instructions, tracking if we've crossed a 607 // potentially throwing call since the last label. 608 if (!MI.isEHLabel()) { 609 if (MI.isCall()) 610 SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); 611 continue; 612 } 613 614 // If this was an end label, return SawPotentiallyThrowing to the start 615 // state and keep going. Otherwise, we will consider the call between the 616 // begin/end labels to be a potentially throwing call and generate extra 617 // table entries. 618 MCSymbol *Label = MI.getOperand(0).getMCSymbol(); 619 if (Label == LastEndLabel) 620 SawPotentiallyThrowing = false; 621 622 // Check if this was a begin label. Otherwise, it must be an end label or 623 // some random label, and we should continue. 624 auto StateAndEnd = FuncInfo.InvokeToStateMap.find(Label); 625 if (StateAndEnd == FuncInfo.InvokeToStateMap.end()) 626 continue; 627 628 // Extract the state and end label. 629 int State; 630 MCSymbol *EndLabel; 631 std::tie(State, EndLabel) = StateAndEnd->second; 632 633 // If there was a potentially throwing call between this begin label and 634 // the last end label, we need an extra base state entry to indicate that 635 // those calls unwind directly to the caller. 636 if (SawPotentiallyThrowing && LastEHState != -1) { 637 IPToStateTable.push_back( 638 std::make_pair(getLabelPlusOne(LastEndLabel), -1)); 639 SawPotentiallyThrowing = false; 640 LastEHState = -1; 641 } 642 643 // Emit an entry indicating that PCs after 'Label' have this EH state. 644 if (State != LastEHState) 645 IPToStateTable.push_back(std::make_pair(create32bitRef(Label), State)); 646 LastEHState = State; 647 LastEndLabel = EndLabel; 648 } 649 } 650 651 if (LastEndLabel != Asm->getFunctionBegin()) { 652 // Indicate that all calls from the last invoke until the epilogue unwind to 653 // caller. This also ensures that we have at least one ip2state entry, if 654 // somehow all invokes were deleted during CodeGen. 655 IPToStateTable.push_back(std::make_pair(getLabelPlusOne(LastEndLabel), -1)); 656 } 657 } 658 659 void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, 660 StringRef FLinkageName) { 661 // Outlined helpers called by the EH runtime need to know the offset of the EH 662 // registration in order to recover the parent frame pointer. Now that we know 663 // we've code generated the parent, we can emit the label assignment that 664 // those helpers use to get the offset of the registration node. 665 assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX && 666 "no EH reg node localescape index"); 667 MCSymbol *ParentFrameOffset = 668 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName); 669 MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol( 670 FLinkageName, FuncInfo.EHRegNodeEscapeIndex); 671 const MCExpr *RegistrationOffsetSymRef = 672 MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext); 673 Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef); 674 } 675 676 /// Emit the language-specific data that _except_handler3 and 4 expect. This is 677 /// functionally equivalent to the __C_specific_handler table, except it is 678 /// indexed by state number instead of IP. 679 void WinException::emitExceptHandlerTable(const MachineFunction *MF) { 680 MCStreamer &OS = *Asm->OutStreamer; 681 const Function *F = MF->getFunction(); 682 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName()); 683 684 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F); 685 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName); 686 687 // Emit the __ehtable label that we use for llvm.x86.seh.lsda. 688 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); 689 OS.EmitValueToAlignment(4); 690 OS.EmitLabel(LSDALabel); 691 692 const Function *Per = 693 dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); 694 StringRef PerName = Per->getName(); 695 int BaseState = -1; 696 if (PerName == "_except_handler4") { 697 // The LSDA for _except_handler4 starts with this struct, followed by the 698 // scope table: 699 // 700 // struct EH4ScopeTable { 701 // int32_t GSCookieOffset; 702 // int32_t GSCookieXOROffset; 703 // int32_t EHCookieOffset; 704 // int32_t EHCookieXOROffset; 705 // ScopeTableEntry ScopeRecord[]; 706 // }; 707 // 708 // Only the EHCookieOffset field appears to vary, and it appears to be the 709 // offset from the final saved SP value to the retaddr. 710 OS.EmitIntValue(-2, 4); 711 OS.EmitIntValue(0, 4); 712 // FIXME: Calculate. 713 OS.EmitIntValue(9999, 4); 714 OS.EmitIntValue(0, 4); 715 BaseState = -2; 716 } 717 718 if (!FuncInfo.SEHUnwindMap.empty()) { 719 for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) { 720 MCSymbol *ExceptOrFinally = 721 UME.Handler.get<MachineBasicBlock *>()->getSymbol(); 722 OS.EmitIntValue(UME.ToState, 4); // ToState 723 OS.EmitValue(create32bitRef(UME.Filter), 4); // Filter 724 OS.EmitValue(create32bitRef(ExceptOrFinally), 4); // Except/Finally 725 } 726 return; 727 } 728 // FIXME: The following code is for the old landingpad-based SEH 729 // implementation. Remove it when possible. 730 731 // Build a list of pointers to LandingPadInfos and then sort by WinEHState. 732 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 733 SmallVector<const LandingPadInfo *, 4> LPads; 734 LPads.reserve((PadInfos.size())); 735 for (const LandingPadInfo &LPInfo : PadInfos) 736 LPads.push_back(&LPInfo); 737 std::sort(LPads.begin(), LPads.end(), 738 [](const LandingPadInfo *L, const LandingPadInfo *R) { 739 return L->WinEHState < R->WinEHState; 740 }); 741 742 // For each action in each lpad, emit one of these: 743 // struct ScopeTableEntry { 744 // int32_t EnclosingLevel; 745 // int32_t (__cdecl *Filter)(); 746 // void *HandlerOrFinally; 747 // }; 748 // 749 // The "outermost" action will use BaseState as its enclosing level. Each 750 // other action will refer to the previous state as its enclosing level. 751 int CurState = 0; 752 for (const LandingPadInfo *LPInfo : LPads) { 753 int EnclosingLevel = BaseState; 754 assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 == 755 LPInfo->WinEHState && 756 "gaps in the SEH scope table"); 757 for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend(); 758 I != E; ++I) { 759 const SEHHandler &Handler = *I; 760 const BlockAddress *BA = Handler.RecoverBA; 761 const Function *F = Handler.FilterOrFinally; 762 assert(F && "cannot catch all in 32-bit SEH without filter function"); 763 const MCExpr *FilterOrNull = 764 create32bitRef(BA ? Asm->getSymbol(F) : nullptr); 765 const MCExpr *ExceptOrFinally = create32bitRef( 766 BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F)); 767 768 OS.EmitIntValue(EnclosingLevel, 4); 769 OS.EmitValue(FilterOrNull, 4); 770 OS.EmitValue(ExceptOrFinally, 4); 771 772 // The next state unwinds to this state. 773 EnclosingLevel = CurState; 774 CurState++; 775 } 776 } 777 } 778