1336 lines · cpp
1//===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains support for writing Win64 exception info into asm files.10//11//===----------------------------------------------------------------------===//12 13#include "WinException.h"14#include "llvm/ADT/Twine.h"15#include "llvm/BinaryFormat/COFF.h"16#include "llvm/BinaryFormat/Dwarf.h"17#include "llvm/CodeGen/AsmPrinter.h"18#include "llvm/CodeGen/MachineFrameInfo.h"19#include "llvm/CodeGen/MachineFunction.h"20#include "llvm/CodeGen/MachineModuleInfo.h"21#include "llvm/CodeGen/TargetFrameLowering.h"22#include "llvm/CodeGen/TargetLowering.h"23#include "llvm/CodeGen/TargetSubtargetInfo.h"24#include "llvm/CodeGen/WinEHFuncInfo.h"25#include "llvm/IR/DataLayout.h"26#include "llvm/IR/Module.h"27#include "llvm/MC/MCAsmInfo.h"28#include "llvm/MC/MCContext.h"29#include "llvm/MC/MCExpr.h"30#include "llvm/MC/MCStreamer.h"31#include "llvm/Target/TargetLoweringObjectFile.h"32#include "llvm/Target/TargetMachine.h"33using namespace llvm;34 35WinException::WinException(AsmPrinter *A) : EHStreamer(A) {36 // MSVC's EH tables are always composed of 32-bit words. All known 64-bit37 // platforms use an imagerel32 relocation to refer to symbols.38 useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);39 isAArch64 = Asm->TM.getTargetTriple().isAArch64();40 isThumb = Asm->TM.getTargetTriple().isThumb();41}42 43WinException::~WinException() = default;44 45/// endModule - Emit all exception information that should come after the46/// content.47void WinException::endModule() {48 auto &OS = *Asm->OutStreamer;49 const Module *M = MMI->getModule();50 for (const Function &F : *M)51 if (F.hasFnAttribute("safeseh"))52 OS.emitCOFFSafeSEH(Asm->getSymbol(&F));53 54 if (M->getModuleFlag("ehcontguard") && !EHContTargets.empty()) {55 // Emit the symbol index of each ehcont target.56 OS.switchSection(Asm->OutContext.getObjectFileInfo()->getGEHContSection());57 for (const MCSymbol *S : EHContTargets) {58 OS.emitCOFFSymbolIndex(S);59 }60 }61}62 63void WinException::beginFunction(const MachineFunction *MF) {64 shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;65 66 // If any landing pads survive, we need an EH table.67 bool hasLandingPads = !MF->getLandingPads().empty();68 bool hasEHFunclets = MF->hasEHFunclets();69 70 const Function &F = MF->getFunction();71 72 shouldEmitMoves = Asm->needsSEHMoves() && MF->hasWinCFI();73 74 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();75 unsigned PerEncoding = TLOF.getPersonalityEncoding();76 77 EHPersonality Per = EHPersonality::Unknown;78 const Function *PerFn = nullptr;79 if (F.hasPersonalityFn()) {80 PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());81 Per = classifyEHPersonality(PerFn);82 }83 84 bool forceEmitPersonality = F.hasPersonalityFn() &&85 !isNoOpWithoutInvoke(Per) &&86 F.needsUnwindTableEntry();87 88 shouldEmitPersonality =89 forceEmitPersonality || ((hasLandingPads || hasEHFunclets) &&90 PerEncoding != dwarf::DW_EH_PE_omit && PerFn);91 92 unsigned LSDAEncoding = TLOF.getLSDAEncoding();93 shouldEmitLSDA = shouldEmitPersonality &&94 LSDAEncoding != dwarf::DW_EH_PE_omit;95 96 // If we're not using CFI, we don't want the CFI or the personality, but we97 // might want EH tables if we had EH pads.98 if (!Asm->MAI->usesWindowsCFI()) {99 if (Per == EHPersonality::MSVC_X86SEH && !hasEHFunclets) {100 // If this is 32-bit SEH and we don't have any funclets (really invokes),101 // make sure we emit the parent offset label. Some unreferenced filter102 // functions may still refer to it.103 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();104 StringRef FLinkageName =105 GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());106 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);107 }108 shouldEmitLSDA = hasEHFunclets;109 shouldEmitPersonality = false;110 return;111 }112 113 beginFunclet(MF->front(), Asm->CurrentFnSym);114}115 116void WinException::markFunctionEnd() {117 if (isAArch64 && CurrentFuncletEntry &&118 (shouldEmitMoves || shouldEmitPersonality))119 Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();120}121 122/// endFunction - Gather and emit post-function exception information.123///124void WinException::endFunction(const MachineFunction *MF) {125 if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA)126 return;127 128 const Function &F = MF->getFunction();129 EHPersonality Per = EHPersonality::Unknown;130 if (F.hasPersonalityFn())131 Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());132 133 endFuncletImpl();134 135 // endFunclet will emit the necessary .xdata tables for table-based SEH.136 if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets())137 return;138 139 if (shouldEmitPersonality || shouldEmitLSDA) {140 Asm->OutStreamer->pushSection();141 142 // Just switch sections to the right xdata section.143 MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection(144 Asm->OutStreamer->getCurrentSectionOnly());145 Asm->OutStreamer->switchSection(XData);146 147 // Emit the tables appropriate to the personality function in use. If we148 // don't recognize the personality, assume it uses an Itanium-style LSDA.149 if (Per == EHPersonality::MSVC_TableSEH)150 emitCSpecificHandlerTable(MF);151 else if (Per == EHPersonality::MSVC_X86SEH)152 emitExceptHandlerTable(MF);153 else if (Per == EHPersonality::MSVC_CXX)154 emitCXXFrameHandler3Table(MF);155 else if (Per == EHPersonality::CoreCLR)156 emitCLRExceptionTable(MF);157 else158 emitExceptionTable();159 160 Asm->OutStreamer->popSection();161 }162 163 if (!MF->getEHContTargets().empty()) {164 // Copy the function's EH Continuation targets to a module-level list.165 llvm::append_range(EHContTargets, MF->getEHContTargets());166 }167}168 169/// Retrieve the MCSymbol for a GlobalValue or MachineBasicBlock.170static MCSymbol *getMCSymbolForMBB(AsmPrinter *Asm,171 const MachineBasicBlock *MBB) {172 if (!MBB)173 return nullptr;174 175 assert(MBB->isEHFuncletEntry());176 177 // Give catches and cleanups a name based off of their parent function and178 // their funclet entry block's number.179 const MachineFunction *MF = MBB->getParent();180 const Function &F = MF->getFunction();181 StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());182 MCContext &Ctx = MF->getContext();183 StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch";184 return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" +185 Twine(MBB->getNumber()) + "@?0?" +186 FuncLinkageName + "@4HA");187}188 189void WinException::beginFunclet(const MachineBasicBlock &MBB,190 MCSymbol *Sym) {191 CurrentFuncletEntry = &MBB;192 193 const Function &F = Asm->MF->getFunction();194 // If a symbol was not provided for the funclet, invent one.195 if (!Sym) {196 Sym = getMCSymbolForMBB(Asm, &MBB);197 198 // Describe our funclet symbol as a function with internal linkage.199 Asm->OutStreamer->beginCOFFSymbolDef(Sym);200 Asm->OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);201 Asm->OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION202 << COFF::SCT_COMPLEX_TYPE_SHIFT);203 Asm->OutStreamer->endCOFFSymbolDef();204 205 // We want our funclet's entry point to be aligned such that no nops will be206 // present after the label.207 Asm->emitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()),208 &F);209 210 // Now that we've emitted the alignment directive, point at our funclet.211 Asm->OutStreamer->emitLabel(Sym);212 }213 214 // Mark 'Sym' as starting our funclet.215 if (shouldEmitMoves || shouldEmitPersonality) {216 CurrentFuncletTextSection = Asm->OutStreamer->getCurrentSectionOnly();217 Asm->OutStreamer->emitWinCFIStartProc(Sym);218 }219 220 if (shouldEmitPersonality) {221 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();222 const Function *PerFn = nullptr;223 224 // Determine which personality routine we are using for this funclet.225 if (F.hasPersonalityFn())226 PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());227 const MCSymbol *PersHandlerSym =228 TLOF.getCFIPersonalitySymbol(PerFn, Asm->TM, MMI);229 230 // 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.235 if (!CurrentFuncletEntry->isCleanupFuncletEntry())236 Asm->OutStreamer->emitWinEHHandler(PersHandlerSym, true, true);237 }238}239 240void WinException::endFunclet() {241 if (isAArch64 && CurrentFuncletEntry &&242 (shouldEmitMoves || shouldEmitPersonality)) {243 Asm->OutStreamer->switchSection(CurrentFuncletTextSection);244 Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();245 }246 endFuncletImpl();247}248 249void WinException::endFuncletImpl() {250 // No funclet to process? Great, we have nothing to do.251 if (!CurrentFuncletEntry)252 return;253 254 const MachineFunction *MF = Asm->MF;255 if (shouldEmitMoves || shouldEmitPersonality) {256 const Function &F = MF->getFunction();257 EHPersonality Per = EHPersonality::Unknown;258 if (F.hasPersonalityFn())259 Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());260 261 if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality &&262 !CurrentFuncletEntry->isCleanupFuncletEntry()) {263 // Emit an UNWIND_INFO struct describing the prologue.264 Asm->OutStreamer->emitWinEHHandlerData();265 266 // If this is a C++ catch funclet (or the parent function),267 // emit a reference to the LSDA for the parent function.268 StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());269 MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(270 Twine("$cppxdata$", FuncLinkageName));271 Asm->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.275 Asm->OutStreamer->emitWinEHHandlerData();276 277 // If this is the parent function in Win64 SEH, emit the LSDA immediately278 // following .seh_handlerdata.279 emitCSpecificHandlerTable(MF);280 } else if (shouldEmitPersonality || shouldEmitLSDA) {281 // Emit an UNWIND_INFO struct describing the prologue.282 Asm->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 }291 292 if (!MF->getEHContTargets().empty()) {293 // Copy the function's EH Continuation targets to a module-level list.294 llvm::append_range(EHContTargets, MF->getEHContTargets());295 }296 297 // Switch back to the funclet start .text section now that we are done298 // writing to .xdata, and emit an .seh_endproc directive to mark the end of299 // the function.300 Asm->OutStreamer->switchSection(CurrentFuncletTextSection);301 Asm->OutStreamer->emitWinCFIEndProc();302 }303 304 // Let's make sure we don't try to end the same funclet twice.305 CurrentFuncletEntry = nullptr;306}307 308const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {309 if (!Value)310 return MCConstantExpr::create(0, Asm->OutContext);311 auto Spec = useImageRel32 ? uint16_t(MCSymbolRefExpr::VK_COFF_IMGREL32) : 0;312 return MCSymbolRefExpr::create(Value, Spec, Asm->OutContext);313}314 315const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {316 if (!GV)317 return MCConstantExpr::create(0, Asm->OutContext);318 return create32bitRef(Asm->getSymbol(GV));319}320 321const MCExpr *WinException::getLabel(const MCSymbol *Label) {322 return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32,323 Asm->OutContext);324}325 326const MCExpr *WinException::getOffset(const MCSymbol *OffsetOf,327 const MCSymbol *OffsetFrom) {328 return MCBinaryExpr::createSub(329 MCSymbolRefExpr::create(OffsetOf, Asm->OutContext),330 MCSymbolRefExpr::create(OffsetFrom, Asm->OutContext), Asm->OutContext);331}332 333const MCExpr *WinException::getOffsetPlusOne(const MCSymbol *OffsetOf,334 const MCSymbol *OffsetFrom) {335 return MCBinaryExpr::createAdd(getOffset(OffsetOf, OffsetFrom),336 MCConstantExpr::create(1, Asm->OutContext),337 Asm->OutContext);338}339 340int WinException::getFrameIndexOffset(int FrameIndex,341 const WinEHFuncInfo &FuncInfo) {342 const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering();343 Register UnusedReg;344 if (Asm->MAI->usesWindowsCFI()) {345 StackOffset Offset =346 TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg,347 /*IgnoreSPUpdates*/ true);348 assert(UnusedReg ==349 Asm->MF->getSubtarget()350 .getTargetLowering()351 ->getStackPointerRegisterToSaveRestore());352 return Offset.getFixed();353 }354 355 // For 32-bit, offsets should be relative to the end of the EH registration356 // node. For 64-bit, it's relative to SP at the end of the prologue.357 assert(FuncInfo.EHRegNodeEndOffset != INT_MAX);358 StackOffset Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg);359 Offset += StackOffset::getFixed(FuncInfo.EHRegNodeEndOffset);360 assert(!Offset.getScalable() &&361 "Frame offsets with a scalable component are not supported");362 return Offset.getFixed();363}364 365namespace {366 367/// Top-level state used to represent unwind to caller368const int NullState = -1;369 370struct InvokeStateChange {371 /// EH Label immediately after the last invoke in the previous state, or372 /// nullptr if the previous state was the null state.373 const MCSymbol *PreviousEndLabel;374 375 /// EH label immediately before the first invoke in the new state, or nullptr376 /// if the new state is the null state.377 const MCSymbol *NewStartLabel;378 379 /// State of the invoke following NewStartLabel, or NullState to indicate380 /// the presence of calls which may unwind to caller.381 int NewState;382};383 384/// Iterator that reports all the invoke state changes in a range of machine385/// basic blocks. Changes to the null state are reported whenever a call that386/// may unwind to caller is encountered. The MBB range is expected to be an387/// entire function or funclet, and the start and end of the range are treated388/// as being in the NullState even if there's not an unwind-to-caller call389/// before the first invoke or after the last one (i.e., the first state change390/// reported is the first change to something other than NullState, and a391/// change back to NullState is always reported at the end of iteration).392class InvokeStateChangeIterator {393 InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo,394 MachineFunction::const_iterator MFI,395 MachineFunction::const_iterator MFE,396 MachineBasicBlock::const_iterator MBBI,397 int BaseState)398 : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) {399 LastStateChange.PreviousEndLabel = nullptr;400 LastStateChange.NewStartLabel = nullptr;401 LastStateChange.NewState = BaseState;402 scan();403 }404 405public:406 static iterator_range<InvokeStateChangeIterator>407 range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin,408 MachineFunction::const_iterator End, int BaseState = NullState) {409 // Reject empty ranges to simplify bookkeeping by ensuring that we can get410 // the end of the last block.411 assert(Begin != End);412 auto BlockBegin = Begin->begin();413 auto BlockEnd = std::prev(End)->end();414 return make_range(415 InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState),416 InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState));417 }418 419 // Iterator methods.420 bool operator==(const InvokeStateChangeIterator &O) const {421 assert(BaseState == O.BaseState);422 // Must be visiting same block.423 if (MFI != O.MFI)424 return false;425 // Must be visiting same isntr.426 if (MBBI != O.MBBI)427 return false;428 // At end of block/instr iteration, we can still have two distinct states:429 // one to report the final EndLabel, and another indicating the end of the430 // state change iteration. Check for CurrentEndLabel equality to431 // distinguish these.432 return CurrentEndLabel == O.CurrentEndLabel;433 }434 435 bool operator!=(const InvokeStateChangeIterator &O) const {436 return !operator==(O);437 }438 InvokeStateChange &operator*() { return LastStateChange; }439 InvokeStateChange *operator->() { return &LastStateChange; }440 InvokeStateChangeIterator &operator++() { return scan(); }441 442private:443 InvokeStateChangeIterator &scan();444 445 const WinEHFuncInfo &EHInfo;446 const MCSymbol *CurrentEndLabel = nullptr;447 MachineFunction::const_iterator MFI;448 MachineFunction::const_iterator MFE;449 MachineBasicBlock::const_iterator MBBI;450 InvokeStateChange LastStateChange;451 bool VisitingInvoke = false;452 int BaseState;453};454 455} // end anonymous namespace456 457InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {458 bool IsNewBlock = false;459 for (; MFI != MFE; ++MFI, IsNewBlock = true) {460 if (IsNewBlock)461 MBBI = MFI->begin();462 for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) {463 const MachineInstr &MI = *MBBI;464 if (!VisitingInvoke && LastStateChange.NewState != BaseState &&465 MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) {466 // Indicate a change of state to the null state. We don't have467 // start/end EH labels handy but the caller won't expect them for468 // null state regions.469 LastStateChange.PreviousEndLabel = CurrentEndLabel;470 LastStateChange.NewStartLabel = nullptr;471 LastStateChange.NewState = BaseState;472 CurrentEndLabel = nullptr;473 // Don't re-visit this instr on the next scan474 ++MBBI;475 return *this;476 }477 478 // All other state changes are at EH labels before/after invokes.479 if (!MI.isEHLabel())480 continue;481 MCSymbol *Label = MI.getOperand(0).getMCSymbol();482 if (Label == CurrentEndLabel) {483 VisitingInvoke = false;484 continue;485 }486 auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label);487 // Ignore EH labels that aren't the ones inserted before an invoke488 if (InvokeMapIter == EHInfo.LabelToStateMap.end())489 continue;490 auto &StateAndEnd = InvokeMapIter->second;491 int NewState = StateAndEnd.first;492 // Keep track of the fact that we're between EH start/end labels so493 // we know not to treat the inoke we'll see as unwinding to caller.494 VisitingInvoke = true;495 if (NewState == LastStateChange.NewState) {496 // The state isn't actually changing here. Record the new end and497 // keep going.498 CurrentEndLabel = StateAndEnd.second;499 continue;500 }501 // Found a state change to report502 LastStateChange.PreviousEndLabel = CurrentEndLabel;503 LastStateChange.NewStartLabel = Label;504 LastStateChange.NewState = NewState;505 // Start keeping track of the new current end506 CurrentEndLabel = StateAndEnd.second;507 // Don't re-visit this instr on the next scan508 ++MBBI;509 return *this;510 }511 }512 // Iteration hit the end of the block range.513 if (LastStateChange.NewState != BaseState) {514 // Report the end of the last new state515 LastStateChange.PreviousEndLabel = CurrentEndLabel;516 LastStateChange.NewStartLabel = nullptr;517 LastStateChange.NewState = BaseState;518 // Leave CurrentEndLabel non-null to distinguish this state from end.519 assert(CurrentEndLabel != nullptr);520 return *this;521 }522 // We've reported all state changes and hit the end state.523 CurrentEndLabel = nullptr;524 return *this;525}526 527/// Emit the language-specific data that __C_specific_handler expects. This528/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning529/// up after faults with __try, __except, and __finally. The typeinfo values530/// are not really RTTI data, but pointers to filter functions that return an531/// integer (1, 0, or -1) indicating how to handle the exception. For __finally532/// blocks and other cleanups, the landing pad label is zero, and the filter533/// function is actually a cleanup handler with the same prototype. A catch-all534/// entry is modeled with a null filter function field and a non-zero landing535/// pad label.536///537/// Possible filter function return values:538/// EXCEPTION_EXECUTE_HANDLER (1):539/// Jump to the landing pad label after cleanups.540/// EXCEPTION_CONTINUE_SEARCH (0):541/// Continue searching this table or continue unwinding.542/// EXCEPTION_CONTINUE_EXECUTION (-1):543/// Resume execution at the trapping PC.544///545/// Inferred table structure:546/// struct Table {547/// int NumEntries;548/// struct Entry {549/// imagerel32 LabelStart; // Inclusive550/// imagerel32 LabelEnd; // Exclusive551/// imagerel32 FilterOrFinally; // One means catch-all.552/// imagerel32 LabelLPad; // Zero means __finally.553/// } Entries[NumEntries];554/// };555void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {556 auto &OS = *Asm->OutStreamer;557 MCContext &Ctx = Asm->OutContext;558 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();559 560 bool VerboseAsm = OS.isVerboseAsm();561 auto AddComment = [&](const Twine &Comment) {562 if (VerboseAsm)563 OS.AddComment(Comment);564 };565 566 if (!isAArch64) {567 // Emit a label assignment with the SEH frame offset so we can use it for568 // llvm.eh.recoverfp.569 StringRef FLinkageName =570 GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());571 MCSymbol *ParentFrameOffset =572 Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);573 const MCExpr *MCOffset =574 MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx);575 Asm->OutStreamer->emitAssignment(ParentFrameOffset, MCOffset);576 }577 578 // Use the assembler to compute the number of table entries through label579 // difference and division.580 MCSymbol *TableBegin =581 Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true);582 MCSymbol *TableEnd =583 Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true);584 const MCExpr *LabelDiff = getOffset(TableEnd, TableBegin);585 const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx);586 const MCExpr *EntryCount = MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx);587 AddComment("Number of call sites");588 OS.emitValue(EntryCount, 4);589 590 OS.emitLabel(TableBegin);591 592 // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only593 // models exceptions from invokes. LLVM also allows arbitrary reordering of594 // the code, so our tables end up looking a bit different. Rather than595 // trying to match MSVC's tables exactly, we emit a denormalized table. For596 // each range of invokes in the same state, we emit table entries for all597 // the actions that would be taken in that state. This means our tables are598 // slightly bigger, which is OK.599 const MCSymbol *LastStartLabel = nullptr;600 int LastEHState = -1;601 // Break out before we enter into a finally funclet.602 // FIXME: We need to emit separate EH tables for cleanups.603 MachineFunction::const_iterator End = MF->end();604 MachineFunction::const_iterator Stop = std::next(MF->begin());605 while (Stop != End && !Stop->isEHFuncletEntry())606 ++Stop;607 for (const auto &StateChange :608 InvokeStateChangeIterator::range(FuncInfo, MF->begin(), Stop)) {609 // Emit all the actions for the state we just transitioned out of610 // if it was not the null state611 if (LastEHState != -1)612 emitSEHActionsForRange(FuncInfo, LastStartLabel,613 StateChange.PreviousEndLabel, LastEHState);614 LastStartLabel = StateChange.NewStartLabel;615 LastEHState = StateChange.NewState;616 }617 618 OS.emitLabel(TableEnd);619}620 621void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo,622 const MCSymbol *BeginLabel,623 const MCSymbol *EndLabel, int State) {624 auto &OS = *Asm->OutStreamer;625 MCContext &Ctx = Asm->OutContext;626 bool VerboseAsm = OS.isVerboseAsm();627 auto AddComment = [&](const Twine &Comment) {628 if (VerboseAsm)629 OS.AddComment(Comment);630 };631 632 assert(BeginLabel && EndLabel);633 while (State != -1) {634 const SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];635 const MCExpr *FilterOrFinally;636 const MCExpr *ExceptOrNull;637 auto *Handler = cast<MachineBasicBlock *>(UME.Handler);638 if (UME.IsFinally) {639 FilterOrFinally = create32bitRef(getMCSymbolForMBB(Asm, Handler));640 ExceptOrNull = MCConstantExpr::create(0, Ctx);641 } else {642 // For an except, the filter can be 1 (catch-all) or a function643 // label.644 FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)645 : MCConstantExpr::create(1, Ctx);646 ExceptOrNull = create32bitRef(Handler->getSymbol());647 }648 649 AddComment("LabelStart");650 OS.emitValue(getLabel(BeginLabel), 4);651 AddComment("LabelEnd");652 OS.emitValue(getLabel(EndLabel), 4);653 AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction"654 : "CatchAll");655 OS.emitValue(FilterOrFinally, 4);656 AddComment(UME.IsFinally ? "Null" : "ExceptionHandler");657 OS.emitValue(ExceptOrNull, 4);658 659 assert(UME.ToState < State && "states should decrease");660 State = UME.ToState;661 }662}663 664void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {665 const Function &F = MF->getFunction();666 auto &OS = *Asm->OutStreamer;667 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();668 669 StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());670 671 SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable;672 MCSymbol *FuncInfoXData = nullptr;673 if (shouldEmitPersonality) {674 // If we're 64-bit, emit a pointer to the C++ EH data, and build a map from675 // IPs to state numbers.676 FuncInfoXData =677 Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName));678 computeIP2StateTable(MF, FuncInfo, IPToStateTable);679 } else {680 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName);681 }682 683 int UnwindHelpOffset = 0;684 // TODO: The check for UnwindHelpFrameIdx against max() below (and the685 // second check further below) can be removed if MS C++ unwinding is686 // implemented for ARM, when test/CodeGen/ARM/Windows/wineh-basic.ll687 // passes without the check.688 if (Asm->MAI->usesWindowsCFI() &&689 FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max())690 UnwindHelpOffset =691 getFrameIndexOffset(FuncInfo.UnwindHelpFrameIdx, FuncInfo);692 693 MCSymbol *UnwindMapXData = nullptr;694 MCSymbol *TryBlockMapXData = nullptr;695 MCSymbol *IPToStateXData = nullptr;696 if (!FuncInfo.CxxUnwindMap.empty())697 UnwindMapXData = Asm->OutContext.getOrCreateSymbol(698 Twine("$stateUnwindMap$", FuncLinkageName));699 if (!FuncInfo.TryBlockMap.empty())700 TryBlockMapXData =701 Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName));702 if (!IPToStateTable.empty())703 IPToStateXData =704 Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName));705 706 bool VerboseAsm = OS.isVerboseAsm();707 auto AddComment = [&](const Twine &Comment) {708 if (VerboseAsm)709 OS.AddComment(Comment);710 };711 712 // FuncInfo {713 // uint32_t MagicNumber714 // int32_t MaxState;715 // UnwindMapEntry *UnwindMap;716 // uint32_t NumTryBlocks;717 // TryBlockMapEntry *TryBlockMap;718 // uint32_t IPMapEntries; // always 0 for x86719 // IPToStateMapEntry *IPToStateMap; // always 0 for x86720 // uint32_t UnwindHelp; // non-x86 only721 // ESTypeList *ESTypeList;722 // int32_t EHFlags;723 // }724 // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.725 // EHFlags & 2 -> ???726 // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.727 OS.emitValueToAlignment(Align(4));728 OS.emitLabel(FuncInfoXData);729 730 AddComment("MagicNumber");731 OS.emitInt32(0x19930522);732 733 AddComment("MaxState");734 OS.emitInt32(FuncInfo.CxxUnwindMap.size());735 736 AddComment("UnwindMap");737 OS.emitValue(create32bitRef(UnwindMapXData), 4);738 739 AddComment("NumTryBlocks");740 OS.emitInt32(FuncInfo.TryBlockMap.size());741 742 AddComment("TryBlockMap");743 OS.emitValue(create32bitRef(TryBlockMapXData), 4);744 745 AddComment("IPMapEntries");746 OS.emitInt32(IPToStateTable.size());747 748 AddComment("IPToStateXData");749 OS.emitValue(create32bitRef(IPToStateXData), 4);750 751 if (Asm->MAI->usesWindowsCFI() &&752 FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max()) {753 AddComment("UnwindHelp");754 OS.emitInt32(UnwindHelpOffset);755 }756 757 AddComment("ESTypeList");758 OS.emitInt32(0);759 760 AddComment("EHFlags");761 if (MMI->getModule()->getModuleFlag("eh-asynch")) {762 OS.emitInt32(0);763 } else {764 OS.emitInt32(1);765 }766 767 // UnwindMapEntry {768 // int32_t ToState;769 // void (*Action)();770 // };771 if (UnwindMapXData) {772 OS.emitLabel(UnwindMapXData);773 for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) {774 MCSymbol *CleanupSym = getMCSymbolForMBB(775 Asm, dyn_cast_if_present<MachineBasicBlock *>(UME.Cleanup));776 AddComment("ToState");777 OS.emitInt32(UME.ToState);778 779 AddComment("Action");780 OS.emitValue(create32bitRef(CleanupSym), 4);781 }782 }783 784 // TryBlockMap {785 // int32_t TryLow;786 // int32_t TryHigh;787 // int32_t CatchHigh;788 // int32_t NumCatches;789 // HandlerType *HandlerArray;790 // };791 if (TryBlockMapXData) {792 OS.emitLabel(TryBlockMapXData);793 SmallVector<MCSymbol *, 1> HandlerMaps;794 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {795 const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];796 797 MCSymbol *HandlerMapXData = nullptr;798 if (!TBME.HandlerArray.empty())799 HandlerMapXData =800 Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")801 .concat(Twine(I))802 .concat("$")803 .concat(FuncLinkageName));804 HandlerMaps.push_back(HandlerMapXData);805 806 // TBMEs should form intervals.807 assert(0 <= TBME.TryLow && "bad trymap interval");808 assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval");809 assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval");810 assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) &&811 "bad trymap interval");812 813 AddComment("TryLow");814 OS.emitInt32(TBME.TryLow);815 816 AddComment("TryHigh");817 OS.emitInt32(TBME.TryHigh);818 819 AddComment("CatchHigh");820 OS.emitInt32(TBME.CatchHigh);821 822 AddComment("NumCatches");823 OS.emitInt32(TBME.HandlerArray.size());824 825 AddComment("HandlerArray");826 OS.emitValue(create32bitRef(HandlerMapXData), 4);827 }828 829 // All funclets use the same parent frame offset currently.830 unsigned ParentFrameOffset = 0;831 if (shouldEmitPersonality) {832 const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();833 ParentFrameOffset = TFI->getWinEHParentFrameOffset(*MF);834 }835 836 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {837 const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];838 MCSymbol *HandlerMapXData = HandlerMaps[I];839 if (!HandlerMapXData)840 continue;841 // HandlerType {842 // int32_t Adjectives;843 // TypeDescriptor *Type;844 // int32_t CatchObjOffset;845 // void (*Handler)();846 // int32_t ParentFrameOffset; // x64 and AArch64 only847 // };848 OS.emitLabel(HandlerMapXData);849 for (const WinEHHandlerType &HT : TBME.HandlerArray) {850 // Get the frame escape label with the offset of the catch object. If851 // the index is INT_MAX, then there is no catch object, and we should852 // emit an offset of zero, indicating that no copy will occur.853 const MCExpr *FrameAllocOffsetRef = nullptr;854 if (HT.CatchObj.FrameIndex != INT_MAX) {855 int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex, FuncInfo);856 assert(Offset != 0 && "Illegal offset for catch object!");857 FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext);858 } else {859 FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);860 }861 862 MCSymbol *HandlerSym = getMCSymbolForMBB(863 Asm, dyn_cast_if_present<MachineBasicBlock *>(HT.Handler));864 865 AddComment("Adjectives");866 OS.emitInt32(HT.Adjectives);867 868 AddComment("Type");869 OS.emitValue(create32bitRef(HT.TypeDescriptor), 4);870 871 AddComment("CatchObjOffset");872 OS.emitValue(FrameAllocOffsetRef, 4);873 874 AddComment("Handler");875 OS.emitValue(create32bitRef(HandlerSym), 4);876 877 if (shouldEmitPersonality) {878 AddComment("ParentFrameOffset");879 OS.emitInt32(ParentFrameOffset);880 }881 }882 }883 }884 885 // IPToStateMapEntry {886 // void *IP;887 // int32_t State;888 // };889 if (IPToStateXData) {890 OS.emitLabel(IPToStateXData);891 for (auto &IPStatePair : IPToStateTable) {892 AddComment("IP");893 OS.emitValue(IPStatePair.first, 4);894 AddComment("ToState");895 OS.emitInt32(IPStatePair.second);896 }897 }898}899 900void WinException::computeIP2StateTable(901 const MachineFunction *MF, const WinEHFuncInfo &FuncInfo,902 SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) {903 904 for (MachineFunction::const_iterator FuncletStart = MF->begin(),905 FuncletEnd = MF->begin(),906 End = MF->end();907 FuncletStart != End; FuncletStart = FuncletEnd) {908 // Find the end of the funclet909 while (++FuncletEnd != End) {910 if (FuncletEnd->isEHFuncletEntry()) {911 break;912 }913 }914 915 // Don't emit ip2state entries for cleanup funclets. Any interesting916 // exceptional actions in cleanups must be handled in a separate IR917 // function.918 if (FuncletStart->isCleanupFuncletEntry())919 continue;920 921 MCSymbol *StartLabel;922 int BaseState;923 if (FuncletStart == MF->begin()) {924 BaseState = NullState;925 StartLabel = Asm->getFunctionBegin();926 } else {927 auto *FuncletPad = cast<FuncletPadInst>(928 FuncletStart->getBasicBlock()->getFirstNonPHIIt());929 assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0);930 BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second;931 StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart);932 }933 assert(StartLabel && "need local function start label");934 IPToStateTable.push_back(935 std::make_pair(create32bitRef(StartLabel), BaseState));936 937 for (const auto &StateChange : InvokeStateChangeIterator::range(938 FuncInfo, FuncletStart, FuncletEnd, BaseState)) {939 // Compute the label to report as the start of this entry; use the EH940 // start label for the invoke if we have one, otherwise (this is a call941 // which may unwind to our caller and does not have an EH start label, so)942 // use the previous end label.943 const MCSymbol *ChangeLabel = StateChange.NewStartLabel;944 if (!ChangeLabel)945 ChangeLabel = StateChange.PreviousEndLabel;946 // Emit an entry indicating that PCs after 'Label' have this EH state.947 const MCExpr *LabelExpression = getLabel(ChangeLabel);948 IPToStateTable.push_back(949 std::make_pair(LabelExpression, StateChange.NewState));950 // FIXME: assert that NewState is between CatchLow and CatchHigh.951 }952 }953}954 955void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,956 StringRef FLinkageName) {957 // Outlined helpers called by the EH runtime need to know the offset of the EH958 // registration in order to recover the parent frame pointer. Now that we know959 // we've code generated the parent, we can emit the label assignment that960 // those helpers use to get the offset of the registration node.961 962 // Compute the parent frame offset. The EHRegNodeFrameIndex will be invalid if963 // after optimization all the invokes were eliminated. We still need to emit964 // the parent frame offset label, but it should be garbage and should never be965 // used.966 int64_t Offset = 0;967 int FI = FuncInfo.EHRegNodeFrameIndex;968 if (FI != INT_MAX) {969 const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();970 Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI).getFixed();971 }972 973 MCContext &Ctx = Asm->OutContext;974 MCSymbol *ParentFrameOffset =975 Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);976 Asm->OutStreamer->emitAssignment(ParentFrameOffset,977 MCConstantExpr::create(Offset, Ctx));978}979 980/// Emit the language-specific data that _except_handler3 and 4 expect. This is981/// functionally equivalent to the __C_specific_handler table, except it is982/// indexed by state number instead of IP.983void WinException::emitExceptHandlerTable(const MachineFunction *MF) {984 MCStreamer &OS = *Asm->OutStreamer;985 const Function &F = MF->getFunction();986 StringRef FLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());987 988 bool VerboseAsm = OS.isVerboseAsm();989 auto AddComment = [&](const Twine &Comment) {990 if (VerboseAsm)991 OS.AddComment(Comment);992 };993 994 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();995 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);996 997 // Emit the __ehtable label that we use for llvm.x86.seh.lsda.998 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);999 OS.emitValueToAlignment(Align(4));1000 OS.emitLabel(LSDALabel);1001 1002 const auto *Per = cast<Function>(F.getPersonalityFn()->stripPointerCasts());1003 StringRef PerName = Per->getName();1004 int BaseState = -1;1005 if (PerName == "_except_handler4") {1006 // The LSDA for _except_handler4 starts with this struct, followed by the1007 // scope table:1008 //1009 // struct EH4ScopeTable {1010 // int32_t GSCookieOffset;1011 // int32_t GSCookieXOROffset;1012 // int32_t EHCookieOffset;1013 // int32_t EHCookieXOROffset;1014 // ScopeTableEntry ScopeRecord[];1015 // };1016 //1017 // Offsets are %ebp relative.1018 //1019 // The GS cookie is present only if the function needs stack protection.1020 // GSCookieOffset = -2 means that GS cookie is not used.1021 //1022 // The EH cookie is always present.1023 //1024 // Check is done the following way:1025 // (ebp+CookieXOROffset) ^ [ebp+CookieOffset] == _security_cookie1026 1027 // Retrieve the Guard Stack slot.1028 int GSCookieOffset = -2;1029 const MachineFrameInfo &MFI = MF->getFrameInfo();1030 if (MFI.hasStackProtectorIndex()) {1031 Register UnusedReg;1032 const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();1033 int SSPIdx = MFI.getStackProtectorIndex();1034 GSCookieOffset =1035 TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg).getFixed();1036 }1037 1038 // Retrieve the EH Guard slot.1039 // TODO(etienneb): Get rid of this value and change it for and assertion.1040 int EHCookieOffset = 9999;1041 if (FuncInfo.EHGuardFrameIndex != INT_MAX) {1042 Register UnusedReg;1043 const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();1044 int EHGuardIdx = FuncInfo.EHGuardFrameIndex;1045 EHCookieOffset =1046 TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg).getFixed();1047 }1048 1049 AddComment("GSCookieOffset");1050 OS.emitInt32(GSCookieOffset);1051 AddComment("GSCookieXOROffset");1052 OS.emitInt32(0);1053 AddComment("EHCookieOffset");1054 OS.emitInt32(EHCookieOffset);1055 AddComment("EHCookieXOROffset");1056 OS.emitInt32(0);1057 BaseState = -2;1058 }1059 1060 assert(!FuncInfo.SEHUnwindMap.empty());1061 for (const SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {1062 auto *Handler = cast<MachineBasicBlock *>(UME.Handler);1063 const MCSymbol *ExceptOrFinally =1064 UME.IsFinally ? getMCSymbolForMBB(Asm, Handler) : Handler->getSymbol();1065 // -1 is usually the base state for "unwind to caller", but for1066 // _except_handler4 it's -2. Do that replacement here if necessary.1067 int ToState = UME.ToState == -1 ? BaseState : UME.ToState;1068 AddComment("ToState");1069 OS.emitInt32(ToState);1070 AddComment(UME.IsFinally ? "Null" : "FilterFunction");1071 OS.emitValue(create32bitRef(UME.Filter), 4);1072 AddComment(UME.IsFinally ? "FinallyFunclet" : "ExceptionHandler");1073 OS.emitValue(create32bitRef(ExceptOrFinally), 4);1074 }1075}1076 1077static int getTryRank(const WinEHFuncInfo &FuncInfo, int State) {1078 int Rank = 0;1079 while (State != -1) {1080 ++Rank;1081 State = FuncInfo.ClrEHUnwindMap[State].TryParentState;1082 }1083 return Rank;1084}1085 1086static int getTryAncestor(const WinEHFuncInfo &FuncInfo, int Left, int Right) {1087 int LeftRank = getTryRank(FuncInfo, Left);1088 int RightRank = getTryRank(FuncInfo, Right);1089 1090 while (LeftRank < RightRank) {1091 Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;1092 --RightRank;1093 }1094 1095 while (RightRank < LeftRank) {1096 Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;1097 --LeftRank;1098 }1099 1100 while (Left != Right) {1101 Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;1102 Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;1103 }1104 1105 return Left;1106}1107 1108void WinException::emitCLRExceptionTable(const MachineFunction *MF) {1109 // CLR EH "states" are really just IDs that identify handlers/funclets;1110 // states, handlers, and funclets all have 1:1 mappings between them, and a1111 // handler/funclet's "state" is its index in the ClrEHUnwindMap.1112 MCStreamer &OS = *Asm->OutStreamer;1113 const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();1114 MCSymbol *FuncBeginSym = Asm->getFunctionBegin();1115 MCSymbol *FuncEndSym = Asm->getFunctionEnd();1116 1117 // A ClrClause describes a protected region.1118 struct ClrClause {1119 const MCSymbol *StartLabel; // Start of protected region1120 const MCSymbol *EndLabel; // End of protected region1121 int State; // Index of handler protecting the protected region1122 int EnclosingState; // Index of funclet enclosing the protected region1123 };1124 SmallVector<ClrClause, 8> Clauses;1125 1126 // Build a map from handler MBBs to their corresponding states (i.e. their1127 // indices in the ClrEHUnwindMap).1128 int NumStates = FuncInfo.ClrEHUnwindMap.size();1129 assert(NumStates > 0 && "Don't need exception table!");1130 DenseMap<const MachineBasicBlock *, int> HandlerStates;1131 for (int State = 0; State < NumStates; ++State) {1132 MachineBasicBlock *HandlerBlock =1133 cast<MachineBasicBlock *>(FuncInfo.ClrEHUnwindMap[State].Handler);1134 HandlerStates[HandlerBlock] = State;1135 // Use this loop through all handlers to verify our assumption (used in1136 // the MinEnclosingState computation) that enclosing funclets have lower1137 // state numbers than their enclosed funclets.1138 assert(FuncInfo.ClrEHUnwindMap[State].HandlerParentState < State &&1139 "ill-formed state numbering");1140 }1141 // Map the main function to the NullState.1142 HandlerStates[&MF->front()] = NullState;1143 1144 // Write out a sentinel indicating the end of the standard (Windows) xdata1145 // and the start of the additional (CLR) info.1146 OS.emitInt32(0xffffffff);1147 // Write out the number of funclets1148 OS.emitInt32(NumStates);1149 1150 // Walk the machine blocks/instrs, computing and emitting a few things:1151 // 1. Emit a list of the offsets to each handler entry, in lexical order.1152 // 2. Compute a map (EndSymbolMap) from each funclet to the symbol at its end.1153 // 3. Compute the list of ClrClauses, in the required order (inner before1154 // outer, earlier before later; the order by which a forward scan with1155 // early termination will find the innermost enclosing clause covering1156 // a given address).1157 // 4. A map (MinClauseMap) from each handler index to the index of the1158 // outermost funclet/function which contains a try clause targeting the1159 // key handler. This will be used to determine IsDuplicate-ness when1160 // emitting ClrClauses. The NullState value is used to indicate that the1161 // top-level function contains a try clause targeting the key handler.1162 // HandlerStack is a stack of (PendingStartLabel, PendingState) pairs for1163 // try regions we entered before entering the PendingState try but which1164 // we haven't yet exited.1165 SmallVector<std::pair<const MCSymbol *, int>, 4> HandlerStack;1166 // EndSymbolMap and MinClauseMap are maps described above.1167 std::unique_ptr<MCSymbol *[]> EndSymbolMap(new MCSymbol *[NumStates]);1168 SmallVector<int, 4> MinClauseMap((size_t)NumStates, NumStates);1169 1170 // Visit the root function and each funclet.1171 for (MachineFunction::const_iterator FuncletStart = MF->begin(),1172 FuncletEnd = MF->begin(),1173 End = MF->end();1174 FuncletStart != End; FuncletStart = FuncletEnd) {1175 int FuncletState = HandlerStates[&*FuncletStart];1176 // Find the end of the funclet1177 MCSymbol *EndSymbol = FuncEndSym;1178 while (++FuncletEnd != End) {1179 if (FuncletEnd->isEHFuncletEntry()) {1180 EndSymbol = getMCSymbolForMBB(Asm, &*FuncletEnd);1181 break;1182 }1183 }1184 // Emit the function/funclet end and, if this is a funclet (and not the1185 // root function), record it in the EndSymbolMap.1186 OS.emitValue(getOffset(EndSymbol, FuncBeginSym), 4);1187 if (FuncletState != NullState) {1188 // Record the end of the handler.1189 EndSymbolMap[FuncletState] = EndSymbol;1190 }1191 1192 // Walk the state changes in this function/funclet and compute its clauses.1193 // Funclets always start in the null state.1194 const MCSymbol *CurrentStartLabel = nullptr;1195 int CurrentState = NullState;1196 assert(HandlerStack.empty());1197 for (const auto &StateChange :1198 InvokeStateChangeIterator::range(FuncInfo, FuncletStart, FuncletEnd)) {1199 // Close any try regions we're not still under1200 int StillPendingState =1201 getTryAncestor(FuncInfo, CurrentState, StateChange.NewState);1202 while (CurrentState != StillPendingState) {1203 assert(CurrentState != NullState &&1204 "Failed to find still-pending state!");1205 // Close the pending clause1206 Clauses.push_back({CurrentStartLabel, StateChange.PreviousEndLabel,1207 CurrentState, FuncletState});1208 // Now the next-outer try region is current1209 CurrentState = FuncInfo.ClrEHUnwindMap[CurrentState].TryParentState;1210 // Pop the new start label from the handler stack if we've exited all1211 // inner try regions of the corresponding try region.1212 if (HandlerStack.back().second == CurrentState)1213 CurrentStartLabel = HandlerStack.pop_back_val().first;1214 }1215 1216 if (StateChange.NewState != CurrentState) {1217 // For each clause we're starting, update the MinClauseMap so we can1218 // know which is the topmost funclet containing a clause targeting1219 // it.1220 for (int EnteredState = StateChange.NewState;1221 EnteredState != CurrentState;1222 EnteredState =1223 FuncInfo.ClrEHUnwindMap[EnteredState].TryParentState) {1224 int &MinEnclosingState = MinClauseMap[EnteredState];1225 if (FuncletState < MinEnclosingState)1226 MinEnclosingState = FuncletState;1227 }1228 // Save the previous current start/label on the stack and update to1229 // the newly-current start/state.1230 HandlerStack.emplace_back(CurrentStartLabel, CurrentState);1231 CurrentStartLabel = StateChange.NewStartLabel;1232 CurrentState = StateChange.NewState;1233 }1234 }1235 assert(HandlerStack.empty());1236 }1237 1238 // Now emit the clause info, starting with the number of clauses.1239 OS.emitInt32(Clauses.size());1240 for (ClrClause &Clause : Clauses) {1241 // Emit a CORINFO_EH_CLAUSE :1242 /*1243 struct CORINFO_EH_CLAUSE1244 {1245 CORINFO_EH_CLAUSE_FLAGS Flags; // actually a CorExceptionFlag1246 DWORD TryOffset;1247 DWORD TryLength; // actually TryEndOffset1248 DWORD HandlerOffset;1249 DWORD HandlerLength; // actually HandlerEndOffset1250 union1251 {1252 DWORD ClassToken; // use for catch clauses1253 DWORD FilterOffset; // use for filter clauses1254 };1255 };1256 1257 enum CORINFO_EH_CLAUSE_FLAGS1258 {1259 CORINFO_EH_CLAUSE_NONE = 0,1260 CORINFO_EH_CLAUSE_FILTER = 0x0001, // This clause is for a filter1261 CORINFO_EH_CLAUSE_FINALLY = 0x0002, // This clause is a finally clause1262 CORINFO_EH_CLAUSE_FAULT = 0x0004, // This clause is a fault clause1263 };1264 typedef enum CorExceptionFlag1265 {1266 COR_ILEXCEPTION_CLAUSE_NONE,1267 COR_ILEXCEPTION_CLAUSE_FILTER = 0x0001, // This is a filter clause1268 COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002, // This is a finally clause1269 COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004, // This is a fault clause1270 COR_ILEXCEPTION_CLAUSE_DUPLICATED = 0x0008, // duplicated clause. This1271 // clause was duplicated1272 // to a funclet which was1273 // pulled out of line1274 } CorExceptionFlag;1275 */1276 // Add 1 to the start/end of the EH clause; the IP associated with a1277 // call when the runtime does its scan is the IP of the next instruction1278 // (the one to which control will return after the call), so we need1279 // to add 1 to the end of the clause to cover that offset. We also add1280 // 1 to the start of the clause to make sure that the ranges reported1281 // for all clauses are disjoint. Note that we'll need some additional1282 // logic when machine traps are supported, since in that case the IP1283 // that the runtime uses is the offset of the faulting instruction1284 // itself; if such an instruction immediately follows a call but the1285 // two belong to different clauses, we'll need to insert a nop between1286 // them so the runtime can distinguish the point to which the call will1287 // return from the point at which the fault occurs.1288 1289 const MCExpr *ClauseBegin =1290 getOffsetPlusOne(Clause.StartLabel, FuncBeginSym);1291 const MCExpr *ClauseEnd = getOffsetPlusOne(Clause.EndLabel, FuncBeginSym);1292 1293 const ClrEHUnwindMapEntry &Entry = FuncInfo.ClrEHUnwindMap[Clause.State];1294 MachineBasicBlock *HandlerBlock = cast<MachineBasicBlock *>(Entry.Handler);1295 MCSymbol *BeginSym = getMCSymbolForMBB(Asm, HandlerBlock);1296 const MCExpr *HandlerBegin = getOffset(BeginSym, FuncBeginSym);1297 MCSymbol *EndSym = EndSymbolMap[Clause.State];1298 const MCExpr *HandlerEnd = getOffset(EndSym, FuncBeginSym);1299 1300 uint32_t Flags = 0;1301 switch (Entry.HandlerType) {1302 case ClrHandlerType::Catch:1303 // Leaving bits 0-2 clear indicates catch.1304 break;1305 case ClrHandlerType::Filter:1306 Flags |= 1;1307 break;1308 case ClrHandlerType::Finally:1309 Flags |= 2;1310 break;1311 case ClrHandlerType::Fault:1312 Flags |= 4;1313 break;1314 }1315 if (Clause.EnclosingState != MinClauseMap[Clause.State]) {1316 // This is a "duplicate" clause; the handler needs to be entered from a1317 // frame above the one holding the invoke.1318 assert(Clause.EnclosingState > MinClauseMap[Clause.State]);1319 Flags |= 8;1320 }1321 OS.emitInt32(Flags);1322 1323 // Write the clause start/end1324 OS.emitValue(ClauseBegin, 4);1325 OS.emitValue(ClauseEnd, 4);1326 1327 // Write out the handler start/end1328 OS.emitValue(HandlerBegin, 4);1329 OS.emitValue(HandlerEnd, 4);1330 1331 // Write out the type token or filter offset1332 assert(Entry.HandlerType != ClrHandlerType::Filter && "NYI: filters");1333 OS.emitInt32(Entry.TypeToken);1334 }1335}1336