X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FCodeGen%2FAsmPrinter%2FWin64Exception.cpp;h=356a35135d13d8c34e3257f67354e31c985ab4af;hp=17d8bff6092d7baab1588090b4b00ae192fc169c;hb=4ceab42509518746afef0370e7aba230736a80f5;hpb=737c9f6005594898eed4746cd310cd161ef209c6 diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/lib/CodeGen/AsmPrinter/Win64Exception.cpp index 17d8bff6092..356a35135d1 100644 --- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ b/lib/CodeGen/AsmPrinter/Win64Exception.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "DwarfException.h" +#include "Win64Exception.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" @@ -38,9 +38,8 @@ using namespace llvm; Win64Exception::Win64Exception(AsmPrinter *A) - : DwarfException(A), - shouldEmitPersonality(false), shouldEmitLSDA(false), shouldEmitMoves(false) - {} + : EHStreamer(A), shouldEmitPersonality(false), shouldEmitLSDA(false), + shouldEmitMoves(false) {} Win64Exception::~Win64Exception() {} @@ -61,7 +60,7 @@ void Win64Exception::beginFunction(const MachineFunction *MF) { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); unsigned PerEncoding = TLOF.getPersonalityEncoding(); - const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()]; + const Function *Per = MF->getMMI().getPersonality(); shouldEmitPersonality = hasLandingPads && PerEncoding != dwarf::DW_EH_PE_omit && Per; @@ -73,17 +72,14 @@ void Win64Exception::beginFunction(const MachineFunction *MF) { if (!shouldEmitPersonality && !shouldEmitMoves) return; - Asm->OutStreamer.EmitWin64EHStartProc(Asm->CurrentFnSym); + Asm->OutStreamer.EmitWinCFIStartProc(Asm->CurrentFnSym); if (!shouldEmitPersonality) return; - MCSymbol *GCCHandlerSym = - Asm->GetExternalSymbolSymbol("_GCC_specific_handler"); - Asm->OutStreamer.EmitWin64EHHandler(GCCHandlerSym, true, true); - - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin", - Asm->getFunctionNumber())); + const MCSymbol *PersHandlerSym = + TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI); + Asm->OutStreamer.EmitWinEHHandler(PersHandlerSym, true, true); } /// endFunction - Gather and emit post-function exception information. @@ -92,24 +88,154 @@ void Win64Exception::endFunction(const MachineFunction *) { if (!shouldEmitPersonality && !shouldEmitMoves) return; - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_end", - Asm->getFunctionNumber())); - // Map all labels and get rid of any dead landing pads. MMI->TidyLandingPads(); if (shouldEmitPersonality) { - const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()]; - const MCSymbol *Sym = - TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI); - Asm->OutStreamer.PushSection(); - Asm->OutStreamer.EmitWin64EHHandlerData(); - Asm->OutStreamer.EmitValue(MCSymbolRefExpr::Create(Sym, Asm->OutContext), - 4); - EmitExceptionTable(); + + // Emit an UNWIND_INFO struct describing the prologue. + Asm->OutStreamer.EmitWinEHHandlerData(); + + // Emit the tables appropriate to the personality function in use. If we + // don't recognize the personality, assume it uses an Itanium-style LSDA. + EHPersonality Per = MMI->getPersonalityType(); + if (Per == EHPersonality::MSVC_Win64SEH) + emitCSpecificHandlerTable(); + else + emitExceptionTable(); + Asm->OutStreamer.PopSection(); } - Asm->OutStreamer.EmitWin64EHEndProc(); + Asm->OutStreamer.EmitWinCFIEndProc(); +} + +const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) { + return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32, + Asm->OutContext); +} + +/// Emit the language-specific data that __C_specific_handler expects. This +/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning +/// up after faults with __try, __except, and __finally. The typeinfo values +/// are not really RTTI data, but pointers to filter functions that return an +/// integer (1, 0, or -1) indicating how to handle the exception. For __finally +/// blocks and other cleanups, the landing pad label is zero, and the filter +/// function is actually a cleanup handler with the same prototype. A catch-all +/// entry is modeled with a null filter function field and a non-zero landing +/// pad label. +/// +/// Possible filter function return values: +/// EXCEPTION_EXECUTE_HANDLER (1): +/// Jump to the landing pad label after cleanups. +/// EXCEPTION_CONTINUE_SEARCH (0): +/// Continue searching this table or continue unwinding. +/// EXCEPTION_CONTINUE_EXECUTION (-1): +/// Resume execution at the trapping PC. +/// +/// Inferred table structure: +/// struct Table { +/// int NumEntries; +/// struct Entry { +/// imagerel32 LabelStart; +/// imagerel32 LabelEnd; +/// imagerel32 FilterOrFinally; // One means catch-all. +/// imagerel32 LabelLPad; // Zero means __finally. +/// } Entries[NumEntries]; +/// }; +void Win64Exception::emitCSpecificHandlerTable() { + const std::vector &PadInfos = MMI->getLandingPads(); + + // Simplifying assumptions for first implementation: + // - Cleanups are not implemented. + // - Filters are not implemented. + + // The Itanium LSDA table sorts similar landing pads together to simplify the + // actions table, but we don't need that. + SmallVector LandingPads; + LandingPads.reserve(PadInfos.size()); + for (const auto &LP : PadInfos) + LandingPads.push_back(&LP); + + // Compute label ranges for call sites as we would for the Itanium LSDA, but + // use an all zero action table because we aren't using these actions. + SmallVector FirstActions; + FirstActions.resize(LandingPads.size()); + SmallVector CallSites; + computeCallSiteTable(CallSites, LandingPads, FirstActions); + + MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); + MCSymbol *EHFuncEndSym = Asm->getFunctionEnd(); + + // Emit the number of table entries. + unsigned NumEntries = 0; + for (const CallSiteEntry &CSE : CallSites) { + if (!CSE.LPad) + continue; // Ignore gaps. + for (int Selector : CSE.LPad->TypeIds) { + // Ignore C++ filter clauses in SEH. + // FIXME: Implement cleanup clauses. + if (isCatchEHSelector(Selector)) + ++NumEntries; + } + } + Asm->OutStreamer.EmitIntValue(NumEntries, 4); + + // Emit the four-label records for each call site entry. The table has to be + // sorted in layout order, and the call sites should already be sorted. + for (const CallSiteEntry &CSE : CallSites) { + // Ignore gaps. Unlike the Itanium model, unwinding through a frame without + // an EH table entry will propagate the exception rather than terminating + // the program. + if (!CSE.LPad) + continue; + const LandingPadInfo *LPad = CSE.LPad; + + // Compute the label range. We may reuse the function begin and end labels + // rather than forming new ones. + const MCExpr *Begin = + createImageRel32(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym); + const MCExpr *End; + if (CSE.EndLabel) { + // The interval is half-open, so we have to add one to include the return + // address of the last invoke in the range. + End = MCBinaryExpr::CreateAdd(createImageRel32(CSE.EndLabel), + MCConstantExpr::Create(1, Asm->OutContext), + Asm->OutContext); + } else { + End = createImageRel32(EHFuncEndSym); + } + + // These aren't really type info globals, they are actually pointers to + // filter functions ordered by selector. The zero selector is used for + // cleanups, so slot zero corresponds to selector 1. + const std::vector &SelectorToFilter = MMI->getTypeInfos(); + + // Do a parallel iteration across typeids and clause labels, skipping filter + // clauses. + size_t NextClauseLabel = 0; + for (size_t I = 0, E = LPad->TypeIds.size(); I < E; ++I) { + // AddLandingPadInfo stores the clauses in reverse, but there is a FIXME + // to change that. + int Selector = LPad->TypeIds[E - I - 1]; + + // Ignore C++ filter clauses in SEH. + // FIXME: Implement cleanup clauses. + if (!isCatchEHSelector(Selector)) + continue; + + Asm->OutStreamer.EmitValue(Begin, 4); + Asm->OutStreamer.EmitValue(End, 4); + if (isCatchEHSelector(Selector)) { + assert(unsigned(Selector - 1) < SelectorToFilter.size()); + const GlobalValue *TI = SelectorToFilter[Selector - 1]; + if (TI) // Emit the filter function pointer. + Asm->OutStreamer.EmitValue(createImageRel32(Asm->getSymbol(TI)), 4); + else // Otherwise, this is a "catch i8* null", or catch all. + Asm->OutStreamer.EmitIntValue(1, 4); + } + MCSymbol *ClauseLabel = LPad->ClauseLabels[NextClauseLabel++]; + Asm->OutStreamer.EmitValue(createImageRel32(ClauseLabel), 4); + } + } }