From: Reid Kleckner Date: Thu, 28 May 2015 22:47:01 +0000 (+0000) Subject: Rename Win64Exception.(cpp|h) to WinException.(cpp|h) X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=178db506297549fa74c34b9d9f3b7ffb11258bb7;p=oota-llvm.git Rename Win64Exception.(cpp|h) to WinException.(cpp|h) This is in preparation for reusing this for 32-bit x86 EH table emission. Also updates the type name for consistency. NFC git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238521 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 206be702e72..c895aa5fdbf 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -14,7 +14,7 @@ #include "llvm/CodeGen/AsmPrinter.h" #include "DwarfDebug.h" #include "DwarfException.h" -#include "Win64Exception.h" +#include "WinException.h" #include "WinCodeViewLineTables.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" @@ -269,7 +269,7 @@ bool AsmPrinter::doInitialization(Module &M) { case WinEH::EncodingType::Invalid: break; case WinEH::EncodingType::Itanium: - ES = new Win64Exception(this); + ES = new WinException(this); break; } break; diff --git a/lib/CodeGen/AsmPrinter/CMakeLists.txt b/lib/CodeGen/AsmPrinter/CMakeLists.txt index 01d2c7220ab..f2da8557a52 100644 --- a/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -18,7 +18,7 @@ add_llvm_library(LLVMAsmPrinter EHStreamer.cpp ErlangGCPrinter.cpp OcamlGCPrinter.cpp - Win64Exception.cpp + WinException.cpp WinCodeViewLineTables.cpp ) diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/lib/CodeGen/AsmPrinter/Win64Exception.cpp deleted file mode 100644 index dc6df9cb014..00000000000 --- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ /dev/null @@ -1,504 +0,0 @@ -//===-- CodeGen/AsmPrinter/Win64Exception.cpp - Dwarf Exception Impl ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains support for writing Win64 exception info into asm files. -// -//===----------------------------------------------------------------------===// - -#include "Win64Exception.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Twine.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/MachineFrameInfo.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/WinEHFuncInfo.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Mangler.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCSection.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Target/TargetFrameLowering.h" -#include "llvm/Target/TargetLoweringObjectFile.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetRegisterInfo.h" -using namespace llvm; - -Win64Exception::Win64Exception(AsmPrinter *A) - : EHStreamer(A), shouldEmitPersonality(false), shouldEmitLSDA(false), - shouldEmitMoves(false) {} - -Win64Exception::~Win64Exception() {} - -/// endModule - Emit all exception information that should come after the -/// content. -void Win64Exception::endModule() { -} - -void Win64Exception::beginFunction(const MachineFunction *MF) { - shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; - - // If any landing pads survive, we need an EH table. - bool hasLandingPads = !MMI->getLandingPads().empty(); - - shouldEmitMoves = Asm->needsSEHMoves(); - - const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - unsigned PerEncoding = TLOF.getPersonalityEncoding(); - const Function *Per = MF->getMMI().getPersonality(); - - shouldEmitPersonality = hasLandingPads && - PerEncoding != dwarf::DW_EH_PE_omit && Per; - - unsigned LSDAEncoding = TLOF.getLSDAEncoding(); - shouldEmitLSDA = shouldEmitPersonality && - LSDAEncoding != dwarf::DW_EH_PE_omit; - - - // If this was an outlined handler, we need to define the label corresponding - // to the offset of the parent frame relative to the stack pointer after the - // prologue. - const Function *F = MF->getFunction(); - const Function *ParentF = MMI->getWinEHParent(F); - if (F != ParentF) { - WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); - auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F); - if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) { - MCSymbol *HandlerTypeParentFrameOffset = - Asm->OutContext.getOrCreateParentFrameOffsetSymbol( - GlobalValue::getRealLinkageName(F->getName())); - - // Emit a symbol assignment. - Asm->OutStreamer->EmitAssignment( - HandlerTypeParentFrameOffset, - MCConstantExpr::Create(I->second, Asm->OutContext)); - } - } - - if (!shouldEmitPersonality && !shouldEmitMoves) - return; - - Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym); - - if (!shouldEmitPersonality) - return; - - 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. -/// -void Win64Exception::endFunction(const MachineFunction *MF) { - if (!shouldEmitPersonality && !shouldEmitMoves) - return; - - EHPersonality Per = MMI->getPersonalityType(); - - // Get rid of any dead landing pads if we're not using a Windows EH scheme. In - // Windows EH schemes, the landing pad is not actually reachable. It only - // exists so that we can emit the right table data. - if (!isMSVCEHPersonality(Per)) - MMI->TidyLandingPads(); - - if (shouldEmitPersonality) { - Asm->OutStreamer->PushSection(); - - // 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. - if (Per == EHPersonality::MSVC_Win64SEH) - emitCSpecificHandlerTable(); - else if (Per == EHPersonality::MSVC_CXX) - emitCXXFrameHandler3Table(MF); - else - emitExceptionTable(); - - Asm->OutStreamer->PopSection(); - } - Asm->OutStreamer->EmitWinCFIEndProc(); -} - -const MCExpr *Win64Exception::createImageRel32(const MCSymbol *Value) { - if (!Value) - return MCConstantExpr::Create(0, Asm->OutContext); - return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32, - Asm->OutContext); -} - -const MCExpr *Win64Exception::createImageRel32(const GlobalValue *GV) { - if (!GV) - return MCConstantExpr::Create(0, Asm->OutContext); - return createImageRel32(Asm->getSymbol(GV)); -} - -/// 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. - NumEntries += CSE.LPad->SEHHandlers.size(); - } - Asm->OutStreamer->EmitIntValue(NumEntries, 4); - - // If there are no actions, we don't need to iterate again. - if (NumEntries == 0) - return; - - // 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); - } - - // Emit an entry for each action. - for (SEHHandler Handler : LPad->SEHHandlers) { - Asm->OutStreamer->EmitValue(Begin, 4); - Asm->OutStreamer->EmitValue(End, 4); - - // Emit the filter or finally function pointer, if present. Otherwise, - // emit '1' to indicate a catch-all. - const Function *F = Handler.FilterOrFinally; - if (F) - Asm->OutStreamer->EmitValue(createImageRel32(Asm->getSymbol(F)), 4); - else - Asm->OutStreamer->EmitIntValue(1, 4); - - // Emit the recovery address, if present. Otherwise, this must be a - // finally. - const BlockAddress *BA = Handler.RecoverBA; - if (BA) - Asm->OutStreamer->EmitValue( - createImageRel32(Asm->GetBlockAddressSymbol(BA)), 4); - else - Asm->OutStreamer->EmitIntValue(0, 4); - } - } -} - -void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) { - const Function *F = MF->getFunction(); - const Function *ParentF = MMI->getWinEHParent(F); - auto &OS = *Asm->OutStreamer; - WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); - - StringRef ParentLinkageName = - GlobalValue::getRealLinkageName(ParentF->getName()); - - MCSymbol *FuncInfoXData = - Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", ParentLinkageName)); - OS.EmitValue(createImageRel32(FuncInfoXData), 4); - - // The Itanium LSDA table sorts similar landing pads together to simplify the - // actions table, but we don't need that. - SmallVector LandingPads; - const std::vector &PadInfos = MMI->getLandingPads(); - LandingPads.reserve(PadInfos.size()); - for (const auto &LP : PadInfos) - LandingPads.push_back(&LP); - - RangeMapType PadMap; - computePadMap(LandingPads, PadMap); - - // The end label of the previous invoke or nounwind try-range. - MCSymbol *LastLabel = Asm->getFunctionBegin(); - - // Whether there is a potentially throwing instruction (currently this means - // an ordinary call) between the end of the previous try-range and now. - bool SawPotentiallyThrowing = false; - - int LastEHState = -2; - - // The parent function and the catch handlers contribute to the 'ip2state' - // table. - - // Include ip2state entries for the beginning of the main function and - // for catch handler functions. - if (F == ParentF) { - FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); - LastEHState = -1; - } else if (FuncInfo.HandlerBaseState.count(F)) { - FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, - FuncInfo.HandlerBaseState[F])); - LastEHState = FuncInfo.HandlerBaseState[F]; - } - for (const auto &MBB : *MF) { - for (const auto &MI : MBB) { - if (!MI.isEHLabel()) { - if (MI.isCall()) - SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); - continue; - } - - // End of the previous try-range? - MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol(); - if (BeginLabel == LastLabel) - SawPotentiallyThrowing = false; - - // Beginning of a new try-range? - RangeMapType::const_iterator L = PadMap.find(BeginLabel); - if (L == PadMap.end()) - // Nope, it was just some random label. - continue; - - const PadRange &P = L->second; - const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; - assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && - "Inconsistent landing pad map!"); - - // FIXME: Should this be using FuncInfo.HandlerBaseState? - if (SawPotentiallyThrowing && LastEHState != -1) { - FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); - SawPotentiallyThrowing = false; - LastEHState = -1; - } - - if (LandingPad->WinEHState != LastEHState) - FuncInfo.IPToStateList.push_back( - std::make_pair(BeginLabel, LandingPad->WinEHState)); - LastEHState = LandingPad->WinEHState; - LastLabel = LandingPad->EndLabels[P.RangeIndex]; - } - } - - // Defer emission until we've visited the parent function and all the catch - // handlers. Cleanups don't contribute to the ip2state table yet, so don't - // count them. - if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F)) - return; - ++FuncInfo.NumIPToStateFuncsVisited; - if (FuncInfo.NumIPToStateFuncsVisited != FuncInfo.CatchHandlerMaxState.size()) - return; - - MCSymbol *UnwindMapXData = nullptr; - MCSymbol *TryBlockMapXData = nullptr; - MCSymbol *IPToStateXData = nullptr; - if (!FuncInfo.UnwindMap.empty()) - UnwindMapXData = Asm->OutContext.getOrCreateSymbol( - Twine("$stateUnwindMap$", ParentLinkageName)); - if (!FuncInfo.TryBlockMap.empty()) - TryBlockMapXData = Asm->OutContext.getOrCreateSymbol( - Twine("$tryMap$", ParentLinkageName)); - if (!FuncInfo.IPToStateList.empty()) - IPToStateXData = Asm->OutContext.getOrCreateSymbol( - Twine("$ip2state$", ParentLinkageName)); - - // FuncInfo { - // uint32_t MagicNumber - // int32_t MaxState; - // UnwindMapEntry *UnwindMap; - // uint32_t NumTryBlocks; - // TryBlockMapEntry *TryBlockMap; - // uint32_t IPMapEntries; - // IPToStateMapEntry *IPToStateMap; - // uint32_t UnwindHelp; // (x64/ARM only) - // ESTypeList *ESTypeList; - // int32_t EHFlags; - // } - // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. - // EHFlags & 2 -> ??? - // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. - OS.EmitLabel(FuncInfoXData); - OS.EmitIntValue(0x19930522, 4); // MagicNumber - OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState - OS.EmitValue(createImageRel32(UnwindMapXData), 4); // UnwindMap - OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks - OS.EmitValue(createImageRel32(TryBlockMapXData), 4); // TryBlockMap - OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries - OS.EmitValue(createImageRel32(IPToStateXData), 4); // IPToStateMap - OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp - OS.EmitIntValue(0, 4); // ESTypeList - OS.EmitIntValue(1, 4); // EHFlags - - // UnwindMapEntry { - // int32_t ToState; - // void (*Action)(); - // }; - if (UnwindMapXData) { - OS.EmitLabel(UnwindMapXData); - for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { - OS.EmitIntValue(UME.ToState, 4); // ToState - OS.EmitValue(createImageRel32(UME.Cleanup), 4); // Action - } - } - - // TryBlockMap { - // int32_t TryLow; - // int32_t TryHigh; - // int32_t CatchHigh; - // int32_t NumCatches; - // HandlerType *HandlerArray; - // }; - if (TryBlockMapXData) { - OS.EmitLabel(TryBlockMapXData); - SmallVector HandlerMaps; - for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { - WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; - MCSymbol *HandlerMapXData = nullptr; - - if (!TBME.HandlerArray.empty()) - HandlerMapXData = - Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") - .concat(Twine(I)) - .concat("$") - .concat(ParentLinkageName)); - - HandlerMaps.push_back(HandlerMapXData); - - int CatchHigh = -1; - for (WinEHHandlerType &HT : TBME.HandlerArray) - CatchHigh = - std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]); - - assert(TBME.TryLow <= TBME.TryHigh); - OS.EmitIntValue(TBME.TryLow, 4); // TryLow - OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh - OS.EmitIntValue(CatchHigh, 4); // CatchHigh - OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches - OS.EmitValue(createImageRel32(HandlerMapXData), 4); // HandlerArray - } - - for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { - WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; - MCSymbol *HandlerMapXData = HandlerMaps[I]; - if (!HandlerMapXData) - continue; - // HandlerType { - // int32_t Adjectives; - // TypeDescriptor *Type; - // int32_t CatchObjOffset; - // void (*Handler)(); - // int32_t ParentFrameOffset; // x64 only - // }; - OS.EmitLabel(HandlerMapXData); - for (const WinEHHandlerType &HT : TBME.HandlerArray) { - MCSymbol *ParentFrameOffset = - Asm->OutContext.getOrCreateParentFrameOffsetSymbol( - GlobalValue::getRealLinkageName(HT.Handler->getName())); - const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::Create( - ParentFrameOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); - - // Get the frame escape label with the offset of the catch object. If - // the index is -1, then there is no catch object, and we should emit an - // offset of zero, indicating that no copy will occur. - const MCExpr *FrameAllocOffsetRef = nullptr; - if (HT.CatchObjRecoverIdx >= 0) { - MCSymbol *FrameAllocOffset = - Asm->OutContext.getOrCreateFrameAllocSymbol( - GlobalValue::getRealLinkageName(ParentF->getName()), - HT.CatchObjRecoverIdx); - FrameAllocOffsetRef = MCSymbolRefExpr::Create( - FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); - } else { - FrameAllocOffsetRef = MCConstantExpr::Create(0, Asm->OutContext); - } - - OS.EmitIntValue(HT.Adjectives, 4); // Adjectives - OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type - OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset - OS.EmitValue(createImageRel32(HT.Handler), 4); // Handler - OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset - } - } - } - - // IPToStateMapEntry { - // void *IP; - // int32_t State; - // }; - if (IPToStateXData) { - OS.EmitLabel(IPToStateXData); - for (auto &IPStatePair : FuncInfo.IPToStateList) { - OS.EmitValue(createImageRel32(IPStatePair.first), 4); // IP - OS.EmitIntValue(IPStatePair.second, 4); // State - } - } -} diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.h b/lib/CodeGen/AsmPrinter/Win64Exception.h deleted file mode 100644 index 5f4237fc015..00000000000 --- a/lib/CodeGen/AsmPrinter/Win64Exception.h +++ /dev/null @@ -1,61 +0,0 @@ -//===-- Win64Exception.h - Windows Exception Handling ----------*- C++ -*--===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains support for writing windows exception info into asm files. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_WIN64EXCEPTION_H -#define LLVM_LIB_CODEGEN_ASMPRINTER_WIN64EXCEPTION_H - -#include "EHStreamer.h" - -namespace llvm { -class GlobalValue; -class MachineFunction; -class MCExpr; - -class Win64Exception : public EHStreamer { - /// Per-function flag to indicate if personality info should be emitted. - bool shouldEmitPersonality; - - /// Per-function flag to indicate if the LSDA should be emitted. - bool shouldEmitLSDA; - - /// Per-function flag to indicate if frame moves info should be emitted. - bool shouldEmitMoves; - - void emitCSpecificHandlerTable(); - - void emitCXXFrameHandler3Table(const MachineFunction *MF); - - const MCExpr *createImageRel32(const MCSymbol *Value); - const MCExpr *createImageRel32(const GlobalValue *GV); - -public: - //===--------------------------------------------------------------------===// - // Main entry points. - // - Win64Exception(AsmPrinter *A); - ~Win64Exception() override; - - /// Emit all exception information that should come after the content. - void endModule() override; - - /// Gather pre-function exception information. Assumes being emitted - /// immediately after the function entry point. - void beginFunction(const MachineFunction *MF) override; - - /// Gather and emit post-function exception information. - void endFunction(const MachineFunction *) override; -}; -} - -#endif - diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp new file mode 100644 index 00000000000..9c6069b41dd --- /dev/null +++ b/lib/CodeGen/AsmPrinter/WinException.cpp @@ -0,0 +1,504 @@ +//===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing Win64 exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "WinException.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +using namespace llvm; + +WinException::WinException(AsmPrinter *A) + : EHStreamer(A), shouldEmitPersonality(false), shouldEmitLSDA(false), + shouldEmitMoves(false) {} + +WinException::~WinException() {} + +/// endModule - Emit all exception information that should come after the +/// content. +void WinException::endModule() { +} + +void WinException::beginFunction(const MachineFunction *MF) { + shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; + + // If any landing pads survive, we need an EH table. + bool hasLandingPads = !MMI->getLandingPads().empty(); + + shouldEmitMoves = Asm->needsSEHMoves(); + + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + unsigned PerEncoding = TLOF.getPersonalityEncoding(); + const Function *Per = MF->getMMI().getPersonality(); + + shouldEmitPersonality = hasLandingPads && + PerEncoding != dwarf::DW_EH_PE_omit && Per; + + unsigned LSDAEncoding = TLOF.getLSDAEncoding(); + shouldEmitLSDA = shouldEmitPersonality && + LSDAEncoding != dwarf::DW_EH_PE_omit; + + + // If this was an outlined handler, we need to define the label corresponding + // to the offset of the parent frame relative to the stack pointer after the + // prologue. + const Function *F = MF->getFunction(); + const Function *ParentF = MMI->getWinEHParent(F); + if (F != ParentF) { + WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); + auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F); + if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) { + MCSymbol *HandlerTypeParentFrameOffset = + Asm->OutContext.getOrCreateParentFrameOffsetSymbol( + GlobalValue::getRealLinkageName(F->getName())); + + // Emit a symbol assignment. + Asm->OutStreamer->EmitAssignment( + HandlerTypeParentFrameOffset, + MCConstantExpr::Create(I->second, Asm->OutContext)); + } + } + + if (!shouldEmitPersonality && !shouldEmitMoves) + return; + + Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym); + + if (!shouldEmitPersonality) + return; + + 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. +/// +void WinException::endFunction(const MachineFunction *MF) { + if (!shouldEmitPersonality && !shouldEmitMoves) + return; + + EHPersonality Per = MMI->getPersonalityType(); + + // Get rid of any dead landing pads if we're not using a Windows EH scheme. In + // Windows EH schemes, the landing pad is not actually reachable. It only + // exists so that we can emit the right table data. + if (!isMSVCEHPersonality(Per)) + MMI->TidyLandingPads(); + + if (shouldEmitPersonality) { + Asm->OutStreamer->PushSection(); + + // 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. + if (Per == EHPersonality::MSVC_Win64SEH) + emitCSpecificHandlerTable(); + else if (Per == EHPersonality::MSVC_CXX) + emitCXXFrameHandler3Table(MF); + else + emitExceptionTable(); + + Asm->OutStreamer->PopSection(); + } + Asm->OutStreamer->EmitWinCFIEndProc(); +} + +const MCExpr *WinException::createImageRel32(const MCSymbol *Value) { + if (!Value) + return MCConstantExpr::Create(0, Asm->OutContext); + return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32, + Asm->OutContext); +} + +const MCExpr *WinException::createImageRel32(const GlobalValue *GV) { + if (!GV) + return MCConstantExpr::Create(0, Asm->OutContext); + return createImageRel32(Asm->getSymbol(GV)); +} + +/// 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 WinException::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. + NumEntries += CSE.LPad->SEHHandlers.size(); + } + Asm->OutStreamer->EmitIntValue(NumEntries, 4); + + // If there are no actions, we don't need to iterate again. + if (NumEntries == 0) + return; + + // 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); + } + + // Emit an entry for each action. + for (SEHHandler Handler : LPad->SEHHandlers) { + Asm->OutStreamer->EmitValue(Begin, 4); + Asm->OutStreamer->EmitValue(End, 4); + + // Emit the filter or finally function pointer, if present. Otherwise, + // emit '1' to indicate a catch-all. + const Function *F = Handler.FilterOrFinally; + if (F) + Asm->OutStreamer->EmitValue(createImageRel32(Asm->getSymbol(F)), 4); + else + Asm->OutStreamer->EmitIntValue(1, 4); + + // Emit the recovery address, if present. Otherwise, this must be a + // finally. + const BlockAddress *BA = Handler.RecoverBA; + if (BA) + Asm->OutStreamer->EmitValue( + createImageRel32(Asm->GetBlockAddressSymbol(BA)), 4); + else + Asm->OutStreamer->EmitIntValue(0, 4); + } + } +} + +void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { + const Function *F = MF->getFunction(); + const Function *ParentF = MMI->getWinEHParent(F); + auto &OS = *Asm->OutStreamer; + WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); + + StringRef ParentLinkageName = + GlobalValue::getRealLinkageName(ParentF->getName()); + + MCSymbol *FuncInfoXData = + Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", ParentLinkageName)); + OS.EmitValue(createImageRel32(FuncInfoXData), 4); + + // The Itanium LSDA table sorts similar landing pads together to simplify the + // actions table, but we don't need that. + SmallVector LandingPads; + const std::vector &PadInfos = MMI->getLandingPads(); + LandingPads.reserve(PadInfos.size()); + for (const auto &LP : PadInfos) + LandingPads.push_back(&LP); + + RangeMapType PadMap; + computePadMap(LandingPads, PadMap); + + // The end label of the previous invoke or nounwind try-range. + MCSymbol *LastLabel = Asm->getFunctionBegin(); + + // Whether there is a potentially throwing instruction (currently this means + // an ordinary call) between the end of the previous try-range and now. + bool SawPotentiallyThrowing = false; + + int LastEHState = -2; + + // The parent function and the catch handlers contribute to the 'ip2state' + // table. + + // Include ip2state entries for the beginning of the main function and + // for catch handler functions. + if (F == ParentF) { + FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); + LastEHState = -1; + } else if (FuncInfo.HandlerBaseState.count(F)) { + FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, + FuncInfo.HandlerBaseState[F])); + LastEHState = FuncInfo.HandlerBaseState[F]; + } + for (const auto &MBB : *MF) { + for (const auto &MI : MBB) { + if (!MI.isEHLabel()) { + if (MI.isCall()) + SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); + continue; + } + + // End of the previous try-range? + MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol(); + if (BeginLabel == LastLabel) + SawPotentiallyThrowing = false; + + // Beginning of a new try-range? + RangeMapType::const_iterator L = PadMap.find(BeginLabel); + if (L == PadMap.end()) + // Nope, it was just some random label. + continue; + + const PadRange &P = L->second; + const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; + assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && + "Inconsistent landing pad map!"); + + // FIXME: Should this be using FuncInfo.HandlerBaseState? + if (SawPotentiallyThrowing && LastEHState != -1) { + FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); + SawPotentiallyThrowing = false; + LastEHState = -1; + } + + if (LandingPad->WinEHState != LastEHState) + FuncInfo.IPToStateList.push_back( + std::make_pair(BeginLabel, LandingPad->WinEHState)); + LastEHState = LandingPad->WinEHState; + LastLabel = LandingPad->EndLabels[P.RangeIndex]; + } + } + + // Defer emission until we've visited the parent function and all the catch + // handlers. Cleanups don't contribute to the ip2state table yet, so don't + // count them. + if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F)) + return; + ++FuncInfo.NumIPToStateFuncsVisited; + if (FuncInfo.NumIPToStateFuncsVisited != FuncInfo.CatchHandlerMaxState.size()) + return; + + MCSymbol *UnwindMapXData = nullptr; + MCSymbol *TryBlockMapXData = nullptr; + MCSymbol *IPToStateXData = nullptr; + if (!FuncInfo.UnwindMap.empty()) + UnwindMapXData = Asm->OutContext.getOrCreateSymbol( + Twine("$stateUnwindMap$", ParentLinkageName)); + if (!FuncInfo.TryBlockMap.empty()) + TryBlockMapXData = Asm->OutContext.getOrCreateSymbol( + Twine("$tryMap$", ParentLinkageName)); + if (!FuncInfo.IPToStateList.empty()) + IPToStateXData = Asm->OutContext.getOrCreateSymbol( + Twine("$ip2state$", ParentLinkageName)); + + // FuncInfo { + // uint32_t MagicNumber + // int32_t MaxState; + // UnwindMapEntry *UnwindMap; + // uint32_t NumTryBlocks; + // TryBlockMapEntry *TryBlockMap; + // uint32_t IPMapEntries; + // IPToStateMapEntry *IPToStateMap; + // uint32_t UnwindHelp; // (x64/ARM only) + // ESTypeList *ESTypeList; + // int32_t EHFlags; + // } + // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. + // EHFlags & 2 -> ??? + // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. + OS.EmitLabel(FuncInfoXData); + OS.EmitIntValue(0x19930522, 4); // MagicNumber + OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState + OS.EmitValue(createImageRel32(UnwindMapXData), 4); // UnwindMap + OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks + OS.EmitValue(createImageRel32(TryBlockMapXData), 4); // TryBlockMap + OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries + OS.EmitValue(createImageRel32(IPToStateXData), 4); // IPToStateMap + OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp + OS.EmitIntValue(0, 4); // ESTypeList + OS.EmitIntValue(1, 4); // EHFlags + + // UnwindMapEntry { + // int32_t ToState; + // void (*Action)(); + // }; + if (UnwindMapXData) { + OS.EmitLabel(UnwindMapXData); + for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { + OS.EmitIntValue(UME.ToState, 4); // ToState + OS.EmitValue(createImageRel32(UME.Cleanup), 4); // Action + } + } + + // TryBlockMap { + // int32_t TryLow; + // int32_t TryHigh; + // int32_t CatchHigh; + // int32_t NumCatches; + // HandlerType *HandlerArray; + // }; + if (TryBlockMapXData) { + OS.EmitLabel(TryBlockMapXData); + SmallVector HandlerMaps; + for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { + WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; + MCSymbol *HandlerMapXData = nullptr; + + if (!TBME.HandlerArray.empty()) + HandlerMapXData = + Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$") + .concat(Twine(I)) + .concat("$") + .concat(ParentLinkageName)); + + HandlerMaps.push_back(HandlerMapXData); + + int CatchHigh = -1; + for (WinEHHandlerType &HT : TBME.HandlerArray) + CatchHigh = + std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]); + + assert(TBME.TryLow <= TBME.TryHigh); + OS.EmitIntValue(TBME.TryLow, 4); // TryLow + OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh + OS.EmitIntValue(CatchHigh, 4); // CatchHigh + OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches + OS.EmitValue(createImageRel32(HandlerMapXData), 4); // HandlerArray + } + + for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { + WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; + MCSymbol *HandlerMapXData = HandlerMaps[I]; + if (!HandlerMapXData) + continue; + // HandlerType { + // int32_t Adjectives; + // TypeDescriptor *Type; + // int32_t CatchObjOffset; + // void (*Handler)(); + // int32_t ParentFrameOffset; // x64 only + // }; + OS.EmitLabel(HandlerMapXData); + for (const WinEHHandlerType &HT : TBME.HandlerArray) { + MCSymbol *ParentFrameOffset = + Asm->OutContext.getOrCreateParentFrameOffsetSymbol( + GlobalValue::getRealLinkageName(HT.Handler->getName())); + const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::Create( + ParentFrameOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); + + // Get the frame escape label with the offset of the catch object. If + // the index is -1, then there is no catch object, and we should emit an + // offset of zero, indicating that no copy will occur. + const MCExpr *FrameAllocOffsetRef = nullptr; + if (HT.CatchObjRecoverIdx >= 0) { + MCSymbol *FrameAllocOffset = + Asm->OutContext.getOrCreateFrameAllocSymbol( + GlobalValue::getRealLinkageName(ParentF->getName()), + HT.CatchObjRecoverIdx); + FrameAllocOffsetRef = MCSymbolRefExpr::Create( + FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); + } else { + FrameAllocOffsetRef = MCConstantExpr::Create(0, Asm->OutContext); + } + + OS.EmitIntValue(HT.Adjectives, 4); // Adjectives + OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type + OS.EmitValue(FrameAllocOffsetRef, 4); // CatchObjOffset + OS.EmitValue(createImageRel32(HT.Handler), 4); // Handler + OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset + } + } + } + + // IPToStateMapEntry { + // void *IP; + // int32_t State; + // }; + if (IPToStateXData) { + OS.EmitLabel(IPToStateXData); + for (auto &IPStatePair : FuncInfo.IPToStateList) { + OS.EmitValue(createImageRel32(IPStatePair.first), 4); // IP + OS.EmitIntValue(IPStatePair.second, 4); // State + } + } +} diff --git a/lib/CodeGen/AsmPrinter/WinException.h b/lib/CodeGen/AsmPrinter/WinException.h new file mode 100644 index 00000000000..ee5f122a49d --- /dev/null +++ b/lib/CodeGen/AsmPrinter/WinException.h @@ -0,0 +1,61 @@ +//===-- WinException.h - Windows Exception Handling ----------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing windows exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_WIN64EXCEPTION_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_WIN64EXCEPTION_H + +#include "EHStreamer.h" + +namespace llvm { +class GlobalValue; +class MachineFunction; +class MCExpr; + +class WinException : public EHStreamer { + /// Per-function flag to indicate if personality info should be emitted. + bool shouldEmitPersonality; + + /// Per-function flag to indicate if the LSDA should be emitted. + bool shouldEmitLSDA; + + /// Per-function flag to indicate if frame moves info should be emitted. + bool shouldEmitMoves; + + void emitCSpecificHandlerTable(); + + void emitCXXFrameHandler3Table(const MachineFunction *MF); + + const MCExpr *createImageRel32(const MCSymbol *Value); + const MCExpr *createImageRel32(const GlobalValue *GV); + +public: + //===--------------------------------------------------------------------===// + // Main entry points. + // + WinException(AsmPrinter *A); + ~WinException() override; + + /// Emit all exception information that should come after the content. + void endModule() override; + + /// Gather pre-function exception information. Assumes being emitted + /// immediately after the function entry point. + void beginFunction(const MachineFunction *MF) override; + + /// Gather and emit post-function exception information. + void endFunction(const MachineFunction *) override; +}; +} + +#endif +