109467b48Spatrick //===- CodeGen/AsmPrinter/EHStreamer.cpp - Exception Directive Streamer ---===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file contains support for writing exception info into assembly files.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick
1309467b48Spatrick #include "EHStreamer.h"
1409467b48Spatrick #include "llvm/ADT/SmallVector.h"
1509467b48Spatrick #include "llvm/ADT/Twine.h"
1609467b48Spatrick #include "llvm/ADT/iterator_range.h"
1709467b48Spatrick #include "llvm/BinaryFormat/Dwarf.h"
1809467b48Spatrick #include "llvm/CodeGen/AsmPrinter.h"
1909467b48Spatrick #include "llvm/CodeGen/MachineFunction.h"
2009467b48Spatrick #include "llvm/CodeGen/MachineInstr.h"
2109467b48Spatrick #include "llvm/CodeGen/MachineOperand.h"
2209467b48Spatrick #include "llvm/IR/Function.h"
2309467b48Spatrick #include "llvm/MC/MCAsmInfo.h"
2409467b48Spatrick #include "llvm/MC/MCContext.h"
2509467b48Spatrick #include "llvm/MC/MCStreamer.h"
2609467b48Spatrick #include "llvm/MC/MCSymbol.h"
2709467b48Spatrick #include "llvm/MC/MCTargetOptions.h"
2809467b48Spatrick #include "llvm/Support/Casting.h"
2909467b48Spatrick #include "llvm/Support/LEB128.h"
3009467b48Spatrick #include "llvm/Target/TargetLoweringObjectFile.h"
3109467b48Spatrick #include <algorithm>
3209467b48Spatrick #include <cassert>
3309467b48Spatrick #include <cstdint>
3409467b48Spatrick #include <vector>
3509467b48Spatrick
3609467b48Spatrick using namespace llvm;
3709467b48Spatrick
EHStreamer(AsmPrinter * A)3809467b48Spatrick EHStreamer::EHStreamer(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {}
3909467b48Spatrick
4009467b48Spatrick EHStreamer::~EHStreamer() = default;
4109467b48Spatrick
4209467b48Spatrick /// How many leading type ids two landing pads have in common.
sharedTypeIDs(const LandingPadInfo * L,const LandingPadInfo * R)4309467b48Spatrick unsigned EHStreamer::sharedTypeIDs(const LandingPadInfo *L,
4409467b48Spatrick const LandingPadInfo *R) {
4509467b48Spatrick const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds;
4673471bf0Spatrick return std::mismatch(LIds.begin(), LIds.end(), RIds.begin(), RIds.end())
4773471bf0Spatrick .first -
4873471bf0Spatrick LIds.begin();
4909467b48Spatrick }
5009467b48Spatrick
5109467b48Spatrick /// Compute the actions table and gather the first action index for each landing
5209467b48Spatrick /// pad site.
computeActionsTable(const SmallVectorImpl<const LandingPadInfo * > & LandingPads,SmallVectorImpl<ActionEntry> & Actions,SmallVectorImpl<unsigned> & FirstActions)5309467b48Spatrick void EHStreamer::computeActionsTable(
5409467b48Spatrick const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
5509467b48Spatrick SmallVectorImpl<ActionEntry> &Actions,
5609467b48Spatrick SmallVectorImpl<unsigned> &FirstActions) {
5709467b48Spatrick // The action table follows the call-site table in the LSDA. The individual
5809467b48Spatrick // records are of two types:
5909467b48Spatrick //
6009467b48Spatrick // * Catch clause
6109467b48Spatrick // * Exception specification
6209467b48Spatrick //
6309467b48Spatrick // The two record kinds have the same format, with only small differences.
6409467b48Spatrick // They are distinguished by the "switch value" field: Catch clauses
6509467b48Spatrick // (TypeInfos) have strictly positive switch values, and exception
6609467b48Spatrick // specifications (FilterIds) have strictly negative switch values. Value 0
6709467b48Spatrick // indicates a catch-all clause.
6809467b48Spatrick //
6909467b48Spatrick // Negative type IDs index into FilterIds. Positive type IDs index into
7009467b48Spatrick // TypeInfos. The value written for a positive type ID is just the type ID
7109467b48Spatrick // itself. For a negative type ID, however, the value written is the
7209467b48Spatrick // (negative) byte offset of the corresponding FilterIds entry. The byte
7309467b48Spatrick // offset is usually equal to the type ID (because the FilterIds entries are
7409467b48Spatrick // written using a variable width encoding, which outputs one byte per entry
7509467b48Spatrick // as long as the value written is not too large) but can differ. This kind
7609467b48Spatrick // of complication does not occur for positive type IDs because type infos are
7709467b48Spatrick // output using a fixed width encoding. FilterOffsets[i] holds the byte
7809467b48Spatrick // offset corresponding to FilterIds[i].
7909467b48Spatrick
8009467b48Spatrick const std::vector<unsigned> &FilterIds = Asm->MF->getFilterIds();
8109467b48Spatrick SmallVector<int, 16> FilterOffsets;
8209467b48Spatrick FilterOffsets.reserve(FilterIds.size());
8309467b48Spatrick int Offset = -1;
8409467b48Spatrick
8573471bf0Spatrick for (unsigned FilterId : FilterIds) {
8609467b48Spatrick FilterOffsets.push_back(Offset);
8773471bf0Spatrick Offset -= getULEB128Size(FilterId);
8809467b48Spatrick }
8909467b48Spatrick
9009467b48Spatrick FirstActions.reserve(LandingPads.size());
9109467b48Spatrick
9209467b48Spatrick int FirstAction = 0;
9309467b48Spatrick unsigned SizeActions = 0; // Total size of all action entries for a function
9409467b48Spatrick const LandingPadInfo *PrevLPI = nullptr;
9509467b48Spatrick
9673471bf0Spatrick for (const LandingPadInfo *LPI : LandingPads) {
9709467b48Spatrick const std::vector<int> &TypeIds = LPI->TypeIds;
9809467b48Spatrick unsigned NumShared = PrevLPI ? sharedTypeIDs(LPI, PrevLPI) : 0;
9909467b48Spatrick unsigned SizeSiteActions = 0; // Total size of all entries for a landingpad
10009467b48Spatrick
10109467b48Spatrick if (NumShared < TypeIds.size()) {
10209467b48Spatrick // Size of one action entry (typeid + next action)
10309467b48Spatrick unsigned SizeActionEntry = 0;
10409467b48Spatrick unsigned PrevAction = (unsigned)-1;
10509467b48Spatrick
10609467b48Spatrick if (NumShared) {
10709467b48Spatrick unsigned SizePrevIds = PrevLPI->TypeIds.size();
10809467b48Spatrick assert(Actions.size());
10909467b48Spatrick PrevAction = Actions.size() - 1;
11009467b48Spatrick SizeActionEntry = getSLEB128Size(Actions[PrevAction].NextAction) +
11109467b48Spatrick getSLEB128Size(Actions[PrevAction].ValueForTypeID);
11209467b48Spatrick
11309467b48Spatrick for (unsigned j = NumShared; j != SizePrevIds; ++j) {
11409467b48Spatrick assert(PrevAction != (unsigned)-1 && "PrevAction is invalid!");
11509467b48Spatrick SizeActionEntry -= getSLEB128Size(Actions[PrevAction].ValueForTypeID);
11609467b48Spatrick SizeActionEntry += -Actions[PrevAction].NextAction;
11709467b48Spatrick PrevAction = Actions[PrevAction].Previous;
11809467b48Spatrick }
11909467b48Spatrick }
12009467b48Spatrick
12109467b48Spatrick // Compute the actions.
12209467b48Spatrick for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) {
12309467b48Spatrick int TypeID = TypeIds[J];
12409467b48Spatrick assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
12509467b48Spatrick int ValueForTypeID =
12609467b48Spatrick isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID;
12709467b48Spatrick unsigned SizeTypeID = getSLEB128Size(ValueForTypeID);
12809467b48Spatrick
12909467b48Spatrick int NextAction = SizeActionEntry ? -(SizeActionEntry + SizeTypeID) : 0;
13009467b48Spatrick SizeActionEntry = SizeTypeID + getSLEB128Size(NextAction);
13109467b48Spatrick SizeSiteActions += SizeActionEntry;
13209467b48Spatrick
13309467b48Spatrick ActionEntry Action = { ValueForTypeID, NextAction, PrevAction };
13409467b48Spatrick Actions.push_back(Action);
13509467b48Spatrick PrevAction = Actions.size() - 1;
13609467b48Spatrick }
13709467b48Spatrick
13809467b48Spatrick // Record the first action of the landing pad site.
13909467b48Spatrick FirstAction = SizeActions + SizeSiteActions - SizeActionEntry + 1;
14009467b48Spatrick } // else identical - re-use previous FirstAction
14109467b48Spatrick
14209467b48Spatrick // Information used when creating the call-site table. The action record
14309467b48Spatrick // field of the call site record is the offset of the first associated
14409467b48Spatrick // action record, relative to the start of the actions table. This value is
14509467b48Spatrick // biased by 1 (1 indicating the start of the actions table), and 0
14609467b48Spatrick // indicates that there are no actions.
14709467b48Spatrick FirstActions.push_back(FirstAction);
14809467b48Spatrick
14909467b48Spatrick // Compute this sites contribution to size.
15009467b48Spatrick SizeActions += SizeSiteActions;
15109467b48Spatrick
15209467b48Spatrick PrevLPI = LPI;
15309467b48Spatrick }
15409467b48Spatrick }
15509467b48Spatrick
15609467b48Spatrick /// Return `true' if this is a call to a function marked `nounwind'. Return
15709467b48Spatrick /// `false' otherwise.
callToNoUnwindFunction(const MachineInstr * MI)15809467b48Spatrick bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) {
15909467b48Spatrick assert(MI->isCall() && "This should be a call instruction!");
16009467b48Spatrick
16109467b48Spatrick bool MarkedNoUnwind = false;
16209467b48Spatrick bool SawFunc = false;
16309467b48Spatrick
164*d415bd75Srobert for (const MachineOperand &MO : MI->operands()) {
16509467b48Spatrick if (!MO.isGlobal()) continue;
16609467b48Spatrick
16709467b48Spatrick const Function *F = dyn_cast<Function>(MO.getGlobal());
16809467b48Spatrick if (!F) continue;
16909467b48Spatrick
17009467b48Spatrick if (SawFunc) {
17109467b48Spatrick // Be conservative. If we have more than one function operand for this
17209467b48Spatrick // call, then we can't make the assumption that it's the callee and
17309467b48Spatrick // not a parameter to the call.
17409467b48Spatrick //
17509467b48Spatrick // FIXME: Determine if there's a way to say that `F' is the callee or
17609467b48Spatrick // parameter.
17709467b48Spatrick MarkedNoUnwind = false;
17809467b48Spatrick break;
17909467b48Spatrick }
18009467b48Spatrick
18109467b48Spatrick MarkedNoUnwind = F->doesNotThrow();
18209467b48Spatrick SawFunc = true;
18309467b48Spatrick }
18409467b48Spatrick
18509467b48Spatrick return MarkedNoUnwind;
18609467b48Spatrick }
18709467b48Spatrick
computePadMap(const SmallVectorImpl<const LandingPadInfo * > & LandingPads,RangeMapType & PadMap)18809467b48Spatrick void EHStreamer::computePadMap(
18909467b48Spatrick const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
19009467b48Spatrick RangeMapType &PadMap) {
19109467b48Spatrick // Invokes and nounwind calls have entries in PadMap (due to being bracketed
19209467b48Spatrick // by try-range labels when lowered). Ordinary calls do not, so appropriate
19309467b48Spatrick // try-ranges for them need be deduced so we can put them in the LSDA.
19409467b48Spatrick for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
19509467b48Spatrick const LandingPadInfo *LandingPad = LandingPads[i];
19609467b48Spatrick for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
19709467b48Spatrick MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
198*d415bd75Srobert MCSymbol *EndLabel = LandingPad->BeginLabels[j];
199*d415bd75Srobert // If we have deleted the code for a given invoke after registering it in
200*d415bd75Srobert // the LandingPad label list, the associated symbols will not have been
201*d415bd75Srobert // emitted. In that case, ignore this callsite entry.
202*d415bd75Srobert if (!BeginLabel->isDefined() || !EndLabel->isDefined())
203*d415bd75Srobert continue;
20409467b48Spatrick assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
20509467b48Spatrick PadRange P = { i, j };
20609467b48Spatrick PadMap[BeginLabel] = P;
20709467b48Spatrick }
20809467b48Spatrick }
20909467b48Spatrick }
21009467b48Spatrick
21109467b48Spatrick /// Compute the call-site table. The entry for an invoke has a try-range
21209467b48Spatrick /// containing the call, a non-zero landing pad, and an appropriate action. The
21309467b48Spatrick /// entry for an ordinary call has a try-range containing the call and zero for
21409467b48Spatrick /// the landing pad and the action. Calls marked 'nounwind' have no entry and
21509467b48Spatrick /// must not be contained in the try-range of any entry - they form gaps in the
21609467b48Spatrick /// table. Entries must be ordered by try-range address.
21773471bf0Spatrick ///
21873471bf0Spatrick /// Call-sites are split into one or more call-site ranges associated with
21973471bf0Spatrick /// different sections of the function.
22073471bf0Spatrick ///
22173471bf0Spatrick /// - Without -basic-block-sections, all call-sites are grouped into one
22273471bf0Spatrick /// call-site-range corresponding to the function section.
22373471bf0Spatrick ///
22473471bf0Spatrick /// - With -basic-block-sections, one call-site range is created for each
22573471bf0Spatrick /// section, with its FragmentBeginLabel and FragmentEndLabel respectively
22673471bf0Spatrick // set to the beginning and ending of the corresponding section and its
22773471bf0Spatrick // ExceptionLabel set to the exception symbol dedicated for this section.
22873471bf0Spatrick // Later, one LSDA header will be emitted for each call-site range with its
22973471bf0Spatrick // call-sites following. The action table and type info table will be
23073471bf0Spatrick // shared across all ranges.
computeCallSiteTable(SmallVectorImpl<CallSiteEntry> & CallSites,SmallVectorImpl<CallSiteRange> & CallSiteRanges,const SmallVectorImpl<const LandingPadInfo * > & LandingPads,const SmallVectorImpl<unsigned> & FirstActions)23173471bf0Spatrick void EHStreamer::computeCallSiteTable(
23273471bf0Spatrick SmallVectorImpl<CallSiteEntry> &CallSites,
23373471bf0Spatrick SmallVectorImpl<CallSiteRange> &CallSiteRanges,
23409467b48Spatrick const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
23509467b48Spatrick const SmallVectorImpl<unsigned> &FirstActions) {
23609467b48Spatrick RangeMapType PadMap;
23709467b48Spatrick computePadMap(LandingPads, PadMap);
23809467b48Spatrick
23909467b48Spatrick // The end label of the previous invoke or nounwind try-range.
24073471bf0Spatrick MCSymbol *LastLabel = Asm->getFunctionBegin();
24109467b48Spatrick
24209467b48Spatrick // Whether there is a potentially throwing instruction (currently this means
24309467b48Spatrick // an ordinary call) between the end of the previous try-range and now.
24409467b48Spatrick bool SawPotentiallyThrowing = false;
24509467b48Spatrick
24609467b48Spatrick // Whether the last CallSite entry was for an invoke.
24709467b48Spatrick bool PreviousIsInvoke = false;
24809467b48Spatrick
24909467b48Spatrick bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
25009467b48Spatrick
25109467b48Spatrick // Visit all instructions in order of address.
25209467b48Spatrick for (const auto &MBB : *Asm->MF) {
25373471bf0Spatrick if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) {
25473471bf0Spatrick // We start a call-site range upon function entry and at the beginning of
25573471bf0Spatrick // every basic block section.
25673471bf0Spatrick CallSiteRanges.push_back(
25773471bf0Spatrick {Asm->MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel,
25873471bf0Spatrick Asm->MBBSectionRanges[MBB.getSectionIDNum()].EndLabel,
25973471bf0Spatrick Asm->getMBBExceptionSym(MBB), CallSites.size()});
26073471bf0Spatrick PreviousIsInvoke = false;
26173471bf0Spatrick SawPotentiallyThrowing = false;
26273471bf0Spatrick LastLabel = nullptr;
26373471bf0Spatrick }
26473471bf0Spatrick
26573471bf0Spatrick if (MBB.isEHPad())
26673471bf0Spatrick CallSiteRanges.back().IsLPRange = true;
26773471bf0Spatrick
26809467b48Spatrick for (const auto &MI : MBB) {
26909467b48Spatrick if (!MI.isEHLabel()) {
27009467b48Spatrick if (MI.isCall())
27109467b48Spatrick SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
27209467b48Spatrick continue;
27309467b48Spatrick }
27409467b48Spatrick
27509467b48Spatrick // End of the previous try-range?
27609467b48Spatrick MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
27709467b48Spatrick if (BeginLabel == LastLabel)
27809467b48Spatrick SawPotentiallyThrowing = false;
27909467b48Spatrick
28009467b48Spatrick // Beginning of a new try-range?
28109467b48Spatrick RangeMapType::const_iterator L = PadMap.find(BeginLabel);
28209467b48Spatrick if (L == PadMap.end())
28309467b48Spatrick // Nope, it was just some random label.
28409467b48Spatrick continue;
28509467b48Spatrick
28609467b48Spatrick const PadRange &P = L->second;
28709467b48Spatrick const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
28809467b48Spatrick assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
28909467b48Spatrick "Inconsistent landing pad map!");
29009467b48Spatrick
29173471bf0Spatrick // For Dwarf and AIX exception handling (SjLj handling doesn't use this).
29273471bf0Spatrick // If some instruction between the previous try-range and this one may
29373471bf0Spatrick // throw, create a call-site entry with no landing pad for the region
29473471bf0Spatrick // between the try-ranges.
29573471bf0Spatrick if (SawPotentiallyThrowing &&
29673471bf0Spatrick (Asm->MAI->usesCFIForEH() ||
29773471bf0Spatrick Asm->MAI->getExceptionHandlingType() == ExceptionHandling::AIX)) {
29873471bf0Spatrick CallSites.push_back({LastLabel, BeginLabel, nullptr, 0});
29909467b48Spatrick PreviousIsInvoke = false;
30009467b48Spatrick }
30109467b48Spatrick
30209467b48Spatrick LastLabel = LandingPad->EndLabels[P.RangeIndex];
30309467b48Spatrick assert(BeginLabel && LastLabel && "Invalid landing pad!");
30409467b48Spatrick
30509467b48Spatrick if (!LandingPad->LandingPadLabel) {
30609467b48Spatrick // Create a gap.
30709467b48Spatrick PreviousIsInvoke = false;
30809467b48Spatrick } else {
30909467b48Spatrick // This try-range is for an invoke.
31009467b48Spatrick CallSiteEntry Site = {
31109467b48Spatrick BeginLabel,
31209467b48Spatrick LastLabel,
31309467b48Spatrick LandingPad,
31409467b48Spatrick FirstActions[P.PadIndex]
31509467b48Spatrick };
31609467b48Spatrick
31709467b48Spatrick // Try to merge with the previous call-site. SJLJ doesn't do this
31809467b48Spatrick if (PreviousIsInvoke && !IsSJLJ) {
31909467b48Spatrick CallSiteEntry &Prev = CallSites.back();
32009467b48Spatrick if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) {
32109467b48Spatrick // Extend the range of the previous entry.
32209467b48Spatrick Prev.EndLabel = Site.EndLabel;
32309467b48Spatrick continue;
32409467b48Spatrick }
32509467b48Spatrick }
32609467b48Spatrick
32709467b48Spatrick // Otherwise, create a new call-site.
32809467b48Spatrick if (!IsSJLJ)
32909467b48Spatrick CallSites.push_back(Site);
33009467b48Spatrick else {
33109467b48Spatrick // SjLj EH must maintain the call sites in the order assigned
33209467b48Spatrick // to them by the SjLjPrepare pass.
33309467b48Spatrick unsigned SiteNo = Asm->MF->getCallSiteBeginLabel(BeginLabel);
33409467b48Spatrick if (CallSites.size() < SiteNo)
33509467b48Spatrick CallSites.resize(SiteNo);
33609467b48Spatrick CallSites[SiteNo - 1] = Site;
33709467b48Spatrick }
33809467b48Spatrick PreviousIsInvoke = true;
33909467b48Spatrick }
34009467b48Spatrick }
34109467b48Spatrick
34273471bf0Spatrick // We end the call-site range upon function exit and at the end of every
34373471bf0Spatrick // basic block section.
34473471bf0Spatrick if (&MBB == &Asm->MF->back() || MBB.isEndSection()) {
34509467b48Spatrick // If some instruction between the previous try-range and the end of the
34673471bf0Spatrick // function may throw, create a call-site entry with no landing pad for
34773471bf0Spatrick // the region following the try-range.
34809467b48Spatrick if (SawPotentiallyThrowing && !IsSJLJ) {
34973471bf0Spatrick CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel,
35073471bf0Spatrick nullptr, 0};
35109467b48Spatrick CallSites.push_back(Site);
35273471bf0Spatrick SawPotentiallyThrowing = false;
35373471bf0Spatrick }
35473471bf0Spatrick CallSiteRanges.back().CallSiteEndIdx = CallSites.size();
35573471bf0Spatrick }
35609467b48Spatrick }
35709467b48Spatrick }
35809467b48Spatrick
35909467b48Spatrick /// Emit landing pads and actions.
36009467b48Spatrick ///
36109467b48Spatrick /// The general organization of the table is complex, but the basic concepts are
36209467b48Spatrick /// easy. First there is a header which describes the location and organization
36309467b48Spatrick /// of the three components that follow.
36409467b48Spatrick ///
36509467b48Spatrick /// 1. The landing pad site information describes the range of code covered by
36609467b48Spatrick /// the try. In our case it's an accumulation of the ranges covered by the
36709467b48Spatrick /// invokes in the try. There is also a reference to the landing pad that
36809467b48Spatrick /// handles the exception once processed. Finally an index into the actions
36909467b48Spatrick /// table.
37009467b48Spatrick /// 2. The action table, in our case, is composed of pairs of type IDs and next
37109467b48Spatrick /// action offset. Starting with the action index from the landing pad
37209467b48Spatrick /// site, each type ID is checked for a match to the current exception. If
37309467b48Spatrick /// it matches then the exception and type id are passed on to the landing
37409467b48Spatrick /// pad. Otherwise the next action is looked up. This chain is terminated
37509467b48Spatrick /// with a next action of zero. If no type id is found then the frame is
37609467b48Spatrick /// unwound and handling continues.
37709467b48Spatrick /// 3. Type ID table contains references to all the C++ typeinfo for all
37809467b48Spatrick /// catches in the function. This tables is reverse indexed base 1.
37909467b48Spatrick ///
38009467b48Spatrick /// Returns the starting symbol of an exception table.
emitExceptionTable()38109467b48Spatrick MCSymbol *EHStreamer::emitExceptionTable() {
38209467b48Spatrick const MachineFunction *MF = Asm->MF;
38309467b48Spatrick const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();
38409467b48Spatrick const std::vector<unsigned> &FilterIds = MF->getFilterIds();
38509467b48Spatrick const std::vector<LandingPadInfo> &PadInfos = MF->getLandingPads();
38609467b48Spatrick
38709467b48Spatrick // Sort the landing pads in order of their type ids. This is used to fold
38809467b48Spatrick // duplicate actions.
38909467b48Spatrick SmallVector<const LandingPadInfo *, 64> LandingPads;
39009467b48Spatrick LandingPads.reserve(PadInfos.size());
39109467b48Spatrick
392*d415bd75Srobert for (const LandingPadInfo &LPI : PadInfos) {
393*d415bd75Srobert // If a landing-pad has an associated label, but the label wasn't ever
394*d415bd75Srobert // emitted, then skip it. (This can occur if the landingpad's MBB was
395*d415bd75Srobert // deleted).
396*d415bd75Srobert if (LPI.LandingPadLabel && !LPI.LandingPadLabel->isDefined())
397*d415bd75Srobert continue;
398*d415bd75Srobert LandingPads.push_back(&LPI);
399*d415bd75Srobert }
40009467b48Spatrick
40109467b48Spatrick // Order landing pads lexicographically by type id.
40209467b48Spatrick llvm::sort(LandingPads, [](const LandingPadInfo *L, const LandingPadInfo *R) {
40309467b48Spatrick return L->TypeIds < R->TypeIds;
40409467b48Spatrick });
40509467b48Spatrick
40609467b48Spatrick // Compute the actions table and gather the first action index for each
40709467b48Spatrick // landing pad site.
40809467b48Spatrick SmallVector<ActionEntry, 32> Actions;
40909467b48Spatrick SmallVector<unsigned, 64> FirstActions;
41009467b48Spatrick computeActionsTable(LandingPads, Actions, FirstActions);
41109467b48Spatrick
41273471bf0Spatrick // Compute the call-site table and call-site ranges. Normally, there is only
41373471bf0Spatrick // one call-site-range which covers the whole funciton. With
41473471bf0Spatrick // -basic-block-sections, there is one call-site-range per basic block
41573471bf0Spatrick // section.
41609467b48Spatrick SmallVector<CallSiteEntry, 64> CallSites;
41773471bf0Spatrick SmallVector<CallSiteRange, 4> CallSiteRanges;
41873471bf0Spatrick computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions);
41909467b48Spatrick
42009467b48Spatrick bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
42109467b48Spatrick bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm;
42273471bf0Spatrick bool HasLEB128Directives = Asm->MAI->hasLEB128Directives();
42309467b48Spatrick unsigned CallSiteEncoding =
42409467b48Spatrick IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) :
42509467b48Spatrick Asm->getObjFileLowering().getCallSiteEncoding();
42609467b48Spatrick bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty();
42709467b48Spatrick
42809467b48Spatrick // Type infos.
42973471bf0Spatrick MCSection *LSDASection = Asm->getObjFileLowering().getSectionForLSDA(
43073471bf0Spatrick MF->getFunction(), *Asm->CurrentFnSym, Asm->TM);
43109467b48Spatrick unsigned TTypeEncoding;
43209467b48Spatrick
43309467b48Spatrick if (!HaveTTData) {
43409467b48Spatrick // If there is no TypeInfo, then we just explicitly say that we're omitting
43509467b48Spatrick // that bit.
43609467b48Spatrick TTypeEncoding = dwarf::DW_EH_PE_omit;
43709467b48Spatrick } else {
43809467b48Spatrick // Okay, we have actual filters or typeinfos to emit. As such, we need to
43909467b48Spatrick // pick a type encoding for them. We're about to emit a list of pointers to
44009467b48Spatrick // typeinfo objects at the end of the LSDA. However, unless we're in static
44109467b48Spatrick // mode, this reference will require a relocation by the dynamic linker.
44209467b48Spatrick //
44309467b48Spatrick // Because of this, we have a couple of options:
44409467b48Spatrick //
44509467b48Spatrick // 1) If we are in -static mode, we can always use an absolute reference
44609467b48Spatrick // from the LSDA, because the static linker will resolve it.
44709467b48Spatrick //
44809467b48Spatrick // 2) Otherwise, if the LSDA section is writable, we can output the direct
44909467b48Spatrick // reference to the typeinfo and allow the dynamic linker to relocate
45009467b48Spatrick // it. Since it is in a writable section, the dynamic linker won't
45109467b48Spatrick // have a problem.
45209467b48Spatrick //
45309467b48Spatrick // 3) Finally, if we're in PIC mode and the LDSA section isn't writable,
45409467b48Spatrick // we need to use some form of indirection. For example, on Darwin,
45509467b48Spatrick // we can output a statically-relocatable reference to a dyld stub. The
45609467b48Spatrick // offset to the stub is constant, but the contents are in a section
45709467b48Spatrick // that is updated by the dynamic linker. This is easy enough, but we
45809467b48Spatrick // need to tell the personality function of the unwinder to indirect
45909467b48Spatrick // through the dyld stub.
46009467b48Spatrick //
46109467b48Spatrick // FIXME: When (3) is actually implemented, we'll have to emit the stubs
46209467b48Spatrick // somewhere. This predicate should be moved to a shared location that is
46309467b48Spatrick // in target-independent code.
46409467b48Spatrick //
46509467b48Spatrick TTypeEncoding = Asm->getObjFileLowering().getTTypeEncoding();
46609467b48Spatrick }
46709467b48Spatrick
46809467b48Spatrick // Begin the exception table.
46909467b48Spatrick // Sometimes we want not to emit the data into separate section (e.g. ARM
47009467b48Spatrick // EHABI). In this case LSDASection will be NULL.
47109467b48Spatrick if (LSDASection)
472*d415bd75Srobert Asm->OutStreamer->switchSection(LSDASection);
473097a140dSpatrick Asm->emitAlignment(Align(4));
47409467b48Spatrick
47509467b48Spatrick // Emit the LSDA.
47609467b48Spatrick MCSymbol *GCCETSym =
47709467b48Spatrick Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+
47809467b48Spatrick Twine(Asm->getFunctionNumber()));
479097a140dSpatrick Asm->OutStreamer->emitLabel(GCCETSym);
48073471bf0Spatrick MCSymbol *CstEndLabel = Asm->createTempSymbol(
48173471bf0Spatrick CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end");
48209467b48Spatrick
48309467b48Spatrick MCSymbol *TTBaseLabel = nullptr;
48473471bf0Spatrick if (HaveTTData)
48573471bf0Spatrick TTBaseLabel = Asm->createTempSymbol("ttbase");
48673471bf0Spatrick
48773471bf0Spatrick const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();
48873471bf0Spatrick
48973471bf0Spatrick // Helper for emitting references (offsets) for type table and the end of the
49073471bf0Spatrick // call-site table (which marks the beginning of the action table).
49173471bf0Spatrick // * For Itanium, these references will be emitted for every callsite range.
49273471bf0Spatrick // * For SJLJ and Wasm, they will be emitted only once in the LSDA header.
49373471bf0Spatrick auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() {
49473471bf0Spatrick Asm->emitEncodingByte(TTypeEncoding, "@TType");
49509467b48Spatrick if (HaveTTData) {
49609467b48Spatrick // N.B.: There is a dependency loop between the size of the TTBase uleb128
49709467b48Spatrick // here and the amount of padding before the aligned type table. The
49873471bf0Spatrick // assembler must sometimes pad this uleb128 or insert extra padding
49973471bf0Spatrick // before the type table. See PR35809 or GNU as bug 4029.
50009467b48Spatrick MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref");
501097a140dSpatrick Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel);
502097a140dSpatrick Asm->OutStreamer->emitLabel(TTBaseRefLabel);
50309467b48Spatrick }
50409467b48Spatrick
50573471bf0Spatrick // The Action table follows the call-site table. So we emit the
50673471bf0Spatrick // label difference from here (start of the call-site table for SJLJ and
50773471bf0Spatrick // Wasm, and start of a call-site range for Itanium) to the end of the
50873471bf0Spatrick // whole call-site table (end of the last call-site range for Itanium).
50909467b48Spatrick MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin");
510097a140dSpatrick Asm->emitEncodingByte(CallSiteEncoding, "Call site");
511097a140dSpatrick Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel);
512097a140dSpatrick Asm->OutStreamer->emitLabel(CstBeginLabel);
51373471bf0Spatrick };
51473471bf0Spatrick
51573471bf0Spatrick // An alternative path to EmitTypeTableRefAndCallSiteTableEndRef.
51673471bf0Spatrick // For some platforms, the system assembler does not accept the form of
51773471bf0Spatrick // `.uleb128 label2 - label1`. In those situations, we would need to calculate
51873471bf0Spatrick // the size between label1 and label2 manually.
51973471bf0Spatrick // In this case, we would need to calculate the LSDA size and the call
52073471bf0Spatrick // site table size.
52173471bf0Spatrick auto EmitTypeTableOffsetAndCallSiteTableOffset = [&]() {
52273471bf0Spatrick assert(CallSiteEncoding == dwarf::DW_EH_PE_udata4 && !HasLEB128Directives &&
52373471bf0Spatrick "Targets supporting .uleb128 do not need to take this path.");
52473471bf0Spatrick if (CallSiteRanges.size() > 1)
52573471bf0Spatrick report_fatal_error(
52673471bf0Spatrick "-fbasic-block-sections is not yet supported on "
52773471bf0Spatrick "platforms that do not have general LEB128 directive support.");
52873471bf0Spatrick
52973471bf0Spatrick uint64_t CallSiteTableSize = 0;
53073471bf0Spatrick const CallSiteRange &CSRange = CallSiteRanges.back();
53173471bf0Spatrick for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
53273471bf0Spatrick CallSiteIdx < CSRange.CallSiteEndIdx; ++CallSiteIdx) {
53373471bf0Spatrick const CallSiteEntry &S = CallSites[CallSiteIdx];
53473471bf0Spatrick // Each call site entry consists of 3 udata4 fields (12 bytes) and
53573471bf0Spatrick // 1 ULEB128 field.
53673471bf0Spatrick CallSiteTableSize += 12 + getULEB128Size(S.Action);
53773471bf0Spatrick assert(isUInt<32>(CallSiteTableSize) && "CallSiteTableSize overflows.");
53873471bf0Spatrick }
53973471bf0Spatrick
54073471bf0Spatrick Asm->emitEncodingByte(TTypeEncoding, "@TType");
54173471bf0Spatrick if (HaveTTData) {
54273471bf0Spatrick const unsigned ByteSizeOfCallSiteOffset =
54373471bf0Spatrick getULEB128Size(CallSiteTableSize);
54473471bf0Spatrick uint64_t ActionTableSize = 0;
54573471bf0Spatrick for (const ActionEntry &Action : Actions) {
54673471bf0Spatrick // Each action entry consists of two SLEB128 fields.
54773471bf0Spatrick ActionTableSize += getSLEB128Size(Action.ValueForTypeID) +
54873471bf0Spatrick getSLEB128Size(Action.NextAction);
54973471bf0Spatrick assert(isUInt<32>(ActionTableSize) && "ActionTableSize overflows.");
55073471bf0Spatrick }
55173471bf0Spatrick
55273471bf0Spatrick const unsigned TypeInfoSize =
55373471bf0Spatrick Asm->GetSizeOfEncodedValue(TTypeEncoding) * MF->getTypeInfos().size();
55473471bf0Spatrick
55573471bf0Spatrick const uint64_t LSDASizeBeforeAlign =
55673471bf0Spatrick 1 // Call site encoding byte.
55773471bf0Spatrick + ByteSizeOfCallSiteOffset // ULEB128 encoding of CallSiteTableSize.
55873471bf0Spatrick + CallSiteTableSize // Call site table content.
55973471bf0Spatrick + ActionTableSize; // Action table content.
56073471bf0Spatrick
56173471bf0Spatrick const uint64_t LSDASizeWithoutAlign = LSDASizeBeforeAlign + TypeInfoSize;
56273471bf0Spatrick const unsigned ByteSizeOfLSDAWithoutAlign =
56373471bf0Spatrick getULEB128Size(LSDASizeWithoutAlign);
56473471bf0Spatrick const uint64_t DisplacementBeforeAlign =
56573471bf0Spatrick 2 // LPStartEncoding and TypeTableEncoding.
56673471bf0Spatrick + ByteSizeOfLSDAWithoutAlign + LSDASizeBeforeAlign;
56773471bf0Spatrick
56873471bf0Spatrick // The type info area starts with 4 byte alignment.
56973471bf0Spatrick const unsigned NeedAlignVal = (4 - DisplacementBeforeAlign % 4) % 4;
57073471bf0Spatrick uint64_t LSDASizeWithAlign = LSDASizeWithoutAlign + NeedAlignVal;
57173471bf0Spatrick const unsigned ByteSizeOfLSDAWithAlign =
57273471bf0Spatrick getULEB128Size(LSDASizeWithAlign);
57373471bf0Spatrick
57473471bf0Spatrick // The LSDASizeWithAlign could use 1 byte less padding for alignment
57573471bf0Spatrick // when the data we use to represent the LSDA Size "needs" to be 1 byte
57673471bf0Spatrick // larger than the one previously calculated without alignment.
57773471bf0Spatrick if (ByteSizeOfLSDAWithAlign > ByteSizeOfLSDAWithoutAlign)
57873471bf0Spatrick LSDASizeWithAlign -= 1;
57973471bf0Spatrick
58073471bf0Spatrick Asm->OutStreamer->emitULEB128IntValue(LSDASizeWithAlign,
58173471bf0Spatrick ByteSizeOfLSDAWithAlign);
58273471bf0Spatrick }
58373471bf0Spatrick
58473471bf0Spatrick Asm->emitEncodingByte(CallSiteEncoding, "Call site");
58573471bf0Spatrick Asm->OutStreamer->emitULEB128IntValue(CallSiteTableSize);
58673471bf0Spatrick };
58709467b48Spatrick
58809467b48Spatrick // SjLj / Wasm Exception handling
58909467b48Spatrick if (IsSJLJ || IsWasm) {
59073471bf0Spatrick Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front()));
59173471bf0Spatrick
59273471bf0Spatrick // emit the LSDA header.
59373471bf0Spatrick Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");
59473471bf0Spatrick EmitTypeTableRefAndCallSiteTableEndRef();
59573471bf0Spatrick
59609467b48Spatrick unsigned idx = 0;
59709467b48Spatrick for (SmallVectorImpl<CallSiteEntry>::const_iterator
59809467b48Spatrick I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) {
59909467b48Spatrick const CallSiteEntry &S = *I;
60009467b48Spatrick
60109467b48Spatrick // Index of the call site entry.
60209467b48Spatrick if (VerboseAsm) {
60309467b48Spatrick Asm->OutStreamer->AddComment(">> Call Site " + Twine(idx) + " <<");
60409467b48Spatrick Asm->OutStreamer->AddComment(" On exception at call site "+Twine(idx));
60509467b48Spatrick }
606097a140dSpatrick Asm->emitULEB128(idx);
60709467b48Spatrick
60809467b48Spatrick // Offset of the first associated action record, relative to the start of
60909467b48Spatrick // the action table. This value is biased by 1 (1 indicates the start of
61009467b48Spatrick // the action table), and 0 indicates that there are no actions.
61109467b48Spatrick if (VerboseAsm) {
61209467b48Spatrick if (S.Action == 0)
61309467b48Spatrick Asm->OutStreamer->AddComment(" Action: cleanup");
61409467b48Spatrick else
61509467b48Spatrick Asm->OutStreamer->AddComment(" Action: " +
61609467b48Spatrick Twine((S.Action - 1) / 2 + 1));
61709467b48Spatrick }
618097a140dSpatrick Asm->emitULEB128(S.Action);
61909467b48Spatrick }
62073471bf0Spatrick Asm->OutStreamer->emitLabel(CstEndLabel);
62109467b48Spatrick } else {
62209467b48Spatrick // Itanium LSDA exception handling
62309467b48Spatrick
62409467b48Spatrick // The call-site table is a list of all call sites that may throw an
62509467b48Spatrick // exception (including C++ 'throw' statements) in the procedure
62609467b48Spatrick // fragment. It immediately follows the LSDA header. Each entry indicates,
62709467b48Spatrick // for a given call, the first corresponding action record and corresponding
62809467b48Spatrick // landing pad.
62909467b48Spatrick //
63009467b48Spatrick // The table begins with the number of bytes, stored as an LEB128
63109467b48Spatrick // compressed, unsigned integer. The records immediately follow the record
63209467b48Spatrick // count. They are sorted in increasing call-site address. Each record
63309467b48Spatrick // indicates:
63409467b48Spatrick //
63509467b48Spatrick // * The position of the call-site.
63609467b48Spatrick // * The position of the landing pad.
63709467b48Spatrick // * The first action record for that call site.
63809467b48Spatrick //
63909467b48Spatrick // A missing entry in the call-site table indicates that a call is not
64009467b48Spatrick // supposed to throw.
64109467b48Spatrick
64273471bf0Spatrick assert(CallSiteRanges.size() != 0 && "No call-site ranges!");
64309467b48Spatrick
64473471bf0Spatrick // There should be only one call-site range which includes all the landing
64573471bf0Spatrick // pads. Find that call-site range here.
64673471bf0Spatrick const CallSiteRange *LandingPadRange = nullptr;
64773471bf0Spatrick for (const CallSiteRange &CSRange : CallSiteRanges) {
64873471bf0Spatrick if (CSRange.IsLPRange) {
64973471bf0Spatrick assert(LandingPadRange == nullptr &&
65073471bf0Spatrick "All landing pads must be in a single callsite range.");
65173471bf0Spatrick LandingPadRange = &CSRange;
65273471bf0Spatrick }
65373471bf0Spatrick }
65473471bf0Spatrick
65573471bf0Spatrick // The call-site table is split into its call-site ranges, each being
65673471bf0Spatrick // emitted as:
65773471bf0Spatrick // [ LPStartEncoding | LPStart ]
65873471bf0Spatrick // [ TypeTableEncoding | TypeTableOffset ]
65973471bf0Spatrick // [ CallSiteEncoding | CallSiteTableEndOffset ]
66073471bf0Spatrick // cst_begin -> { call-site entries contained in this range }
66173471bf0Spatrick //
66273471bf0Spatrick // and is followed by the next call-site range.
66373471bf0Spatrick //
66473471bf0Spatrick // For each call-site range, CallSiteTableEndOffset is computed as the
66573471bf0Spatrick // difference between cst_begin of that range and the last call-site-table's
66673471bf0Spatrick // end label. This offset is used to find the action table.
66773471bf0Spatrick
66873471bf0Spatrick unsigned Entry = 0;
66973471bf0Spatrick for (const CallSiteRange &CSRange : CallSiteRanges) {
67073471bf0Spatrick if (CSRange.CallSiteBeginIdx != 0) {
67173471bf0Spatrick // Align the call-site range for all ranges except the first. The
67273471bf0Spatrick // first range is already aligned due to the exception table alignment.
67373471bf0Spatrick Asm->emitAlignment(Align(4));
67473471bf0Spatrick }
67573471bf0Spatrick Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel);
67673471bf0Spatrick
67773471bf0Spatrick // Emit the LSDA header.
678*d415bd75Srobert // LPStart is omitted if either we have a single call-site range (in which
679*d415bd75Srobert // case the function entry is treated as @LPStart) or if this function has
680*d415bd75Srobert // no landing pads (in which case @LPStart is undefined).
681*d415bd75Srobert if (CallSiteRanges.size() == 1 || LandingPadRange == nullptr) {
68273471bf0Spatrick Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");
68373471bf0Spatrick } else if (!Asm->isPositionIndependent()) {
68473471bf0Spatrick // For more than one call-site ranges, LPStart must be explicitly
68573471bf0Spatrick // specified.
68673471bf0Spatrick // For non-PIC we can simply use the absolute value.
68773471bf0Spatrick Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart");
68873471bf0Spatrick Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel,
68973471bf0Spatrick Asm->MAI->getCodePointerSize());
69073471bf0Spatrick } else {
69173471bf0Spatrick // For PIC mode, we Emit a PC-relative address for LPStart.
69273471bf0Spatrick Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart");
69373471bf0Spatrick MCContext &Context = Asm->OutStreamer->getContext();
69473471bf0Spatrick MCSymbol *Dot = Context.createTempSymbol();
69573471bf0Spatrick Asm->OutStreamer->emitLabel(Dot);
69673471bf0Spatrick Asm->OutStreamer->emitValue(
69773471bf0Spatrick MCBinaryExpr::createSub(
69873471bf0Spatrick MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel,
69973471bf0Spatrick Context),
70073471bf0Spatrick MCSymbolRefExpr::create(Dot, Context), Context),
70173471bf0Spatrick Asm->MAI->getCodePointerSize());
70273471bf0Spatrick }
70373471bf0Spatrick
70473471bf0Spatrick if (HasLEB128Directives)
70573471bf0Spatrick EmitTypeTableRefAndCallSiteTableEndRef();
70673471bf0Spatrick else
70773471bf0Spatrick EmitTypeTableOffsetAndCallSiteTableOffset();
70873471bf0Spatrick
70973471bf0Spatrick for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
71073471bf0Spatrick CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) {
71173471bf0Spatrick const CallSiteEntry &S = CallSites[CallSiteIdx];
71273471bf0Spatrick
71373471bf0Spatrick MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel;
71473471bf0Spatrick MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel;
71509467b48Spatrick
71609467b48Spatrick MCSymbol *BeginLabel = S.BeginLabel;
71709467b48Spatrick if (!BeginLabel)
71809467b48Spatrick BeginLabel = EHFuncBeginSym;
71909467b48Spatrick MCSymbol *EndLabel = S.EndLabel;
72009467b48Spatrick if (!EndLabel)
72173471bf0Spatrick EndLabel = EHFuncEndSym;
72209467b48Spatrick
72309467b48Spatrick // Offset of the call site relative to the start of the procedure.
72409467b48Spatrick if (VerboseAsm)
72573471bf0Spatrick Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) +
72673471bf0Spatrick " <<");
727097a140dSpatrick Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding);
72809467b48Spatrick if (VerboseAsm)
72909467b48Spatrick Asm->OutStreamer->AddComment(Twine(" Call between ") +
73009467b48Spatrick BeginLabel->getName() + " and " +
73109467b48Spatrick EndLabel->getName());
732097a140dSpatrick Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding);
73309467b48Spatrick
73473471bf0Spatrick // Offset of the landing pad relative to the start of the landing pad
73573471bf0Spatrick // fragment.
73609467b48Spatrick if (!S.LPad) {
73709467b48Spatrick if (VerboseAsm)
73809467b48Spatrick Asm->OutStreamer->AddComment(" has no landing pad");
739097a140dSpatrick Asm->emitCallSiteValue(0, CallSiteEncoding);
74009467b48Spatrick } else {
74109467b48Spatrick if (VerboseAsm)
74209467b48Spatrick Asm->OutStreamer->AddComment(Twine(" jumps to ") +
74309467b48Spatrick S.LPad->LandingPadLabel->getName());
74473471bf0Spatrick Asm->emitCallSiteOffset(S.LPad->LandingPadLabel,
74573471bf0Spatrick LandingPadRange->FragmentBeginLabel,
74609467b48Spatrick CallSiteEncoding);
74709467b48Spatrick }
74809467b48Spatrick
74973471bf0Spatrick // Offset of the first associated action record, relative to the start
75073471bf0Spatrick // of the action table. This value is biased by 1 (1 indicates the start
75173471bf0Spatrick // of the action table), and 0 indicates that there are no actions.
75209467b48Spatrick if (VerboseAsm) {
75309467b48Spatrick if (S.Action == 0)
75409467b48Spatrick Asm->OutStreamer->AddComment(" On action: cleanup");
75509467b48Spatrick else
75609467b48Spatrick Asm->OutStreamer->AddComment(" On action: " +
75709467b48Spatrick Twine((S.Action - 1) / 2 + 1));
75809467b48Spatrick }
759097a140dSpatrick Asm->emitULEB128(S.Action);
76009467b48Spatrick }
76109467b48Spatrick }
762097a140dSpatrick Asm->OutStreamer->emitLabel(CstEndLabel);
76373471bf0Spatrick }
76409467b48Spatrick
76509467b48Spatrick // Emit the Action Table.
76609467b48Spatrick int Entry = 0;
76773471bf0Spatrick for (const ActionEntry &Action : Actions) {
76809467b48Spatrick if (VerboseAsm) {
76909467b48Spatrick // Emit comments that decode the action table.
77009467b48Spatrick Asm->OutStreamer->AddComment(">> Action Record " + Twine(++Entry) + " <<");
77109467b48Spatrick }
77209467b48Spatrick
77309467b48Spatrick // Type Filter
77409467b48Spatrick //
77509467b48Spatrick // Used by the runtime to match the type of the thrown exception to the
77609467b48Spatrick // type of the catch clauses or the types in the exception specification.
77709467b48Spatrick if (VerboseAsm) {
77809467b48Spatrick if (Action.ValueForTypeID > 0)
77909467b48Spatrick Asm->OutStreamer->AddComment(" Catch TypeInfo " +
78009467b48Spatrick Twine(Action.ValueForTypeID));
78109467b48Spatrick else if (Action.ValueForTypeID < 0)
78209467b48Spatrick Asm->OutStreamer->AddComment(" Filter TypeInfo " +
78309467b48Spatrick Twine(Action.ValueForTypeID));
78409467b48Spatrick else
78509467b48Spatrick Asm->OutStreamer->AddComment(" Cleanup");
78609467b48Spatrick }
787097a140dSpatrick Asm->emitSLEB128(Action.ValueForTypeID);
78809467b48Spatrick
78909467b48Spatrick // Action Record
79009467b48Spatrick if (VerboseAsm) {
79173471bf0Spatrick if (Action.Previous == unsigned(-1)) {
79209467b48Spatrick Asm->OutStreamer->AddComment(" No further actions");
79309467b48Spatrick } else {
79473471bf0Spatrick Asm->OutStreamer->AddComment(" Continue to action " +
79573471bf0Spatrick Twine(Action.Previous + 1));
79609467b48Spatrick }
79709467b48Spatrick }
798097a140dSpatrick Asm->emitSLEB128(Action.NextAction);
79909467b48Spatrick }
80009467b48Spatrick
80109467b48Spatrick if (HaveTTData) {
802097a140dSpatrick Asm->emitAlignment(Align(4));
80309467b48Spatrick emitTypeInfos(TTypeEncoding, TTBaseLabel);
80409467b48Spatrick }
80509467b48Spatrick
806097a140dSpatrick Asm->emitAlignment(Align(4));
80709467b48Spatrick return GCCETSym;
80809467b48Spatrick }
80909467b48Spatrick
emitTypeInfos(unsigned TTypeEncoding,MCSymbol * TTBaseLabel)81009467b48Spatrick void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) {
81109467b48Spatrick const MachineFunction *MF = Asm->MF;
81209467b48Spatrick const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();
81309467b48Spatrick const std::vector<unsigned> &FilterIds = MF->getFilterIds();
81409467b48Spatrick
81573471bf0Spatrick const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();
81609467b48Spatrick
81709467b48Spatrick int Entry = 0;
81809467b48Spatrick // Emit the Catch TypeInfos.
81909467b48Spatrick if (VerboseAsm && !TypeInfos.empty()) {
82009467b48Spatrick Asm->OutStreamer->AddComment(">> Catch TypeInfos <<");
821*d415bd75Srobert Asm->OutStreamer->addBlankLine();
82209467b48Spatrick Entry = TypeInfos.size();
82309467b48Spatrick }
82409467b48Spatrick
825*d415bd75Srobert for (const GlobalValue *GV : llvm::reverse(TypeInfos)) {
82609467b48Spatrick if (VerboseAsm)
82709467b48Spatrick Asm->OutStreamer->AddComment("TypeInfo " + Twine(Entry--));
828097a140dSpatrick Asm->emitTTypeReference(GV, TTypeEncoding);
82909467b48Spatrick }
83009467b48Spatrick
831097a140dSpatrick Asm->OutStreamer->emitLabel(TTBaseLabel);
83209467b48Spatrick
83309467b48Spatrick // Emit the Exception Specifications.
83409467b48Spatrick if (VerboseAsm && !FilterIds.empty()) {
83509467b48Spatrick Asm->OutStreamer->AddComment(">> Filter TypeInfos <<");
836*d415bd75Srobert Asm->OutStreamer->addBlankLine();
83709467b48Spatrick Entry = 0;
83809467b48Spatrick }
83909467b48Spatrick for (std::vector<unsigned>::const_iterator
84009467b48Spatrick I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) {
84109467b48Spatrick unsigned TypeID = *I;
84209467b48Spatrick if (VerboseAsm) {
84309467b48Spatrick --Entry;
84409467b48Spatrick if (isFilterEHSelector(TypeID))
84509467b48Spatrick Asm->OutStreamer->AddComment("FilterInfo " + Twine(Entry));
84609467b48Spatrick }
84709467b48Spatrick
848097a140dSpatrick Asm->emitULEB128(TypeID);
84909467b48Spatrick }
85009467b48Spatrick }
851