WinException.cpp revision 285181
1284184Sdim//===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===// 2284184Sdim// 3284184Sdim// The LLVM Compiler Infrastructure 4284184Sdim// 5284184Sdim// This file is distributed under the University of Illinois Open Source 6284184Sdim// License. See LICENSE.TXT for details. 7284184Sdim// 8284184Sdim//===----------------------------------------------------------------------===// 9284184Sdim// 10284184Sdim// This file contains support for writing Win64 exception info into asm files. 11284184Sdim// 12284184Sdim//===----------------------------------------------------------------------===// 13284184Sdim 14284184Sdim#include "WinException.h" 15284184Sdim#include "llvm/ADT/SmallString.h" 16284184Sdim#include "llvm/ADT/StringExtras.h" 17284184Sdim#include "llvm/ADT/Twine.h" 18284184Sdim#include "llvm/CodeGen/AsmPrinter.h" 19284184Sdim#include "llvm/CodeGen/MachineFrameInfo.h" 20284184Sdim#include "llvm/CodeGen/MachineFunction.h" 21284184Sdim#include "llvm/CodeGen/MachineModuleInfo.h" 22284184Sdim#include "llvm/CodeGen/WinEHFuncInfo.h" 23284184Sdim#include "llvm/IR/DataLayout.h" 24284184Sdim#include "llvm/IR/Mangler.h" 25284184Sdim#include "llvm/IR/Module.h" 26284184Sdim#include "llvm/MC/MCAsmInfo.h" 27284184Sdim#include "llvm/MC/MCContext.h" 28284184Sdim#include "llvm/MC/MCExpr.h" 29284184Sdim#include "llvm/MC/MCSection.h" 30284184Sdim#include "llvm/MC/MCStreamer.h" 31284184Sdim#include "llvm/MC/MCSymbol.h" 32284184Sdim#include "llvm/MC/MCWin64EH.h" 33284184Sdim#include "llvm/Support/Dwarf.h" 34284184Sdim#include "llvm/Support/ErrorHandling.h" 35284184Sdim#include "llvm/Support/FormattedStream.h" 36284184Sdim#include "llvm/Target/TargetFrameLowering.h" 37284184Sdim#include "llvm/Target/TargetLoweringObjectFile.h" 38284184Sdim#include "llvm/Target/TargetOptions.h" 39284184Sdim#include "llvm/Target/TargetRegisterInfo.h" 40284184Sdimusing namespace llvm; 41284184Sdim 42284184SdimWinException::WinException(AsmPrinter *A) : EHStreamer(A) { 43284184Sdim // MSVC's EH tables are always composed of 32-bit words. All known 64-bit 44284184Sdim // platforms use an imagerel32 relocation to refer to symbols. 45284184Sdim useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64); 46284184Sdim} 47284184Sdim 48284184SdimWinException::~WinException() {} 49284184Sdim 50284184Sdim/// endModule - Emit all exception information that should come after the 51284184Sdim/// content. 52284184Sdimvoid WinException::endModule() { 53284734Sdim auto &OS = *Asm->OutStreamer; 54284734Sdim const Module *M = MMI->getModule(); 55284734Sdim for (const Function &F : *M) 56284734Sdim if (F.hasFnAttribute("safeseh")) 57284734Sdim OS.EmitCOFFSafeSEH(Asm->getSymbol(&F)); 58284184Sdim} 59284184Sdim 60284184Sdimvoid WinException::beginFunction(const MachineFunction *MF) { 61284184Sdim shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; 62284184Sdim 63284184Sdim // If any landing pads survive, we need an EH table. 64284184Sdim bool hasLandingPads = !MMI->getLandingPads().empty(); 65284184Sdim 66284184Sdim const Function *F = MF->getFunction(); 67284184Sdim const Function *ParentF = MMI->getWinEHParent(F); 68284184Sdim 69284184Sdim shouldEmitMoves = Asm->needsSEHMoves(); 70284184Sdim 71284184Sdim const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 72284184Sdim unsigned PerEncoding = TLOF.getPersonalityEncoding(); 73284184Sdim const Function *Per = MMI->getPersonality(); 74284184Sdim 75284184Sdim shouldEmitPersonality = hasLandingPads && 76284184Sdim PerEncoding != dwarf::DW_EH_PE_omit && Per; 77284184Sdim 78284184Sdim unsigned LSDAEncoding = TLOF.getLSDAEncoding(); 79284184Sdim shouldEmitLSDA = shouldEmitPersonality && 80284184Sdim LSDAEncoding != dwarf::DW_EH_PE_omit; 81284184Sdim 82284184Sdim // If we're not using CFI, we don't want the CFI or the personality. Emit the 83284184Sdim // LSDA if this is the parent function. 84284184Sdim if (!Asm->MAI->usesWindowsCFI()) { 85284184Sdim shouldEmitLSDA = (hasLandingPads && F == ParentF); 86284184Sdim shouldEmitPersonality = false; 87284184Sdim return; 88284184Sdim } 89284184Sdim 90284184Sdim // If this was an outlined handler, we need to define the label corresponding 91284184Sdim // to the offset of the parent frame relative to the stack pointer after the 92284184Sdim // prologue. 93284184Sdim if (F != ParentF) { 94284184Sdim WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); 95284184Sdim auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F); 96284184Sdim if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) { 97284184Sdim MCSymbol *HandlerTypeParentFrameOffset = 98284184Sdim Asm->OutContext.getOrCreateParentFrameOffsetSymbol( 99284184Sdim GlobalValue::getRealLinkageName(F->getName())); 100284184Sdim 101284184Sdim // Emit a symbol assignment. 102284184Sdim Asm->OutStreamer->EmitAssignment( 103284184Sdim HandlerTypeParentFrameOffset, 104284184Sdim MCConstantExpr::create(I->second, Asm->OutContext)); 105284184Sdim } 106284184Sdim } 107284184Sdim 108284184Sdim if (shouldEmitMoves || shouldEmitPersonality) 109284184Sdim Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym); 110284184Sdim 111284184Sdim if (shouldEmitPersonality) { 112284184Sdim const MCSymbol *PersHandlerSym = 113284184Sdim TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI); 114284184Sdim Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true); 115284184Sdim } 116284184Sdim} 117284184Sdim 118284184Sdim/// endFunction - Gather and emit post-function exception information. 119284184Sdim/// 120284184Sdimvoid WinException::endFunction(const MachineFunction *MF) { 121284184Sdim if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA) 122284184Sdim return; 123284184Sdim 124284184Sdim EHPersonality Per = MMI->getPersonalityType(); 125284184Sdim 126284184Sdim // Get rid of any dead landing pads if we're not using a Windows EH scheme. In 127284184Sdim // Windows EH schemes, the landing pad is not actually reachable. It only 128284184Sdim // exists so that we can emit the right table data. 129284184Sdim if (!isMSVCEHPersonality(Per)) 130284184Sdim MMI->TidyLandingPads(); 131284184Sdim 132284184Sdim if (shouldEmitPersonality || shouldEmitLSDA) { 133284184Sdim Asm->OutStreamer->PushSection(); 134284184Sdim 135284184Sdim if (shouldEmitMoves || shouldEmitPersonality) { 136284184Sdim // Emit an UNWIND_INFO struct describing the prologue. 137284184Sdim Asm->OutStreamer->EmitWinEHHandlerData(); 138284184Sdim } else { 139284184Sdim // Just switch sections to the right xdata section. This use of 140284184Sdim // CurrentFnSym assumes that we only emit the LSDA when ending the parent 141284184Sdim // function. 142284184Sdim MCSection *XData = WinEH::UnwindEmitter::getXDataSection( 143284184Sdim Asm->CurrentFnSym, Asm->OutContext); 144284184Sdim Asm->OutStreamer->SwitchSection(XData); 145284184Sdim } 146284184Sdim 147284184Sdim // Emit the tables appropriate to the personality function in use. If we 148284184Sdim // don't recognize the personality, assume it uses an Itanium-style LSDA. 149284184Sdim if (Per == EHPersonality::MSVC_Win64SEH) 150284184Sdim emitCSpecificHandlerTable(); 151284184Sdim else if (Per == EHPersonality::MSVC_X86SEH) 152284734Sdim emitExceptHandlerTable(MF); 153284184Sdim else if (Per == EHPersonality::MSVC_CXX) 154284184Sdim emitCXXFrameHandler3Table(MF); 155284184Sdim else 156284184Sdim emitExceptionTable(); 157284184Sdim 158284184Sdim Asm->OutStreamer->PopSection(); 159284184Sdim } 160284184Sdim 161284184Sdim if (shouldEmitMoves) 162284184Sdim Asm->OutStreamer->EmitWinCFIEndProc(); 163284184Sdim} 164284184Sdim 165284184Sdimconst MCExpr *WinException::create32bitRef(const MCSymbol *Value) { 166284184Sdim if (!Value) 167284184Sdim return MCConstantExpr::create(0, Asm->OutContext); 168284184Sdim return MCSymbolRefExpr::create(Value, useImageRel32 169284184Sdim ? MCSymbolRefExpr::VK_COFF_IMGREL32 170284184Sdim : MCSymbolRefExpr::VK_None, 171284184Sdim Asm->OutContext); 172284184Sdim} 173284184Sdim 174284184Sdimconst MCExpr *WinException::create32bitRef(const GlobalValue *GV) { 175284184Sdim if (!GV) 176284184Sdim return MCConstantExpr::create(0, Asm->OutContext); 177284184Sdim return create32bitRef(Asm->getSymbol(GV)); 178284184Sdim} 179284184Sdim 180284184Sdim/// Emit the language-specific data that __C_specific_handler expects. This 181284184Sdim/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning 182284184Sdim/// up after faults with __try, __except, and __finally. The typeinfo values 183284184Sdim/// are not really RTTI data, but pointers to filter functions that return an 184284184Sdim/// integer (1, 0, or -1) indicating how to handle the exception. For __finally 185284184Sdim/// blocks and other cleanups, the landing pad label is zero, and the filter 186284184Sdim/// function is actually a cleanup handler with the same prototype. A catch-all 187284184Sdim/// entry is modeled with a null filter function field and a non-zero landing 188284184Sdim/// pad label. 189284184Sdim/// 190284184Sdim/// Possible filter function return values: 191284184Sdim/// EXCEPTION_EXECUTE_HANDLER (1): 192284184Sdim/// Jump to the landing pad label after cleanups. 193284184Sdim/// EXCEPTION_CONTINUE_SEARCH (0): 194284184Sdim/// Continue searching this table or continue unwinding. 195284184Sdim/// EXCEPTION_CONTINUE_EXECUTION (-1): 196284184Sdim/// Resume execution at the trapping PC. 197284184Sdim/// 198284184Sdim/// Inferred table structure: 199284184Sdim/// struct Table { 200284184Sdim/// int NumEntries; 201284184Sdim/// struct Entry { 202284184Sdim/// imagerel32 LabelStart; 203284184Sdim/// imagerel32 LabelEnd; 204284184Sdim/// imagerel32 FilterOrFinally; // One means catch-all. 205284184Sdim/// imagerel32 LabelLPad; // Zero means __finally. 206284184Sdim/// } Entries[NumEntries]; 207284184Sdim/// }; 208284184Sdimvoid WinException::emitCSpecificHandlerTable() { 209284184Sdim const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 210284184Sdim 211284184Sdim // Simplifying assumptions for first implementation: 212284184Sdim // - Cleanups are not implemented. 213284184Sdim // - Filters are not implemented. 214284184Sdim 215284184Sdim // The Itanium LSDA table sorts similar landing pads together to simplify the 216284184Sdim // actions table, but we don't need that. 217284184Sdim SmallVector<const LandingPadInfo *, 64> LandingPads; 218284184Sdim LandingPads.reserve(PadInfos.size()); 219284184Sdim for (const auto &LP : PadInfos) 220284184Sdim LandingPads.push_back(&LP); 221284184Sdim 222284184Sdim // Compute label ranges for call sites as we would for the Itanium LSDA, but 223284184Sdim // use an all zero action table because we aren't using these actions. 224284184Sdim SmallVector<unsigned, 64> FirstActions; 225284184Sdim FirstActions.resize(LandingPads.size()); 226284184Sdim SmallVector<CallSiteEntry, 64> CallSites; 227284184Sdim computeCallSiteTable(CallSites, LandingPads, FirstActions); 228284184Sdim 229284184Sdim MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); 230284184Sdim MCSymbol *EHFuncEndSym = Asm->getFunctionEnd(); 231284184Sdim 232284184Sdim // Emit the number of table entries. 233284184Sdim unsigned NumEntries = 0; 234284184Sdim for (const CallSiteEntry &CSE : CallSites) { 235284184Sdim if (!CSE.LPad) 236284184Sdim continue; // Ignore gaps. 237284184Sdim NumEntries += CSE.LPad->SEHHandlers.size(); 238284184Sdim } 239284184Sdim Asm->OutStreamer->EmitIntValue(NumEntries, 4); 240284184Sdim 241284184Sdim // If there are no actions, we don't need to iterate again. 242284184Sdim if (NumEntries == 0) 243284184Sdim return; 244284184Sdim 245284184Sdim // Emit the four-label records for each call site entry. The table has to be 246284184Sdim // sorted in layout order, and the call sites should already be sorted. 247284184Sdim for (const CallSiteEntry &CSE : CallSites) { 248284184Sdim // Ignore gaps. Unlike the Itanium model, unwinding through a frame without 249284184Sdim // an EH table entry will propagate the exception rather than terminating 250284184Sdim // the program. 251284184Sdim if (!CSE.LPad) 252284184Sdim continue; 253284184Sdim const LandingPadInfo *LPad = CSE.LPad; 254284184Sdim 255284184Sdim // Compute the label range. We may reuse the function begin and end labels 256284184Sdim // rather than forming new ones. 257284184Sdim const MCExpr *Begin = 258284184Sdim create32bitRef(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym); 259284184Sdim const MCExpr *End; 260284184Sdim if (CSE.EndLabel) { 261284184Sdim // The interval is half-open, so we have to add one to include the return 262284184Sdim // address of the last invoke in the range. 263284184Sdim End = MCBinaryExpr::createAdd(create32bitRef(CSE.EndLabel), 264284184Sdim MCConstantExpr::create(1, Asm->OutContext), 265284184Sdim Asm->OutContext); 266284184Sdim } else { 267284184Sdim End = create32bitRef(EHFuncEndSym); 268284184Sdim } 269284184Sdim 270284184Sdim // Emit an entry for each action. 271284184Sdim for (SEHHandler Handler : LPad->SEHHandlers) { 272284184Sdim Asm->OutStreamer->EmitValue(Begin, 4); 273284184Sdim Asm->OutStreamer->EmitValue(End, 4); 274284184Sdim 275284184Sdim // Emit the filter or finally function pointer, if present. Otherwise, 276284184Sdim // emit '1' to indicate a catch-all. 277284184Sdim const Function *F = Handler.FilterOrFinally; 278284184Sdim if (F) 279284184Sdim Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4); 280284184Sdim else 281284184Sdim Asm->OutStreamer->EmitIntValue(1, 4); 282284184Sdim 283284184Sdim // Emit the recovery address, if present. Otherwise, this must be a 284284184Sdim // finally. 285284184Sdim const BlockAddress *BA = Handler.RecoverBA; 286284184Sdim if (BA) 287284184Sdim Asm->OutStreamer->EmitValue( 288284184Sdim create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4); 289284184Sdim else 290284184Sdim Asm->OutStreamer->EmitIntValue(0, 4); 291284184Sdim } 292284184Sdim } 293284184Sdim} 294284184Sdim 295284184Sdimvoid WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { 296284184Sdim const Function *F = MF->getFunction(); 297284184Sdim const Function *ParentF = MMI->getWinEHParent(F); 298284184Sdim auto &OS = *Asm->OutStreamer; 299284184Sdim WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); 300284184Sdim 301284184Sdim StringRef ParentLinkageName = 302284184Sdim GlobalValue::getRealLinkageName(ParentF->getName()); 303284184Sdim 304284184Sdim MCSymbol *FuncInfoXData = nullptr; 305284184Sdim if (shouldEmitPersonality) { 306284184Sdim FuncInfoXData = Asm->OutContext.getOrCreateSymbol( 307284184Sdim Twine("$cppxdata$", ParentLinkageName)); 308284184Sdim OS.EmitValue(create32bitRef(FuncInfoXData), 4); 309284184Sdim 310284184Sdim extendIP2StateTable(MF, ParentF, FuncInfo); 311284184Sdim 312284184Sdim // Defer emission until we've visited the parent function and all the catch 313284184Sdim // handlers. Cleanups don't contribute to the ip2state table, so don't count 314284184Sdim // them. 315284184Sdim if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F)) 316284184Sdim return; 317284184Sdim ++FuncInfo.NumIPToStateFuncsVisited; 318284184Sdim if (FuncInfo.NumIPToStateFuncsVisited != FuncInfo.CatchHandlerMaxState.size()) 319284184Sdim return; 320284184Sdim } else { 321284184Sdim FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(ParentLinkageName); 322285181Sdim emitEHRegistrationOffsetLabel(FuncInfo, ParentLinkageName); 323284184Sdim } 324284184Sdim 325284184Sdim MCSymbol *UnwindMapXData = nullptr; 326284184Sdim MCSymbol *TryBlockMapXData = nullptr; 327284184Sdim MCSymbol *IPToStateXData = nullptr; 328284184Sdim if (!FuncInfo.UnwindMap.empty()) 329284184Sdim UnwindMapXData = Asm->OutContext.getOrCreateSymbol( 330284184Sdim Twine("$stateUnwindMap$", ParentLinkageName)); 331284184Sdim if (!FuncInfo.TryBlockMap.empty()) 332284184Sdim TryBlockMapXData = Asm->OutContext.getOrCreateSymbol( 333284184Sdim Twine("$tryMap$", ParentLinkageName)); 334284184Sdim if (!FuncInfo.IPToStateList.empty()) 335284184Sdim IPToStateXData = Asm->OutContext.getOrCreateSymbol( 336284184Sdim Twine("$ip2state$", ParentLinkageName)); 337284184Sdim 338284184Sdim // FuncInfo { 339284184Sdim // uint32_t MagicNumber 340284184Sdim // int32_t MaxState; 341284184Sdim // UnwindMapEntry *UnwindMap; 342284184Sdim // uint32_t NumTryBlocks; 343284184Sdim // TryBlockMapEntry *TryBlockMap; 344284184Sdim // uint32_t IPMapEntries; // always 0 for x86 345284184Sdim // IPToStateMapEntry *IPToStateMap; // always 0 for x86 346284184Sdim // uint32_t UnwindHelp; // non-x86 only 347284184Sdim // ESTypeList *ESTypeList; 348284184Sdim // int32_t EHFlags; 349284184Sdim // } 350284184Sdim // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. 351284184Sdim // EHFlags & 2 -> ??? 352284184Sdim // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. 353284184Sdim OS.EmitLabel(FuncInfoXData); 354284184Sdim OS.EmitIntValue(0x19930522, 4); // MagicNumber 355284184Sdim OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState 356284184Sdim OS.EmitValue(create32bitRef(UnwindMapXData), 4); // UnwindMap 357284184Sdim OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks 358284184Sdim OS.EmitValue(create32bitRef(TryBlockMapXData), 4); // TryBlockMap 359284184Sdim OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries 360284184Sdim OS.EmitValue(create32bitRef(IPToStateXData), 4); // IPToStateMap 361284184Sdim if (Asm->MAI->usesWindowsCFI()) 362284184Sdim OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp 363284184Sdim OS.EmitIntValue(0, 4); // ESTypeList 364284184Sdim OS.EmitIntValue(1, 4); // EHFlags 365284184Sdim 366284184Sdim // UnwindMapEntry { 367284184Sdim // int32_t ToState; 368284184Sdim // void (*Action)(); 369284184Sdim // }; 370284184Sdim if (UnwindMapXData) { 371284184Sdim OS.EmitLabel(UnwindMapXData); 372284184Sdim for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { 373284184Sdim OS.EmitIntValue(UME.ToState, 4); // ToState 374284184Sdim OS.EmitValue(create32bitRef(UME.Cleanup), 4); // Action 375284184Sdim } 376284184Sdim } 377284184Sdim 378284184Sdim // TryBlockMap { 379284184Sdim // int32_t TryLow; 380284184Sdim // int32_t TryHigh; 381284184Sdim // int32_t CatchHigh; 382284184Sdim // int32_t NumCatches; 383284184Sdim // HandlerType *HandlerArray; 384284184Sdim // }; 385284184Sdim if (TryBlockMapXData) { 386284184Sdim OS.EmitLabel(TryBlockMapXData); 387284184Sdim SmallVector<MCSymbol *, 1> HandlerMaps; 388284184Sdim for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 389284184Sdim WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 390284184Sdim MCSymbol *HandlerMapXData = nullptr; 391284184Sdim 392284184Sdim if (!TBME.HandlerArray.empty()) 393284184Sdim HandlerMapXData = 394284184Sdim Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") 395284184Sdim .concat(Twine(I)) 396284184Sdim .concat("$") 397284184Sdim .concat(ParentLinkageName)); 398284184Sdim 399284184Sdim HandlerMaps.push_back(HandlerMapXData); 400284184Sdim 401284184Sdim int CatchHigh = -1; 402284184Sdim for (WinEHHandlerType &HT : TBME.HandlerArray) 403284184Sdim CatchHigh = 404284184Sdim std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]); 405284184Sdim 406284184Sdim assert(TBME.TryLow <= TBME.TryHigh); 407284184Sdim OS.EmitIntValue(TBME.TryLow, 4); // TryLow 408284184Sdim OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh 409284184Sdim OS.EmitIntValue(CatchHigh, 4); // CatchHigh 410284184Sdim OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches 411284184Sdim OS.EmitValue(create32bitRef(HandlerMapXData), 4); // HandlerArray 412284184Sdim } 413284184Sdim 414284184Sdim for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 415284184Sdim WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 416284184Sdim MCSymbol *HandlerMapXData = HandlerMaps[I]; 417284184Sdim if (!HandlerMapXData) 418284184Sdim continue; 419284184Sdim // HandlerType { 420284184Sdim // int32_t Adjectives; 421284184Sdim // TypeDescriptor *Type; 422284184Sdim // int32_t CatchObjOffset; 423284184Sdim // void (*Handler)(); 424284184Sdim // int32_t ParentFrameOffset; // x64 only 425284184Sdim // }; 426284184Sdim OS.EmitLabel(HandlerMapXData); 427284184Sdim for (const WinEHHandlerType &HT : TBME.HandlerArray) { 428284184Sdim // Get the frame escape label with the offset of the catch object. If 429284184Sdim // the index is -1, then there is no catch object, and we should emit an 430284184Sdim // offset of zero, indicating that no copy will occur. 431284184Sdim const MCExpr *FrameAllocOffsetRef = nullptr; 432284184Sdim if (HT.CatchObjRecoverIdx >= 0) { 433284184Sdim MCSymbol *FrameAllocOffset = 434284184Sdim Asm->OutContext.getOrCreateFrameAllocSymbol( 435284184Sdim GlobalValue::getRealLinkageName(ParentF->getName()), 436284184Sdim HT.CatchObjRecoverIdx); 437284184Sdim FrameAllocOffsetRef = MCSymbolRefExpr::create( 438284184Sdim FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); 439284184Sdim } else { 440284184Sdim FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext); 441284184Sdim } 442284184Sdim 443284184Sdim OS.EmitIntValue(HT.Adjectives, 4); // Adjectives 444284184Sdim OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); // Type 445284184Sdim OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset 446284184Sdim OS.EmitValue(create32bitRef(HT.Handler), 4); // Handler 447284184Sdim 448284184Sdim if (shouldEmitPersonality) { 449284184Sdim MCSymbol *ParentFrameOffset = 450284184Sdim Asm->OutContext.getOrCreateParentFrameOffsetSymbol( 451284184Sdim GlobalValue::getRealLinkageName(HT.Handler->getName())); 452284184Sdim const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::create( 453284734Sdim ParentFrameOffset, Asm->OutContext); 454284184Sdim OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset 455284184Sdim } 456284184Sdim } 457284184Sdim } 458284184Sdim } 459284184Sdim 460284184Sdim // IPToStateMapEntry { 461284184Sdim // void *IP; 462284184Sdim // int32_t State; 463284184Sdim // }; 464284184Sdim if (IPToStateXData) { 465284184Sdim OS.EmitLabel(IPToStateXData); 466284184Sdim for (auto &IPStatePair : FuncInfo.IPToStateList) { 467284184Sdim OS.EmitValue(create32bitRef(IPStatePair.first), 4); // IP 468284184Sdim OS.EmitIntValue(IPStatePair.second, 4); // State 469284184Sdim } 470284184Sdim } 471284184Sdim} 472284184Sdim 473284184Sdimvoid WinException::extendIP2StateTable(const MachineFunction *MF, 474284184Sdim const Function *ParentF, 475284184Sdim WinEHFuncInfo &FuncInfo) { 476284184Sdim const Function *F = MF->getFunction(); 477284184Sdim 478284184Sdim // The Itanium LSDA table sorts similar landing pads together to simplify the 479284184Sdim // actions table, but we don't need that. 480284184Sdim SmallVector<const LandingPadInfo *, 64> LandingPads; 481284184Sdim const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 482284184Sdim LandingPads.reserve(PadInfos.size()); 483284184Sdim for (const auto &LP : PadInfos) 484284184Sdim LandingPads.push_back(&LP); 485284184Sdim 486284184Sdim RangeMapType PadMap; 487284184Sdim computePadMap(LandingPads, PadMap); 488284184Sdim 489284184Sdim // The end label of the previous invoke or nounwind try-range. 490284184Sdim MCSymbol *LastLabel = Asm->getFunctionBegin(); 491284184Sdim 492284184Sdim // Whether there is a potentially throwing instruction (currently this means 493284184Sdim // an ordinary call) between the end of the previous try-range and now. 494284184Sdim bool SawPotentiallyThrowing = false; 495284184Sdim 496284184Sdim int LastEHState = -2; 497284184Sdim 498284184Sdim // The parent function and the catch handlers contribute to the 'ip2state' 499284184Sdim // table. 500284184Sdim 501284184Sdim // Include ip2state entries for the beginning of the main function and 502284184Sdim // for catch handler functions. 503284184Sdim if (F == ParentF) { 504284184Sdim FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); 505284184Sdim LastEHState = -1; 506284184Sdim } else if (FuncInfo.HandlerBaseState.count(F)) { 507284184Sdim FuncInfo.IPToStateList.push_back( 508284184Sdim std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F])); 509284184Sdim LastEHState = FuncInfo.HandlerBaseState[F]; 510284184Sdim } 511284184Sdim for (const auto &MBB : *MF) { 512284184Sdim for (const auto &MI : MBB) { 513284184Sdim if (!MI.isEHLabel()) { 514284184Sdim if (MI.isCall()) 515284184Sdim SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); 516284184Sdim continue; 517284184Sdim } 518284184Sdim 519284184Sdim // End of the previous try-range? 520284184Sdim MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol(); 521284184Sdim if (BeginLabel == LastLabel) 522284184Sdim SawPotentiallyThrowing = false; 523284184Sdim 524284184Sdim // Beginning of a new try-range? 525284184Sdim RangeMapType::const_iterator L = PadMap.find(BeginLabel); 526284184Sdim if (L == PadMap.end()) 527284184Sdim // Nope, it was just some random label. 528284184Sdim continue; 529284184Sdim 530284184Sdim const PadRange &P = L->second; 531284184Sdim const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; 532284184Sdim assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && 533284184Sdim "Inconsistent landing pad map!"); 534284184Sdim 535284184Sdim // FIXME: Should this be using FuncInfo.HandlerBaseState? 536284184Sdim if (SawPotentiallyThrowing && LastEHState != -1) { 537284184Sdim FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); 538284184Sdim SawPotentiallyThrowing = false; 539284184Sdim LastEHState = -1; 540284184Sdim } 541284184Sdim 542284184Sdim if (LandingPad->WinEHState != LastEHState) 543284184Sdim FuncInfo.IPToStateList.push_back( 544284184Sdim std::make_pair(BeginLabel, LandingPad->WinEHState)); 545284184Sdim LastEHState = LandingPad->WinEHState; 546284184Sdim LastLabel = LandingPad->EndLabels[P.RangeIndex]; 547284184Sdim } 548284184Sdim } 549284184Sdim} 550284734Sdim 551285181Sdimvoid WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, 552285181Sdim StringRef FLinkageName) { 553285181Sdim // Outlined helpers called by the EH runtime need to know the offset of the EH 554285181Sdim // registration in order to recover the parent frame pointer. Now that we know 555285181Sdim // we've code generated the parent, we can emit the label assignment that 556285181Sdim // those helpers use to get the offset of the registration node. 557285181Sdim assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX && 558285181Sdim "no EH reg node frameescape index"); 559285181Sdim MCSymbol *ParentFrameOffset = 560285181Sdim Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName); 561285181Sdim MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol( 562285181Sdim FLinkageName, FuncInfo.EHRegNodeEscapeIndex); 563285181Sdim const MCExpr *RegistrationOffsetSymRef = 564285181Sdim MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext); 565285181Sdim Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef); 566285181Sdim} 567285181Sdim 568284734Sdim/// Emit the language-specific data that _except_handler3 and 4 expect. This is 569284734Sdim/// functionally equivalent to the __C_specific_handler table, except it is 570284734Sdim/// indexed by state number instead of IP. 571284734Sdimvoid WinException::emitExceptHandlerTable(const MachineFunction *MF) { 572284734Sdim MCStreamer &OS = *Asm->OutStreamer; 573284734Sdim const Function *F = MF->getFunction(); 574284734Sdim StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName()); 575284734Sdim 576285181Sdim WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F); 577285181Sdim emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName); 578285181Sdim 579284734Sdim // Emit the __ehtable label that we use for llvm.x86.seh.lsda. 580284734Sdim MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); 581284734Sdim OS.EmitLabel(LSDALabel); 582284734Sdim 583284734Sdim const Function *Per = MMI->getPersonality(); 584284734Sdim StringRef PerName = Per->getName(); 585284734Sdim int BaseState = -1; 586284734Sdim if (PerName == "_except_handler4") { 587284734Sdim // The LSDA for _except_handler4 starts with this struct, followed by the 588284734Sdim // scope table: 589284734Sdim // 590284734Sdim // struct EH4ScopeTable { 591284734Sdim // int32_t GSCookieOffset; 592284734Sdim // int32_t GSCookieXOROffset; 593284734Sdim // int32_t EHCookieOffset; 594284734Sdim // int32_t EHCookieXOROffset; 595284734Sdim // ScopeTableEntry ScopeRecord[]; 596284734Sdim // }; 597284734Sdim // 598284734Sdim // Only the EHCookieOffset field appears to vary, and it appears to be the 599284734Sdim // offset from the final saved SP value to the retaddr. 600284734Sdim OS.EmitIntValue(-2, 4); 601284734Sdim OS.EmitIntValue(0, 4); 602284734Sdim // FIXME: Calculate. 603284734Sdim OS.EmitIntValue(9999, 4); 604284734Sdim OS.EmitIntValue(0, 4); 605284734Sdim BaseState = -2; 606284734Sdim } 607284734Sdim 608284734Sdim // Build a list of pointers to LandingPadInfos and then sort by WinEHState. 609284734Sdim const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); 610284734Sdim SmallVector<const LandingPadInfo *, 4> LPads; 611284734Sdim LPads.reserve((PadInfos.size())); 612284734Sdim for (const LandingPadInfo &LPInfo : PadInfos) 613284734Sdim LPads.push_back(&LPInfo); 614284734Sdim std::sort(LPads.begin(), LPads.end(), 615284734Sdim [](const LandingPadInfo *L, const LandingPadInfo *R) { 616284734Sdim return L->WinEHState < R->WinEHState; 617284734Sdim }); 618284734Sdim 619284734Sdim // For each action in each lpad, emit one of these: 620284734Sdim // struct ScopeTableEntry { 621284734Sdim // int32_t EnclosingLevel; 622284734Sdim // int32_t (__cdecl *Filter)(); 623284734Sdim // void *HandlerOrFinally; 624284734Sdim // }; 625284734Sdim // 626284734Sdim // The "outermost" action will use BaseState as its enclosing level. Each 627284734Sdim // other action will refer to the previous state as its enclosing level. 628284734Sdim int CurState = 0; 629284734Sdim for (const LandingPadInfo *LPInfo : LPads) { 630284734Sdim int EnclosingLevel = BaseState; 631284734Sdim assert(CurState + int(LPInfo->SEHHandlers.size()) - 1 == 632284734Sdim LPInfo->WinEHState && 633284734Sdim "gaps in the SEH scope table"); 634284734Sdim for (auto I = LPInfo->SEHHandlers.rbegin(), E = LPInfo->SEHHandlers.rend(); 635284734Sdim I != E; ++I) { 636284734Sdim const SEHHandler &Handler = *I; 637284734Sdim const BlockAddress *BA = Handler.RecoverBA; 638284734Sdim const Function *F = Handler.FilterOrFinally; 639284734Sdim assert(F && "cannot catch all in 32-bit SEH without filter function"); 640284734Sdim const MCExpr *FilterOrNull = 641284734Sdim create32bitRef(BA ? Asm->getSymbol(F) : nullptr); 642284734Sdim const MCExpr *ExceptOrFinally = create32bitRef( 643284734Sdim BA ? Asm->GetBlockAddressSymbol(BA) : Asm->getSymbol(F)); 644284734Sdim 645284734Sdim OS.EmitIntValue(EnclosingLevel, 4); 646284734Sdim OS.EmitValue(FilterOrNull, 4); 647284734Sdim OS.EmitValue(ExceptOrFinally, 4); 648284734Sdim 649284734Sdim // The next state unwinds to this state. 650284734Sdim EnclosingLevel = CurState; 651284734Sdim CurState++; 652284734Sdim } 653284734Sdim } 654284734Sdim} 655