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/Dwarf.h" 34 #include "llvm/Support/ErrorHandling.h" 35 #include "llvm/Support/FormattedStream.h" 36 #include "llvm/Target/TargetFrameLowering.h" 37 #include "llvm/Target/TargetLoweringObjectFile.h" 38 #include "llvm/Target/TargetOptions.h" 39 #include "llvm/Target/TargetRegisterInfo.h" 40 using namespace llvm; 41 42 WinException::WinException(AsmPrinter *A) : EHStreamer(A) { 43 // MSVC's EH tables are always composed of 32-bit words. All known 64-bit 44 // platforms use an imagerel32 relocation to refer to symbols. 45 useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64); 46 } 47 48 WinException::~WinException() {} 49 50 /// endModule - Emit all exception information that should come after the 51 /// content. 52 void WinException::endModule() { 53 auto &OS = *Asm->OutStreamer; 54 const Module *M = MMI->getModule(); 55 for (const Function &F : *M) 56 if (F.hasFnAttribute("safeseh")) 57 OS.EmitCOFFSafeSEH(Asm->getSymbol(&F)); 58 } 59 60 void WinException::beginFunction(const MachineFunction *MF) { 61 shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; 62 63 // If any landing pads survive, we need an EH table. 64 bool hasLandingPads = !MMI->getLandingPads().empty(); 65 bool hasEHFunclets = MMI->hasEHFunclets(); 66 67 const Function *F = MF->getFunction(); 68 const Function *ParentF = MMI->getWinEHParent(F); 69 70 shouldEmitMoves = Asm->needsSEHMoves(); 71 72 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 73 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 74 const Function *Per = nullptr; 75 if (F->hasPersonalityFn()) 76 Per = dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); 77 78 bool forceEmitPersonality = 79 F->hasPersonalityFn() && !isNoOpWithoutInvoke(classifyEHPersonality(Per)) && 80 F->needsUnwindTableEntry(); 81 82 shouldEmitPersonality = 83 forceEmitPersonality || ((hasLandingPads || hasEHFunclets) && 84 PerEncoding != dwarf::DW_EH_PE_omit && Per); 85 86 unsigned LSDAEncoding = TLOF.getLSDAEncoding(); 87 shouldEmitLSDA = shouldEmitPersonality && 88 LSDAEncoding != dwarf::DW_EH_PE_omit; 89 90 // If we're not using CFI, we don't want the CFI or the personality, but we 91 // might want EH tables if we had EH pads. 92 // FIXME: If WinEHPrepare outlined something, we should emit the LSDA. Remove 93 // this once WinEHPrepare stops doing that. 94 if (!Asm->MAI->usesWindowsCFI()) { 95 shouldEmitLSDA = 96 hasEHFunclets || (F->hasFnAttribute("wineh-parent") && F == ParentF); 97 shouldEmitPersonality = false; 98 return; 99 } 100 101 // If this was an outlined handler, we need to define the label corresponding 102 // to the offset of the parent frame relative to the stack pointer after the 103 // prologue. 104 if (F != ParentF) { 105 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); 106 auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F); 107 if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) { 108 MCSymbol *HandlerTypeParentFrameOffset = 109 Asm->OutContext.getOrCreateParentFrameOffsetSymbol( 110 GlobalValue::getRealLinkageName(F->getName())); 111 112 // Emit a symbol assignment. 113 Asm->OutStreamer->EmitAssignment( 114 HandlerTypeParentFrameOffset, 115 MCConstantExpr::create(I->second, Asm->OutContext)); 116 } 117 } 118 119 if (shouldEmitMoves || shouldEmitPersonality) 120 Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym); 121 122 if (shouldEmitPersonality) { 123 const MCSymbol *PersHandlerSym = 124 TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI); 125 Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true); 126 } 127 } 128 129 /// endFunction - Gather and emit post-function exception information. 130 /// 131 void WinException::endFunction(const MachineFunction *MF) { 132 if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA) 133 return; 134 135 const Function *F = MF->getFunction(); 136 EHPersonality Per = EHPersonality::Unknown; 137 if (F->hasPersonalityFn()) 138 Per = classifyEHPersonality(F->getPersonalityFn()); 139 140 // Get rid of any dead landing pads if we're not using a Windows EH scheme. In 141 // Windows EH schemes, the landing pad is not actually reachable. It only 142 // exists so that we can emit the right table data. 143 if (!isMSVCEHPersonality(Per)) 144 MMI->TidyLandingPads(); 145 146 if (shouldEmitPersonality || shouldEmitLSDA) { 147 Asm->OutStreamer->PushSection(); 148 149 if (shouldEmitMoves || shouldEmitPersonality) { 150 // Emit an UNWIND_INFO struct describing the prologue. 151 Asm->OutStreamer->EmitWinEHHandlerData(); 152 } else { 153 // Just switch sections to the right xdata section. This use of 154 // CurrentFnSym assumes that we only emit the LSDA when ending the parent 155 // function. 156 MCSection *XData = WinEH::UnwindEmitter::getXDataSection( 157 Asm->CurrentFnSym, Asm->OutContext); 158 Asm->OutStreamer->SwitchSection(XData); 159 } 160 161 // Emit the tables appropriate to the personality function in use. If we 162 // don't recognize the personality, assume it uses an Itanium-style LSDA. 163 if (Per == EHPersonality::MSVC_Win64SEH) 164 emitCSpecificHandlerTable(MF); 165 else if (Per == EHPersonality::MSVC_X86SEH) 166 emitExceptHandlerTable(MF); 167 else if (Per == EHPersonality::MSVC_CXX) 168 emitCXXFrameHandler3Table(MF); 169 else 170 emitExceptionTable(); 171 172 Asm->OutStreamer->PopSection(); 173 } 174 175 if (shouldEmitMoves || shouldEmitPersonality) 176 Asm->OutStreamer->EmitWinCFIEndProc(); 177 } 178 179 const MCExpr *WinException::create32bitRef(const MCSymbol *Value) { 180 if (!Value) 181 return MCConstantExpr::create(0, Asm->OutContext); 182 return MCSymbolRefExpr::create(Value, useImageRel32 183 ? MCSymbolRefExpr::VK_COFF_IMGREL32 184 : MCSymbolRefExpr::VK_None, 185 Asm->OutContext); 186 } 187 188 const MCExpr *WinException::create32bitRef(const Value *V) { 189 if (!V) 190 return MCConstantExpr::create(0, Asm->OutContext); 191 // FIXME: Delete the GlobalValue case once the new IR is fully functional. 192 if (const auto *GV = dyn_cast<GlobalValue>(V)) 193 return create32bitRef(Asm->getSymbol(GV)); 194 return create32bitRef(MMI->getAddrLabelSymbol(cast<BasicBlock>(V))); 195 } 196 197 /// Emit the language-specific data that __C_specific_handler expects. This 198 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning 199 /// up after faults with __try, __except, and __finally. The typeinfo values 200 /// are not really RTTI data, but pointers to filter functions that return an 201 /// integer (1, 0, or -1) indicating how to handle the exception. For __finally 202 /// blocks and other cleanups, the landing pad label is zero, and the filter 203 /// function is actually a cleanup handler with the same prototype. A catch-all 204 /// entry is modeled with a null filter function field and a non-zero landing 205 /// pad label. 206 /// 207 /// Possible filter function return values: 208 /// EXCEPTION_EXECUTE_HANDLER (1): 209 /// Jump to the landing pad label after cleanups. 210 /// EXCEPTION_CONTINUE_SEARCH (0): 211 /// Continue searching this table or continue unwinding. 212 /// EXCEPTION_CONTINUE_EXECUTION (-1): 213 /// Resume execution at the trapping PC. 214 /// 215 /// Inferred table structure: 216 /// struct Table { 217 /// int NumEntries; 218 /// struct Entry { 219 /// imagerel32 LabelStart; 220 /// imagerel32 LabelEnd; 221 /// imagerel32 FilterOrFinally; // One means catch-all. 222 /// imagerel32 LabelLPad; // Zero means __finally. 223 /// } Entries[NumEntries]; 224 /// }; 225 void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { 226 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 227 228 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction()); 229 if (!FuncInfo.SEHUnwindMap.empty()) 230 report_fatal_error("x64 SEH tables not yet implemented"); 231 232 // Simplifying assumptions for first implementation: 233 // - Cleanups are not implemented. 234 // - Filters are not implemented. 235 236 // The Itanium LSDA table sorts similar landing pads together to simplify the 237 // actions table, but we don't need that. 238 SmallVector<const LandingPadInfo *, 64> LandingPads; 239 LandingPads.reserve(PadInfos.size()); 240 for (const auto &LP : PadInfos) 241 LandingPads.push_back(&LP); 242 243 // Compute label ranges for call sites as we would for the Itanium LSDA, but 244 // use an all zero action table because we aren't using these actions. 245 SmallVector<unsigned, 64> FirstActions; 246 FirstActions.resize(LandingPads.size()); 247 SmallVector<CallSiteEntry, 64> CallSites; 248 computeCallSiteTable(CallSites, LandingPads, FirstActions); 249 250 MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); 251 MCSymbol *EHFuncEndSym = Asm->getFunctionEnd(); 252 253 // Emit the number of table entries. 254 unsigned NumEntries = 0; 255 for (const CallSiteEntry &CSE : CallSites) { 256 if (!CSE.LPad) 257 continue; // Ignore gaps. 258 NumEntries += CSE.LPad->SEHHandlers.size(); 259 } 260 Asm->OutStreamer->EmitIntValue(NumEntries, 4); 261 262 // If there are no actions, we don't need to iterate again. 263 if (NumEntries == 0) 264 return; 265 266 // Emit the four-label records for each call site entry. The table has to be 267 // sorted in layout order, and the call sites should already be sorted. 268 for (const CallSiteEntry &CSE : CallSites) { 269 // Ignore gaps. Unlike the Itanium model, unwinding through a frame without 270 // an EH table entry will propagate the exception rather than terminating 271 // the program. 272 if (!CSE.LPad) 273 continue; 274 const LandingPadInfo *LPad = CSE.LPad; 275 276 // Compute the label range. We may reuse the function begin and end labels 277 // rather than forming new ones. 278 const MCExpr *Begin = 279 create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym); 280 const MCExpr *End; 281 if (CSE.EndLabel) { 282 // The interval is half-open, so we have to add one to include the return 283 // address of the last invoke in the range. 284 End = MCBinaryExpr::createAdd(create32bitRef(CSE.EndLabel), 285 MCConstantExpr::create(1, Asm->OutContext), 286 Asm->OutContext); 287 } else { 288 End = create32bitRef(EHFuncEndSym); 289 } 290 291 // Emit an entry for each action. 292 for (SEHHandler Handler : LPad->SEHHandlers) { 293 Asm->OutStreamer->EmitValue(Begin, 4); 294 Asm->OutStreamer->EmitValue(End, 4); 295 296 // Emit the filter or finally function pointer, if present. Otherwise, 297 // emit '1' to indicate a catch-all. 298 const Function *F = Handler.FilterOrFinally; 299 if (F) 300 Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4); 301 else 302 Asm->OutStreamer->EmitIntValue(1, 4); 303 304 // Emit the recovery address, if present. Otherwise, this must be a 305 // finally. 306 const BlockAddress *BA = Handler.RecoverBA; 307 if (BA) 308 Asm->OutStreamer->EmitValue( 309 create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4); 310 else 311 Asm->OutStreamer->EmitIntValue(0, 4); 312 } 313 } 314 } 315 316 /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues 317 /// are used in the old WinEH scheme, and they will be removed eventually. 318 static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) { 319 if (!Handler) 320 return nullptr; 321 if (Handler.is<MachineBasicBlock *>()) 322 return Handler.get<MachineBasicBlock *>()->getSymbol(); 323 return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>())); 324 } 325 326 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { 327 const Function *F = MF->getFunction(); 328 const Function *ParentF = MMI->getWinEHParent(F); 329 auto &OS = *Asm->OutStreamer; 330 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); 331 332 StringRef ParentLinkageName = 333 GlobalValue::getRealLinkageName(ParentF->getName()); 334 335 MCSymbol *FuncInfoXData = nullptr; 336 if (shouldEmitPersonality) { 337 FuncInfoXData = Asm->OutContext.getOrCreateSymbol( 338 Twine("$cppxdata$", ParentLinkageName)); 339 OS.EmitValue(create32bitRef(FuncInfoXData), 4); 340 341 extendIP2StateTable(MF, ParentF, FuncInfo); 342 343 if (!MMI->hasEHFunclets()) { 344 // Defer emission until we've visited the parent function and all the 345 // catch handlers. Cleanups don't contribute to the ip2state table, so 346 // don't count them. 347 if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F)) 348 return; 349 ++FuncInfo.NumIPToStateFuncsVisited; 350 if (FuncInfo.NumIPToStateFuncsVisited != 351 FuncInfo.CatchHandlerMaxState.size()) 352 return; 353 } 354 } else { 355 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(ParentLinkageName); 356 emitEHRegistrationOffsetLabel(FuncInfo, ParentLinkageName); 357 } 358 359 MCSymbol *UnwindMapXData = nullptr; 360 MCSymbol *TryBlockMapXData = nullptr; 361 MCSymbol *IPToStateXData = nullptr; 362 if (!FuncInfo.UnwindMap.empty()) 363 UnwindMapXData = Asm->OutContext.getOrCreateSymbol( 364 Twine("$stateUnwindMap$", ParentLinkageName)); 365 if (!FuncInfo.TryBlockMap.empty()) 366 TryBlockMapXData = Asm->OutContext.getOrCreateSymbol( 367 Twine("$tryMap$", ParentLinkageName)); 368 if (!FuncInfo.IPToStateList.empty()) 369 IPToStateXData = Asm->OutContext.getOrCreateSymbol( 370 Twine("$ip2state$", ParentLinkageName)); 371 372 // FuncInfo { 373 // uint32_t MagicNumber 374 // int32_t MaxState; 375 // UnwindMapEntry *UnwindMap; 376 // uint32_t NumTryBlocks; 377 // TryBlockMapEntry *TryBlockMap; 378 // uint32_t IPMapEntries; // always 0 for x86 379 // IPToStateMapEntry *IPToStateMap; // always 0 for x86 380 // uint32_t UnwindHelp; // non-x86 only 381 // ESTypeList *ESTypeList; 382 // int32_t EHFlags; 383 // } 384 // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. 385 // EHFlags & 2 -> ??? 386 // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. 387 OS.EmitValueToAlignment(4); 388 OS.EmitLabel(FuncInfoXData); 389 OS.EmitIntValue(0x19930522, 4); // MagicNumber 390 OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState 391 OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap 392 OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks 393 OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap 394 OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries 395 OS.EmitValue(create32bitRef(IPToStateXData), 4); // IPToStateMap 396 if (Asm->MAI->usesWindowsCFI()) 397 OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp 398 OS.EmitIntValue(0, 4); // ESTypeList 399 OS.EmitIntValue(1, 4); // EHFlags 400 401 // UnwindMapEntry { 402 // int32_t ToState; 403 // void (*Action)(); 404 // }; 405 if (UnwindMapXData) { 406 OS.EmitLabel(UnwindMapXData); 407 for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { 408 MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup); 409 OS.EmitIntValue(UME.ToState, 4); // ToState 410 OS.EmitValue(create32bitRef(CleanupSym), 4); // Action 411 } 412 } 413 414 // TryBlockMap { 415 // int32_t TryLow; 416 // int32_t TryHigh; 417 // int32_t CatchHigh; 418 // int32_t NumCatches; 419 // HandlerType *HandlerArray; 420 // }; 421 if (TryBlockMapXData) { 422 OS.EmitLabel(TryBlockMapXData); 423 SmallVector<MCSymbol *, 1> HandlerMaps; 424 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 425 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 426 MCSymbol *HandlerMapXData = nullptr; 427 428 if (!TBME.HandlerArray.empty()) 429 HandlerMapXData = 430 Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") 431 .concat(Twine(I)) 432 .concat("$") 433 .concat(ParentLinkageName)); 434 435 HandlerMaps.push_back(HandlerMapXData); 436 437 int CatchHigh = TBME.CatchHigh; 438 if (CatchHigh == -1) { 439 for (WinEHHandlerType &HT : TBME.HandlerArray) 440 CatchHigh = 441 std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[cast<Function>( 442 HT.Handler.get<const Value *>())]); 443 } 444 445 assert(TBME.TryLow <= TBME.TryHigh); 446 OS.EmitIntValue(TBME.TryLow, 4); // TryLow 447 OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh 448 OS.EmitIntValue(CatchHigh, 4); // CatchHigh 449 OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches 450 OS.EmitValue(create32bitRef(HandlerMapXData), 4); // HandlerArray 451 } 452 453 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 454 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 455 MCSymbol *HandlerMapXData = HandlerMaps[I]; 456 if (!HandlerMapXData) 457 continue; 458 // HandlerType { 459 // int32_t Adjectives; 460 // TypeDescriptor *Type; 461 // int32_t CatchObjOffset; 462 // void (*Handler)(); 463 // int32_t ParentFrameOffset; // x64 only 464 // }; 465 OS.EmitLabel(HandlerMapXData); 466 for (const WinEHHandlerType &HT : TBME.HandlerArray) { 467 // Get the frame escape label with the offset of the catch object. If 468 // the index is -1, then there is no catch object, and we should emit an 469 // offset of zero, indicating that no copy will occur. 470 const MCExpr *FrameAllocOffsetRef = nullptr; 471 if (HT.CatchObjRecoverIdx >= 0) { 472 MCSymbol *FrameAllocOffset = 473 Asm->OutContext.getOrCreateFrameAllocSymbol( 474 GlobalValue::getRealLinkageName(ParentF->getName()), 475 HT.CatchObjRecoverIdx); 476 FrameAllocOffsetRef = MCSymbolRefExpr::create( 477 FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); 478 } else { 479 FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext); 480 } 481 482 MCSymbol *HandlerSym = getMCSymbolForMBBOrGV(Asm, HT.Handler); 483 484 OS.EmitIntValue(HT.Adjectives, 4); // Adjectives 485 OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); // Type 486 OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset 487 OS.EmitValue(create32bitRef(HandlerSym), 4); // Handler 488 489 if (shouldEmitPersonality) { 490 if (FuncInfo.CatchHandlerParentFrameObjOffset.empty()) { 491 // With the new IR, this is always 16 + 8 + getMaxCallFrameSize(). 492 // Keep this in sync with X86FrameLowering::emitPrologue. 493 int ParentFrameOffset = 494 16 + 8 + MF->getFrameInfo()->getMaxCallFrameSize(); 495 OS.EmitIntValue(ParentFrameOffset, 4); // ParentFrameOffset 496 } else { 497 MCSymbol *ParentFrameOffset = 498 Asm->OutContext.getOrCreateParentFrameOffsetSymbol( 499 GlobalValue::getRealLinkageName( 500 HT.Handler.get<const Value *>()->getName())); 501 const MCSymbolRefExpr *ParentFrameOffsetRef = 502 MCSymbolRefExpr::create(ParentFrameOffset, Asm->OutContext); 503 OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset 504 } 505 } 506 } 507 } 508 } 509 510 // IPToStateMapEntry { 511 // void *IP; 512 // int32_t State; 513 // }; 514 if (IPToStateXData) { 515 OS.EmitLabel(IPToStateXData); 516 for (auto &IPStatePair : FuncInfo.IPToStateList) { 517 OS.EmitValue(create32bitRef(IPStatePair.first), 4); // IP 518 OS.EmitIntValue(IPStatePair.second, 4); // State 519 } 520 } 521 } 522 523 void WinException::extendIP2StateTable(const MachineFunction *MF, 524 const Function *ParentF, 525 WinEHFuncInfo &FuncInfo) { 526 const Function *F = MF->getFunction(); 527 528 // The Itanium LSDA table sorts similar landing pads together to simplify the 529 // actions table, but we don't need that. 530 SmallVector<const LandingPadInfo *, 64> LandingPads; 531 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 532 LandingPads.reserve(PadInfos.size()); 533 for (const auto &LP : PadInfos) 534 LandingPads.push_back(&LP); 535 536 RangeMapType PadMap; 537 computePadMap(LandingPads, PadMap); 538 539 // The end label of the previous invoke or nounwind try-range. 540 MCSymbol *LastLabel = Asm->getFunctionBegin(); 541 542 // Whether there is a potentially throwing instruction (currently this means 543 // an ordinary call) between the end of the previous try-range and now. 544 bool SawPotentiallyThrowing = false; 545 546 int LastEHState = -2; 547 548 // The parent function and the catch handlers contribute to the 'ip2state' 549 // table. 550 551 // Include ip2state entries for the beginning of the main function and 552 // for catch handler functions. 553 if (F == ParentF) { 554 FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); 555 LastEHState = -1; 556 } else if (FuncInfo.HandlerBaseState.count(F)) { 557 FuncInfo.IPToStateList.push_back( 558 std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F])); 559 LastEHState = FuncInfo.HandlerBaseState[F]; 560 } 561 for (const auto &MBB : *MF) { 562 for (const auto &MI : MBB) { 563 if (!MI.isEHLabel()) { 564 if (MI.isCall()) 565 SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); 566 continue; 567 } 568 569 // End of the previous try-range? 570 MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol(); 571 if (BeginLabel == LastLabel) 572 SawPotentiallyThrowing = false; 573 574 // Beginning of a new try-range? 575 RangeMapType::const_iterator L = PadMap.find(BeginLabel); 576 if (L == PadMap.end()) 577 // Nope, it was just some random label. 578 continue; 579 580 const PadRange &P = L->second; 581 const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; 582 assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && 583 "Inconsistent landing pad map!"); 584 585 // FIXME: Should this be using FuncInfo.HandlerBaseState? 586 if (SawPotentiallyThrowing && LastEHState != -1) { 587 FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); 588 SawPotentiallyThrowing = false; 589 LastEHState = -1; 590 } 591 592 if (LandingPad->WinEHState != LastEHState) 593 FuncInfo.IPToStateList.push_back( 594 std::make_pair(BeginLabel, LandingPad->WinEHState)); 595 LastEHState = LandingPad->WinEHState; 596 LastLabel = LandingPad->EndLabels[P.RangeIndex]; 597 } 598 } 599 } 600 601 void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, 602 StringRef FLinkageName) { 603 // Outlined helpers called by the EH runtime need to know the offset of the EH 604 // registration in order to recover the parent frame pointer. Now that we know 605 // we've code generated the parent, we can emit the label assignment that 606 // those helpers use to get the offset of the registration node. 607 assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX && 608 "no EH reg node localescape index"); 609 MCSymbol *ParentFrameOffset = 610 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName); 611 MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol( 612 FLinkageName, FuncInfo.EHRegNodeEscapeIndex); 613 const MCExpr *RegistrationOffsetSymRef = 614 MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext); 615 Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef); 616 } 617 618 /// Emit the language-specific data that _except_handler3 and 4 expect. This is 619 /// functionally equivalent to the __C_specific_handler table, except it is 620 /// indexed by state number instead of IP. 621 void WinException::emitExceptHandlerTable(const MachineFunction *MF) { 622 MCStreamer &OS = *Asm->OutStreamer; 623 const Function *F = MF->getFunction(); 624 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName()); 625 626 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F); 627 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName); 628 629 // Emit the __ehtable label that we use for llvm.x86.seh.lsda. 630 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); 631 OS.EmitValueToAlignment(4); 632 OS.EmitLabel(LSDALabel); 633 634 const Function *Per = 635 dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); 636 StringRef PerName = Per->getName(); 637 int BaseState = -1; 638 if (PerName == "_except_handler4") { 639 // The LSDA for _except_handler4 starts with this struct, followed by the 640 // scope table: 641 // 642 // struct EH4ScopeTable { 643 // int32_t GSCookieOffset; 644 // int32_t GSCookieXOROffset; 645 // int32_t EHCookieOffset; 646 // int32_t EHCookieXOROffset; 647 // ScopeTableEntry ScopeRecord[]; 648 // }; 649 // 650 // Only the EHCookieOffset field appears to vary, and it appears to be the 651 // offset from the final saved SP value to the retaddr. 652 OS.EmitIntValue(-2, 4); 653 OS.EmitIntValue(0, 4); 654 // FIXME: Calculate. 655 OS.EmitIntValue(9999, 4); 656 OS.EmitIntValue(0, 4); 657 BaseState = -2; 658 } 659 660 if (!FuncInfo.SEHUnwindMap.empty()) { 661 for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) { 662 MCSymbol *ExceptOrFinally = 663 UME.Handler.get<MachineBasicBlock *>()->getSymbol(); 664 OS.EmitIntValue(UME.ToState, 4); // ToState 665 OS.EmitValue(create32bitRef(UME.Filter), 4); // Filter 666 OS.EmitValue(create32bitRef(ExceptOrFinally), 4); // Except/Finally 667 } 668 return; 669 } 670 // FIXME: The following code is for the old landingpad-based SEH 671 // implementation. Remove it when possible. 672 673 // Build a list of pointers to LandingPadInfos and then sort by WinEHState. 674 const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 675 SmallVector<const LandingPadInfo *, 4> LPads; 676 LPads.reserve((PadInfos.size())); 677 for (const LandingPadInfo &LPInfo : PadInfos) 678 LPads.push_back(&LPInfo); 679 std::sort(LPads.begin(), LPads.end(), 680 [](const LandingPadInfo *L, const LandingPadInfo *R) { 681 return L->WinEHState < R->WinEHState; 682 }); 683 684 // For each action in each lpad, emit one of these: 685 // struct ScopeTableEntry { 686 // int32_t EnclosingLevel; 687 // int32_t (__cdecl *Filter)(); 688 // void *HandlerOrFinally; 689 // }; 690 // 691 // The "outermost" action will use BaseState as its enclosing level. Each 692 // other action will refer to the previous state as its enclosing level. 693 int CurState = 0; 694 for (const LandingPadInfo *LPInfo : LPads) { 695 int EnclosingLevel = BaseState; 696 assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 == 697 LPInfo->WinEHState && 698 "gaps in the SEH scope table"); 699 for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend(); 700 I != E; ++I) { 701 const SEHHandler &Handler = *I; 702 const BlockAddress *BA = Handler.RecoverBA; 703 const Function *F = Handler.FilterOrFinally; 704 assert(F && "cannot catch all in 32-bit SEH without filter function"); 705 const MCExpr *FilterOrNull = 706 create32bitRef(BA ? Asm->getSymbol(F) : nullptr); 707 const MCExpr *ExceptOrFinally = create32bitRef( 708 BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F)); 709 710 OS.EmitIntValue(EnclosingLevel, 4); 711 OS.EmitValue(FilterOrNull, 4); 712 OS.EmitValue(ExceptOrFinally, 4); 713 714 // The next state unwinds to this state. 715 EnclosingLevel = CurState; 716 CurState++; 717 } 718 } 719 } 720