Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
35271 views
//===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains support for writing Win64 exception info into asm files.9//10//===----------------------------------------------------------------------===//1112#include "WinException.h"13#include "llvm/ADT/Twine.h"14#include "llvm/BinaryFormat/COFF.h"15#include "llvm/BinaryFormat/Dwarf.h"16#include "llvm/CodeGen/AsmPrinter.h"17#include "llvm/CodeGen/MachineFrameInfo.h"18#include "llvm/CodeGen/MachineFunction.h"19#include "llvm/CodeGen/MachineModuleInfo.h"20#include "llvm/CodeGen/TargetFrameLowering.h"21#include "llvm/CodeGen/TargetLowering.h"22#include "llvm/CodeGen/TargetSubtargetInfo.h"23#include "llvm/CodeGen/WinEHFuncInfo.h"24#include "llvm/IR/DataLayout.h"25#include "llvm/IR/Module.h"26#include "llvm/MC/MCAsmInfo.h"27#include "llvm/MC/MCContext.h"28#include "llvm/MC/MCExpr.h"29#include "llvm/MC/MCStreamer.h"30#include "llvm/Target/TargetLoweringObjectFile.h"31#include "llvm/Target/TargetMachine.h"32using namespace llvm;3334WinException::WinException(AsmPrinter *A) : EHStreamer(A) {35// MSVC's EH tables are always composed of 32-bit words. All known 64-bit36// platforms use an imagerel32 relocation to refer to symbols.37useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);38isAArch64 = Asm->TM.getTargetTriple().isAArch64();39isThumb = Asm->TM.getTargetTriple().isThumb();40}4142WinException::~WinException() = default;4344/// endModule - Emit all exception information that should come after the45/// content.46void WinException::endModule() {47auto &OS = *Asm->OutStreamer;48const Module *M = MMI->getModule();49for (const Function &F : *M)50if (F.hasFnAttribute("safeseh"))51OS.emitCOFFSafeSEH(Asm->getSymbol(&F));5253if (M->getModuleFlag("ehcontguard") && !EHContTargets.empty()) {54// Emit the symbol index of each ehcont target.55OS.switchSection(Asm->OutContext.getObjectFileInfo()->getGEHContSection());56for (const MCSymbol *S : EHContTargets) {57OS.emitCOFFSymbolIndex(S);58}59}60}6162void WinException::beginFunction(const MachineFunction *MF) {63shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;6465// If any landing pads survive, we need an EH table.66bool hasLandingPads = !MF->getLandingPads().empty();67bool hasEHFunclets = MF->hasEHFunclets();6869const Function &F = MF->getFunction();7071shouldEmitMoves = Asm->needsSEHMoves() && MF->hasWinCFI();7273const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();74unsigned PerEncoding = TLOF.getPersonalityEncoding();7576EHPersonality Per = EHPersonality::Unknown;77const Function *PerFn = nullptr;78if (F.hasPersonalityFn()) {79PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());80Per = classifyEHPersonality(PerFn);81}8283bool forceEmitPersonality = F.hasPersonalityFn() &&84!isNoOpWithoutInvoke(Per) &&85F.needsUnwindTableEntry();8687shouldEmitPersonality =88forceEmitPersonality || ((hasLandingPads || hasEHFunclets) &&89PerEncoding != dwarf::DW_EH_PE_omit && PerFn);9091unsigned LSDAEncoding = TLOF.getLSDAEncoding();92shouldEmitLSDA = shouldEmitPersonality &&93LSDAEncoding != dwarf::DW_EH_PE_omit;9495// If we're not using CFI, we don't want the CFI or the personality, but we96// might want EH tables if we had EH pads.97if (!Asm->MAI->usesWindowsCFI()) {98if (Per == EHPersonality::MSVC_X86SEH && !hasEHFunclets) {99// If this is 32-bit SEH and we don't have any funclets (really invokes),100// make sure we emit the parent offset label. Some unreferenced filter101// functions may still refer to it.102const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();103StringRef FLinkageName =104GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());105emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);106}107shouldEmitLSDA = hasEHFunclets;108shouldEmitPersonality = false;109return;110}111112beginFunclet(MF->front(), Asm->CurrentFnSym);113}114115void WinException::markFunctionEnd() {116if (isAArch64 && CurrentFuncletEntry &&117(shouldEmitMoves || shouldEmitPersonality))118Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();119}120121/// endFunction - Gather and emit post-function exception information.122///123void WinException::endFunction(const MachineFunction *MF) {124if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA)125return;126127const Function &F = MF->getFunction();128EHPersonality Per = EHPersonality::Unknown;129if (F.hasPersonalityFn())130Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());131132endFuncletImpl();133134// endFunclet will emit the necessary .xdata tables for table-based SEH.135if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets())136return;137138if (shouldEmitPersonality || shouldEmitLSDA) {139Asm->OutStreamer->pushSection();140141// Just switch sections to the right xdata section.142MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection(143Asm->OutStreamer->getCurrentSectionOnly());144Asm->OutStreamer->switchSection(XData);145146// Emit the tables appropriate to the personality function in use. If we147// don't recognize the personality, assume it uses an Itanium-style LSDA.148if (Per == EHPersonality::MSVC_TableSEH)149emitCSpecificHandlerTable(MF);150else if (Per == EHPersonality::MSVC_X86SEH)151emitExceptHandlerTable(MF);152else if (Per == EHPersonality::MSVC_CXX)153emitCXXFrameHandler3Table(MF);154else if (Per == EHPersonality::CoreCLR)155emitCLRExceptionTable(MF);156else157emitExceptionTable();158159Asm->OutStreamer->popSection();160}161162if (!MF->getCatchretTargets().empty()) {163// Copy the function's catchret targets to a module-level list.164EHContTargets.insert(EHContTargets.end(), MF->getCatchretTargets().begin(),165MF->getCatchretTargets().end());166}167}168169/// Retrieve the MCSymbol for a GlobalValue or MachineBasicBlock.170static MCSymbol *getMCSymbolForMBB(AsmPrinter *Asm,171const MachineBasicBlock *MBB) {172if (!MBB)173return nullptr;174175assert(MBB->isEHFuncletEntry());176177// Give catches and cleanups a name based off of their parent function and178// their funclet entry block's number.179const MachineFunction *MF = MBB->getParent();180const Function &F = MF->getFunction();181StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());182MCContext &Ctx = MF->getContext();183StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch";184return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" +185Twine(MBB->getNumber()) + "@?0?" +186FuncLinkageName + "@4HA");187}188189void WinException::beginFunclet(const MachineBasicBlock &MBB,190MCSymbol *Sym) {191CurrentFuncletEntry = &MBB;192193const Function &F = Asm->MF->getFunction();194// If a symbol was not provided for the funclet, invent one.195if (!Sym) {196Sym = getMCSymbolForMBB(Asm, &MBB);197198// Describe our funclet symbol as a function with internal linkage.199Asm->OutStreamer->beginCOFFSymbolDef(Sym);200Asm->OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);201Asm->OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION202<< COFF::SCT_COMPLEX_TYPE_SHIFT);203Asm->OutStreamer->endCOFFSymbolDef();204205// We want our funclet's entry point to be aligned such that no nops will be206// present after the label.207Asm->emitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()),208&F);209210// Now that we've emitted the alignment directive, point at our funclet.211Asm->OutStreamer->emitLabel(Sym);212}213214// Mark 'Sym' as starting our funclet.215if (shouldEmitMoves || shouldEmitPersonality) {216CurrentFuncletTextSection = Asm->OutStreamer->getCurrentSectionOnly();217Asm->OutStreamer->emitWinCFIStartProc(Sym);218}219220if (shouldEmitPersonality) {221const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();222const Function *PerFn = nullptr;223224// Determine which personality routine we are using for this funclet.225if (F.hasPersonalityFn())226PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());227const MCSymbol *PersHandlerSym =228TLOF.getCFIPersonalitySymbol(PerFn, Asm->TM, MMI);229230// Do not emit a .seh_handler directives for cleanup funclets.231// FIXME: This means cleanup funclets cannot handle exceptions. Given that232// Clang doesn't produce EH constructs inside cleanup funclets and LLVM's233// inliner doesn't allow inlining them, this isn't a major problem in234// practice.235if (!CurrentFuncletEntry->isCleanupFuncletEntry())236Asm->OutStreamer->emitWinEHHandler(PersHandlerSym, true, true);237}238}239240void WinException::endFunclet() {241if (isAArch64 && CurrentFuncletEntry &&242(shouldEmitMoves || shouldEmitPersonality)) {243Asm->OutStreamer->switchSection(CurrentFuncletTextSection);244Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();245}246endFuncletImpl();247}248249void WinException::endFuncletImpl() {250// No funclet to process? Great, we have nothing to do.251if (!CurrentFuncletEntry)252return;253254const MachineFunction *MF = Asm->MF;255if (shouldEmitMoves || shouldEmitPersonality) {256const Function &F = MF->getFunction();257EHPersonality Per = EHPersonality::Unknown;258if (F.hasPersonalityFn())259Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());260261if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality &&262!CurrentFuncletEntry->isCleanupFuncletEntry()) {263// Emit an UNWIND_INFO struct describing the prologue.264Asm->OutStreamer->emitWinEHHandlerData();265266// If this is a C++ catch funclet (or the parent function),267// emit a reference to the LSDA for the parent function.268StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());269MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(270Twine("$cppxdata$", FuncLinkageName));271Asm->OutStreamer->emitValue(create32bitRef(FuncInfoXData), 4);272} else if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets() &&273!CurrentFuncletEntry->isEHFuncletEntry()) {274// Emit an UNWIND_INFO struct describing the prologue.275Asm->OutStreamer->emitWinEHHandlerData();276277// If this is the parent function in Win64 SEH, emit the LSDA immediately278// following .seh_handlerdata.279emitCSpecificHandlerTable(MF);280} else if (shouldEmitPersonality || shouldEmitLSDA) {281// Emit an UNWIND_INFO struct describing the prologue.282Asm->OutStreamer->emitWinEHHandlerData();283// In these cases, no further info is written to the .xdata section284// right here, but is written by e.g. emitExceptionTable in endFunction()285// above.286} else {287// No need to emit the EH handler data right here if nothing needs288// writing to the .xdata section; it will be emitted for all289// functions that need it in the end anyway.290}291292// Switch back to the funclet start .text section now that we are done293// writing to .xdata, and emit an .seh_endproc directive to mark the end of294// the function.295Asm->OutStreamer->switchSection(CurrentFuncletTextSection);296Asm->OutStreamer->emitWinCFIEndProc();297}298299// Let's make sure we don't try to end the same funclet twice.300CurrentFuncletEntry = nullptr;301}302303const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {304if (!Value)305return MCConstantExpr::create(0, Asm->OutContext);306return MCSymbolRefExpr::create(Value, useImageRel32307? MCSymbolRefExpr::VK_COFF_IMGREL32308: MCSymbolRefExpr::VK_None,309Asm->OutContext);310}311312const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {313if (!GV)314return MCConstantExpr::create(0, Asm->OutContext);315return create32bitRef(Asm->getSymbol(GV));316}317318const MCExpr *WinException::getLabel(const MCSymbol *Label) {319return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32,320Asm->OutContext);321}322323const MCExpr *WinException::getLabelPlusOne(const MCSymbol *Label) {324return MCBinaryExpr::createAdd(getLabel(Label),325MCConstantExpr::create(1, Asm->OutContext),326Asm->OutContext);327}328329const MCExpr *WinException::getOffset(const MCSymbol *OffsetOf,330const MCSymbol *OffsetFrom) {331return MCBinaryExpr::createSub(332MCSymbolRefExpr::create(OffsetOf, Asm->OutContext),333MCSymbolRefExpr::create(OffsetFrom, Asm->OutContext), Asm->OutContext);334}335336const MCExpr *WinException::getOffsetPlusOne(const MCSymbol *OffsetOf,337const MCSymbol *OffsetFrom) {338return MCBinaryExpr::createAdd(getOffset(OffsetOf, OffsetFrom),339MCConstantExpr::create(1, Asm->OutContext),340Asm->OutContext);341}342343int WinException::getFrameIndexOffset(int FrameIndex,344const WinEHFuncInfo &FuncInfo) {345const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering();346Register UnusedReg;347if (Asm->MAI->usesWindowsCFI()) {348StackOffset Offset =349TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg,350/*IgnoreSPUpdates*/ true);351assert(UnusedReg ==352Asm->MF->getSubtarget()353.getTargetLowering()354->getStackPointerRegisterToSaveRestore());355return Offset.getFixed();356}357358// For 32-bit, offsets should be relative to the end of the EH registration359// node. For 64-bit, it's relative to SP at the end of the prologue.360assert(FuncInfo.EHRegNodeEndOffset != INT_MAX);361StackOffset Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg);362Offset += StackOffset::getFixed(FuncInfo.EHRegNodeEndOffset);363assert(!Offset.getScalable() &&364"Frame offsets with a scalable component are not supported");365return Offset.getFixed();366}367368namespace {369370/// Top-level state used to represent unwind to caller371const int NullState = -1;372373struct InvokeStateChange {374/// EH Label immediately after the last invoke in the previous state, or375/// nullptr if the previous state was the null state.376const MCSymbol *PreviousEndLabel;377378/// EH label immediately before the first invoke in the new state, or nullptr379/// if the new state is the null state.380const MCSymbol *NewStartLabel;381382/// State of the invoke following NewStartLabel, or NullState to indicate383/// the presence of calls which may unwind to caller.384int NewState;385};386387/// Iterator that reports all the invoke state changes in a range of machine388/// basic blocks. Changes to the null state are reported whenever a call that389/// may unwind to caller is encountered. The MBB range is expected to be an390/// entire function or funclet, and the start and end of the range are treated391/// as being in the NullState even if there's not an unwind-to-caller call392/// before the first invoke or after the last one (i.e., the first state change393/// reported is the first change to something other than NullState, and a394/// change back to NullState is always reported at the end of iteration).395class InvokeStateChangeIterator {396InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo,397MachineFunction::const_iterator MFI,398MachineFunction::const_iterator MFE,399MachineBasicBlock::const_iterator MBBI,400int BaseState)401: EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) {402LastStateChange.PreviousEndLabel = nullptr;403LastStateChange.NewStartLabel = nullptr;404LastStateChange.NewState = BaseState;405scan();406}407408public:409static iterator_range<InvokeStateChangeIterator>410range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin,411MachineFunction::const_iterator End, int BaseState = NullState) {412// Reject empty ranges to simplify bookkeeping by ensuring that we can get413// the end of the last block.414assert(Begin != End);415auto BlockBegin = Begin->begin();416auto BlockEnd = std::prev(End)->end();417return make_range(418InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState),419InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState));420}421422// Iterator methods.423bool operator==(const InvokeStateChangeIterator &O) const {424assert(BaseState == O.BaseState);425// Must be visiting same block.426if (MFI != O.MFI)427return false;428// Must be visiting same isntr.429if (MBBI != O.MBBI)430return false;431// At end of block/instr iteration, we can still have two distinct states:432// one to report the final EndLabel, and another indicating the end of the433// state change iteration. Check for CurrentEndLabel equality to434// distinguish these.435return CurrentEndLabel == O.CurrentEndLabel;436}437438bool operator!=(const InvokeStateChangeIterator &O) const {439return !operator==(O);440}441InvokeStateChange &operator*() { return LastStateChange; }442InvokeStateChange *operator->() { return &LastStateChange; }443InvokeStateChangeIterator &operator++() { return scan(); }444445private:446InvokeStateChangeIterator &scan();447448const WinEHFuncInfo &EHInfo;449const MCSymbol *CurrentEndLabel = nullptr;450MachineFunction::const_iterator MFI;451MachineFunction::const_iterator MFE;452MachineBasicBlock::const_iterator MBBI;453InvokeStateChange LastStateChange;454bool VisitingInvoke = false;455int BaseState;456};457458} // end anonymous namespace459460InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {461bool IsNewBlock = false;462for (; MFI != MFE; ++MFI, IsNewBlock = true) {463if (IsNewBlock)464MBBI = MFI->begin();465for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) {466const MachineInstr &MI = *MBBI;467if (!VisitingInvoke && LastStateChange.NewState != BaseState &&468MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) {469// Indicate a change of state to the null state. We don't have470// start/end EH labels handy but the caller won't expect them for471// null state regions.472LastStateChange.PreviousEndLabel = CurrentEndLabel;473LastStateChange.NewStartLabel = nullptr;474LastStateChange.NewState = BaseState;475CurrentEndLabel = nullptr;476// Don't re-visit this instr on the next scan477++MBBI;478return *this;479}480481// All other state changes are at EH labels before/after invokes.482if (!MI.isEHLabel())483continue;484MCSymbol *Label = MI.getOperand(0).getMCSymbol();485if (Label == CurrentEndLabel) {486VisitingInvoke = false;487continue;488}489auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label);490// Ignore EH labels that aren't the ones inserted before an invoke491if (InvokeMapIter == EHInfo.LabelToStateMap.end())492continue;493auto &StateAndEnd = InvokeMapIter->second;494int NewState = StateAndEnd.first;495// Keep track of the fact that we're between EH start/end labels so496// we know not to treat the inoke we'll see as unwinding to caller.497VisitingInvoke = true;498if (NewState == LastStateChange.NewState) {499// The state isn't actually changing here. Record the new end and500// keep going.501CurrentEndLabel = StateAndEnd.second;502continue;503}504// Found a state change to report505LastStateChange.PreviousEndLabel = CurrentEndLabel;506LastStateChange.NewStartLabel = Label;507LastStateChange.NewState = NewState;508// Start keeping track of the new current end509CurrentEndLabel = StateAndEnd.second;510// Don't re-visit this instr on the next scan511++MBBI;512return *this;513}514}515// Iteration hit the end of the block range.516if (LastStateChange.NewState != BaseState) {517// Report the end of the last new state518LastStateChange.PreviousEndLabel = CurrentEndLabel;519LastStateChange.NewStartLabel = nullptr;520LastStateChange.NewState = BaseState;521// Leave CurrentEndLabel non-null to distinguish this state from end.522assert(CurrentEndLabel != nullptr);523return *this;524}525// We've reported all state changes and hit the end state.526CurrentEndLabel = nullptr;527return *this;528}529530/// Emit the language-specific data that __C_specific_handler expects. This531/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning532/// up after faults with __try, __except, and __finally. The typeinfo values533/// are not really RTTI data, but pointers to filter functions that return an534/// integer (1, 0, or -1) indicating how to handle the exception. For __finally535/// blocks and other cleanups, the landing pad label is zero, and the filter536/// function is actually a cleanup handler with the same prototype. A catch-all537/// entry is modeled with a null filter function field and a non-zero landing538/// pad label.539///540/// Possible filter function return values:541/// EXCEPTION_EXECUTE_HANDLER (1):542/// Jump to the landing pad label after cleanups.543/// EXCEPTION_CONTINUE_SEARCH (0):544/// Continue searching this table or continue unwinding.545/// EXCEPTION_CONTINUE_EXECUTION (-1):546/// Resume execution at the trapping PC.547///548/// Inferred table structure:549/// struct Table {550/// int NumEntries;551/// struct Entry {552/// imagerel32 LabelStart; // Inclusive553/// imagerel32 LabelEnd; // Exclusive554/// imagerel32 FilterOrFinally; // One means catch-all.555/// imagerel32 LabelLPad; // Zero means __finally.556/// } Entries[NumEntries];557/// };558void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {559auto &OS = *Asm->OutStreamer;560MCContext &Ctx = Asm->OutContext;561const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();562563bool VerboseAsm = OS.isVerboseAsm();564auto AddComment = [&](const Twine &Comment) {565if (VerboseAsm)566OS.AddComment(Comment);567};568569if (!isAArch64) {570// Emit a label assignment with the SEH frame offset so we can use it for571// llvm.eh.recoverfp.572StringRef FLinkageName =573GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());574MCSymbol *ParentFrameOffset =575Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);576const MCExpr *MCOffset =577MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx);578Asm->OutStreamer->emitAssignment(ParentFrameOffset, MCOffset);579}580581// Use the assembler to compute the number of table entries through label582// difference and division.583MCSymbol *TableBegin =584Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true);585MCSymbol *TableEnd =586Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true);587const MCExpr *LabelDiff = getOffset(TableEnd, TableBegin);588const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx);589const MCExpr *EntryCount = MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx);590AddComment("Number of call sites");591OS.emitValue(EntryCount, 4);592593OS.emitLabel(TableBegin);594595// Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only596// models exceptions from invokes. LLVM also allows arbitrary reordering of597// the code, so our tables end up looking a bit different. Rather than598// trying to match MSVC's tables exactly, we emit a denormalized table. For599// each range of invokes in the same state, we emit table entries for all600// the actions that would be taken in that state. This means our tables are601// slightly bigger, which is OK.602const MCSymbol *LastStartLabel = nullptr;603int LastEHState = -1;604// Break out before we enter into a finally funclet.605// FIXME: We need to emit separate EH tables for cleanups.606MachineFunction::const_iterator End = MF->end();607MachineFunction::const_iterator Stop = std::next(MF->begin());608while (Stop != End && !Stop->isEHFuncletEntry())609++Stop;610for (const auto &StateChange :611InvokeStateChangeIterator::range(FuncInfo, MF->begin(), Stop)) {612// Emit all the actions for the state we just transitioned out of613// if it was not the null state614if (LastEHState != -1)615emitSEHActionsForRange(FuncInfo, LastStartLabel,616StateChange.PreviousEndLabel, LastEHState);617LastStartLabel = StateChange.NewStartLabel;618LastEHState = StateChange.NewState;619}620621OS.emitLabel(TableEnd);622}623624void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo,625const MCSymbol *BeginLabel,626const MCSymbol *EndLabel, int State) {627auto &OS = *Asm->OutStreamer;628MCContext &Ctx = Asm->OutContext;629bool VerboseAsm = OS.isVerboseAsm();630auto AddComment = [&](const Twine &Comment) {631if (VerboseAsm)632OS.AddComment(Comment);633};634635assert(BeginLabel && EndLabel);636while (State != -1) {637const SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];638const MCExpr *FilterOrFinally;639const MCExpr *ExceptOrNull;640auto *Handler = cast<MachineBasicBlock *>(UME.Handler);641if (UME.IsFinally) {642FilterOrFinally = create32bitRef(getMCSymbolForMBB(Asm, Handler));643ExceptOrNull = MCConstantExpr::create(0, Ctx);644} else {645// For an except, the filter can be 1 (catch-all) or a function646// label.647FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)648: MCConstantExpr::create(1, Ctx);649ExceptOrNull = create32bitRef(Handler->getSymbol());650}651652AddComment("LabelStart");653OS.emitValue(getLabel(BeginLabel), 4);654AddComment("LabelEnd");655OS.emitValue(getLabelPlusOne(EndLabel), 4);656AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction"657: "CatchAll");658OS.emitValue(FilterOrFinally, 4);659AddComment(UME.IsFinally ? "Null" : "ExceptionHandler");660OS.emitValue(ExceptOrNull, 4);661662assert(UME.ToState < State && "states should decrease");663State = UME.ToState;664}665}666667void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {668const Function &F = MF->getFunction();669auto &OS = *Asm->OutStreamer;670const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();671672StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());673674SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable;675MCSymbol *FuncInfoXData = nullptr;676if (shouldEmitPersonality) {677// If we're 64-bit, emit a pointer to the C++ EH data, and build a map from678// IPs to state numbers.679FuncInfoXData =680Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName));681computeIP2StateTable(MF, FuncInfo, IPToStateTable);682} else {683FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName);684}685686int UnwindHelpOffset = 0;687// TODO: The check for UnwindHelpFrameIdx against max() below (and the688// second check further below) can be removed if MS C++ unwinding is689// implemented for ARM, when test/CodeGen/ARM/Windows/wineh-basic.ll690// passes without the check.691if (Asm->MAI->usesWindowsCFI() &&692FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max())693UnwindHelpOffset =694getFrameIndexOffset(FuncInfo.UnwindHelpFrameIdx, FuncInfo);695696MCSymbol *UnwindMapXData = nullptr;697MCSymbol *TryBlockMapXData = nullptr;698MCSymbol *IPToStateXData = nullptr;699if (!FuncInfo.CxxUnwindMap.empty())700UnwindMapXData = Asm->OutContext.getOrCreateSymbol(701Twine("$stateUnwindMap$", FuncLinkageName));702if (!FuncInfo.TryBlockMap.empty())703TryBlockMapXData =704Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName));705if (!IPToStateTable.empty())706IPToStateXData =707Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName));708709bool VerboseAsm = OS.isVerboseAsm();710auto AddComment = [&](const Twine &Comment) {711if (VerboseAsm)712OS.AddComment(Comment);713};714715// FuncInfo {716// uint32_t MagicNumber717// int32_t MaxState;718// UnwindMapEntry *UnwindMap;719// uint32_t NumTryBlocks;720// TryBlockMapEntry *TryBlockMap;721// uint32_t IPMapEntries; // always 0 for x86722// IPToStateMapEntry *IPToStateMap; // always 0 for x86723// uint32_t UnwindHelp; // non-x86 only724// ESTypeList *ESTypeList;725// int32_t EHFlags;726// }727// EHFlags & 1 -> Synchronous exceptions only, no async exceptions.728// EHFlags & 2 -> ???729// EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.730OS.emitValueToAlignment(Align(4));731OS.emitLabel(FuncInfoXData);732733AddComment("MagicNumber");734OS.emitInt32(0x19930522);735736AddComment("MaxState");737OS.emitInt32(FuncInfo.CxxUnwindMap.size());738739AddComment("UnwindMap");740OS.emitValue(create32bitRef(UnwindMapXData), 4);741742AddComment("NumTryBlocks");743OS.emitInt32(FuncInfo.TryBlockMap.size());744745AddComment("TryBlockMap");746OS.emitValue(create32bitRef(TryBlockMapXData), 4);747748AddComment("IPMapEntries");749OS.emitInt32(IPToStateTable.size());750751AddComment("IPToStateXData");752OS.emitValue(create32bitRef(IPToStateXData), 4);753754if (Asm->MAI->usesWindowsCFI() &&755FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max()) {756AddComment("UnwindHelp");757OS.emitInt32(UnwindHelpOffset);758}759760AddComment("ESTypeList");761OS.emitInt32(0);762763AddComment("EHFlags");764if (MMI->getModule()->getModuleFlag("eh-asynch")) {765OS.emitInt32(0);766} else {767OS.emitInt32(1);768}769770// UnwindMapEntry {771// int32_t ToState;772// void (*Action)();773// };774if (UnwindMapXData) {775OS.emitLabel(UnwindMapXData);776for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) {777MCSymbol *CleanupSym = getMCSymbolForMBB(778Asm, dyn_cast_if_present<MachineBasicBlock *>(UME.Cleanup));779AddComment("ToState");780OS.emitInt32(UME.ToState);781782AddComment("Action");783OS.emitValue(create32bitRef(CleanupSym), 4);784}785}786787// TryBlockMap {788// int32_t TryLow;789// int32_t TryHigh;790// int32_t CatchHigh;791// int32_t NumCatches;792// HandlerType *HandlerArray;793// };794if (TryBlockMapXData) {795OS.emitLabel(TryBlockMapXData);796SmallVector<MCSymbol *, 1> HandlerMaps;797for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {798const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];799800MCSymbol *HandlerMapXData = nullptr;801if (!TBME.HandlerArray.empty())802HandlerMapXData =803Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")804.concat(Twine(I))805.concat("$")806.concat(FuncLinkageName));807HandlerMaps.push_back(HandlerMapXData);808809// TBMEs should form intervals.810assert(0 <= TBME.TryLow && "bad trymap interval");811assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval");812assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval");813assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) &&814"bad trymap interval");815816AddComment("TryLow");817OS.emitInt32(TBME.TryLow);818819AddComment("TryHigh");820OS.emitInt32(TBME.TryHigh);821822AddComment("CatchHigh");823OS.emitInt32(TBME.CatchHigh);824825AddComment("NumCatches");826OS.emitInt32(TBME.HandlerArray.size());827828AddComment("HandlerArray");829OS.emitValue(create32bitRef(HandlerMapXData), 4);830}831832// All funclets use the same parent frame offset currently.833unsigned ParentFrameOffset = 0;834if (shouldEmitPersonality) {835const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();836ParentFrameOffset = TFI->getWinEHParentFrameOffset(*MF);837}838839for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {840const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];841MCSymbol *HandlerMapXData = HandlerMaps[I];842if (!HandlerMapXData)843continue;844// HandlerType {845// int32_t Adjectives;846// TypeDescriptor *Type;847// int32_t CatchObjOffset;848// void (*Handler)();849// int32_t ParentFrameOffset; // x64 and AArch64 only850// };851OS.emitLabel(HandlerMapXData);852for (const WinEHHandlerType &HT : TBME.HandlerArray) {853// Get the frame escape label with the offset of the catch object. If854// the index is INT_MAX, then there is no catch object, and we should855// emit an offset of zero, indicating that no copy will occur.856const MCExpr *FrameAllocOffsetRef = nullptr;857if (HT.CatchObj.FrameIndex != INT_MAX) {858int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex, FuncInfo);859assert(Offset != 0 && "Illegal offset for catch object!");860FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext);861} else {862FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);863}864865MCSymbol *HandlerSym = getMCSymbolForMBB(866Asm, dyn_cast_if_present<MachineBasicBlock *>(HT.Handler));867868AddComment("Adjectives");869OS.emitInt32(HT.Adjectives);870871AddComment("Type");872OS.emitValue(create32bitRef(HT.TypeDescriptor), 4);873874AddComment("CatchObjOffset");875OS.emitValue(FrameAllocOffsetRef, 4);876877AddComment("Handler");878OS.emitValue(create32bitRef(HandlerSym), 4);879880if (shouldEmitPersonality) {881AddComment("ParentFrameOffset");882OS.emitInt32(ParentFrameOffset);883}884}885}886}887888// IPToStateMapEntry {889// void *IP;890// int32_t State;891// };892if (IPToStateXData) {893OS.emitLabel(IPToStateXData);894for (auto &IPStatePair : IPToStateTable) {895AddComment("IP");896OS.emitValue(IPStatePair.first, 4);897AddComment("ToState");898OS.emitInt32(IPStatePair.second);899}900}901}902903void WinException::computeIP2StateTable(904const MachineFunction *MF, const WinEHFuncInfo &FuncInfo,905SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) {906907for (MachineFunction::const_iterator FuncletStart = MF->begin(),908FuncletEnd = MF->begin(),909End = MF->end();910FuncletStart != End; FuncletStart = FuncletEnd) {911// Find the end of the funclet912while (++FuncletEnd != End) {913if (FuncletEnd->isEHFuncletEntry()) {914break;915}916}917918// Don't emit ip2state entries for cleanup funclets. Any interesting919// exceptional actions in cleanups must be handled in a separate IR920// function.921if (FuncletStart->isCleanupFuncletEntry())922continue;923924MCSymbol *StartLabel;925int BaseState;926if (FuncletStart == MF->begin()) {927BaseState = NullState;928StartLabel = Asm->getFunctionBegin();929} else {930auto *FuncletPad =931cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI());932assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0);933BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second;934StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart);935}936assert(StartLabel && "need local function start label");937IPToStateTable.push_back(938std::make_pair(create32bitRef(StartLabel), BaseState));939940for (const auto &StateChange : InvokeStateChangeIterator::range(941FuncInfo, FuncletStart, FuncletEnd, BaseState)) {942// Compute the label to report as the start of this entry; use the EH943// start label for the invoke if we have one, otherwise (this is a call944// which may unwind to our caller and does not have an EH start label, so)945// use the previous end label.946const MCSymbol *ChangeLabel = StateChange.NewStartLabel;947if (!ChangeLabel)948ChangeLabel = StateChange.PreviousEndLabel;949// Emit an entry indicating that PCs after 'Label' have this EH state.950// NOTE: On ARM architectures, the StateFromIp automatically takes into951// account that the return address is after the call instruction (whose EH952// state we should be using), but on other platforms we need to +1 to the953// label so that we are using the correct EH state.954const MCExpr *LabelExpression = (isAArch64 || isThumb)955? getLabel(ChangeLabel)956: getLabelPlusOne(ChangeLabel);957IPToStateTable.push_back(958std::make_pair(LabelExpression, StateChange.NewState));959// FIXME: assert that NewState is between CatchLow and CatchHigh.960}961}962}963964void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,965StringRef FLinkageName) {966// Outlined helpers called by the EH runtime need to know the offset of the EH967// registration in order to recover the parent frame pointer. Now that we know968// we've code generated the parent, we can emit the label assignment that969// those helpers use to get the offset of the registration node.970971// Compute the parent frame offset. The EHRegNodeFrameIndex will be invalid if972// after optimization all the invokes were eliminated. We still need to emit973// the parent frame offset label, but it should be garbage and should never be974// used.975int64_t Offset = 0;976int FI = FuncInfo.EHRegNodeFrameIndex;977if (FI != INT_MAX) {978const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();979Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI).getFixed();980}981982MCContext &Ctx = Asm->OutContext;983MCSymbol *ParentFrameOffset =984Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);985Asm->OutStreamer->emitAssignment(ParentFrameOffset,986MCConstantExpr::create(Offset, Ctx));987}988989/// Emit the language-specific data that _except_handler3 and 4 expect. This is990/// functionally equivalent to the __C_specific_handler table, except it is991/// indexed by state number instead of IP.992void WinException::emitExceptHandlerTable(const MachineFunction *MF) {993MCStreamer &OS = *Asm->OutStreamer;994const Function &F = MF->getFunction();995StringRef FLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());996997bool VerboseAsm = OS.isVerboseAsm();998auto AddComment = [&](const Twine &Comment) {999if (VerboseAsm)1000OS.AddComment(Comment);1001};10021003const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();1004emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);10051006// Emit the __ehtable label that we use for llvm.x86.seh.lsda.1007MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);1008OS.emitValueToAlignment(Align(4));1009OS.emitLabel(LSDALabel);10101011const auto *Per = cast<Function>(F.getPersonalityFn()->stripPointerCasts());1012StringRef PerName = Per->getName();1013int BaseState = -1;1014if (PerName == "_except_handler4") {1015// The LSDA for _except_handler4 starts with this struct, followed by the1016// scope table:1017//1018// struct EH4ScopeTable {1019// int32_t GSCookieOffset;1020// int32_t GSCookieXOROffset;1021// int32_t EHCookieOffset;1022// int32_t EHCookieXOROffset;1023// ScopeTableEntry ScopeRecord[];1024// };1025//1026// Offsets are %ebp relative.1027//1028// The GS cookie is present only if the function needs stack protection.1029// GSCookieOffset = -2 means that GS cookie is not used.1030//1031// The EH cookie is always present.1032//1033// Check is done the following way:1034// (ebp+CookieXOROffset) ^ [ebp+CookieOffset] == _security_cookie10351036// Retrieve the Guard Stack slot.1037int GSCookieOffset = -2;1038const MachineFrameInfo &MFI = MF->getFrameInfo();1039if (MFI.hasStackProtectorIndex()) {1040Register UnusedReg;1041const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();1042int SSPIdx = MFI.getStackProtectorIndex();1043GSCookieOffset =1044TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg).getFixed();1045}10461047// Retrieve the EH Guard slot.1048// TODO(etienneb): Get rid of this value and change it for and assertion.1049int EHCookieOffset = 9999;1050if (FuncInfo.EHGuardFrameIndex != INT_MAX) {1051Register UnusedReg;1052const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();1053int EHGuardIdx = FuncInfo.EHGuardFrameIndex;1054EHCookieOffset =1055TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg).getFixed();1056}10571058AddComment("GSCookieOffset");1059OS.emitInt32(GSCookieOffset);1060AddComment("GSCookieXOROffset");1061OS.emitInt32(0);1062AddComment("EHCookieOffset");1063OS.emitInt32(EHCookieOffset);1064AddComment("EHCookieXOROffset");1065OS.emitInt32(0);1066BaseState = -2;1067}10681069assert(!FuncInfo.SEHUnwindMap.empty());1070for (const SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {1071auto *Handler = cast<MachineBasicBlock *>(UME.Handler);1072const MCSymbol *ExceptOrFinally =1073UME.IsFinally ? getMCSymbolForMBB(Asm, Handler) : Handler->getSymbol();1074// -1 is usually the base state for "unwind to caller", but for1075// _except_handler4 it's -2. Do that replacement here if necessary.1076int ToState = UME.ToState == -1 ? BaseState : UME.ToState;1077AddComment("ToState");1078OS.emitInt32(ToState);1079AddComment(UME.IsFinally ? "Null" : "FilterFunction");1080OS.emitValue(create32bitRef(UME.Filter), 4);1081AddComment(UME.IsFinally ? "FinallyFunclet" : "ExceptionHandler");1082OS.emitValue(create32bitRef(ExceptOrFinally), 4);1083}1084}10851086static int getTryRank(const WinEHFuncInfo &FuncInfo, int State) {1087int Rank = 0;1088while (State != -1) {1089++Rank;1090State = FuncInfo.ClrEHUnwindMap[State].TryParentState;1091}1092return Rank;1093}10941095static int getTryAncestor(const WinEHFuncInfo &FuncInfo, int Left, int Right) {1096int LeftRank = getTryRank(FuncInfo, Left);1097int RightRank = getTryRank(FuncInfo, Right);10981099while (LeftRank < RightRank) {1100Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;1101--RightRank;1102}11031104while (RightRank < LeftRank) {1105Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;1106--LeftRank;1107}11081109while (Left != Right) {1110Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;1111Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;1112}11131114return Left;1115}11161117void WinException::emitCLRExceptionTable(const MachineFunction *MF) {1118// CLR EH "states" are really just IDs that identify handlers/funclets;1119// states, handlers, and funclets all have 1:1 mappings between them, and a1120// handler/funclet's "state" is its index in the ClrEHUnwindMap.1121MCStreamer &OS = *Asm->OutStreamer;1122const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();1123MCSymbol *FuncBeginSym = Asm->getFunctionBegin();1124MCSymbol *FuncEndSym = Asm->getFunctionEnd();11251126// A ClrClause describes a protected region.1127struct ClrClause {1128const MCSymbol *StartLabel; // Start of protected region1129const MCSymbol *EndLabel; // End of protected region1130int State; // Index of handler protecting the protected region1131int EnclosingState; // Index of funclet enclosing the protected region1132};1133SmallVector<ClrClause, 8> Clauses;11341135// Build a map from handler MBBs to their corresponding states (i.e. their1136// indices in the ClrEHUnwindMap).1137int NumStates = FuncInfo.ClrEHUnwindMap.size();1138assert(NumStates > 0 && "Don't need exception table!");1139DenseMap<const MachineBasicBlock *, int> HandlerStates;1140for (int State = 0; State < NumStates; ++State) {1141MachineBasicBlock *HandlerBlock =1142cast<MachineBasicBlock *>(FuncInfo.ClrEHUnwindMap[State].Handler);1143HandlerStates[HandlerBlock] = State;1144// Use this loop through all handlers to verify our assumption (used in1145// the MinEnclosingState computation) that enclosing funclets have lower1146// state numbers than their enclosed funclets.1147assert(FuncInfo.ClrEHUnwindMap[State].HandlerParentState < State &&1148"ill-formed state numbering");1149}1150// Map the main function to the NullState.1151HandlerStates[&MF->front()] = NullState;11521153// Write out a sentinel indicating the end of the standard (Windows) xdata1154// and the start of the additional (CLR) info.1155OS.emitInt32(0xffffffff);1156// Write out the number of funclets1157OS.emitInt32(NumStates);11581159// Walk the machine blocks/instrs, computing and emitting a few things:1160// 1. Emit a list of the offsets to each handler entry, in lexical order.1161// 2. Compute a map (EndSymbolMap) from each funclet to the symbol at its end.1162// 3. Compute the list of ClrClauses, in the required order (inner before1163// outer, earlier before later; the order by which a forward scan with1164// early termination will find the innermost enclosing clause covering1165// a given address).1166// 4. A map (MinClauseMap) from each handler index to the index of the1167// outermost funclet/function which contains a try clause targeting the1168// key handler. This will be used to determine IsDuplicate-ness when1169// emitting ClrClauses. The NullState value is used to indicate that the1170// top-level function contains a try clause targeting the key handler.1171// HandlerStack is a stack of (PendingStartLabel, PendingState) pairs for1172// try regions we entered before entering the PendingState try but which1173// we haven't yet exited.1174SmallVector<std::pair<const MCSymbol *, int>, 4> HandlerStack;1175// EndSymbolMap and MinClauseMap are maps described above.1176std::unique_ptr<MCSymbol *[]> EndSymbolMap(new MCSymbol *[NumStates]);1177SmallVector<int, 4> MinClauseMap((size_t)NumStates, NumStates);11781179// Visit the root function and each funclet.1180for (MachineFunction::const_iterator FuncletStart = MF->begin(),1181FuncletEnd = MF->begin(),1182End = MF->end();1183FuncletStart != End; FuncletStart = FuncletEnd) {1184int FuncletState = HandlerStates[&*FuncletStart];1185// Find the end of the funclet1186MCSymbol *EndSymbol = FuncEndSym;1187while (++FuncletEnd != End) {1188if (FuncletEnd->isEHFuncletEntry()) {1189EndSymbol = getMCSymbolForMBB(Asm, &*FuncletEnd);1190break;1191}1192}1193// Emit the function/funclet end and, if this is a funclet (and not the1194// root function), record it in the EndSymbolMap.1195OS.emitValue(getOffset(EndSymbol, FuncBeginSym), 4);1196if (FuncletState != NullState) {1197// Record the end of the handler.1198EndSymbolMap[FuncletState] = EndSymbol;1199}12001201// Walk the state changes in this function/funclet and compute its clauses.1202// Funclets always start in the null state.1203const MCSymbol *CurrentStartLabel = nullptr;1204int CurrentState = NullState;1205assert(HandlerStack.empty());1206for (const auto &StateChange :1207InvokeStateChangeIterator::range(FuncInfo, FuncletStart, FuncletEnd)) {1208// Close any try regions we're not still under1209int StillPendingState =1210getTryAncestor(FuncInfo, CurrentState, StateChange.NewState);1211while (CurrentState != StillPendingState) {1212assert(CurrentState != NullState &&1213"Failed to find still-pending state!");1214// Close the pending clause1215Clauses.push_back({CurrentStartLabel, StateChange.PreviousEndLabel,1216CurrentState, FuncletState});1217// Now the next-outer try region is current1218CurrentState = FuncInfo.ClrEHUnwindMap[CurrentState].TryParentState;1219// Pop the new start label from the handler stack if we've exited all1220// inner try regions of the corresponding try region.1221if (HandlerStack.back().second == CurrentState)1222CurrentStartLabel = HandlerStack.pop_back_val().first;1223}12241225if (StateChange.NewState != CurrentState) {1226// For each clause we're starting, update the MinClauseMap so we can1227// know which is the topmost funclet containing a clause targeting1228// it.1229for (int EnteredState = StateChange.NewState;1230EnteredState != CurrentState;1231EnteredState =1232FuncInfo.ClrEHUnwindMap[EnteredState].TryParentState) {1233int &MinEnclosingState = MinClauseMap[EnteredState];1234if (FuncletState < MinEnclosingState)1235MinEnclosingState = FuncletState;1236}1237// Save the previous current start/label on the stack and update to1238// the newly-current start/state.1239HandlerStack.emplace_back(CurrentStartLabel, CurrentState);1240CurrentStartLabel = StateChange.NewStartLabel;1241CurrentState = StateChange.NewState;1242}1243}1244assert(HandlerStack.empty());1245}12461247// Now emit the clause info, starting with the number of clauses.1248OS.emitInt32(Clauses.size());1249for (ClrClause &Clause : Clauses) {1250// Emit a CORINFO_EH_CLAUSE :1251/*1252struct CORINFO_EH_CLAUSE1253{1254CORINFO_EH_CLAUSE_FLAGS Flags; // actually a CorExceptionFlag1255DWORD TryOffset;1256DWORD TryLength; // actually TryEndOffset1257DWORD HandlerOffset;1258DWORD HandlerLength; // actually HandlerEndOffset1259union1260{1261DWORD ClassToken; // use for catch clauses1262DWORD FilterOffset; // use for filter clauses1263};1264};12651266enum CORINFO_EH_CLAUSE_FLAGS1267{1268CORINFO_EH_CLAUSE_NONE = 0,1269CORINFO_EH_CLAUSE_FILTER = 0x0001, // This clause is for a filter1270CORINFO_EH_CLAUSE_FINALLY = 0x0002, // This clause is a finally clause1271CORINFO_EH_CLAUSE_FAULT = 0x0004, // This clause is a fault clause1272};1273typedef enum CorExceptionFlag1274{1275COR_ILEXCEPTION_CLAUSE_NONE,1276COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001, // This is a filter clause1277COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002, // This is a finally clause1278COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004, // This is a fault clause1279COR_ILEXCEPTION_CLAUSE_DUPLICATED = 0x0008, // duplicated clause. This1280// clause was duplicated1281// to a funclet which was1282// pulled out of line1283} CorExceptionFlag;1284*/1285// Add 1 to the start/end of the EH clause; the IP associated with a1286// call when the runtime does its scan is the IP of the next instruction1287// (the one to which control will return after the call), so we need1288// to add 1 to the end of the clause to cover that offset. We also add1289// 1 to the start of the clause to make sure that the ranges reported1290// for all clauses are disjoint. Note that we'll need some additional1291// logic when machine traps are supported, since in that case the IP1292// that the runtime uses is the offset of the faulting instruction1293// itself; if such an instruction immediately follows a call but the1294// two belong to different clauses, we'll need to insert a nop between1295// them so the runtime can distinguish the point to which the call will1296// return from the point at which the fault occurs.12971298const MCExpr *ClauseBegin =1299getOffsetPlusOne(Clause.StartLabel, FuncBeginSym);1300const MCExpr *ClauseEnd = getOffsetPlusOne(Clause.EndLabel, FuncBeginSym);13011302const ClrEHUnwindMapEntry &Entry = FuncInfo.ClrEHUnwindMap[Clause.State];1303MachineBasicBlock *HandlerBlock = cast<MachineBasicBlock *>(Entry.Handler);1304MCSymbol *BeginSym = getMCSymbolForMBB(Asm, HandlerBlock);1305const MCExpr *HandlerBegin = getOffset(BeginSym, FuncBeginSym);1306MCSymbol *EndSym = EndSymbolMap[Clause.State];1307const MCExpr *HandlerEnd = getOffset(EndSym, FuncBeginSym);13081309uint32_t Flags = 0;1310switch (Entry.HandlerType) {1311case ClrHandlerType::Catch:1312// Leaving bits 0-2 clear indicates catch.1313break;1314case ClrHandlerType::Filter:1315Flags |= 1;1316break;1317case ClrHandlerType::Finally:1318Flags |= 2;1319break;1320case ClrHandlerType::Fault:1321Flags |= 4;1322break;1323}1324if (Clause.EnclosingState != MinClauseMap[Clause.State]) {1325// This is a "duplicate" clause; the handler needs to be entered from a1326// frame above the one holding the invoke.1327assert(Clause.EnclosingState > MinClauseMap[Clause.State]);1328Flags |= 8;1329}1330OS.emitInt32(Flags);13311332// Write the clause start/end1333OS.emitValue(ClauseBegin, 4);1334OS.emitValue(ClauseEnd, 4);13351336// Write out the handler start/end1337OS.emitValue(HandlerBegin, 4);1338OS.emitValue(HandlerEnd, 4);13391340// Write out the type token or filter offset1341assert(Entry.HandlerType != ClrHandlerType::Filter && "NYI: filters");1342OS.emitInt32(Entry.TypeToken);1343}1344}134513461347