From: Bill Wendling Date: Fri, 15 May 2009 01:12:28 +0000 (+0000) Subject: Split out the DwarfException class into its own file. No functionality change, X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=eb9072195ca7d777a71194dcaaaa369d82f24f53;p=oota-llvm.git Split out the DwarfException class into its own file. No functionality change, though the classes have been marked with "VISIBILITY_HIDDEN". git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71827 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/AsmPrinter/DwarfException.cpp b/lib/CodeGen/AsmPrinter/DwarfException.cpp new file mode 100644 index 00000000000..b68f5213d1c --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfException.cpp @@ -0,0 +1,709 @@ +//===-- CodeGen/AsmPrinter/DwarfException.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 dwarf exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "DwarfException.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/ADT/StringExtras.h" +using namespace llvm; + +static TimerGroup &getDwarfTimerGroup() { + static TimerGroup DwarfTimerGroup("Dwarf Exception"); + return DwarfTimerGroup; +} + +void DwarfException::EmitCommonEHFrame(const Function *Personality, + unsigned Index) { + // Size and sign of stack growth. + int stackGrowth = + Asm->TM.getFrameInfo()->getStackGrowthDirection() == + TargetFrameInfo::StackGrowsUp ? + TD->getPointerSize() : -TD->getPointerSize(); + + // Begin eh frame section. + Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection()); + + if (!TAI->doesRequireNonLocalEHFrameLabel()) + O << TAI->getEHGlobalPrefix(); + + O << "EH_frame" << Index << ":\n"; + EmitLabel("section_eh_frame", Index); + + // Define base labels. + EmitLabel("eh_frame_common", Index); + + // Define the eh frame length. + EmitDifference("eh_frame_common_end", Index, + "eh_frame_common_begin", Index, true); + Asm->EOL("Length of Common Information Entry"); + + // EH frame header. + EmitLabel("eh_frame_common_begin", Index); + Asm->EmitInt32((int)0); + Asm->EOL("CIE Identifier Tag"); + Asm->EmitInt8(dwarf::DW_CIE_VERSION); + Asm->EOL("CIE Version"); + + // The personality presence indicates that language specific information will + // show up in the eh frame. + Asm->EmitString(Personality ? "zPLR" : "zR"); + Asm->EOL("CIE Augmentation"); + + // Round out reader. + Asm->EmitULEB128Bytes(1); + Asm->EOL("CIE Code Alignment Factor"); + Asm->EmitSLEB128Bytes(stackGrowth); + Asm->EOL("CIE Data Alignment Factor"); + Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true)); + Asm->EOL("CIE Return Address Column"); + + // If there is a personality, we need to indicate the functions location. + if (Personality) { + Asm->EmitULEB128Bytes(7); + Asm->EOL("Augmentation Size"); + + if (TAI->getNeedsIndirectEncoding()) { + Asm->EmitInt8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 | + dwarf::DW_EH_PE_indirect); + Asm->EOL("Personality (pcrel sdata4 indirect)"); + } else { + Asm->EmitInt8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); + Asm->EOL("Personality (pcrel sdata4)"); + } + + PrintRelDirective(true); + O << TAI->getPersonalityPrefix(); + Asm->EmitExternalGlobal((const GlobalVariable *)(Personality)); + O << TAI->getPersonalitySuffix(); + if (strcmp(TAI->getPersonalitySuffix(), "+4@GOTPCREL")) + O << "-" << TAI->getPCSymbol(); + Asm->EOL("Personality"); + + Asm->EmitInt8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); + Asm->EOL("LSDA Encoding (pcrel sdata4)"); + + Asm->EmitInt8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); + Asm->EOL("FDE Encoding (pcrel sdata4)"); + } else { + Asm->EmitULEB128Bytes(1); + Asm->EOL("Augmentation Size"); + + Asm->EmitInt8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); + Asm->EOL("FDE Encoding (pcrel sdata4)"); + } + + // Indicate locations of general callee saved registers in frame. + std::vector Moves; + RI->getInitialFrameState(Moves); + EmitFrameMoves(NULL, 0, Moves, true); + + // On Darwin the linker honors the alignment of eh_frame, which means it must + // be 8-byte on 64-bit targets to match what gcc does. Otherwise you get + // holes which confuse readers of eh_frame. + Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, + 0, 0, false); + EmitLabel("eh_frame_common_end", Index); + + Asm->EOL(); +} + +/// EmitEHFrame - Emit function exception frame information. +/// +void DwarfException::EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo) { + assert(!EHFrameInfo.function->hasAvailableExternallyLinkage() && + "Should not emit 'available externally' functions at all"); + + Function::LinkageTypes linkage = EHFrameInfo.function->getLinkage(); + Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection()); + + // Externally visible entry into the functions eh frame info. If the + // corresponding function is static, this should not be externally visible. + if (linkage != Function::InternalLinkage && + linkage != Function::PrivateLinkage) { + if (const char *GlobalEHDirective = TAI->getGlobalEHDirective()) + O << GlobalEHDirective << EHFrameInfo.FnName << "\n"; + } + + // If corresponding function is weak definition, this should be too. + if ((linkage == Function::WeakAnyLinkage || + linkage == Function::WeakODRLinkage || + linkage == Function::LinkOnceAnyLinkage || + linkage == Function::LinkOnceODRLinkage) && + TAI->getWeakDefDirective()) + O << TAI->getWeakDefDirective() << EHFrameInfo.FnName << "\n"; + + // If there are no calls then you can't unwind. This may mean we can omit the + // EH Frame, but some environments do not handle weak absolute symbols. If + // UnwindTablesMandatory is set we cannot do this optimization; the unwind + // info is to be available for non-EH uses. + if (!EHFrameInfo.hasCalls && + !UnwindTablesMandatory && + ((linkage != Function::WeakAnyLinkage && + linkage != Function::WeakODRLinkage && + linkage != Function::LinkOnceAnyLinkage && + linkage != Function::LinkOnceODRLinkage) || + !TAI->getWeakDefDirective() || + TAI->getSupportsWeakOmittedEHFrame())) { + O << EHFrameInfo.FnName << " = 0\n"; + // This name has no connection to the function, so it might get + // dead-stripped when the function is not, erroneously. Prohibit + // dead-stripping unconditionally. + if (const char *UsedDirective = TAI->getUsedDirective()) + O << UsedDirective << EHFrameInfo.FnName << "\n\n"; + } else { + O << EHFrameInfo.FnName << ":\n"; + + // EH frame header. + EmitDifference("eh_frame_end", EHFrameInfo.Number, + "eh_frame_begin", EHFrameInfo.Number, true); + Asm->EOL("Length of Frame Information Entry"); + + EmitLabel("eh_frame_begin", EHFrameInfo.Number); + + if (TAI->doesRequireNonLocalEHFrameLabel()) { + PrintRelDirective(true, true); + PrintLabelName("eh_frame_begin", EHFrameInfo.Number); + + if (!TAI->isAbsoluteEHSectionOffsets()) + O << "-EH_frame" << EHFrameInfo.PersonalityIndex; + } else { + EmitSectionOffset("eh_frame_begin", "eh_frame_common", + EHFrameInfo.Number, EHFrameInfo.PersonalityIndex, + true, true, false); + } + + Asm->EOL("FDE CIE offset"); + + EmitReference("eh_func_begin", EHFrameInfo.Number, true, true); + Asm->EOL("FDE initial location"); + EmitDifference("eh_func_end", EHFrameInfo.Number, + "eh_func_begin", EHFrameInfo.Number, true); + Asm->EOL("FDE address range"); + + // If there is a personality and landing pads then point to the language + // specific data area in the exception table. + if (EHFrameInfo.PersonalityIndex) { + Asm->EmitULEB128Bytes(4); + Asm->EOL("Augmentation size"); + + if (EHFrameInfo.hasLandingPads) + EmitReference("exception", EHFrameInfo.Number, true, true); + else + Asm->EmitInt32((int)0); + Asm->EOL("Language Specific Data Area"); + } else { + Asm->EmitULEB128Bytes(0); + Asm->EOL("Augmentation size"); + } + + // Indicate locations of function specific callee saved registers in frame. + EmitFrameMoves("eh_func_begin", EHFrameInfo.Number, EHFrameInfo.Moves, + true); + + // On Darwin the linker honors the alignment of eh_frame, which means it + // must be 8-byte on 64-bit targets to match what gcc does. Otherwise you + // get holes which confuse readers of eh_frame. + Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, + 0, 0, false); + EmitLabel("eh_frame_end", EHFrameInfo.Number); + + // If the function is marked used, this table should be also. We cannot + // make the mark unconditional in this case, since retaining the table also + // retains the function in this case, and there is code around that depends + // on unused functions (calling undefined externals) being dead-stripped to + // link correctly. Yes, there really is. + if (MMI->getUsedFunctions().count(EHFrameInfo.function)) + if (const char *UsedDirective = TAI->getUsedDirective()) + O << UsedDirective << EHFrameInfo.FnName << "\n\n"; + } +} + +/// EmitExceptionTable - Emit landing pads and actions. +/// +/// The general organization of the table is complex, but the basic concepts are +/// easy. First there is a header which describes the location and organization +/// of the three components that follow. +/// +/// 1. The landing pad site information describes the range of code covered by +/// the try. In our case it's an accumulation of the ranges covered by the +/// invokes in the try. There is also a reference to the landing pad that +/// handles the exception once processed. Finally an index into the actions +/// table. +/// 2. The action table, in our case, is composed of pairs of type ids and next +/// action offset. Starting with the action index from the landing pad +/// site, each type Id is checked for a match to the current exception. If +/// it matches then the exception and type id are passed on to the landing +/// pad. Otherwise the next action is looked up. This chain is terminated +/// with a next action of zero. If no type id is found the the frame is +/// unwound and handling continues. +/// 3. Type id table contains references to all the C++ typeinfo for all +/// catches in the function. This tables is reversed indexed base 1. + +/// SharedTypeIds - How many leading type ids two landing pads have in common. +unsigned DwarfException::SharedTypeIds(const LandingPadInfo *L, + const LandingPadInfo *R) { + const std::vector &LIds = L->TypeIds, &RIds = R->TypeIds; + unsigned LSize = LIds.size(), RSize = RIds.size(); + unsigned MinSize = LSize < RSize ? LSize : RSize; + unsigned Count = 0; + + for (; Count != MinSize; ++Count) + if (LIds[Count] != RIds[Count]) + return Count; + + return Count; +} + +/// PadLT - Order landing pads lexicographically by type id. +bool DwarfException::PadLT(const LandingPadInfo *L, const LandingPadInfo *R) { + const std::vector &LIds = L->TypeIds, &RIds = R->TypeIds; + unsigned LSize = LIds.size(), RSize = RIds.size(); + unsigned MinSize = LSize < RSize ? LSize : RSize; + + for (unsigned i = 0; i != MinSize; ++i) + if (LIds[i] != RIds[i]) + return LIds[i] < RIds[i]; + + return LSize < RSize; +} + +void DwarfException::EmitExceptionTable() { + const std::vector &TypeInfos = MMI->getTypeInfos(); + const std::vector &FilterIds = MMI->getFilterIds(); + const std::vector &PadInfos = MMI->getLandingPads(); + if (PadInfos.empty()) return; + + // Sort the landing pads in order of their type ids. This is used to fold + // duplicate actions. + SmallVector LandingPads; + LandingPads.reserve(PadInfos.size()); + for (unsigned i = 0, N = PadInfos.size(); i != N; ++i) + LandingPads.push_back(&PadInfos[i]); + std::sort(LandingPads.begin(), LandingPads.end(), PadLT); + + // Negative type ids index into FilterIds, positive type ids index into + // TypeInfos. The value written for a positive type id is just the type id + // itself. For a negative type id, however, the value written is the + // (negative) byte offset of the corresponding FilterIds entry. The byte + // offset is usually equal to the type id, because the FilterIds entries are + // written using a variable width encoding which outputs one byte per entry as + // long as the value written is not too large, but can differ. This kind of + // complication does not occur for positive type ids because type infos are + // output using a fixed width encoding. FilterOffsets[i] holds the byte + // offset corresponding to FilterIds[i]. + SmallVector FilterOffsets; + FilterOffsets.reserve(FilterIds.size()); + int Offset = -1; + for(std::vector::const_iterator I = FilterIds.begin(), + E = FilterIds.end(); I != E; ++I) { + FilterOffsets.push_back(Offset); + Offset -= TargetAsmInfo::getULEB128Size(*I); + } + + // Compute the actions table and gather the first action index for each + // landing pad site. + SmallVector Actions; + SmallVector FirstActions; + FirstActions.reserve(LandingPads.size()); + + int FirstAction = 0; + unsigned SizeActions = 0; + for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { + const LandingPadInfo *LP = LandingPads[i]; + const std::vector &TypeIds = LP->TypeIds; + const unsigned NumShared = i ? SharedTypeIds(LP, LandingPads[i-1]) : 0; + unsigned SizeSiteActions = 0; + + if (NumShared < TypeIds.size()) { + unsigned SizeAction = 0; + ActionEntry *PrevAction = 0; + + if (NumShared) { + const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size(); + assert(Actions.size()); + PrevAction = &Actions.back(); + SizeAction = TargetAsmInfo::getSLEB128Size(PrevAction->NextAction) + + TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); + + for (unsigned j = NumShared; j != SizePrevIds; ++j) { + SizeAction -= + TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); + SizeAction += -PrevAction->NextAction; + PrevAction = PrevAction->Previous; + } + } + + // Compute the actions. + for (unsigned I = NumShared, M = TypeIds.size(); I != M; ++I) { + int TypeID = TypeIds[I]; + assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!"); + int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID; + unsigned SizeTypeID = TargetAsmInfo::getSLEB128Size(ValueForTypeID); + + int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0; + SizeAction = SizeTypeID + TargetAsmInfo::getSLEB128Size(NextAction); + SizeSiteActions += SizeAction; + + ActionEntry Action = {ValueForTypeID, NextAction, PrevAction}; + Actions.push_back(Action); + + PrevAction = &Actions.back(); + } + + // Record the first action of the landing pad site. + FirstAction = SizeActions + SizeSiteActions - SizeAction + 1; + } // else identical - re-use previous FirstAction + + FirstActions.push_back(FirstAction); + + // Compute this sites contribution to size. + SizeActions += SizeSiteActions; + } + + // Compute the call-site table. The entry for an invoke has a try-range + // containing the call, a non-zero landing pad and an appropriate action. The + // entry for an ordinary call has a try-range containing the call and zero for + // the landing pad and the action. Calls marked 'nounwind' have no entry and + // must not be contained in the try-range of any entry - they form gaps in the + // table. Entries must be ordered by try-range address. + SmallVector CallSites; + + RangeMapType PadMap; + + // Invokes and nounwind calls have entries in PadMap (due to being bracketed + // by try-range labels when lowered). Ordinary calls do not, so appropriate + // try-ranges for them need be deduced. + for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { + const LandingPadInfo *LandingPad = LandingPads[i]; + for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { + unsigned BeginLabel = LandingPad->BeginLabels[j]; + assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); + PadRange P = { i, j }; + PadMap[BeginLabel] = P; + } + } + + // The end label of the previous invoke or nounwind try-range. + unsigned LastLabel = 0; + + // 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; + + // Whether the last callsite entry was for an invoke. + bool PreviousIsInvoke = false; + + // Visit all instructions in order of address. + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); + I != E; ++I) { + for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); + MI != E; ++MI) { + if (!MI->isLabel()) { + SawPotentiallyThrowing |= MI->getDesc().isCall(); + continue; + } + + unsigned BeginLabel = MI->getOperand(0).getImm(); + assert(BeginLabel && "Invalid label!"); + + // End of the previous try-range? + if (BeginLabel == LastLabel) + SawPotentiallyThrowing = false; + + // Beginning of a new try-range? + RangeMapType::iterator L = PadMap.find(BeginLabel); + if (L == PadMap.end()) + // Nope, it was just some random label. + continue; + + PadRange P = L->second; + const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; + + assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && + "Inconsistent landing pad map!"); + + // If some instruction between the previous try-range and this one may + // throw, create a call-site entry with no landing pad for the region + // between the try-ranges. + if (SawPotentiallyThrowing) { + CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0}; + CallSites.push_back(Site); + PreviousIsInvoke = false; + } + + LastLabel = LandingPad->EndLabels[P.RangeIndex]; + assert(BeginLabel && LastLabel && "Invalid landing pad!"); + + if (LandingPad->LandingPadLabel) { + // This try-range is for an invoke. + CallSiteEntry Site = {BeginLabel, LastLabel, + LandingPad->LandingPadLabel, + FirstActions[P.PadIndex]}; + + // Try to merge with the previous call-site. + if (PreviousIsInvoke) { + CallSiteEntry &Prev = CallSites.back(); + if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { + // Extend the range of the previous entry. + Prev.EndLabel = Site.EndLabel; + continue; + } + } + + // Otherwise, create a new call-site. + CallSites.push_back(Site); + PreviousIsInvoke = true; + } else { + // Create a gap. + PreviousIsInvoke = false; + } + } + } + + // If some instruction between the previous try-range and the end of the + // function may throw, create a call-site entry with no landing pad for the + // region following the try-range. + if (SawPotentiallyThrowing) { + CallSiteEntry Site = {LastLabel, 0, 0, 0}; + CallSites.push_back(Site); + } + + // Final tallies. + + // Call sites. + const unsigned SiteStartSize = sizeof(int32_t); // DW_EH_PE_udata4 + const unsigned SiteLengthSize = sizeof(int32_t); // DW_EH_PE_udata4 + const unsigned LandingPadSize = sizeof(int32_t); // DW_EH_PE_udata4 + unsigned SizeSites = CallSites.size() * (SiteStartSize + + SiteLengthSize + + LandingPadSize); + for (unsigned i = 0, e = CallSites.size(); i < e; ++i) + SizeSites += TargetAsmInfo::getULEB128Size(CallSites[i].Action); + + // Type infos. + const unsigned TypeInfoSize = TD->getPointerSize(); // DW_EH_PE_absptr + unsigned SizeTypes = TypeInfos.size() * TypeInfoSize; + + unsigned TypeOffset = sizeof(int8_t) + // Call site format + TargetAsmInfo::getULEB128Size(SizeSites) + // Call-site table length + SizeSites + SizeActions + SizeTypes; + + unsigned TotalSize = sizeof(int8_t) + // LPStart format + sizeof(int8_t) + // TType format + TargetAsmInfo::getULEB128Size(TypeOffset) + // TType base offset + TypeOffset; + + unsigned SizeAlign = (4 - TotalSize) & 3; + + // Begin the exception table. + Asm->SwitchToDataSection(TAI->getDwarfExceptionSection()); + Asm->EmitAlignment(2, 0, 0, false); + O << "GCC_except_table" << SubprogramCount << ":\n"; + + for (unsigned i = 0; i != SizeAlign; ++i) { + Asm->EmitInt8(0); + Asm->EOL("Padding"); + } + + EmitLabel("exception", SubprogramCount); + + // Emit the header. + Asm->EmitInt8(dwarf::DW_EH_PE_omit); + Asm->EOL("LPStart format (DW_EH_PE_omit)"); + Asm->EmitInt8(dwarf::DW_EH_PE_absptr); + Asm->EOL("TType format (DW_EH_PE_absptr)"); + Asm->EmitULEB128Bytes(TypeOffset); + Asm->EOL("TType base offset"); + Asm->EmitInt8(dwarf::DW_EH_PE_udata4); + Asm->EOL("Call site format (DW_EH_PE_udata4)"); + Asm->EmitULEB128Bytes(SizeSites); + Asm->EOL("Call-site table length"); + + // Emit the landing pad site information. + for (unsigned i = 0; i < CallSites.size(); ++i) { + CallSiteEntry &S = CallSites[i]; + const char *BeginTag; + unsigned BeginNumber; + + if (!S.BeginLabel) { + BeginTag = "eh_func_begin"; + BeginNumber = SubprogramCount; + } else { + BeginTag = "label"; + BeginNumber = S.BeginLabel; + } + + EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount, + true, true); + Asm->EOL("Region start"); + + if (!S.EndLabel) + EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber, + true); + else + EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, true); + + Asm->EOL("Region length"); + + if (!S.PadLabel) + Asm->EmitInt32(0); + else + EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount, + true, true); + + Asm->EOL("Landing pad"); + + Asm->EmitULEB128Bytes(S.Action); + Asm->EOL("Action"); + } + + // Emit the actions. + for (unsigned I = 0, N = Actions.size(); I != N; ++I) { + ActionEntry &Action = Actions[I]; + + Asm->EmitSLEB128Bytes(Action.ValueForTypeID); + Asm->EOL("TypeInfo index"); + Asm->EmitSLEB128Bytes(Action.NextAction); + Asm->EOL("Next action"); + } + + // Emit the type ids. + for (unsigned M = TypeInfos.size(); M; --M) { + GlobalVariable *GV = TypeInfos[M - 1]; + PrintRelDirective(); + + if (GV) { + std::string GLN; + O << Asm->getGlobalLinkName(GV, GLN); + } else { + O << "0"; + } + + Asm->EOL("TypeInfo"); + } + + // Emit the filter typeids. + for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) { + unsigned TypeID = FilterIds[j]; + Asm->EmitULEB128Bytes(TypeID); + Asm->EOL("Filter TypeInfo index"); + } + + Asm->EmitAlignment(2, 0, 0, false); +} + + //===--------------------------------------------------------------------===// + // Main entry points. + // +DwarfException::DwarfException(raw_ostream &OS, AsmPrinter *A, + const TargetAsmInfo *T) + : Dwarf(OS, A, T, "eh"), shouldEmitTable(false), shouldEmitMoves(false), + shouldEmitTableModule(false), shouldEmitMovesModule(false), + ExceptionTimer(0) { + if (TimePassesIsEnabled) + ExceptionTimer = new Timer("Dwarf Exception Writer", + getDwarfTimerGroup()); +} + +DwarfException::~DwarfException() { + delete ExceptionTimer; +} + +/// EndModule - Emit all exception information that should come after the +/// content. +void DwarfException::EndModule() { + if (TimePassesIsEnabled) + ExceptionTimer->startTimer(); + + if (shouldEmitMovesModule || shouldEmitTableModule) { + const std::vector Personalities = MMI->getPersonalities(); + for (unsigned i = 0; i < Personalities.size(); ++i) + EmitCommonEHFrame(Personalities[i], i); + + for (std::vector::iterator I = EHFrames.begin(), + E = EHFrames.end(); I != E; ++I) + EmitEHFrame(*I); + } + + if (TimePassesIsEnabled) + ExceptionTimer->stopTimer(); +} + +/// BeginFunction - Gather pre-function exception information. Assumes being +/// emitted immediately after the function entry point. +void DwarfException::BeginFunction(MachineFunction *MF) { + if (TimePassesIsEnabled) + ExceptionTimer->startTimer(); + + this->MF = MF; + shouldEmitTable = shouldEmitMoves = false; + + if (MMI && TAI->doesSupportExceptionHandling()) { + // Map all labels and get rid of any dead landing pads. + MMI->TidyLandingPads(); + + // If any landing pads survive, we need an EH table. + if (MMI->getLandingPads().size()) + shouldEmitTable = true; + + // See if we need frame move info. + if (!MF->getFunction()->doesNotThrow() || UnwindTablesMandatory) + shouldEmitMoves = true; + + if (shouldEmitMoves || shouldEmitTable) + // Assumes in correct section after the entry point. + EmitLabel("eh_func_begin", ++SubprogramCount); + } + + shouldEmitTableModule |= shouldEmitTable; + shouldEmitMovesModule |= shouldEmitMoves; + + if (TimePassesIsEnabled) + ExceptionTimer->stopTimer(); +} + +/// EndFunction - Gather and emit post-function exception information. +/// +void DwarfException::EndFunction() { + if (TimePassesIsEnabled) + ExceptionTimer->startTimer(); + + if (shouldEmitMoves || shouldEmitTable) { + EmitLabel("eh_func_end", SubprogramCount); + EmitExceptionTable(); + + // Save EH frame information + std::string Name; + EHFrames.push_back( + FunctionEHFrameInfo(getAsm()->getCurrentFunctionEHName(MF, Name), + SubprogramCount, + MMI->getPersonalityIndex(), + MF->getFrameInfo()->hasCalls(), + !MMI->getLandingPads().empty(), + MMI->getFrameMoves(), + MF->getFunction())); + } + + if (TimePassesIsEnabled) + ExceptionTimer->stopTimer(); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfException.h b/lib/CodeGen/AsmPrinter/DwarfException.h new file mode 100644 index 00000000000..a5944019d67 --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfException.h @@ -0,0 +1,178 @@ +//===-- DwarfException.h - Dwarf Exception Framework -----------*- 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 dwarf exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#ifndef DWARFEXCEPTION_H__ +#define DWARFEXCEPTION_H__ + +#include "DIE.h" +#include "DwarfPrinter.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/ADT/DenseMap.h" +#include + +namespace llvm { + +struct LandingPadInfo; +class MachineModuleInfo; +class TargetAsmInfo; +class Timer; +class raw_ostream; + +//===----------------------------------------------------------------------===// +/// DwarfException - Emits Dwarf exception handling directives. +/// +class VISIBILITY_HIDDEN DwarfException : public Dwarf { + struct FunctionEHFrameInfo { + std::string FnName; + unsigned Number; + unsigned PersonalityIndex; + bool hasCalls; + bool hasLandingPads; + std::vector Moves; + const Function * function; + + FunctionEHFrameInfo(const std::string &FN, unsigned Num, unsigned P, + bool hC, bool hL, + const std::vector &M, + const Function *f): + FnName(FN), Number(Num), PersonalityIndex(P), + hasCalls(hC), hasLandingPads(hL), Moves(M), function (f) { } + }; + + std::vector EHFrames; + + /// shouldEmitTable - Per-function flag to indicate if EH tables should + /// be emitted. + bool shouldEmitTable; + + /// shouldEmitMoves - Per-function flag to indicate if frame moves info + /// should be emitted. + bool shouldEmitMoves; + + /// shouldEmitTableModule - Per-module flag to indicate if EH tables + /// should be emitted. + bool shouldEmitTableModule; + + /// shouldEmitFrameModule - Per-module flag to indicate if frame moves + /// should be emitted. + bool shouldEmitMovesModule; + + /// ExceptionTimer - Timer for the Dwarf exception writer. + Timer *ExceptionTimer; + + /// EmitCommonEHFrame - Emit the common eh unwind frame. + /// + void EmitCommonEHFrame(const Function *Personality, unsigned Index); + + /// EmitEHFrame - Emit function exception frame information. + /// + void EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo); + + /// EmitExceptionTable - Emit landing pads and actions. + /// + /// The general organization of the table is complex, but the basic concepts + /// are easy. First there is a header which describes the location and + /// organization of the three components that follow. + /// 1. The landing pad site information describes the range of code covered + /// by the try. In our case it's an accumulation of the ranges covered + /// by the invokes in the try. There is also a reference to the landing + /// pad that handles the exception once processed. Finally an index into + /// the actions table. + /// 2. The action table, in our case, is composed of pairs of type ids + /// and next action offset. Starting with the action index from the + /// landing pad site, each type Id is checked for a match to the current + /// exception. If it matches then the exception and type id are passed + /// on to the landing pad. Otherwise the next action is looked up. This + /// chain is terminated with a next action of zero. If no type id is + /// found the the frame is unwound and handling continues. + /// 3. Type id table contains references to all the C++ typeinfo for all + /// catches in the function. This tables is reversed indexed base 1. + + /// SharedTypeIds - How many leading type ids two landing pads have in common. + static unsigned SharedTypeIds(const LandingPadInfo *L, + const LandingPadInfo *R); + + /// PadLT - Order landing pads lexicographically by type id. + static bool PadLT(const LandingPadInfo *L, const LandingPadInfo *R); + + struct KeyInfo { + static inline unsigned getEmptyKey() { return -1U; } + static inline unsigned getTombstoneKey() { return -2U; } + static unsigned getHashValue(const unsigned &Key) { return Key; } + static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; } + static bool isPod() { return true; } + }; + + /// ActionEntry - Structure describing an entry in the actions table. + struct ActionEntry { + int ValueForTypeID; // The value to write - may not be equal to the type id. + int NextAction; + struct ActionEntry *Previous; + }; + + /// PadRange - Structure holding a try-range and the associated landing pad. + struct PadRange { + // The index of the landing pad. + unsigned PadIndex; + // The index of the begin and end labels in the landing pad's label lists. + unsigned RangeIndex; + }; + + typedef DenseMap RangeMapType; + + /// CallSiteEntry - Structure describing an entry in the call-site table. + struct CallSiteEntry { + // The 'try-range' is BeginLabel .. EndLabel. + unsigned BeginLabel; // zero indicates the start of the function. + unsigned EndLabel; // zero indicates the end of the function. + // The landing pad starts at PadLabel. + unsigned PadLabel; // zero indicates that there is no landing pad. + unsigned Action; + }; + + void EmitExceptionTable(); + +public: + //===--------------------------------------------------------------------===// + // Main entry points. + // + DwarfException(raw_ostream &OS, AsmPrinter *A, const TargetAsmInfo *T); + virtual ~DwarfException(); + + /// SetModuleInfo - Set machine module information when it's known that pass + /// manager has created it. Set by the target AsmPrinter. + void SetModuleInfo(MachineModuleInfo *mmi) { + MMI = mmi; + } + + /// BeginModule - Emit all exception information that should come prior to the + /// content. + void BeginModule(Module *M) { + this->M = M; + } + + /// EndModule - Emit all exception information that should come after the + /// content. + void EndModule(); + + /// BeginFunction - Gather pre-function exception information. Assumes being + /// emitted immediately after the function entry point. + void BeginFunction(MachineFunction *MF); + + /// EndFunction - Gather and emit post-function exception information. + void EndFunction(); +}; + +} // End of namespace llvm + +#endif diff --git a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp index 83275fb92eb..71f73a59f57 100644 --- a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp @@ -13,6 +13,7 @@ #include "llvm/CodeGen/DwarfWriter.h" #include "DIE.h" +#include "DwarfException.h" #include "DwarfPrinter.h" #include "llvm/Module.h" #include "llvm/DerivedTypes.h" @@ -68,7 +69,7 @@ static const unsigned InitValuesSetSize = 9; // log2(512) //===----------------------------------------------------------------------===// /// CompileUnit - This dwarf writer support class manages information associate /// with a source file. -class CompileUnit { +class VISIBILITY_HIDDEN CompileUnit { /// ID - File identifier for source. /// unsigned ID; @@ -153,7 +154,7 @@ public: //===----------------------------------------------------------------------===// /// SrcLineInfo - This class is used to record source line correspondence. /// -class SrcLineInfo { +class VISIBILITY_HIDDEN SrcLineInfo { unsigned Line; // Source line number. unsigned Column; // Source column. unsigned SourceID; // Source ID number. @@ -172,7 +173,7 @@ public: //===----------------------------------------------------------------------===// /// DbgVariable - This class is used to track local variable information. /// -class DbgVariable { +class VISIBILITY_HIDDEN DbgVariable { DIVariable Var; // Variable Descriptor. unsigned FrameIndex; // Variable frame index. public: @@ -187,7 +188,7 @@ public: /// DbgScope - This class is used to track scope information. /// class DbgConcreteScope; -class DbgScope { +class VISIBILITY_HIDDEN DbgScope { DbgScope *Parent; // Parent to this scope. DIDescriptor Desc; // Debug info descriptor for scope. // Either subprogram or block. @@ -251,7 +252,7 @@ void DbgScope::dump() const { /// DbgConcreteScope - This class is used to track a scope that holds concrete /// instance information. /// -class DbgConcreteScope : public DbgScope { +class VISIBILITY_HIDDEN DbgConcreteScope : public DbgScope { CompileUnit *Unit; DIE *Die; // Debug info for this concrete scope. public: @@ -274,7 +275,7 @@ DbgScope::~DbgScope() { //===----------------------------------------------------------------------===// /// DwarfDebug - Emits Dwarf debug directives. /// -class DwarfDebug : public Dwarf { +class VISIBILITY_HIDDEN DwarfDebug : public Dwarf { //===--------------------------------------------------------------------===// // Attributes used to construct specific Dwarf sections. // @@ -2813,769 +2814,6 @@ public: } }; -//===----------------------------------------------------------------------===// -/// DwarfException - Emits Dwarf exception handling directives. -/// -class DwarfException : public Dwarf { - struct FunctionEHFrameInfo { - std::string FnName; - unsigned Number; - unsigned PersonalityIndex; - bool hasCalls; - bool hasLandingPads; - std::vector Moves; - const Function * function; - - FunctionEHFrameInfo(const std::string &FN, unsigned Num, unsigned P, - bool hC, bool hL, - const std::vector &M, - const Function *f): - FnName(FN), Number(Num), PersonalityIndex(P), - hasCalls(hC), hasLandingPads(hL), Moves(M), function (f) { } - }; - - std::vector EHFrames; - - /// shouldEmitTable - Per-function flag to indicate if EH tables should - /// be emitted. - bool shouldEmitTable; - - /// shouldEmitMoves - Per-function flag to indicate if frame moves info - /// should be emitted. - bool shouldEmitMoves; - - /// shouldEmitTableModule - Per-module flag to indicate if EH tables - /// should be emitted. - bool shouldEmitTableModule; - - /// shouldEmitFrameModule - Per-module flag to indicate if frame moves - /// should be emitted. - bool shouldEmitMovesModule; - - /// ExceptionTimer - Timer for the Dwarf exception writer. - Timer *ExceptionTimer; - - /// EmitCommonEHFrame - Emit the common eh unwind frame. - /// - void EmitCommonEHFrame(const Function *Personality, unsigned Index) { - // Size and sign of stack growth. - int stackGrowth = - Asm->TM.getFrameInfo()->getStackGrowthDirection() == - TargetFrameInfo::StackGrowsUp ? - TD->getPointerSize() : -TD->getPointerSize(); - - // Begin eh frame section. - Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection()); - - if (!TAI->doesRequireNonLocalEHFrameLabel()) - O << TAI->getEHGlobalPrefix(); - O << "EH_frame" << Index << ":\n"; - EmitLabel("section_eh_frame", Index); - - // Define base labels. - EmitLabel("eh_frame_common", Index); - - // Define the eh frame length. - EmitDifference("eh_frame_common_end", Index, - "eh_frame_common_begin", Index, true); - Asm->EOL("Length of Common Information Entry"); - - // EH frame header. - EmitLabel("eh_frame_common_begin", Index); - Asm->EmitInt32((int)0); - Asm->EOL("CIE Identifier Tag"); - Asm->EmitInt8(DW_CIE_VERSION); - Asm->EOL("CIE Version"); - - // The personality presence indicates that language specific information - // will show up in the eh frame. - Asm->EmitString(Personality ? "zPLR" : "zR"); - Asm->EOL("CIE Augmentation"); - - // Round out reader. - Asm->EmitULEB128Bytes(1); - Asm->EOL("CIE Code Alignment Factor"); - Asm->EmitSLEB128Bytes(stackGrowth); - Asm->EOL("CIE Data Alignment Factor"); - Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true)); - Asm->EOL("CIE Return Address Column"); - - // If there is a personality, we need to indicate the functions location. - if (Personality) { - Asm->EmitULEB128Bytes(7); - Asm->EOL("Augmentation Size"); - - if (TAI->getNeedsIndirectEncoding()) { - Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect); - Asm->EOL("Personality (pcrel sdata4 indirect)"); - } else { - Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); - Asm->EOL("Personality (pcrel sdata4)"); - } - - PrintRelDirective(true); - O << TAI->getPersonalityPrefix(); - Asm->EmitExternalGlobal((const GlobalVariable *)(Personality)); - O << TAI->getPersonalitySuffix(); - if (strcmp(TAI->getPersonalitySuffix(), "+4@GOTPCREL")) - O << "-" << TAI->getPCSymbol(); - Asm->EOL("Personality"); - - Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); - Asm->EOL("LSDA Encoding (pcrel sdata4)"); - - Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); - Asm->EOL("FDE Encoding (pcrel sdata4)"); - } else { - Asm->EmitULEB128Bytes(1); - Asm->EOL("Augmentation Size"); - - Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); - Asm->EOL("FDE Encoding (pcrel sdata4)"); - } - - // Indicate locations of general callee saved registers in frame. - std::vector Moves; - RI->getInitialFrameState(Moves); - EmitFrameMoves(NULL, 0, Moves, true); - - // On Darwin the linker honors the alignment of eh_frame, which means it - // must be 8-byte on 64-bit targets to match what gcc does. Otherwise - // you get holes which confuse readers of eh_frame. - Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, - 0, 0, false); - EmitLabel("eh_frame_common_end", Index); - - Asm->EOL(); - } - - /// EmitEHFrame - Emit function exception frame information. - /// - void EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo) { - Function::LinkageTypes linkage = EHFrameInfo.function->getLinkage(); - - assert(!EHFrameInfo.function->hasAvailableExternallyLinkage() && - "Should not emit 'available externally' functions at all"); - - Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection()); - - // Externally visible entry into the functions eh frame info. - // If the corresponding function is static, this should not be - // externally visible. - if (linkage != Function::InternalLinkage && - linkage != Function::PrivateLinkage) { - if (const char *GlobalEHDirective = TAI->getGlobalEHDirective()) - O << GlobalEHDirective << EHFrameInfo.FnName << "\n"; - } - - // If corresponding function is weak definition, this should be too. - if ((linkage == Function::WeakAnyLinkage || - linkage == Function::WeakODRLinkage || - linkage == Function::LinkOnceAnyLinkage || - linkage == Function::LinkOnceODRLinkage) && - TAI->getWeakDefDirective()) - O << TAI->getWeakDefDirective() << EHFrameInfo.FnName << "\n"; - - // If there are no calls then you can't unwind. This may mean we can - // omit the EH Frame, but some environments do not handle weak absolute - // symbols. - // If UnwindTablesMandatory is set we cannot do this optimization; the - // unwind info is to be available for non-EH uses. - if (!EHFrameInfo.hasCalls && - !UnwindTablesMandatory && - ((linkage != Function::WeakAnyLinkage && - linkage != Function::WeakODRLinkage && - linkage != Function::LinkOnceAnyLinkage && - linkage != Function::LinkOnceODRLinkage) || - !TAI->getWeakDefDirective() || - TAI->getSupportsWeakOmittedEHFrame())) - { - O << EHFrameInfo.FnName << " = 0\n"; - // This name has no connection to the function, so it might get - // dead-stripped when the function is not, erroneously. Prohibit - // dead-stripping unconditionally. - if (const char *UsedDirective = TAI->getUsedDirective()) - O << UsedDirective << EHFrameInfo.FnName << "\n\n"; - } else { - O << EHFrameInfo.FnName << ":\n"; - - // EH frame header. - EmitDifference("eh_frame_end", EHFrameInfo.Number, - "eh_frame_begin", EHFrameInfo.Number, true); - Asm->EOL("Length of Frame Information Entry"); - - EmitLabel("eh_frame_begin", EHFrameInfo.Number); - - if (TAI->doesRequireNonLocalEHFrameLabel()) { - PrintRelDirective(true, true); - PrintLabelName("eh_frame_begin", EHFrameInfo.Number); - - if (!TAI->isAbsoluteEHSectionOffsets()) - O << "-EH_frame" << EHFrameInfo.PersonalityIndex; - } else { - EmitSectionOffset("eh_frame_begin", "eh_frame_common", - EHFrameInfo.Number, EHFrameInfo.PersonalityIndex, - true, true, false); - } - - Asm->EOL("FDE CIE offset"); - - EmitReference("eh_func_begin", EHFrameInfo.Number, true, true); - Asm->EOL("FDE initial location"); - EmitDifference("eh_func_end", EHFrameInfo.Number, - "eh_func_begin", EHFrameInfo.Number, true); - Asm->EOL("FDE address range"); - - // If there is a personality and landing pads then point to the language - // specific data area in the exception table. - if (EHFrameInfo.PersonalityIndex) { - Asm->EmitULEB128Bytes(4); - Asm->EOL("Augmentation size"); - - if (EHFrameInfo.hasLandingPads) - EmitReference("exception", EHFrameInfo.Number, true, true); - else - Asm->EmitInt32((int)0); - Asm->EOL("Language Specific Data Area"); - } else { - Asm->EmitULEB128Bytes(0); - Asm->EOL("Augmentation size"); - } - - // Indicate locations of function specific callee saved registers in - // frame. - EmitFrameMoves("eh_func_begin", EHFrameInfo.Number, EHFrameInfo.Moves, - true); - - // On Darwin the linker honors the alignment of eh_frame, which means it - // must be 8-byte on 64-bit targets to match what gcc does. Otherwise - // you get holes which confuse readers of eh_frame. - Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, - 0, 0, false); - EmitLabel("eh_frame_end", EHFrameInfo.Number); - - // If the function is marked used, this table should be also. We cannot - // make the mark unconditional in this case, since retaining the table - // also retains the function in this case, and there is code around - // that depends on unused functions (calling undefined externals) being - // dead-stripped to link correctly. Yes, there really is. - if (MMI->getUsedFunctions().count(EHFrameInfo.function)) - if (const char *UsedDirective = TAI->getUsedDirective()) - O << UsedDirective << EHFrameInfo.FnName << "\n\n"; - } - } - - /// EmitExceptionTable - Emit landing pads and actions. - /// - /// The general organization of the table is complex, but the basic concepts - /// are easy. First there is a header which describes the location and - /// organization of the three components that follow. - /// 1. The landing pad site information describes the range of code covered - /// by the try. In our case it's an accumulation of the ranges covered - /// by the invokes in the try. There is also a reference to the landing - /// pad that handles the exception once processed. Finally an index into - /// the actions table. - /// 2. The action table, in our case, is composed of pairs of type ids - /// and next action offset. Starting with the action index from the - /// landing pad site, each type Id is checked for a match to the current - /// exception. If it matches then the exception and type id are passed - /// on to the landing pad. Otherwise the next action is looked up. This - /// chain is terminated with a next action of zero. If no type id is - /// found the the frame is unwound and handling continues. - /// 3. Type id table contains references to all the C++ typeinfo for all - /// catches in the function. This tables is reversed indexed base 1. - - /// SharedTypeIds - How many leading type ids two landing pads have in common. - static unsigned SharedTypeIds(const LandingPadInfo *L, - const LandingPadInfo *R) { - const std::vector &LIds = L->TypeIds, &RIds = R->TypeIds; - unsigned LSize = LIds.size(), RSize = RIds.size(); - unsigned MinSize = LSize < RSize ? LSize : RSize; - unsigned Count = 0; - - for (; Count != MinSize; ++Count) - if (LIds[Count] != RIds[Count]) - return Count; - - return Count; - } - - /// PadLT - Order landing pads lexicographically by type id. - static bool PadLT(const LandingPadInfo *L, const LandingPadInfo *R) { - const std::vector &LIds = L->TypeIds, &RIds = R->TypeIds; - unsigned LSize = LIds.size(), RSize = RIds.size(); - unsigned MinSize = LSize < RSize ? LSize : RSize; - - for (unsigned i = 0; i != MinSize; ++i) - if (LIds[i] != RIds[i]) - return LIds[i] < RIds[i]; - - return LSize < RSize; - } - - struct KeyInfo { - static inline unsigned getEmptyKey() { return -1U; } - static inline unsigned getTombstoneKey() { return -2U; } - static unsigned getHashValue(const unsigned &Key) { return Key; } - static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; } - static bool isPod() { return true; } - }; - - /// ActionEntry - Structure describing an entry in the actions table. - struct ActionEntry { - int ValueForTypeID; // The value to write - may not be equal to the type id. - int NextAction; - struct ActionEntry *Previous; - }; - - /// PadRange - Structure holding a try-range and the associated landing pad. - struct PadRange { - // The index of the landing pad. - unsigned PadIndex; - // The index of the begin and end labels in the landing pad's label lists. - unsigned RangeIndex; - }; - - typedef DenseMap RangeMapType; - - /// CallSiteEntry - Structure describing an entry in the call-site table. - struct CallSiteEntry { - // The 'try-range' is BeginLabel .. EndLabel. - unsigned BeginLabel; // zero indicates the start of the function. - unsigned EndLabel; // zero indicates the end of the function. - // The landing pad starts at PadLabel. - unsigned PadLabel; // zero indicates that there is no landing pad. - unsigned Action; - }; - - void EmitExceptionTable() { - const std::vector &TypeInfos = MMI->getTypeInfos(); - const std::vector &FilterIds = MMI->getFilterIds(); - const std::vector &PadInfos = MMI->getLandingPads(); - if (PadInfos.empty()) return; - - // Sort the landing pads in order of their type ids. This is used to fold - // duplicate actions. - SmallVector LandingPads; - LandingPads.reserve(PadInfos.size()); - for (unsigned i = 0, N = PadInfos.size(); i != N; ++i) - LandingPads.push_back(&PadInfos[i]); - std::sort(LandingPads.begin(), LandingPads.end(), PadLT); - - // Negative type ids index into FilterIds, positive type ids index into - // TypeInfos. The value written for a positive type id is just the type - // id itself. For a negative type id, however, the value written is the - // (negative) byte offset of the corresponding FilterIds entry. The byte - // offset is usually equal to the type id, because the FilterIds entries - // are written using a variable width encoding which outputs one byte per - // entry as long as the value written is not too large, but can differ. - // This kind of complication does not occur for positive type ids because - // type infos are output using a fixed width encoding. - // FilterOffsets[i] holds the byte offset corresponding to FilterIds[i]. - SmallVector FilterOffsets; - FilterOffsets.reserve(FilterIds.size()); - int Offset = -1; - for(std::vector::const_iterator I = FilterIds.begin(), - E = FilterIds.end(); I != E; ++I) { - FilterOffsets.push_back(Offset); - Offset -= TargetAsmInfo::getULEB128Size(*I); - } - - // Compute the actions table and gather the first action index for each - // landing pad site. - SmallVector Actions; - SmallVector FirstActions; - FirstActions.reserve(LandingPads.size()); - - int FirstAction = 0; - unsigned SizeActions = 0; - for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { - const LandingPadInfo *LP = LandingPads[i]; - const std::vector &TypeIds = LP->TypeIds; - const unsigned NumShared = i ? SharedTypeIds(LP, LandingPads[i-1]) : 0; - unsigned SizeSiteActions = 0; - - if (NumShared < TypeIds.size()) { - unsigned SizeAction = 0; - ActionEntry *PrevAction = 0; - - if (NumShared) { - const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size(); - assert(Actions.size()); - PrevAction = &Actions.back(); - SizeAction = TargetAsmInfo::getSLEB128Size(PrevAction->NextAction) + - TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); - for (unsigned j = NumShared; j != SizePrevIds; ++j) { - SizeAction -= - TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); - SizeAction += -PrevAction->NextAction; - PrevAction = PrevAction->Previous; - } - } - - // Compute the actions. - for (unsigned I = NumShared, M = TypeIds.size(); I != M; ++I) { - int TypeID = TypeIds[I]; - assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!"); - int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID; - unsigned SizeTypeID = TargetAsmInfo::getSLEB128Size(ValueForTypeID); - - int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0; - SizeAction = SizeTypeID + TargetAsmInfo::getSLEB128Size(NextAction); - SizeSiteActions += SizeAction; - - ActionEntry Action = {ValueForTypeID, NextAction, PrevAction}; - Actions.push_back(Action); - - PrevAction = &Actions.back(); - } - - // Record the first action of the landing pad site. - FirstAction = SizeActions + SizeSiteActions - SizeAction + 1; - } // else identical - re-use previous FirstAction - - FirstActions.push_back(FirstAction); - - // Compute this sites contribution to size. - SizeActions += SizeSiteActions; - } - - // Compute the call-site table. The entry for an invoke has a try-range - // containing the call, a non-zero landing pad and an appropriate action. - // The entry for an ordinary call has a try-range containing the call and - // zero for the landing pad and the action. Calls marked 'nounwind' have - // no entry and must not be contained in the try-range of any entry - they - // form gaps in the table. Entries must be ordered by try-range address. - SmallVector CallSites; - - RangeMapType PadMap; - // Invokes and nounwind calls have entries in PadMap (due to being bracketed - // by try-range labels when lowered). Ordinary calls do not, so appropriate - // try-ranges for them need be deduced. - for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { - const LandingPadInfo *LandingPad = LandingPads[i]; - for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { - unsigned BeginLabel = LandingPad->BeginLabels[j]; - assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); - PadRange P = { i, j }; - PadMap[BeginLabel] = P; - } - } - - // The end label of the previous invoke or nounwind try-range. - unsigned LastLabel = 0; - - // 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; - - // Whether the last callsite entry was for an invoke. - bool PreviousIsInvoke = false; - - // Visit all instructions in order of address. - for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); - I != E; ++I) { - for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); - MI != E; ++MI) { - if (!MI->isLabel()) { - SawPotentiallyThrowing |= MI->getDesc().isCall(); - continue; - } - - unsigned BeginLabel = MI->getOperand(0).getImm(); - assert(BeginLabel && "Invalid label!"); - - // End of the previous try-range? - if (BeginLabel == LastLabel) - SawPotentiallyThrowing = false; - - // Beginning of a new try-range? - RangeMapType::iterator L = PadMap.find(BeginLabel); - if (L == PadMap.end()) - // Nope, it was just some random label. - continue; - - PadRange P = L->second; - const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; - - assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && - "Inconsistent landing pad map!"); - - // If some instruction between the previous try-range and this one may - // throw, create a call-site entry with no landing pad for the region - // between the try-ranges. - if (SawPotentiallyThrowing) { - CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0}; - CallSites.push_back(Site); - PreviousIsInvoke = false; - } - - LastLabel = LandingPad->EndLabels[P.RangeIndex]; - assert(BeginLabel && LastLabel && "Invalid landing pad!"); - - if (LandingPad->LandingPadLabel) { - // This try-range is for an invoke. - CallSiteEntry Site = {BeginLabel, LastLabel, - LandingPad->LandingPadLabel, FirstActions[P.PadIndex]}; - - // Try to merge with the previous call-site. - if (PreviousIsInvoke) { - CallSiteEntry &Prev = CallSites.back(); - if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { - // Extend the range of the previous entry. - Prev.EndLabel = Site.EndLabel; - continue; - } - } - - // Otherwise, create a new call-site. - CallSites.push_back(Site); - PreviousIsInvoke = true; - } else { - // Create a gap. - PreviousIsInvoke = false; - } - } - } - // If some instruction between the previous try-range and the end of the - // function may throw, create a call-site entry with no landing pad for the - // region following the try-range. - if (SawPotentiallyThrowing) { - CallSiteEntry Site = {LastLabel, 0, 0, 0}; - CallSites.push_back(Site); - } - - // Final tallies. - - // Call sites. - const unsigned SiteStartSize = sizeof(int32_t); // DW_EH_PE_udata4 - const unsigned SiteLengthSize = sizeof(int32_t); // DW_EH_PE_udata4 - const unsigned LandingPadSize = sizeof(int32_t); // DW_EH_PE_udata4 - unsigned SizeSites = CallSites.size() * (SiteStartSize + - SiteLengthSize + - LandingPadSize); - for (unsigned i = 0, e = CallSites.size(); i < e; ++i) - SizeSites += TargetAsmInfo::getULEB128Size(CallSites[i].Action); - - // Type infos. - const unsigned TypeInfoSize = TD->getPointerSize(); // DW_EH_PE_absptr - unsigned SizeTypes = TypeInfos.size() * TypeInfoSize; - - unsigned TypeOffset = sizeof(int8_t) + // Call site format - TargetAsmInfo::getULEB128Size(SizeSites) + // Call-site table length - SizeSites + SizeActions + SizeTypes; - - unsigned TotalSize = sizeof(int8_t) + // LPStart format - sizeof(int8_t) + // TType format - TargetAsmInfo::getULEB128Size(TypeOffset) + // TType base offset - TypeOffset; - - unsigned SizeAlign = (4 - TotalSize) & 3; - - // Begin the exception table. - Asm->SwitchToDataSection(TAI->getDwarfExceptionSection()); - Asm->EmitAlignment(2, 0, 0, false); - O << "GCC_except_table" << SubprogramCount << ":\n"; - for (unsigned i = 0; i != SizeAlign; ++i) { - Asm->EmitInt8(0); - Asm->EOL("Padding"); - } - EmitLabel("exception", SubprogramCount); - - // Emit the header. - Asm->EmitInt8(DW_EH_PE_omit); - Asm->EOL("LPStart format (DW_EH_PE_omit)"); - Asm->EmitInt8(DW_EH_PE_absptr); - Asm->EOL("TType format (DW_EH_PE_absptr)"); - Asm->EmitULEB128Bytes(TypeOffset); - Asm->EOL("TType base offset"); - Asm->EmitInt8(DW_EH_PE_udata4); - Asm->EOL("Call site format (DW_EH_PE_udata4)"); - Asm->EmitULEB128Bytes(SizeSites); - Asm->EOL("Call-site table length"); - - // Emit the landing pad site information. - for (unsigned i = 0; i < CallSites.size(); ++i) { - CallSiteEntry &S = CallSites[i]; - const char *BeginTag; - unsigned BeginNumber; - - if (!S.BeginLabel) { - BeginTag = "eh_func_begin"; - BeginNumber = SubprogramCount; - } else { - BeginTag = "label"; - BeginNumber = S.BeginLabel; - } - - EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount, - true, true); - Asm->EOL("Region start"); - - if (!S.EndLabel) { - EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber, - true); - } else { - EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, true); - } - Asm->EOL("Region length"); - - if (!S.PadLabel) - Asm->EmitInt32(0); - else - EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount, - true, true); - Asm->EOL("Landing pad"); - - Asm->EmitULEB128Bytes(S.Action); - Asm->EOL("Action"); - } - - // Emit the actions. - for (unsigned I = 0, N = Actions.size(); I != N; ++I) { - ActionEntry &Action = Actions[I]; - - Asm->EmitSLEB128Bytes(Action.ValueForTypeID); - Asm->EOL("TypeInfo index"); - Asm->EmitSLEB128Bytes(Action.NextAction); - Asm->EOL("Next action"); - } - - // Emit the type ids. - for (unsigned M = TypeInfos.size(); M; --M) { - GlobalVariable *GV = TypeInfos[M - 1]; - - PrintRelDirective(); - - if (GV) { - std::string GLN; - O << Asm->getGlobalLinkName(GV, GLN); - } else { - O << "0"; - } - - Asm->EOL("TypeInfo"); - } - - // Emit the filter typeids. - for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) { - unsigned TypeID = FilterIds[j]; - Asm->EmitULEB128Bytes(TypeID); - Asm->EOL("Filter TypeInfo index"); - } - - Asm->EmitAlignment(2, 0, 0, false); - } - -public: - //===--------------------------------------------------------------------===// - // Main entry points. - // - DwarfException(raw_ostream &OS, AsmPrinter *A, const TargetAsmInfo *T) - : Dwarf(OS, A, T, "eh"), shouldEmitTable(false), shouldEmitMoves(false), - shouldEmitTableModule(false), shouldEmitMovesModule(false), - ExceptionTimer(0) { - if (TimePassesIsEnabled) - ExceptionTimer = new Timer("Dwarf Exception Writer", - getDwarfTimerGroup()); - } - - virtual ~DwarfException() { - delete ExceptionTimer; - } - - /// SetModuleInfo - Set machine module information when it's known that pass - /// manager has created it. Set by the target AsmPrinter. - void SetModuleInfo(MachineModuleInfo *mmi) { - MMI = mmi; - } - - /// BeginModule - Emit all exception information that should come prior to the - /// content. - void BeginModule(Module *M) { - this->M = M; - } - - /// EndModule - Emit all exception information that should come after the - /// content. - void EndModule() { - if (TimePassesIsEnabled) - ExceptionTimer->startTimer(); - - if (shouldEmitMovesModule || shouldEmitTableModule) { - const std::vector Personalities = MMI->getPersonalities(); - for (unsigned i = 0; i < Personalities.size(); ++i) - EmitCommonEHFrame(Personalities[i], i); - - for (std::vector::iterator I = EHFrames.begin(), - E = EHFrames.end(); I != E; ++I) - EmitEHFrame(*I); - } - - if (TimePassesIsEnabled) - ExceptionTimer->stopTimer(); - } - - /// BeginFunction - Gather pre-function exception information. Assumes being - /// emitted immediately after the function entry point. - void BeginFunction(MachineFunction *MF) { - if (TimePassesIsEnabled) - ExceptionTimer->startTimer(); - - this->MF = MF; - shouldEmitTable = shouldEmitMoves = false; - - if (MMI && TAI->doesSupportExceptionHandling()) { - // Map all labels and get rid of any dead landing pads. - MMI->TidyLandingPads(); - - // If any landing pads survive, we need an EH table. - if (MMI->getLandingPads().size()) - shouldEmitTable = true; - - // See if we need frame move info. - if (!MF->getFunction()->doesNotThrow() || UnwindTablesMandatory) - shouldEmitMoves = true; - - if (shouldEmitMoves || shouldEmitTable) - // Assumes in correct section after the entry point. - EmitLabel("eh_func_begin", ++SubprogramCount); - } - - shouldEmitTableModule |= shouldEmitTable; - shouldEmitMovesModule |= shouldEmitMoves; - - if (TimePassesIsEnabled) - ExceptionTimer->stopTimer(); - } - - /// EndFunction - Gather and emit post-function exception information. - /// - void EndFunction() { - if (TimePassesIsEnabled) - ExceptionTimer->startTimer(); - - if (shouldEmitMoves || shouldEmitTable) { - EmitLabel("eh_func_end", SubprogramCount); - EmitExceptionTable(); - - // Save EH frame information - std::string Name; - EHFrames.push_back( - FunctionEHFrameInfo(getAsm()->getCurrentFunctionEHName(MF, Name), - SubprogramCount, - MMI->getPersonalityIndex(), - MF->getFrameInfo()->hasCalls(), - !MMI->getLandingPads().empty(), - MMI->getFrameMoves(), - MF->getFunction())); - } - - if (TimePassesIsEnabled) - ExceptionTimer->stopTimer(); - } -}; - } // End of namespace llvm //===----------------------------------------------------------------------===//