1284184Sdim//===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===// 2284184Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6284184Sdim// 7284184Sdim//===----------------------------------------------------------------------===// 8284184Sdim// 9284184Sdim// This file contains support for writing Win64 exception info into asm files. 10284184Sdim// 11284184Sdim//===----------------------------------------------------------------------===// 12284184Sdim 13284184Sdim#include "WinException.h" 14284184Sdim#include "llvm/ADT/Twine.h" 15321369Sdim#include "llvm/BinaryFormat/COFF.h" 16321369Sdim#include "llvm/BinaryFormat/Dwarf.h" 17284184Sdim#include "llvm/CodeGen/AsmPrinter.h" 18284184Sdim#include "llvm/CodeGen/MachineFrameInfo.h" 19284184Sdim#include "llvm/CodeGen/MachineFunction.h" 20284184Sdim#include "llvm/CodeGen/MachineModuleInfo.h" 21327952Sdim#include "llvm/CodeGen/TargetFrameLowering.h" 22327952Sdim#include "llvm/CodeGen/TargetLowering.h" 23327952Sdim#include "llvm/CodeGen/TargetSubtargetInfo.h" 24284184Sdim#include "llvm/CodeGen/WinEHFuncInfo.h" 25284184Sdim#include "llvm/IR/DataLayout.h" 26284184Sdim#include "llvm/IR/Mangler.h" 27284184Sdim#include "llvm/IR/Module.h" 28284184Sdim#include "llvm/MC/MCAsmInfo.h" 29284184Sdim#include "llvm/MC/MCContext.h" 30284184Sdim#include "llvm/MC/MCExpr.h" 31284184Sdim#include "llvm/MC/MCSection.h" 32284184Sdim#include "llvm/MC/MCStreamer.h" 33284184Sdim#include "llvm/MC/MCSymbol.h" 34284184Sdim#include "llvm/Support/ErrorHandling.h" 35284184Sdim#include "llvm/Support/FormattedStream.h" 36341825Sdim#include "llvm/Target/TargetLoweringObjectFile.h" 37284184Sdim#include "llvm/Target/TargetOptions.h" 38284184Sdimusing namespace llvm; 39284184Sdim 40284184SdimWinException::WinException(AsmPrinter *A) : EHStreamer(A) { 41284184Sdim // MSVC's EH tables are always composed of 32-bit words. All known 64-bit 42284184Sdim // platforms use an imagerel32 relocation to refer to symbols. 43284184Sdim useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64); 44344779Sdim isAArch64 = Asm->TM.getTargetTriple().isAArch64(); 45284184Sdim} 46284184Sdim 47284184SdimWinException::~WinException() {} 48284184Sdim 49284184Sdim/// endModule - Emit all exception information that should come after the 50284184Sdim/// content. 51284184Sdimvoid WinException::endModule() { 52284734Sdim auto &OS = *Asm->OutStreamer; 53284734Sdim const Module *M = MMI->getModule(); 54284734Sdim for (const Function &F : *M) 55284734Sdim if (F.hasFnAttribute("safeseh")) 56284734Sdim OS.EmitCOFFSafeSEH(Asm->getSymbol(&F)); 57284184Sdim} 58284184Sdim 59284184Sdimvoid WinException::beginFunction(const MachineFunction *MF) { 60284184Sdim shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; 61284184Sdim 62284184Sdim // If any landing pads survive, we need an EH table. 63314564Sdim bool hasLandingPads = !MF->getLandingPads().empty(); 64314564Sdim bool hasEHFunclets = MF->hasEHFunclets(); 65284184Sdim 66327952Sdim const Function &F = MF->getFunction(); 67284184Sdim 68321369Sdim shouldEmitMoves = Asm->needsSEHMoves() && MF->hasWinCFI(); 69284184Sdim 70284184Sdim const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 71284184Sdim unsigned PerEncoding = TLOF.getPersonalityEncoding(); 72284184Sdim 73314564Sdim EHPersonality Per = EHPersonality::Unknown; 74314564Sdim const Function *PerFn = nullptr; 75327952Sdim if (F.hasPersonalityFn()) { 76327952Sdim PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts()); 77314564Sdim Per = classifyEHPersonality(PerFn); 78314564Sdim } 79284184Sdim 80327952Sdim bool forceEmitPersonality = F.hasPersonalityFn() && 81314564Sdim !isNoOpWithoutInvoke(Per) && 82327952Sdim F.needsUnwindTableEntry(); 83314564Sdim 84296417Sdim shouldEmitPersonality = 85296417Sdim forceEmitPersonality || ((hasLandingPads || hasEHFunclets) && 86314564Sdim PerEncoding != dwarf::DW_EH_PE_omit && PerFn); 87286684Sdim 88284184Sdim unsigned LSDAEncoding = TLOF.getLSDAEncoding(); 89284184Sdim shouldEmitLSDA = shouldEmitPersonality && 90284184Sdim LSDAEncoding != dwarf::DW_EH_PE_omit; 91284184Sdim 92296417Sdim // If we're not using CFI, we don't want the CFI or the personality, but we 93296417Sdim // might want EH tables if we had EH pads. 94321369Sdim if (!Asm->MAI->usesWindowsCFI()) { 95314564Sdim if (Per == EHPersonality::MSVC_X86SEH && !hasEHFunclets) { 96314564Sdim // If this is 32-bit SEH and we don't have any funclets (really invokes), 97314564Sdim // make sure we emit the parent offset label. Some unreferenced filter 98314564Sdim // functions may still refer to it. 99314564Sdim const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 100314564Sdim StringRef FLinkageName = 101327952Sdim GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName()); 102314564Sdim emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName); 103314564Sdim } 104296417Sdim shouldEmitLSDA = hasEHFunclets; 105284184Sdim shouldEmitPersonality = false; 106284184Sdim return; 107284184Sdim } 108284184Sdim 109296417Sdim beginFunclet(MF->front(), Asm->CurrentFnSym); 110284184Sdim} 111284184Sdim 112353358Sdimvoid WinException::markFunctionEnd() { 113353358Sdim if (isAArch64 && CurrentFuncletEntry && 114353358Sdim (shouldEmitMoves || shouldEmitPersonality)) 115353358Sdim Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); 116353358Sdim} 117353358Sdim 118284184Sdim/// endFunction - Gather and emit post-function exception information. 119284184Sdim/// 120284184Sdimvoid WinException::endFunction(const MachineFunction *MF) { 121284184Sdim if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA) 122284184Sdim return; 123284184Sdim 124327952Sdim const Function &F = MF->getFunction(); 125286684Sdim EHPersonality Per = EHPersonality::Unknown; 126327952Sdim if (F.hasPersonalityFn()) 127327952Sdim Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts()); 128284184Sdim 129296417Sdim // Get rid of any dead landing pads if we're not using funclets. In funclet 130296417Sdim // schemes, the landing pad is not actually reachable. It only exists so 131296417Sdim // that we can emit the right table data. 132314564Sdim if (!isFuncletEHPersonality(Per)) { 133314564Sdim MachineFunction *NonConstMF = const_cast<MachineFunction*>(MF); 134314564Sdim NonConstMF->tidyLandingPads(); 135314564Sdim } 136284184Sdim 137353358Sdim endFuncletImpl(); 138296417Sdim 139296417Sdim // endFunclet will emit the necessary .xdata tables for x64 SEH. 140314564Sdim if (Per == EHPersonality::MSVC_Win64SEH && MF->hasEHFunclets()) 141296417Sdim return; 142296417Sdim 143284184Sdim if (shouldEmitPersonality || shouldEmitLSDA) { 144284184Sdim Asm->OutStreamer->PushSection(); 145284184Sdim 146309124Sdim // Just switch sections to the right xdata section. 147309124Sdim MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection( 148309124Sdim Asm->OutStreamer->getCurrentSectionOnly()); 149296417Sdim Asm->OutStreamer->SwitchSection(XData); 150284184Sdim 151284184Sdim // Emit the tables appropriate to the personality function in use. If we 152284184Sdim // don't recognize the personality, assume it uses an Itanium-style LSDA. 153284184Sdim if (Per == EHPersonality::MSVC_Win64SEH) 154296417Sdim emitCSpecificHandlerTable(MF); 155284184Sdim else if (Per == EHPersonality::MSVC_X86SEH) 156284734Sdim emitExceptHandlerTable(MF); 157284184Sdim else if (Per == EHPersonality::MSVC_CXX) 158284184Sdim emitCXXFrameHandler3Table(MF); 159296417Sdim else if (Per == EHPersonality::CoreCLR) 160296417Sdim emitCLRExceptionTable(MF); 161284184Sdim else 162284184Sdim emitExceptionTable(); 163284184Sdim 164284184Sdim Asm->OutStreamer->PopSection(); 165284184Sdim } 166296417Sdim} 167284184Sdim 168314564Sdim/// Retrieve the MCSymbol for a GlobalValue or MachineBasicBlock. 169296417Sdimstatic MCSymbol *getMCSymbolForMBB(AsmPrinter *Asm, 170296417Sdim const MachineBasicBlock *MBB) { 171296417Sdim if (!MBB) 172296417Sdim return nullptr; 173296417Sdim 174296417Sdim assert(MBB->isEHFuncletEntry()); 175296417Sdim 176296417Sdim // Give catches and cleanups a name based off of their parent function and 177296417Sdim // their funclet entry block's number. 178296417Sdim const MachineFunction *MF = MBB->getParent(); 179327952Sdim const Function &F = MF->getFunction(); 180327952Sdim StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName()); 181296417Sdim MCContext &Ctx = MF->getContext(); 182296417Sdim StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch"; 183296417Sdim return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" + 184296417Sdim Twine(MBB->getNumber()) + "@?0?" + 185296417Sdim FuncLinkageName + "@4HA"); 186296417Sdim} 187296417Sdim 188296417Sdimvoid WinException::beginFunclet(const MachineBasicBlock &MBB, 189296417Sdim MCSymbol *Sym) { 190296417Sdim CurrentFuncletEntry = &MBB; 191296417Sdim 192327952Sdim const Function &F = Asm->MF->getFunction(); 193296417Sdim // If a symbol was not provided for the funclet, invent one. 194296417Sdim if (!Sym) { 195296417Sdim Sym = getMCSymbolForMBB(Asm, &MBB); 196296417Sdim 197296417Sdim // Describe our funclet symbol as a function with internal linkage. 198296417Sdim Asm->OutStreamer->BeginCOFFSymbolDef(Sym); 199296417Sdim Asm->OutStreamer->EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC); 200296417Sdim Asm->OutStreamer->EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION 201296417Sdim << COFF::SCT_COMPLEX_TYPE_SHIFT); 202296417Sdim Asm->OutStreamer->EndCOFFSymbolDef(); 203296417Sdim 204296417Sdim // We want our funclet's entry point to be aligned such that no nops will be 205296417Sdim // present after the label. 206296417Sdim Asm->EmitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()), 207327952Sdim &F); 208296417Sdim 209296417Sdim // Now that we've emitted the alignment directive, point at our funclet. 210296417Sdim Asm->OutStreamer->EmitLabel(Sym); 211296417Sdim } 212296417Sdim 213296417Sdim // Mark 'Sym' as starting our funclet. 214314564Sdim if (shouldEmitMoves || shouldEmitPersonality) { 215314564Sdim CurrentFuncletTextSection = Asm->OutStreamer->getCurrentSectionOnly(); 216296417Sdim Asm->OutStreamer->EmitWinCFIStartProc(Sym); 217314564Sdim } 218296417Sdim 219296417Sdim if (shouldEmitPersonality) { 220296417Sdim const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 221296417Sdim const Function *PerFn = nullptr; 222296417Sdim 223296417Sdim // Determine which personality routine we are using for this funclet. 224327952Sdim if (F.hasPersonalityFn()) 225327952Sdim PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts()); 226296417Sdim const MCSymbol *PersHandlerSym = 227314564Sdim TLOF.getCFIPersonalitySymbol(PerFn, Asm->TM, MMI); 228296417Sdim 229314564Sdim // Do not emit a .seh_handler directives for cleanup funclets. 230314564Sdim // FIXME: This means cleanup funclets cannot handle exceptions. Given that 231314564Sdim // Clang doesn't produce EH constructs inside cleanup funclets and LLVM's 232314564Sdim // inliner doesn't allow inlining them, this isn't a major problem in 233314564Sdim // practice. 234314564Sdim if (!CurrentFuncletEntry->isCleanupFuncletEntry()) 235296417Sdim Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true); 236296417Sdim } 237296417Sdim} 238296417Sdim 239296417Sdimvoid WinException::endFunclet() { 240353358Sdim if (isAArch64 && CurrentFuncletEntry && 241353358Sdim (shouldEmitMoves || shouldEmitPersonality)) { 242353358Sdim Asm->OutStreamer->SwitchSection(CurrentFuncletTextSection); 243353358Sdim Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); 244353358Sdim } 245353358Sdim endFuncletImpl(); 246353358Sdim} 247353358Sdim 248353358Sdimvoid WinException::endFuncletImpl() { 249296417Sdim // No funclet to process? Great, we have nothing to do. 250296417Sdim if (!CurrentFuncletEntry) 251296417Sdim return; 252296417Sdim 253314564Sdim const MachineFunction *MF = Asm->MF; 254296417Sdim if (shouldEmitMoves || shouldEmitPersonality) { 255327952Sdim const Function &F = MF->getFunction(); 256296417Sdim EHPersonality Per = EHPersonality::Unknown; 257327952Sdim if (F.hasPersonalityFn()) 258327952Sdim Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts()); 259296417Sdim 260344779Sdim // On funclet exit, we emit a fake "function" end marker, so that the call 261344779Sdim // to EmitWinEHHandlerData below can calculate the size of the funclet or 262344779Sdim // function. 263344779Sdim if (isAArch64) { 264344779Sdim MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection( 265344779Sdim Asm->OutStreamer->getCurrentSectionOnly()); 266344779Sdim Asm->OutStreamer->SwitchSection(XData); 267344779Sdim } 268344779Sdim 269296417Sdim // Emit an UNWIND_INFO struct describing the prologue. 270296417Sdim Asm->OutStreamer->EmitWinEHHandlerData(); 271296417Sdim 272296417Sdim if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality && 273296417Sdim !CurrentFuncletEntry->isCleanupFuncletEntry()) { 274296417Sdim // If this is a C++ catch funclet (or the parent function), 275296417Sdim // emit a reference to the LSDA for the parent function. 276327952Sdim StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName()); 277296417Sdim MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol( 278296417Sdim Twine("$cppxdata$", FuncLinkageName)); 279296417Sdim Asm->OutStreamer->EmitValue(create32bitRef(FuncInfoXData), 4); 280314564Sdim } else if (Per == EHPersonality::MSVC_Win64SEH && MF->hasEHFunclets() && 281296417Sdim !CurrentFuncletEntry->isEHFuncletEntry()) { 282296417Sdim // If this is the parent function in Win64 SEH, emit the LSDA immediately 283296417Sdim // following .seh_handlerdata. 284314564Sdim emitCSpecificHandlerTable(MF); 285296417Sdim } 286296417Sdim 287314564Sdim // Switch back to the funclet start .text section now that we are done 288314564Sdim // writing to .xdata, and emit an .seh_endproc directive to mark the end of 289314564Sdim // the function. 290314564Sdim Asm->OutStreamer->SwitchSection(CurrentFuncletTextSection); 291284184Sdim Asm->OutStreamer->EmitWinCFIEndProc(); 292296417Sdim } 293296417Sdim 294296417Sdim // Let's make sure we don't try to end the same funclet twice. 295296417Sdim CurrentFuncletEntry = nullptr; 296284184Sdim} 297284184Sdim 298284184Sdimconst MCExpr *WinException::create32bitRef(const MCSymbol *Value) { 299284184Sdim if (!Value) 300284184Sdim return MCConstantExpr::create(0, Asm->OutContext); 301284184Sdim return MCSymbolRefExpr::create(Value, useImageRel32 302284184Sdim ? MCSymbolRefExpr::VK_COFF_IMGREL32 303284184Sdim : MCSymbolRefExpr::VK_None, 304284184Sdim Asm->OutContext); 305284184Sdim} 306284184Sdim 307284184Sdimconst MCExpr *WinException::create32bitRef(const GlobalValue *GV) { 308284184Sdim if (!GV) 309284184Sdim return MCConstantExpr::create(0, Asm->OutContext); 310284184Sdim return create32bitRef(Asm->getSymbol(GV)); 311284184Sdim} 312284184Sdim 313344779Sdimconst MCExpr *WinException::getLabel(const MCSymbol *Label) { 314344779Sdim if (isAArch64) 315344779Sdim return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32, 316344779Sdim Asm->OutContext); 317296417Sdim return MCBinaryExpr::createAdd(create32bitRef(Label), 318296417Sdim MCConstantExpr::create(1, Asm->OutContext), 319296417Sdim Asm->OutContext); 320296417Sdim} 321296417Sdim 322296417Sdimconst MCExpr *WinException::getOffset(const MCSymbol *OffsetOf, 323296417Sdim const MCSymbol *OffsetFrom) { 324296417Sdim return MCBinaryExpr::createSub( 325296417Sdim MCSymbolRefExpr::create(OffsetOf, Asm->OutContext), 326296417Sdim MCSymbolRefExpr::create(OffsetFrom, Asm->OutContext), Asm->OutContext); 327296417Sdim} 328296417Sdim 329296417Sdimconst MCExpr *WinException::getOffsetPlusOne(const MCSymbol *OffsetOf, 330296417Sdim const MCSymbol *OffsetFrom) { 331296417Sdim return MCBinaryExpr::createAdd(getOffset(OffsetOf, OffsetFrom), 332296417Sdim MCConstantExpr::create(1, Asm->OutContext), 333296417Sdim Asm->OutContext); 334296417Sdim} 335296417Sdim 336296417Sdimint WinException::getFrameIndexOffset(int FrameIndex, 337296417Sdim const WinEHFuncInfo &FuncInfo) { 338296417Sdim const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering(); 339296417Sdim unsigned UnusedReg; 340309124Sdim if (Asm->MAI->usesWindowsCFI()) { 341309124Sdim int Offset = 342309124Sdim TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg, 343309124Sdim /*IgnoreSPUpdates*/ true); 344309124Sdim assert(UnusedReg == 345309124Sdim Asm->MF->getSubtarget() 346309124Sdim .getTargetLowering() 347309124Sdim ->getStackPointerRegisterToSaveRestore()); 348309124Sdim return Offset; 349309124Sdim } 350309124Sdim 351296417Sdim // For 32-bit, offsets should be relative to the end of the EH registration 352296417Sdim // node. For 64-bit, it's relative to SP at the end of the prologue. 353296417Sdim assert(FuncInfo.EHRegNodeEndOffset != INT_MAX); 354296417Sdim int Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg); 355296417Sdim Offset += FuncInfo.EHRegNodeEndOffset; 356296417Sdim return Offset; 357296417Sdim} 358296417Sdim 359296417Sdimnamespace { 360296417Sdim 361296417Sdim/// Top-level state used to represent unwind to caller 362296417Sdimconst int NullState = -1; 363296417Sdim 364296417Sdimstruct InvokeStateChange { 365296417Sdim /// EH Label immediately after the last invoke in the previous state, or 366296417Sdim /// nullptr if the previous state was the null state. 367296417Sdim const MCSymbol *PreviousEndLabel; 368296417Sdim 369296417Sdim /// EH label immediately before the first invoke in the new state, or nullptr 370296417Sdim /// if the new state is the null state. 371296417Sdim const MCSymbol *NewStartLabel; 372296417Sdim 373296417Sdim /// State of the invoke following NewStartLabel, or NullState to indicate 374296417Sdim /// the presence of calls which may unwind to caller. 375296417Sdim int NewState; 376296417Sdim}; 377296417Sdim 378296417Sdim/// Iterator that reports all the invoke state changes in a range of machine 379296417Sdim/// basic blocks. Changes to the null state are reported whenever a call that 380296417Sdim/// may unwind to caller is encountered. The MBB range is expected to be an 381296417Sdim/// entire function or funclet, and the start and end of the range are treated 382296417Sdim/// as being in the NullState even if there's not an unwind-to-caller call 383296417Sdim/// before the first invoke or after the last one (i.e., the first state change 384296417Sdim/// reported is the first change to something other than NullState, and a 385296417Sdim/// change back to NullState is always reported at the end of iteration). 386296417Sdimclass InvokeStateChangeIterator { 387296417Sdim InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo, 388296417Sdim MachineFunction::const_iterator MFI, 389296417Sdim MachineFunction::const_iterator MFE, 390296417Sdim MachineBasicBlock::const_iterator MBBI, 391296417Sdim int BaseState) 392296417Sdim : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) { 393296417Sdim LastStateChange.PreviousEndLabel = nullptr; 394296417Sdim LastStateChange.NewStartLabel = nullptr; 395296417Sdim LastStateChange.NewState = BaseState; 396296417Sdim scan(); 397296417Sdim } 398296417Sdim 399296417Sdimpublic: 400296417Sdim static iterator_range<InvokeStateChangeIterator> 401296417Sdim range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin, 402296417Sdim MachineFunction::const_iterator End, int BaseState = NullState) { 403296417Sdim // Reject empty ranges to simplify bookkeeping by ensuring that we can get 404296417Sdim // the end of the last block. 405296417Sdim assert(Begin != End); 406296417Sdim auto BlockBegin = Begin->begin(); 407296417Sdim auto BlockEnd = std::prev(End)->end(); 408296417Sdim return make_range( 409296417Sdim InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState), 410296417Sdim InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState)); 411296417Sdim } 412296417Sdim 413296417Sdim // Iterator methods. 414296417Sdim bool operator==(const InvokeStateChangeIterator &O) const { 415296417Sdim assert(BaseState == O.BaseState); 416296417Sdim // Must be visiting same block. 417296417Sdim if (MFI != O.MFI) 418296417Sdim return false; 419296417Sdim // Must be visiting same isntr. 420296417Sdim if (MBBI != O.MBBI) 421296417Sdim return false; 422296417Sdim // At end of block/instr iteration, we can still have two distinct states: 423296417Sdim // one to report the final EndLabel, and another indicating the end of the 424296417Sdim // state change iteration. Check for CurrentEndLabel equality to 425296417Sdim // distinguish these. 426296417Sdim return CurrentEndLabel == O.CurrentEndLabel; 427296417Sdim } 428296417Sdim 429296417Sdim bool operator!=(const InvokeStateChangeIterator &O) const { 430296417Sdim return !operator==(O); 431296417Sdim } 432296417Sdim InvokeStateChange &operator*() { return LastStateChange; } 433296417Sdim InvokeStateChange *operator->() { return &LastStateChange; } 434296417Sdim InvokeStateChangeIterator &operator++() { return scan(); } 435296417Sdim 436296417Sdimprivate: 437296417Sdim InvokeStateChangeIterator &scan(); 438296417Sdim 439296417Sdim const WinEHFuncInfo &EHInfo; 440296417Sdim const MCSymbol *CurrentEndLabel = nullptr; 441296417Sdim MachineFunction::const_iterator MFI; 442296417Sdim MachineFunction::const_iterator MFE; 443296417Sdim MachineBasicBlock::const_iterator MBBI; 444296417Sdim InvokeStateChange LastStateChange; 445296417Sdim bool VisitingInvoke = false; 446296417Sdim int BaseState; 447296417Sdim}; 448296417Sdim 449296417Sdim} // end anonymous namespace 450296417Sdim 451296417SdimInvokeStateChangeIterator &InvokeStateChangeIterator::scan() { 452296417Sdim bool IsNewBlock = false; 453296417Sdim for (; MFI != MFE; ++MFI, IsNewBlock = true) { 454296417Sdim if (IsNewBlock) 455296417Sdim MBBI = MFI->begin(); 456296417Sdim for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) { 457296417Sdim const MachineInstr &MI = *MBBI; 458296417Sdim if (!VisitingInvoke && LastStateChange.NewState != BaseState && 459296417Sdim MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) { 460296417Sdim // Indicate a change of state to the null state. We don't have 461296417Sdim // start/end EH labels handy but the caller won't expect them for 462296417Sdim // null state regions. 463296417Sdim LastStateChange.PreviousEndLabel = CurrentEndLabel; 464296417Sdim LastStateChange.NewStartLabel = nullptr; 465296417Sdim LastStateChange.NewState = BaseState; 466296417Sdim CurrentEndLabel = nullptr; 467296417Sdim // Don't re-visit this instr on the next scan 468296417Sdim ++MBBI; 469296417Sdim return *this; 470296417Sdim } 471296417Sdim 472296417Sdim // All other state changes are at EH labels before/after invokes. 473296417Sdim if (!MI.isEHLabel()) 474296417Sdim continue; 475296417Sdim MCSymbol *Label = MI.getOperand(0).getMCSymbol(); 476296417Sdim if (Label == CurrentEndLabel) { 477296417Sdim VisitingInvoke = false; 478296417Sdim continue; 479296417Sdim } 480296417Sdim auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label); 481296417Sdim // Ignore EH labels that aren't the ones inserted before an invoke 482296417Sdim if (InvokeMapIter == EHInfo.LabelToStateMap.end()) 483296417Sdim continue; 484296417Sdim auto &StateAndEnd = InvokeMapIter->second; 485296417Sdim int NewState = StateAndEnd.first; 486296417Sdim // Keep track of the fact that we're between EH start/end labels so 487296417Sdim // we know not to treat the inoke we'll see as unwinding to caller. 488296417Sdim VisitingInvoke = true; 489296417Sdim if (NewState == LastStateChange.NewState) { 490296417Sdim // The state isn't actually changing here. Record the new end and 491296417Sdim // keep going. 492296417Sdim CurrentEndLabel = StateAndEnd.second; 493296417Sdim continue; 494296417Sdim } 495296417Sdim // Found a state change to report 496296417Sdim LastStateChange.PreviousEndLabel = CurrentEndLabel; 497296417Sdim LastStateChange.NewStartLabel = Label; 498296417Sdim LastStateChange.NewState = NewState; 499296417Sdim // Start keeping track of the new current end 500296417Sdim CurrentEndLabel = StateAndEnd.second; 501296417Sdim // Don't re-visit this instr on the next scan 502296417Sdim ++MBBI; 503296417Sdim return *this; 504296417Sdim } 505296417Sdim } 506296417Sdim // Iteration hit the end of the block range. 507296417Sdim if (LastStateChange.NewState != BaseState) { 508296417Sdim // Report the end of the last new state 509296417Sdim LastStateChange.PreviousEndLabel = CurrentEndLabel; 510296417Sdim LastStateChange.NewStartLabel = nullptr; 511296417Sdim LastStateChange.NewState = BaseState; 512296417Sdim // Leave CurrentEndLabel non-null to distinguish this state from end. 513296417Sdim assert(CurrentEndLabel != nullptr); 514296417Sdim return *this; 515296417Sdim } 516296417Sdim // We've reported all state changes and hit the end state. 517296417Sdim CurrentEndLabel = nullptr; 518296417Sdim return *this; 519296417Sdim} 520296417Sdim 521284184Sdim/// Emit the language-specific data that __C_specific_handler expects. This 522284184Sdim/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning 523284184Sdim/// up after faults with __try, __except, and __finally. The typeinfo values 524284184Sdim/// are not really RTTI data, but pointers to filter functions that return an 525284184Sdim/// integer (1, 0, or -1) indicating how to handle the exception. For __finally 526284184Sdim/// blocks and other cleanups, the landing pad label is zero, and the filter 527284184Sdim/// function is actually a cleanup handler with the same prototype. A catch-all 528284184Sdim/// entry is modeled with a null filter function field and a non-zero landing 529284184Sdim/// pad label. 530284184Sdim/// 531284184Sdim/// Possible filter function return values: 532284184Sdim/// EXCEPTION_EXECUTE_HANDLER (1): 533284184Sdim/// Jump to the landing pad label after cleanups. 534284184Sdim/// EXCEPTION_CONTINUE_SEARCH (0): 535284184Sdim/// Continue searching this table or continue unwinding. 536284184Sdim/// EXCEPTION_CONTINUE_EXECUTION (-1): 537284184Sdim/// Resume execution at the trapping PC. 538284184Sdim/// 539284184Sdim/// Inferred table structure: 540284184Sdim/// struct Table { 541284184Sdim/// int NumEntries; 542284184Sdim/// struct Entry { 543284184Sdim/// imagerel32 LabelStart; 544284184Sdim/// imagerel32 LabelEnd; 545284184Sdim/// imagerel32 FilterOrFinally; // One means catch-all. 546284184Sdim/// imagerel32 LabelLPad; // Zero means __finally. 547284184Sdim/// } Entries[NumEntries]; 548284184Sdim/// }; 549296417Sdimvoid WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { 550296417Sdim auto &OS = *Asm->OutStreamer; 551296417Sdim MCContext &Ctx = Asm->OutContext; 552296417Sdim const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 553284184Sdim 554296417Sdim bool VerboseAsm = OS.isVerboseAsm(); 555296417Sdim auto AddComment = [&](const Twine &Comment) { 556296417Sdim if (VerboseAsm) 557296417Sdim OS.AddComment(Comment); 558296417Sdim }; 559284184Sdim 560344779Sdim if (!isAArch64) { 561344779Sdim // Emit a label assignment with the SEH frame offset so we can use it for 562344779Sdim // llvm.eh.recoverfp. 563344779Sdim StringRef FLinkageName = 564344779Sdim GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName()); 565344779Sdim MCSymbol *ParentFrameOffset = 566344779Sdim Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName); 567344779Sdim const MCExpr *MCOffset = 568344779Sdim MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx); 569344779Sdim Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset); 570344779Sdim } 571284184Sdim 572296417Sdim // Use the assembler to compute the number of table entries through label 573296417Sdim // difference and division. 574296417Sdim MCSymbol *TableBegin = 575296417Sdim Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true); 576296417Sdim MCSymbol *TableEnd = 577296417Sdim Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true); 578296417Sdim const MCExpr *LabelDiff = getOffset(TableEnd, TableBegin); 579296417Sdim const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx); 580296417Sdim const MCExpr *EntryCount = MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx); 581296417Sdim AddComment("Number of call sites"); 582296417Sdim OS.EmitValue(EntryCount, 4); 583284184Sdim 584296417Sdim OS.EmitLabel(TableBegin); 585284184Sdim 586296417Sdim // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only 587296417Sdim // models exceptions from invokes. LLVM also allows arbitrary reordering of 588296417Sdim // the code, so our tables end up looking a bit different. Rather than 589296417Sdim // trying to match MSVC's tables exactly, we emit a denormalized table. For 590296417Sdim // each range of invokes in the same state, we emit table entries for all 591296417Sdim // the actions that would be taken in that state. This means our tables are 592296417Sdim // slightly bigger, which is OK. 593296417Sdim const MCSymbol *LastStartLabel = nullptr; 594296417Sdim int LastEHState = -1; 595296417Sdim // Break out before we enter into a finally funclet. 596296417Sdim // FIXME: We need to emit separate EH tables for cleanups. 597296417Sdim MachineFunction::const_iterator End = MF->end(); 598296417Sdim MachineFunction::const_iterator Stop = std::next(MF->begin()); 599296417Sdim while (Stop != End && !Stop->isEHFuncletEntry()) 600296417Sdim ++Stop; 601296417Sdim for (const auto &StateChange : 602296417Sdim InvokeStateChangeIterator::range(FuncInfo, MF->begin(), Stop)) { 603296417Sdim // Emit all the actions for the state we just transitioned out of 604296417Sdim // if it was not the null state 605296417Sdim if (LastEHState != -1) 606296417Sdim emitSEHActionsForRange(FuncInfo, LastStartLabel, 607296417Sdim StateChange.PreviousEndLabel, LastEHState); 608296417Sdim LastStartLabel = StateChange.NewStartLabel; 609296417Sdim LastEHState = StateChange.NewState; 610284184Sdim } 611284184Sdim 612296417Sdim OS.EmitLabel(TableEnd); 613296417Sdim} 614284184Sdim 615296417Sdimvoid WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo, 616296417Sdim const MCSymbol *BeginLabel, 617296417Sdim const MCSymbol *EndLabel, int State) { 618296417Sdim auto &OS = *Asm->OutStreamer; 619296417Sdim MCContext &Ctx = Asm->OutContext; 620296417Sdim bool VerboseAsm = OS.isVerboseAsm(); 621296417Sdim auto AddComment = [&](const Twine &Comment) { 622296417Sdim if (VerboseAsm) 623296417Sdim OS.AddComment(Comment); 624296417Sdim }; 625296417Sdim 626296417Sdim assert(BeginLabel && EndLabel); 627296417Sdim while (State != -1) { 628296417Sdim const SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State]; 629296417Sdim const MCExpr *FilterOrFinally; 630296417Sdim const MCExpr *ExceptOrNull; 631296417Sdim auto *Handler = UME.Handler.get<MachineBasicBlock *>(); 632296417Sdim if (UME.IsFinally) { 633296417Sdim FilterOrFinally = create32bitRef(getMCSymbolForMBB(Asm, Handler)); 634296417Sdim ExceptOrNull = MCConstantExpr::create(0, Ctx); 635284184Sdim } else { 636296417Sdim // For an except, the filter can be 1 (catch-all) or a function 637296417Sdim // label. 638296417Sdim FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter) 639296417Sdim : MCConstantExpr::create(1, Ctx); 640296417Sdim ExceptOrNull = create32bitRef(Handler->getSymbol()); 641284184Sdim } 642284184Sdim 643296417Sdim AddComment("LabelStart"); 644344779Sdim OS.EmitValue(getLabel(BeginLabel), 4); 645296417Sdim AddComment("LabelEnd"); 646344779Sdim OS.EmitValue(getLabel(EndLabel), 4); 647296417Sdim AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction" 648296417Sdim : "CatchAll"); 649296417Sdim OS.EmitValue(FilterOrFinally, 4); 650296417Sdim AddComment(UME.IsFinally ? "Null" : "ExceptionHandler"); 651296417Sdim OS.EmitValue(ExceptOrNull, 4); 652284184Sdim 653296417Sdim assert(UME.ToState < State && "states should decrease"); 654296417Sdim State = UME.ToState; 655284184Sdim } 656284184Sdim} 657284184Sdim 658284184Sdimvoid WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { 659327952Sdim const Function &F = MF->getFunction(); 660284184Sdim auto &OS = *Asm->OutStreamer; 661296417Sdim const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 662284184Sdim 663327952Sdim StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName()); 664284184Sdim 665296417Sdim SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable; 666284184Sdim MCSymbol *FuncInfoXData = nullptr; 667284184Sdim if (shouldEmitPersonality) { 668296417Sdim // If we're 64-bit, emit a pointer to the C++ EH data, and build a map from 669296417Sdim // IPs to state numbers. 670296417Sdim FuncInfoXData = 671296417Sdim Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName)); 672296417Sdim computeIP2StateTable(MF, FuncInfo, IPToStateTable); 673284184Sdim } else { 674296417Sdim FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName); 675284184Sdim } 676284184Sdim 677296417Sdim int UnwindHelpOffset = 0; 678296417Sdim if (Asm->MAI->usesWindowsCFI()) 679296417Sdim UnwindHelpOffset = 680296417Sdim getFrameIndexOffset(FuncInfo.UnwindHelpFrameIdx, FuncInfo); 681296417Sdim 682284184Sdim MCSymbol *UnwindMapXData = nullptr; 683284184Sdim MCSymbol *TryBlockMapXData = nullptr; 684284184Sdim MCSymbol *IPToStateXData = nullptr; 685296417Sdim if (!FuncInfo.CxxUnwindMap.empty()) 686284184Sdim UnwindMapXData = Asm->OutContext.getOrCreateSymbol( 687296417Sdim Twine("$stateUnwindMap$", FuncLinkageName)); 688284184Sdim if (!FuncInfo.TryBlockMap.empty()) 689296417Sdim TryBlockMapXData = 690296417Sdim Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName)); 691296417Sdim if (!IPToStateTable.empty()) 692296417Sdim IPToStateXData = 693296417Sdim Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName)); 694284184Sdim 695296417Sdim bool VerboseAsm = OS.isVerboseAsm(); 696296417Sdim auto AddComment = [&](const Twine &Comment) { 697296417Sdim if (VerboseAsm) 698296417Sdim OS.AddComment(Comment); 699296417Sdim }; 700296417Sdim 701284184Sdim // FuncInfo { 702284184Sdim // uint32_t MagicNumber 703284184Sdim // int32_t MaxState; 704284184Sdim // UnwindMapEntry *UnwindMap; 705284184Sdim // uint32_t NumTryBlocks; 706284184Sdim // TryBlockMapEntry *TryBlockMap; 707284184Sdim // uint32_t IPMapEntries; // always 0 for x86 708284184Sdim // IPToStateMapEntry *IPToStateMap; // always 0 for x86 709284184Sdim // uint32_t UnwindHelp; // non-x86 only 710284184Sdim // ESTypeList *ESTypeList; 711284184Sdim // int32_t EHFlags; 712284184Sdim // } 713284184Sdim // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. 714284184Sdim // EHFlags & 2 -> ??? 715284184Sdim // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. 716286684Sdim OS.EmitValueToAlignment(4); 717284184Sdim OS.EmitLabel(FuncInfoXData); 718284184Sdim 719296417Sdim AddComment("MagicNumber"); 720296417Sdim OS.EmitIntValue(0x19930522, 4); 721296417Sdim 722296417Sdim AddComment("MaxState"); 723296417Sdim OS.EmitIntValue(FuncInfo.CxxUnwindMap.size(), 4); 724296417Sdim 725296417Sdim AddComment("UnwindMap"); 726296417Sdim OS.EmitValue(create32bitRef(UnwindMapXData), 4); 727296417Sdim 728296417Sdim AddComment("NumTryBlocks"); 729296417Sdim OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); 730296417Sdim 731296417Sdim AddComment("TryBlockMap"); 732296417Sdim OS.EmitValue(create32bitRef(TryBlockMapXData), 4); 733296417Sdim 734296417Sdim AddComment("IPMapEntries"); 735296417Sdim OS.EmitIntValue(IPToStateTable.size(), 4); 736296417Sdim 737296417Sdim AddComment("IPToStateXData"); 738296417Sdim OS.EmitValue(create32bitRef(IPToStateXData), 4); 739296417Sdim 740296417Sdim if (Asm->MAI->usesWindowsCFI()) { 741296417Sdim AddComment("UnwindHelp"); 742296417Sdim OS.EmitIntValue(UnwindHelpOffset, 4); 743296417Sdim } 744296417Sdim 745296417Sdim AddComment("ESTypeList"); 746296417Sdim OS.EmitIntValue(0, 4); 747296417Sdim 748296417Sdim AddComment("EHFlags"); 749296417Sdim OS.EmitIntValue(1, 4); 750296417Sdim 751284184Sdim // UnwindMapEntry { 752284184Sdim // int32_t ToState; 753284184Sdim // void (*Action)(); 754284184Sdim // }; 755284184Sdim if (UnwindMapXData) { 756284184Sdim OS.EmitLabel(UnwindMapXData); 757296417Sdim for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) { 758296417Sdim MCSymbol *CleanupSym = 759296417Sdim getMCSymbolForMBB(Asm, UME.Cleanup.dyn_cast<MachineBasicBlock *>()); 760296417Sdim AddComment("ToState"); 761296417Sdim OS.EmitIntValue(UME.ToState, 4); 762296417Sdim 763296417Sdim AddComment("Action"); 764296417Sdim OS.EmitValue(create32bitRef(CleanupSym), 4); 765284184Sdim } 766284184Sdim } 767284184Sdim 768284184Sdim // TryBlockMap { 769284184Sdim // int32_t TryLow; 770284184Sdim // int32_t TryHigh; 771284184Sdim // int32_t CatchHigh; 772284184Sdim // int32_t NumCatches; 773284184Sdim // HandlerType *HandlerArray; 774284184Sdim // }; 775284184Sdim if (TryBlockMapXData) { 776284184Sdim OS.EmitLabel(TryBlockMapXData); 777284184Sdim SmallVector<MCSymbol *, 1> HandlerMaps; 778284184Sdim for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 779296417Sdim const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 780296417Sdim 781284184Sdim MCSymbol *HandlerMapXData = nullptr; 782284184Sdim if (!TBME.HandlerArray.empty()) 783284184Sdim HandlerMapXData = 784284184Sdim Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") 785284184Sdim .concat(Twine(I)) 786284184Sdim .concat("$") 787296417Sdim .concat(FuncLinkageName)); 788284184Sdim HandlerMaps.push_back(HandlerMapXData); 789284184Sdim 790296417Sdim // TBMEs should form intervals. 791296417Sdim assert(0 <= TBME.TryLow && "bad trymap interval"); 792296417Sdim assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval"); 793296417Sdim assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval"); 794296417Sdim assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) && 795296417Sdim "bad trymap interval"); 796284184Sdim 797296417Sdim AddComment("TryLow"); 798296417Sdim OS.EmitIntValue(TBME.TryLow, 4); 799296417Sdim 800296417Sdim AddComment("TryHigh"); 801296417Sdim OS.EmitIntValue(TBME.TryHigh, 4); 802296417Sdim 803296417Sdim AddComment("CatchHigh"); 804296417Sdim OS.EmitIntValue(TBME.CatchHigh, 4); 805296417Sdim 806296417Sdim AddComment("NumCatches"); 807296417Sdim OS.EmitIntValue(TBME.HandlerArray.size(), 4); 808296417Sdim 809296417Sdim AddComment("HandlerArray"); 810296417Sdim OS.EmitValue(create32bitRef(HandlerMapXData), 4); 811284184Sdim } 812284184Sdim 813296417Sdim // All funclets use the same parent frame offset currently. 814296417Sdim unsigned ParentFrameOffset = 0; 815296417Sdim if (shouldEmitPersonality) { 816296417Sdim const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); 817296417Sdim ParentFrameOffset = TFI->getWinEHParentFrameOffset(*MF); 818296417Sdim } 819296417Sdim 820284184Sdim for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { 821296417Sdim const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; 822284184Sdim MCSymbol *HandlerMapXData = HandlerMaps[I]; 823284184Sdim if (!HandlerMapXData) 824284184Sdim continue; 825284184Sdim // HandlerType { 826284184Sdim // int32_t Adjectives; 827284184Sdim // TypeDescriptor *Type; 828284184Sdim // int32_t CatchObjOffset; 829284184Sdim // void (*Handler)(); 830344779Sdim // int32_t ParentFrameOffset; // x64 and AArch64 only 831284184Sdim // }; 832284184Sdim OS.EmitLabel(HandlerMapXData); 833284184Sdim for (const WinEHHandlerType &HT : TBME.HandlerArray) { 834284184Sdim // Get the frame escape label with the offset of the catch object. If 835296417Sdim // the index is INT_MAX, then there is no catch object, and we should 836296417Sdim // emit an offset of zero, indicating that no copy will occur. 837284184Sdim const MCExpr *FrameAllocOffsetRef = nullptr; 838296417Sdim if (HT.CatchObj.FrameIndex != INT_MAX) { 839296417Sdim int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex, FuncInfo); 840309124Sdim assert(Offset != 0 && "Illegal offset for catch object!"); 841296417Sdim FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext); 842284184Sdim } else { 843284184Sdim FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext); 844284184Sdim } 845284184Sdim 846296417Sdim MCSymbol *HandlerSym = 847296417Sdim getMCSymbolForMBB(Asm, HT.Handler.dyn_cast<MachineBasicBlock *>()); 848284184Sdim 849296417Sdim AddComment("Adjectives"); 850296417Sdim OS.EmitIntValue(HT.Adjectives, 4); 851296417Sdim 852296417Sdim AddComment("Type"); 853296417Sdim OS.EmitValue(create32bitRef(HT.TypeDescriptor), 4); 854296417Sdim 855296417Sdim AddComment("CatchObjOffset"); 856296417Sdim OS.EmitValue(FrameAllocOffsetRef, 4); 857296417Sdim 858296417Sdim AddComment("Handler"); 859296417Sdim OS.EmitValue(create32bitRef(HandlerSym), 4); 860296417Sdim 861284184Sdim if (shouldEmitPersonality) { 862296417Sdim AddComment("ParentFrameOffset"); 863296417Sdim OS.EmitIntValue(ParentFrameOffset, 4); 864284184Sdim } 865284184Sdim } 866284184Sdim } 867284184Sdim } 868284184Sdim 869284184Sdim // IPToStateMapEntry { 870284184Sdim // void *IP; 871284184Sdim // int32_t State; 872284184Sdim // }; 873284184Sdim if (IPToStateXData) { 874284184Sdim OS.EmitLabel(IPToStateXData); 875296417Sdim for (auto &IPStatePair : IPToStateTable) { 876296417Sdim AddComment("IP"); 877296417Sdim OS.EmitValue(IPStatePair.first, 4); 878296417Sdim AddComment("ToState"); 879296417Sdim OS.EmitIntValue(IPStatePair.second, 4); 880284184Sdim } 881284184Sdim } 882284184Sdim} 883284184Sdim 884296417Sdimvoid WinException::computeIP2StateTable( 885296417Sdim const MachineFunction *MF, const WinEHFuncInfo &FuncInfo, 886296417Sdim SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) { 887284184Sdim 888296417Sdim for (MachineFunction::const_iterator FuncletStart = MF->begin(), 889296417Sdim FuncletEnd = MF->begin(), 890296417Sdim End = MF->end(); 891296417Sdim FuncletStart != End; FuncletStart = FuncletEnd) { 892296417Sdim // Find the end of the funclet 893296417Sdim while (++FuncletEnd != End) { 894296417Sdim if (FuncletEnd->isEHFuncletEntry()) { 895296417Sdim break; 896284184Sdim } 897296417Sdim } 898284184Sdim 899296417Sdim // Don't emit ip2state entries for cleanup funclets. Any interesting 900296417Sdim // exceptional actions in cleanups must be handled in a separate IR 901296417Sdim // function. 902296417Sdim if (FuncletStart->isCleanupFuncletEntry()) 903296417Sdim continue; 904284184Sdim 905296417Sdim MCSymbol *StartLabel; 906296417Sdim int BaseState; 907296417Sdim if (FuncletStart == MF->begin()) { 908296417Sdim BaseState = NullState; 909296417Sdim StartLabel = Asm->getFunctionBegin(); 910296417Sdim } else { 911296417Sdim auto *FuncletPad = 912296417Sdim cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI()); 913296417Sdim assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0); 914296417Sdim BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second; 915296417Sdim StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart); 916296417Sdim } 917296417Sdim assert(StartLabel && "need local function start label"); 918296417Sdim IPToStateTable.push_back( 919296417Sdim std::make_pair(create32bitRef(StartLabel), BaseState)); 920284184Sdim 921296417Sdim for (const auto &StateChange : InvokeStateChangeIterator::range( 922296417Sdim FuncInfo, FuncletStart, FuncletEnd, BaseState)) { 923296417Sdim // Compute the label to report as the start of this entry; use the EH 924296417Sdim // start label for the invoke if we have one, otherwise (this is a call 925296417Sdim // which may unwind to our caller and does not have an EH start label, so) 926296417Sdim // use the previous end label. 927296417Sdim const MCSymbol *ChangeLabel = StateChange.NewStartLabel; 928296417Sdim if (!ChangeLabel) 929296417Sdim ChangeLabel = StateChange.PreviousEndLabel; 930296417Sdim // Emit an entry indicating that PCs after 'Label' have this EH state. 931296417Sdim IPToStateTable.push_back( 932344779Sdim std::make_pair(getLabel(ChangeLabel), StateChange.NewState)); 933296417Sdim // FIXME: assert that NewState is between CatchLow and CatchHigh. 934284184Sdim } 935284184Sdim } 936284184Sdim} 937284734Sdim 938285181Sdimvoid WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, 939285181Sdim StringRef FLinkageName) { 940285181Sdim // Outlined helpers called by the EH runtime need to know the offset of the EH 941285181Sdim // registration in order to recover the parent frame pointer. Now that we know 942285181Sdim // we've code generated the parent, we can emit the label assignment that 943285181Sdim // those helpers use to get the offset of the registration node. 944314564Sdim 945314564Sdim // Compute the parent frame offset. The EHRegNodeFrameIndex will be invalid if 946314564Sdim // after optimization all the invokes were eliminated. We still need to emit 947314564Sdim // the parent frame offset label, but it should be garbage and should never be 948314564Sdim // used. 949314564Sdim int64_t Offset = 0; 950314564Sdim int FI = FuncInfo.EHRegNodeFrameIndex; 951314564Sdim if (FI != INT_MAX) { 952314564Sdim const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); 953353358Sdim Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI); 954314564Sdim } 955314564Sdim 956296417Sdim MCContext &Ctx = Asm->OutContext; 957285181Sdim MCSymbol *ParentFrameOffset = 958296417Sdim Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName); 959314564Sdim Asm->OutStreamer->EmitAssignment(ParentFrameOffset, 960314564Sdim MCConstantExpr::create(Offset, Ctx)); 961285181Sdim} 962285181Sdim 963284734Sdim/// Emit the language-specific data that _except_handler3 and 4 expect. This is 964284734Sdim/// functionally equivalent to the __C_specific_handler table, except it is 965284734Sdim/// indexed by state number instead of IP. 966284734Sdimvoid WinException::emitExceptHandlerTable(const MachineFunction *MF) { 967284734Sdim MCStreamer &OS = *Asm->OutStreamer; 968327952Sdim const Function &F = MF->getFunction(); 969327952Sdim StringRef FLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName()); 970284734Sdim 971296417Sdim bool VerboseAsm = OS.isVerboseAsm(); 972296417Sdim auto AddComment = [&](const Twine &Comment) { 973296417Sdim if (VerboseAsm) 974296417Sdim OS.AddComment(Comment); 975296417Sdim }; 976296417Sdim 977296417Sdim const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 978285181Sdim emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName); 979285181Sdim 980284734Sdim // Emit the __ehtable label that we use for llvm.x86.seh.lsda. 981284734Sdim MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); 982286684Sdim OS.EmitValueToAlignment(4); 983284734Sdim OS.EmitLabel(LSDALabel); 984284734Sdim 985360784Sdim const auto *Per = cast<Function>(F.getPersonalityFn()->stripPointerCasts()); 986284734Sdim StringRef PerName = Per->getName(); 987284734Sdim int BaseState = -1; 988284734Sdim if (PerName == "_except_handler4") { 989284734Sdim // The LSDA for _except_handler4 starts with this struct, followed by the 990284734Sdim // scope table: 991284734Sdim // 992284734Sdim // struct EH4ScopeTable { 993284734Sdim // int32_t GSCookieOffset; 994284734Sdim // int32_t GSCookieXOROffset; 995284734Sdim // int32_t EHCookieOffset; 996284734Sdim // int32_t EHCookieXOROffset; 997284734Sdim // ScopeTableEntry ScopeRecord[]; 998284734Sdim // }; 999284734Sdim // 1000309124Sdim // Offsets are %ebp relative. 1001309124Sdim // 1002309124Sdim // The GS cookie is present only if the function needs stack protection. 1003309124Sdim // GSCookieOffset = -2 means that GS cookie is not used. 1004309124Sdim // 1005309124Sdim // The EH cookie is always present. 1006309124Sdim // 1007309124Sdim // Check is done the following way: 1008309124Sdim // (ebp+CookieXOROffset) ^ [ebp+CookieOffset] == _security_cookie 1009309124Sdim 1010309124Sdim // Retrieve the Guard Stack slot. 1011309124Sdim int GSCookieOffset = -2; 1012314564Sdim const MachineFrameInfo &MFI = MF->getFrameInfo(); 1013314564Sdim if (MFI.hasStackProtectorIndex()) { 1014309124Sdim unsigned UnusedReg; 1015309124Sdim const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); 1016314564Sdim int SSPIdx = MFI.getStackProtectorIndex(); 1017309124Sdim GSCookieOffset = TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg); 1018309124Sdim } 1019309124Sdim 1020309124Sdim // Retrieve the EH Guard slot. 1021309124Sdim // TODO(etienneb): Get rid of this value and change it for and assertion. 1022309124Sdim int EHCookieOffset = 9999; 1023309124Sdim if (FuncInfo.EHGuardFrameIndex != INT_MAX) { 1024309124Sdim unsigned UnusedReg; 1025309124Sdim const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); 1026309124Sdim int EHGuardIdx = FuncInfo.EHGuardFrameIndex; 1027309124Sdim EHCookieOffset = TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg); 1028309124Sdim } 1029309124Sdim 1030296417Sdim AddComment("GSCookieOffset"); 1031309124Sdim OS.EmitIntValue(GSCookieOffset, 4); 1032296417Sdim AddComment("GSCookieXOROffset"); 1033284734Sdim OS.EmitIntValue(0, 4); 1034296417Sdim AddComment("EHCookieOffset"); 1035309124Sdim OS.EmitIntValue(EHCookieOffset, 4); 1036296417Sdim AddComment("EHCookieXOROffset"); 1037284734Sdim OS.EmitIntValue(0, 4); 1038284734Sdim BaseState = -2; 1039284734Sdim } 1040284734Sdim 1041296417Sdim assert(!FuncInfo.SEHUnwindMap.empty()); 1042296417Sdim for (const SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) { 1043296417Sdim auto *Handler = UME.Handler.get<MachineBasicBlock *>(); 1044296417Sdim const MCSymbol *ExceptOrFinally = 1045296417Sdim UME.IsFinally ? getMCSymbolForMBB(Asm, Handler) : Handler->getSymbol(); 1046296417Sdim // -1 is usually the base state for "unwind to caller", but for 1047296417Sdim // _except_handler4 it's -2. Do that replacement here if necessary. 1048296417Sdim int ToState = UME.ToState == -1 ? BaseState : UME.ToState; 1049296417Sdim AddComment("ToState"); 1050296417Sdim OS.EmitIntValue(ToState, 4); 1051296417Sdim AddComment(UME.IsFinally ? "Null" : "FilterFunction"); 1052296417Sdim OS.EmitValue(create32bitRef(UME.Filter), 4); 1053296417Sdim AddComment(UME.IsFinally ? "FinallyFunclet" : "ExceptionHandler"); 1054296417Sdim OS.EmitValue(create32bitRef(ExceptOrFinally), 4); 1055296417Sdim } 1056296417Sdim} 1057284734Sdim 1058296417Sdimstatic int getTryRank(const WinEHFuncInfo &FuncInfo, int State) { 1059296417Sdim int Rank = 0; 1060296417Sdim while (State != -1) { 1061296417Sdim ++Rank; 1062296417Sdim State = FuncInfo.ClrEHUnwindMap[State].TryParentState; 1063296417Sdim } 1064296417Sdim return Rank; 1065296417Sdim} 1066284734Sdim 1067296417Sdimstatic int getTryAncestor(const WinEHFuncInfo &FuncInfo, int Left, int Right) { 1068296417Sdim int LeftRank = getTryRank(FuncInfo, Left); 1069296417Sdim int RightRank = getTryRank(FuncInfo, Right); 1070284734Sdim 1071296417Sdim while (LeftRank < RightRank) { 1072296417Sdim Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState; 1073296417Sdim --RightRank; 1074296417Sdim } 1075296417Sdim 1076296417Sdim while (RightRank < LeftRank) { 1077296417Sdim Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState; 1078296417Sdim --LeftRank; 1079296417Sdim } 1080296417Sdim 1081296417Sdim while (Left != Right) { 1082296417Sdim Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState; 1083296417Sdim Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState; 1084296417Sdim } 1085296417Sdim 1086296417Sdim return Left; 1087296417Sdim} 1088296417Sdim 1089296417Sdimvoid WinException::emitCLRExceptionTable(const MachineFunction *MF) { 1090296417Sdim // CLR EH "states" are really just IDs that identify handlers/funclets; 1091296417Sdim // states, handlers, and funclets all have 1:1 mappings between them, and a 1092296417Sdim // handler/funclet's "state" is its index in the ClrEHUnwindMap. 1093296417Sdim MCStreamer &OS = *Asm->OutStreamer; 1094296417Sdim const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo(); 1095296417Sdim MCSymbol *FuncBeginSym = Asm->getFunctionBegin(); 1096296417Sdim MCSymbol *FuncEndSym = Asm->getFunctionEnd(); 1097296417Sdim 1098296417Sdim // A ClrClause describes a protected region. 1099296417Sdim struct ClrClause { 1100296417Sdim const MCSymbol *StartLabel; // Start of protected region 1101296417Sdim const MCSymbol *EndLabel; // End of protected region 1102296417Sdim int State; // Index of handler protecting the protected region 1103296417Sdim int EnclosingState; // Index of funclet enclosing the protected region 1104296417Sdim }; 1105296417Sdim SmallVector<ClrClause, 8> Clauses; 1106296417Sdim 1107296417Sdim // Build a map from handler MBBs to their corresponding states (i.e. their 1108296417Sdim // indices in the ClrEHUnwindMap). 1109296417Sdim int NumStates = FuncInfo.ClrEHUnwindMap.size(); 1110296417Sdim assert(NumStates > 0 && "Don't need exception table!"); 1111296417Sdim DenseMap<const MachineBasicBlock *, int> HandlerStates; 1112296417Sdim for (int State = 0; State < NumStates; ++State) { 1113296417Sdim MachineBasicBlock *HandlerBlock = 1114296417Sdim FuncInfo.ClrEHUnwindMap[State].Handler.get<MachineBasicBlock *>(); 1115296417Sdim HandlerStates[HandlerBlock] = State; 1116296417Sdim // Use this loop through all handlers to verify our assumption (used in 1117296417Sdim // the MinEnclosingState computation) that enclosing funclets have lower 1118296417Sdim // state numbers than their enclosed funclets. 1119296417Sdim assert(FuncInfo.ClrEHUnwindMap[State].HandlerParentState < State && 1120296417Sdim "ill-formed state numbering"); 1121296417Sdim } 1122296417Sdim // Map the main function to the NullState. 1123296417Sdim HandlerStates[&MF->front()] = NullState; 1124296417Sdim 1125296417Sdim // Write out a sentinel indicating the end of the standard (Windows) xdata 1126296417Sdim // and the start of the additional (CLR) info. 1127296417Sdim OS.EmitIntValue(0xffffffff, 4); 1128296417Sdim // Write out the number of funclets 1129296417Sdim OS.EmitIntValue(NumStates, 4); 1130296417Sdim 1131296417Sdim // Walk the machine blocks/instrs, computing and emitting a few things: 1132296417Sdim // 1. Emit a list of the offsets to each handler entry, in lexical order. 1133296417Sdim // 2. Compute a map (EndSymbolMap) from each funclet to the symbol at its end. 1134296417Sdim // 3. Compute the list of ClrClauses, in the required order (inner before 1135296417Sdim // outer, earlier before later; the order by which a forward scan with 1136296417Sdim // early termination will find the innermost enclosing clause covering 1137296417Sdim // a given address). 1138296417Sdim // 4. A map (MinClauseMap) from each handler index to the index of the 1139296417Sdim // outermost funclet/function which contains a try clause targeting the 1140296417Sdim // key handler. This will be used to determine IsDuplicate-ness when 1141296417Sdim // emitting ClrClauses. The NullState value is used to indicate that the 1142296417Sdim // top-level function contains a try clause targeting the key handler. 1143296417Sdim // HandlerStack is a stack of (PendingStartLabel, PendingState) pairs for 1144296417Sdim // try regions we entered before entering the PendingState try but which 1145296417Sdim // we haven't yet exited. 1146296417Sdim SmallVector<std::pair<const MCSymbol *, int>, 4> HandlerStack; 1147296417Sdim // EndSymbolMap and MinClauseMap are maps described above. 1148296417Sdim std::unique_ptr<MCSymbol *[]> EndSymbolMap(new MCSymbol *[NumStates]); 1149296417Sdim SmallVector<int, 4> MinClauseMap((size_t)NumStates, NumStates); 1150296417Sdim 1151296417Sdim // Visit the root function and each funclet. 1152296417Sdim for (MachineFunction::const_iterator FuncletStart = MF->begin(), 1153296417Sdim FuncletEnd = MF->begin(), 1154296417Sdim End = MF->end(); 1155296417Sdim FuncletStart != End; FuncletStart = FuncletEnd) { 1156296417Sdim int FuncletState = HandlerStates[&*FuncletStart]; 1157296417Sdim // Find the end of the funclet 1158296417Sdim MCSymbol *EndSymbol = FuncEndSym; 1159296417Sdim while (++FuncletEnd != End) { 1160296417Sdim if (FuncletEnd->isEHFuncletEntry()) { 1161296417Sdim EndSymbol = getMCSymbolForMBB(Asm, &*FuncletEnd); 1162296417Sdim break; 1163296417Sdim } 1164284734Sdim } 1165296417Sdim // Emit the function/funclet end and, if this is a funclet (and not the 1166296417Sdim // root function), record it in the EndSymbolMap. 1167296417Sdim OS.EmitValue(getOffset(EndSymbol, FuncBeginSym), 4); 1168296417Sdim if (FuncletState != NullState) { 1169296417Sdim // Record the end of the handler. 1170296417Sdim EndSymbolMap[FuncletState] = EndSymbol; 1171296417Sdim } 1172296417Sdim 1173296417Sdim // Walk the state changes in this function/funclet and compute its clauses. 1174296417Sdim // Funclets always start in the null state. 1175296417Sdim const MCSymbol *CurrentStartLabel = nullptr; 1176296417Sdim int CurrentState = NullState; 1177296417Sdim assert(HandlerStack.empty()); 1178296417Sdim for (const auto &StateChange : 1179296417Sdim InvokeStateChangeIterator::range(FuncInfo, FuncletStart, FuncletEnd)) { 1180296417Sdim // Close any try regions we're not still under 1181296417Sdim int StillPendingState = 1182296417Sdim getTryAncestor(FuncInfo, CurrentState, StateChange.NewState); 1183296417Sdim while (CurrentState != StillPendingState) { 1184296417Sdim assert(CurrentState != NullState && 1185296417Sdim "Failed to find still-pending state!"); 1186296417Sdim // Close the pending clause 1187296417Sdim Clauses.push_back({CurrentStartLabel, StateChange.PreviousEndLabel, 1188296417Sdim CurrentState, FuncletState}); 1189296417Sdim // Now the next-outer try region is current 1190296417Sdim CurrentState = FuncInfo.ClrEHUnwindMap[CurrentState].TryParentState; 1191296417Sdim // Pop the new start label from the handler stack if we've exited all 1192296417Sdim // inner try regions of the corresponding try region. 1193296417Sdim if (HandlerStack.back().second == CurrentState) 1194296417Sdim CurrentStartLabel = HandlerStack.pop_back_val().first; 1195296417Sdim } 1196296417Sdim 1197296417Sdim if (StateChange.NewState != CurrentState) { 1198296417Sdim // For each clause we're starting, update the MinClauseMap so we can 1199296417Sdim // know which is the topmost funclet containing a clause targeting 1200296417Sdim // it. 1201296417Sdim for (int EnteredState = StateChange.NewState; 1202296417Sdim EnteredState != CurrentState; 1203296417Sdim EnteredState = 1204296417Sdim FuncInfo.ClrEHUnwindMap[EnteredState].TryParentState) { 1205296417Sdim int &MinEnclosingState = MinClauseMap[EnteredState]; 1206296417Sdim if (FuncletState < MinEnclosingState) 1207296417Sdim MinEnclosingState = FuncletState; 1208296417Sdim } 1209296417Sdim // Save the previous current start/label on the stack and update to 1210296417Sdim // the newly-current start/state. 1211296417Sdim HandlerStack.emplace_back(CurrentStartLabel, CurrentState); 1212296417Sdim CurrentStartLabel = StateChange.NewStartLabel; 1213296417Sdim CurrentState = StateChange.NewState; 1214296417Sdim } 1215296417Sdim } 1216296417Sdim assert(HandlerStack.empty()); 1217284734Sdim } 1218296417Sdim 1219296417Sdim // Now emit the clause info, starting with the number of clauses. 1220296417Sdim OS.EmitIntValue(Clauses.size(), 4); 1221296417Sdim for (ClrClause &Clause : Clauses) { 1222296417Sdim // Emit a CORINFO_EH_CLAUSE : 1223296417Sdim /* 1224296417Sdim struct CORINFO_EH_CLAUSE 1225296417Sdim { 1226296417Sdim CORINFO_EH_CLAUSE_FLAGS Flags; // actually a CorExceptionFlag 1227296417Sdim DWORD TryOffset; 1228296417Sdim DWORD TryLength; // actually TryEndOffset 1229296417Sdim DWORD HandlerOffset; 1230296417Sdim DWORD HandlerLength; // actually HandlerEndOffset 1231296417Sdim union 1232296417Sdim { 1233296417Sdim DWORD ClassToken; // use for catch clauses 1234296417Sdim DWORD FilterOffset; // use for filter clauses 1235296417Sdim }; 1236296417Sdim }; 1237296417Sdim 1238296417Sdim enum CORINFO_EH_CLAUSE_FLAGS 1239296417Sdim { 1240296417Sdim CORINFO_EH_CLAUSE_NONE = 0, 1241296417Sdim CORINFO_EH_CLAUSE_FILTER = 0x0001, // This clause is for a filter 1242296417Sdim CORINFO_EH_CLAUSE_FINALLY = 0x0002, // This clause is a finally clause 1243296417Sdim CORINFO_EH_CLAUSE_FAULT = 0x0004, // This clause is a fault clause 1244296417Sdim }; 1245296417Sdim typedef enum CorExceptionFlag 1246296417Sdim { 1247296417Sdim COR_ILEXCEPTION_CLAUSE_NONE, 1248296417Sdim COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001, // This is a filter clause 1249296417Sdim COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002, // This is a finally clause 1250296417Sdim COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004, // This is a fault clause 1251296417Sdim COR_ILEXCEPTION_CLAUSE_DUPLICATED = 0x0008, // duplicated clause. This 1252296417Sdim // clause was duplicated 1253296417Sdim // to a funclet which was 1254296417Sdim // pulled out of line 1255296417Sdim } CorExceptionFlag; 1256296417Sdim */ 1257296417Sdim // Add 1 to the start/end of the EH clause; the IP associated with a 1258296417Sdim // call when the runtime does its scan is the IP of the next instruction 1259296417Sdim // (the one to which control will return after the call), so we need 1260296417Sdim // to add 1 to the end of the clause to cover that offset. We also add 1261296417Sdim // 1 to the start of the clause to make sure that the ranges reported 1262296417Sdim // for all clauses are disjoint. Note that we'll need some additional 1263296417Sdim // logic when machine traps are supported, since in that case the IP 1264296417Sdim // that the runtime uses is the offset of the faulting instruction 1265296417Sdim // itself; if such an instruction immediately follows a call but the 1266296417Sdim // two belong to different clauses, we'll need to insert a nop between 1267296417Sdim // them so the runtime can distinguish the point to which the call will 1268296417Sdim // return from the point at which the fault occurs. 1269296417Sdim 1270296417Sdim const MCExpr *ClauseBegin = 1271296417Sdim getOffsetPlusOne(Clause.StartLabel, FuncBeginSym); 1272296417Sdim const MCExpr *ClauseEnd = getOffsetPlusOne(Clause.EndLabel, FuncBeginSym); 1273296417Sdim 1274296417Sdim const ClrEHUnwindMapEntry &Entry = FuncInfo.ClrEHUnwindMap[Clause.State]; 1275296417Sdim MachineBasicBlock *HandlerBlock = Entry.Handler.get<MachineBasicBlock *>(); 1276296417Sdim MCSymbol *BeginSym = getMCSymbolForMBB(Asm, HandlerBlock); 1277296417Sdim const MCExpr *HandlerBegin = getOffset(BeginSym, FuncBeginSym); 1278296417Sdim MCSymbol *EndSym = EndSymbolMap[Clause.State]; 1279296417Sdim const MCExpr *HandlerEnd = getOffset(EndSym, FuncBeginSym); 1280296417Sdim 1281296417Sdim uint32_t Flags = 0; 1282296417Sdim switch (Entry.HandlerType) { 1283296417Sdim case ClrHandlerType::Catch: 1284296417Sdim // Leaving bits 0-2 clear indicates catch. 1285296417Sdim break; 1286296417Sdim case ClrHandlerType::Filter: 1287296417Sdim Flags |= 1; 1288296417Sdim break; 1289296417Sdim case ClrHandlerType::Finally: 1290296417Sdim Flags |= 2; 1291296417Sdim break; 1292296417Sdim case ClrHandlerType::Fault: 1293296417Sdim Flags |= 4; 1294296417Sdim break; 1295296417Sdim } 1296296417Sdim if (Clause.EnclosingState != MinClauseMap[Clause.State]) { 1297296417Sdim // This is a "duplicate" clause; the handler needs to be entered from a 1298296417Sdim // frame above the one holding the invoke. 1299296417Sdim assert(Clause.EnclosingState > MinClauseMap[Clause.State]); 1300296417Sdim Flags |= 8; 1301296417Sdim } 1302296417Sdim OS.EmitIntValue(Flags, 4); 1303296417Sdim 1304296417Sdim // Write the clause start/end 1305296417Sdim OS.EmitValue(ClauseBegin, 4); 1306296417Sdim OS.EmitValue(ClauseEnd, 4); 1307296417Sdim 1308296417Sdim // Write out the handler start/end 1309296417Sdim OS.EmitValue(HandlerBegin, 4); 1310296417Sdim OS.EmitValue(HandlerEnd, 4); 1311296417Sdim 1312296417Sdim // Write out the type token or filter offset 1313296417Sdim assert(Entry.HandlerType != ClrHandlerType::Filter && "NYI: filters"); 1314296417Sdim OS.EmitIntValue(Entry.TypeToken, 4); 1315296417Sdim } 1316284734Sdim} 1317