Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
35271 views
//===- CodeGen/AsmPrinter/EHStreamer.cpp - Exception Directive Streamer ---===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains support for writing exception info into assembly files.9//10//===----------------------------------------------------------------------===//1112#include "EHStreamer.h"13#include "llvm/ADT/SmallVector.h"14#include "llvm/ADT/Twine.h"15#include "llvm/BinaryFormat/Dwarf.h"16#include "llvm/CodeGen/AsmPrinter.h"17#include "llvm/CodeGen/MachineFunction.h"18#include "llvm/CodeGen/MachineInstr.h"19#include "llvm/CodeGen/MachineOperand.h"20#include "llvm/IR/Function.h"21#include "llvm/MC/MCAsmInfo.h"22#include "llvm/MC/MCContext.h"23#include "llvm/MC/MCStreamer.h"24#include "llvm/MC/MCSymbol.h"25#include "llvm/MC/MCTargetOptions.h"26#include "llvm/Support/Casting.h"27#include "llvm/Support/LEB128.h"28#include "llvm/Target/TargetLoweringObjectFile.h"29#include <algorithm>30#include <cassert>31#include <cstdint>32#include <vector>3334using namespace llvm;3536EHStreamer::EHStreamer(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {}3738EHStreamer::~EHStreamer() = default;3940/// How many leading type ids two landing pads have in common.41unsigned EHStreamer::sharedTypeIDs(const LandingPadInfo *L,42const LandingPadInfo *R) {43const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds;44return std::mismatch(LIds.begin(), LIds.end(), RIds.begin(), RIds.end())45.first -46LIds.begin();47}4849/// Compute the actions table and gather the first action index for each landing50/// pad site.51void EHStreamer::computeActionsTable(52const SmallVectorImpl<const LandingPadInfo *> &LandingPads,53SmallVectorImpl<ActionEntry> &Actions,54SmallVectorImpl<unsigned> &FirstActions) {55// The action table follows the call-site table in the LSDA. The individual56// records are of two types:57//58// * Catch clause59// * Exception specification60//61// The two record kinds have the same format, with only small differences.62// They are distinguished by the "switch value" field: Catch clauses63// (TypeInfos) have strictly positive switch values, and exception64// specifications (FilterIds) have strictly negative switch values. Value 065// indicates a catch-all clause.66//67// Negative type IDs index into FilterIds. Positive type IDs index into68// TypeInfos. The value written for a positive type ID is just the type ID69// itself. For a negative type ID, however, the value written is the70// (negative) byte offset of the corresponding FilterIds entry. The byte71// offset is usually equal to the type ID (because the FilterIds entries are72// written using a variable width encoding, which outputs one byte per entry73// as long as the value written is not too large) but can differ. This kind74// of complication does not occur for positive type IDs because type infos are75// output using a fixed width encoding. FilterOffsets[i] holds the byte76// offset corresponding to FilterIds[i].7778const std::vector<unsigned> &FilterIds = Asm->MF->getFilterIds();79SmallVector<int, 16> FilterOffsets;80FilterOffsets.reserve(FilterIds.size());81int Offset = -1;8283for (unsigned FilterId : FilterIds) {84FilterOffsets.push_back(Offset);85Offset -= getULEB128Size(FilterId);86}8788FirstActions.reserve(LandingPads.size());8990int FirstAction = 0;91unsigned SizeActions = 0; // Total size of all action entries for a function92const LandingPadInfo *PrevLPI = nullptr;9394for (const LandingPadInfo *LPI : LandingPads) {95const std::vector<int> &TypeIds = LPI->TypeIds;96unsigned NumShared = PrevLPI ? sharedTypeIDs(LPI, PrevLPI) : 0;97unsigned SizeSiteActions = 0; // Total size of all entries for a landingpad9899if (NumShared < TypeIds.size()) {100// Size of one action entry (typeid + next action)101unsigned SizeActionEntry = 0;102unsigned PrevAction = (unsigned)-1;103104if (NumShared) {105unsigned SizePrevIds = PrevLPI->TypeIds.size();106assert(Actions.size());107PrevAction = Actions.size() - 1;108SizeActionEntry = getSLEB128Size(Actions[PrevAction].NextAction) +109getSLEB128Size(Actions[PrevAction].ValueForTypeID);110111for (unsigned j = NumShared; j != SizePrevIds; ++j) {112assert(PrevAction != (unsigned)-1 && "PrevAction is invalid!");113SizeActionEntry -= getSLEB128Size(Actions[PrevAction].ValueForTypeID);114SizeActionEntry += -Actions[PrevAction].NextAction;115PrevAction = Actions[PrevAction].Previous;116}117}118119// Compute the actions.120for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) {121int TypeID = TypeIds[J];122assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!");123int ValueForTypeID =124isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID;125unsigned SizeTypeID = getSLEB128Size(ValueForTypeID);126127int NextAction = SizeActionEntry ? -(SizeActionEntry + SizeTypeID) : 0;128SizeActionEntry = SizeTypeID + getSLEB128Size(NextAction);129SizeSiteActions += SizeActionEntry;130131ActionEntry Action = { ValueForTypeID, NextAction, PrevAction };132Actions.push_back(Action);133PrevAction = Actions.size() - 1;134}135136// Record the first action of the landing pad site.137FirstAction = SizeActions + SizeSiteActions - SizeActionEntry + 1;138} // else identical - re-use previous FirstAction139140// Information used when creating the call-site table. The action record141// field of the call site record is the offset of the first associated142// action record, relative to the start of the actions table. This value is143// biased by 1 (1 indicating the start of the actions table), and 0144// indicates that there are no actions.145FirstActions.push_back(FirstAction);146147// Compute this sites contribution to size.148SizeActions += SizeSiteActions;149150PrevLPI = LPI;151}152}153154/// Return `true' if this is a call to a function marked `nounwind'. Return155/// `false' otherwise.156bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) {157assert(MI->isCall() && "This should be a call instruction!");158159bool MarkedNoUnwind = false;160bool SawFunc = false;161162for (const MachineOperand &MO : MI->operands()) {163if (!MO.isGlobal()) continue;164165const Function *F = dyn_cast<Function>(MO.getGlobal());166if (!F) continue;167168if (SawFunc) {169// Be conservative. If we have more than one function operand for this170// call, then we can't make the assumption that it's the callee and171// not a parameter to the call.172//173// FIXME: Determine if there's a way to say that `F' is the callee or174// parameter.175MarkedNoUnwind = false;176break;177}178179MarkedNoUnwind = F->doesNotThrow();180SawFunc = true;181}182183return MarkedNoUnwind;184}185186void EHStreamer::computePadMap(187const SmallVectorImpl<const LandingPadInfo *> &LandingPads,188RangeMapType &PadMap) {189// Invokes and nounwind calls have entries in PadMap (due to being bracketed190// by try-range labels when lowered). Ordinary calls do not, so appropriate191// try-ranges for them need be deduced so we can put them in the LSDA.192for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {193const LandingPadInfo *LandingPad = LandingPads[i];194for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {195MCSymbol *BeginLabel = LandingPad->BeginLabels[j];196MCSymbol *EndLabel = LandingPad->BeginLabels[j];197// If we have deleted the code for a given invoke after registering it in198// the LandingPad label list, the associated symbols will not have been199// emitted. In that case, ignore this callsite entry.200if (!BeginLabel->isDefined() || !EndLabel->isDefined())201continue;202assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");203PadRange P = { i, j };204PadMap[BeginLabel] = P;205}206}207}208209/// Compute the call-site table. The entry for an invoke has a try-range210/// containing the call, a non-zero landing pad, and an appropriate action. The211/// entry for an ordinary call has a try-range containing the call and zero for212/// the landing pad and the action. Calls marked 'nounwind' have no entry and213/// must not be contained in the try-range of any entry - they form gaps in the214/// table. Entries must be ordered by try-range address.215///216/// Call-sites are split into one or more call-site ranges associated with217/// different sections of the function.218///219/// - Without -basic-block-sections, all call-sites are grouped into one220/// call-site-range corresponding to the function section.221///222/// - With -basic-block-sections, one call-site range is created for each223/// section, with its FragmentBeginLabel and FragmentEndLabel respectively224// set to the beginning and ending of the corresponding section and its225// ExceptionLabel set to the exception symbol dedicated for this section.226// Later, one LSDA header will be emitted for each call-site range with its227// call-sites following. The action table and type info table will be228// shared across all ranges.229void EHStreamer::computeCallSiteTable(230SmallVectorImpl<CallSiteEntry> &CallSites,231SmallVectorImpl<CallSiteRange> &CallSiteRanges,232const SmallVectorImpl<const LandingPadInfo *> &LandingPads,233const SmallVectorImpl<unsigned> &FirstActions) {234RangeMapType PadMap;235computePadMap(LandingPads, PadMap);236237// The end label of the previous invoke or nounwind try-range.238MCSymbol *LastLabel = Asm->getFunctionBegin();239240// Whether there is a potentially throwing instruction (currently this means241// an ordinary call) between the end of the previous try-range and now.242bool SawPotentiallyThrowing = false;243244// Whether the last CallSite entry was for an invoke.245bool PreviousIsInvoke = false;246247bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;248249// Visit all instructions in order of address.250for (const auto &MBB : *Asm->MF) {251if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) {252// We start a call-site range upon function entry and at the beginning of253// every basic block section.254CallSiteRanges.push_back(255{Asm->MBBSectionRanges[MBB.getSectionID()].BeginLabel,256Asm->MBBSectionRanges[MBB.getSectionID()].EndLabel,257Asm->getMBBExceptionSym(MBB), CallSites.size()});258PreviousIsInvoke = false;259SawPotentiallyThrowing = false;260LastLabel = nullptr;261}262263if (MBB.isEHPad())264CallSiteRanges.back().IsLPRange = true;265266for (const auto &MI : MBB) {267if (!MI.isEHLabel()) {268if (MI.isCall())269SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);270continue;271}272273// End of the previous try-range?274MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();275if (BeginLabel == LastLabel)276SawPotentiallyThrowing = false;277278// Beginning of a new try-range?279RangeMapType::const_iterator L = PadMap.find(BeginLabel);280if (L == PadMap.end())281// Nope, it was just some random label.282continue;283284const PadRange &P = L->second;285const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];286assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&287"Inconsistent landing pad map!");288289// For Dwarf and AIX exception handling (SjLj handling doesn't use this).290// If some instruction between the previous try-range and this one may291// throw, create a call-site entry with no landing pad for the region292// between the try-ranges.293if (SawPotentiallyThrowing &&294(Asm->MAI->usesCFIForEH() ||295Asm->MAI->getExceptionHandlingType() == ExceptionHandling::AIX)) {296CallSites.push_back({LastLabel, BeginLabel, nullptr, 0});297PreviousIsInvoke = false;298}299300LastLabel = LandingPad->EndLabels[P.RangeIndex];301assert(BeginLabel && LastLabel && "Invalid landing pad!");302303if (!LandingPad->LandingPadLabel) {304// Create a gap.305PreviousIsInvoke = false;306} else {307// This try-range is for an invoke.308CallSiteEntry Site = {309BeginLabel,310LastLabel,311LandingPad,312FirstActions[P.PadIndex]313};314315// Try to merge with the previous call-site. SJLJ doesn't do this316if (PreviousIsInvoke && !IsSJLJ) {317CallSiteEntry &Prev = CallSites.back();318if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) {319// Extend the range of the previous entry.320Prev.EndLabel = Site.EndLabel;321continue;322}323}324325// Otherwise, create a new call-site.326if (!IsSJLJ)327CallSites.push_back(Site);328else {329// SjLj EH must maintain the call sites in the order assigned330// to them by the SjLjPrepare pass.331unsigned SiteNo = Asm->MF->getCallSiteBeginLabel(BeginLabel);332if (CallSites.size() < SiteNo)333CallSites.resize(SiteNo);334CallSites[SiteNo - 1] = Site;335}336PreviousIsInvoke = true;337}338}339340// We end the call-site range upon function exit and at the end of every341// basic block section.342if (&MBB == &Asm->MF->back() || MBB.isEndSection()) {343// If some instruction between the previous try-range and the end of the344// function may throw, create a call-site entry with no landing pad for345// the region following the try-range.346if (SawPotentiallyThrowing && !IsSJLJ) {347CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel,348nullptr, 0};349CallSites.push_back(Site);350SawPotentiallyThrowing = false;351}352CallSiteRanges.back().CallSiteEndIdx = CallSites.size();353}354}355}356357/// Emit landing pads and actions.358///359/// The general organization of the table is complex, but the basic concepts are360/// easy. First there is a header which describes the location and organization361/// of the three components that follow.362///363/// 1. The landing pad site information describes the range of code covered by364/// the try. In our case it's an accumulation of the ranges covered by the365/// invokes in the try. There is also a reference to the landing pad that366/// handles the exception once processed. Finally an index into the actions367/// table.368/// 2. The action table, in our case, is composed of pairs of type IDs and next369/// action offset. Starting with the action index from the landing pad370/// site, each type ID is checked for a match to the current exception. If371/// it matches then the exception and type id are passed on to the landing372/// pad. Otherwise the next action is looked up. This chain is terminated373/// with a next action of zero. If no type id is found then the frame is374/// unwound and handling continues.375/// 3. Type ID table contains references to all the C++ typeinfo for all376/// catches in the function. This tables is reverse indexed base 1.377///378/// Returns the starting symbol of an exception table.379MCSymbol *EHStreamer::emitExceptionTable() {380const MachineFunction *MF = Asm->MF;381const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();382const std::vector<unsigned> &FilterIds = MF->getFilterIds();383const std::vector<LandingPadInfo> &PadInfos = MF->getLandingPads();384385// Sort the landing pads in order of their type ids. This is used to fold386// duplicate actions.387SmallVector<const LandingPadInfo *, 64> LandingPads;388LandingPads.reserve(PadInfos.size());389390for (const LandingPadInfo &LPI : PadInfos) {391// If a landing-pad has an associated label, but the label wasn't ever392// emitted, then skip it. (This can occur if the landingpad's MBB was393// deleted).394if (LPI.LandingPadLabel && !LPI.LandingPadLabel->isDefined())395continue;396LandingPads.push_back(&LPI);397}398399// Order landing pads lexicographically by type id.400llvm::sort(LandingPads, [](const LandingPadInfo *L, const LandingPadInfo *R) {401return L->TypeIds < R->TypeIds;402});403404// Compute the actions table and gather the first action index for each405// landing pad site.406SmallVector<ActionEntry, 32> Actions;407SmallVector<unsigned, 64> FirstActions;408computeActionsTable(LandingPads, Actions, FirstActions);409410// Compute the call-site table and call-site ranges. Normally, there is only411// one call-site-range which covers the whole function. With412// -basic-block-sections, there is one call-site-range per basic block413// section.414SmallVector<CallSiteEntry, 64> CallSites;415SmallVector<CallSiteRange, 4> CallSiteRanges;416computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions);417418bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;419bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm;420bool HasLEB128Directives = Asm->MAI->hasLEB128Directives();421unsigned CallSiteEncoding =422IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) :423Asm->getObjFileLowering().getCallSiteEncoding();424bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty();425426// Type infos.427MCSection *LSDASection = Asm->getObjFileLowering().getSectionForLSDA(428MF->getFunction(), *Asm->CurrentFnSym, Asm->TM);429unsigned TTypeEncoding;430431if (!HaveTTData) {432// If there is no TypeInfo, then we just explicitly say that we're omitting433// that bit.434TTypeEncoding = dwarf::DW_EH_PE_omit;435} else {436// Okay, we have actual filters or typeinfos to emit. As such, we need to437// pick a type encoding for them. We're about to emit a list of pointers to438// typeinfo objects at the end of the LSDA. However, unless we're in static439// mode, this reference will require a relocation by the dynamic linker.440//441// Because of this, we have a couple of options:442//443// 1) If we are in -static mode, we can always use an absolute reference444// from the LSDA, because the static linker will resolve it.445//446// 2) Otherwise, if the LSDA section is writable, we can output the direct447// reference to the typeinfo and allow the dynamic linker to relocate448// it. Since it is in a writable section, the dynamic linker won't449// have a problem.450//451// 3) Finally, if we're in PIC mode and the LDSA section isn't writable,452// we need to use some form of indirection. For example, on Darwin,453// we can output a statically-relocatable reference to a dyld stub. The454// offset to the stub is constant, but the contents are in a section455// that is updated by the dynamic linker. This is easy enough, but we456// need to tell the personality function of the unwinder to indirect457// through the dyld stub.458//459// FIXME: When (3) is actually implemented, we'll have to emit the stubs460// somewhere. This predicate should be moved to a shared location that is461// in target-independent code.462//463TTypeEncoding = Asm->getObjFileLowering().getTTypeEncoding();464}465466// Begin the exception table.467// Sometimes we want not to emit the data into separate section (e.g. ARM468// EHABI). In this case LSDASection will be NULL.469if (LSDASection)470Asm->OutStreamer->switchSection(LSDASection);471Asm->emitAlignment(Align(4));472473// Emit the LSDA.474MCSymbol *GCCETSym =475Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+476Twine(Asm->getFunctionNumber()));477Asm->OutStreamer->emitLabel(GCCETSym);478MCSymbol *CstEndLabel = Asm->createTempSymbol(479CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end");480481MCSymbol *TTBaseLabel = nullptr;482if (HaveTTData)483TTBaseLabel = Asm->createTempSymbol("ttbase");484485const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();486487// Helper for emitting references (offsets) for type table and the end of the488// call-site table (which marks the beginning of the action table).489// * For Itanium, these references will be emitted for every callsite range.490// * For SJLJ and Wasm, they will be emitted only once in the LSDA header.491auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() {492Asm->emitEncodingByte(TTypeEncoding, "@TType");493if (HaveTTData) {494// N.B.: There is a dependency loop between the size of the TTBase uleb128495// here and the amount of padding before the aligned type table. The496// assembler must sometimes pad this uleb128 or insert extra padding497// before the type table. See PR35809 or GNU as bug 4029.498MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref");499Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel);500Asm->OutStreamer->emitLabel(TTBaseRefLabel);501}502503// The Action table follows the call-site table. So we emit the504// label difference from here (start of the call-site table for SJLJ and505// Wasm, and start of a call-site range for Itanium) to the end of the506// whole call-site table (end of the last call-site range for Itanium).507MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin");508Asm->emitEncodingByte(CallSiteEncoding, "Call site");509Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel);510Asm->OutStreamer->emitLabel(CstBeginLabel);511};512513// An alternative path to EmitTypeTableRefAndCallSiteTableEndRef.514// For some platforms, the system assembler does not accept the form of515// `.uleb128 label2 - label1`. In those situations, we would need to calculate516// the size between label1 and label2 manually.517// In this case, we would need to calculate the LSDA size and the call518// site table size.519auto EmitTypeTableOffsetAndCallSiteTableOffset = [&]() {520assert(CallSiteEncoding == dwarf::DW_EH_PE_udata4 && !HasLEB128Directives &&521"Targets supporting .uleb128 do not need to take this path.");522if (CallSiteRanges.size() > 1)523report_fatal_error(524"-fbasic-block-sections is not yet supported on "525"platforms that do not have general LEB128 directive support.");526527uint64_t CallSiteTableSize = 0;528const CallSiteRange &CSRange = CallSiteRanges.back();529for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;530CallSiteIdx < CSRange.CallSiteEndIdx; ++CallSiteIdx) {531const CallSiteEntry &S = CallSites[CallSiteIdx];532// Each call site entry consists of 3 udata4 fields (12 bytes) and533// 1 ULEB128 field.534CallSiteTableSize += 12 + getULEB128Size(S.Action);535assert(isUInt<32>(CallSiteTableSize) && "CallSiteTableSize overflows.");536}537538Asm->emitEncodingByte(TTypeEncoding, "@TType");539if (HaveTTData) {540const unsigned ByteSizeOfCallSiteOffset =541getULEB128Size(CallSiteTableSize);542uint64_t ActionTableSize = 0;543for (const ActionEntry &Action : Actions) {544// Each action entry consists of two SLEB128 fields.545ActionTableSize += getSLEB128Size(Action.ValueForTypeID) +546getSLEB128Size(Action.NextAction);547assert(isUInt<32>(ActionTableSize) && "ActionTableSize overflows.");548}549550const unsigned TypeInfoSize =551Asm->GetSizeOfEncodedValue(TTypeEncoding) * MF->getTypeInfos().size();552553const uint64_t LSDASizeBeforeAlign =5541 // Call site encoding byte.555+ ByteSizeOfCallSiteOffset // ULEB128 encoding of CallSiteTableSize.556+ CallSiteTableSize // Call site table content.557+ ActionTableSize; // Action table content.558559const uint64_t LSDASizeWithoutAlign = LSDASizeBeforeAlign + TypeInfoSize;560const unsigned ByteSizeOfLSDAWithoutAlign =561getULEB128Size(LSDASizeWithoutAlign);562const uint64_t DisplacementBeforeAlign =5632 // LPStartEncoding and TypeTableEncoding.564+ ByteSizeOfLSDAWithoutAlign + LSDASizeBeforeAlign;565566// The type info area starts with 4 byte alignment.567const unsigned NeedAlignVal = (4 - DisplacementBeforeAlign % 4) % 4;568uint64_t LSDASizeWithAlign = LSDASizeWithoutAlign + NeedAlignVal;569const unsigned ByteSizeOfLSDAWithAlign =570getULEB128Size(LSDASizeWithAlign);571572// The LSDASizeWithAlign could use 1 byte less padding for alignment573// when the data we use to represent the LSDA Size "needs" to be 1 byte574// larger than the one previously calculated without alignment.575if (ByteSizeOfLSDAWithAlign > ByteSizeOfLSDAWithoutAlign)576LSDASizeWithAlign -= 1;577578Asm->OutStreamer->emitULEB128IntValue(LSDASizeWithAlign,579ByteSizeOfLSDAWithAlign);580}581582Asm->emitEncodingByte(CallSiteEncoding, "Call site");583Asm->OutStreamer->emitULEB128IntValue(CallSiteTableSize);584};585586// SjLj / Wasm Exception handling587if (IsSJLJ || IsWasm) {588Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front()));589590// emit the LSDA header.591Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");592EmitTypeTableRefAndCallSiteTableEndRef();593594unsigned idx = 0;595for (SmallVectorImpl<CallSiteEntry>::const_iterator596I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) {597const CallSiteEntry &S = *I;598599// Index of the call site entry.600if (VerboseAsm) {601Asm->OutStreamer->AddComment(">> Call Site " + Twine(idx) + " <<");602Asm->OutStreamer->AddComment(" On exception at call site "+Twine(idx));603}604Asm->emitULEB128(idx);605606// Offset of the first associated action record, relative to the start of607// the action table. This value is biased by 1 (1 indicates the start of608// the action table), and 0 indicates that there are no actions.609if (VerboseAsm) {610if (S.Action == 0)611Asm->OutStreamer->AddComment(" Action: cleanup");612else613Asm->OutStreamer->AddComment(" Action: " +614Twine((S.Action - 1) / 2 + 1));615}616Asm->emitULEB128(S.Action);617}618Asm->OutStreamer->emitLabel(CstEndLabel);619} else {620// Itanium LSDA exception handling621622// The call-site table is a list of all call sites that may throw an623// exception (including C++ 'throw' statements) in the procedure624// fragment. It immediately follows the LSDA header. Each entry indicates,625// for a given call, the first corresponding action record and corresponding626// landing pad.627//628// The table begins with the number of bytes, stored as an LEB128629// compressed, unsigned integer. The records immediately follow the record630// count. They are sorted in increasing call-site address. Each record631// indicates:632//633// * The position of the call-site.634// * The position of the landing pad.635// * The first action record for that call site.636//637// A missing entry in the call-site table indicates that a call is not638// supposed to throw.639640assert(CallSiteRanges.size() != 0 && "No call-site ranges!");641642// There should be only one call-site range which includes all the landing643// pads. Find that call-site range here.644const CallSiteRange *LandingPadRange = nullptr;645for (const CallSiteRange &CSRange : CallSiteRanges) {646if (CSRange.IsLPRange) {647assert(LandingPadRange == nullptr &&648"All landing pads must be in a single callsite range.");649LandingPadRange = &CSRange;650}651}652653// The call-site table is split into its call-site ranges, each being654// emitted as:655// [ LPStartEncoding | LPStart ]656// [ TypeTableEncoding | TypeTableOffset ]657// [ CallSiteEncoding | CallSiteTableEndOffset ]658// cst_begin -> { call-site entries contained in this range }659//660// and is followed by the next call-site range.661//662// For each call-site range, CallSiteTableEndOffset is computed as the663// difference between cst_begin of that range and the last call-site-table's664// end label. This offset is used to find the action table.665666unsigned Entry = 0;667for (const CallSiteRange &CSRange : CallSiteRanges) {668if (CSRange.CallSiteBeginIdx != 0) {669// Align the call-site range for all ranges except the first. The670// first range is already aligned due to the exception table alignment.671Asm->emitAlignment(Align(4));672}673Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel);674675// Emit the LSDA header.676// LPStart is omitted if either we have a single call-site range (in which677// case the function entry is treated as @LPStart) or if this function has678// no landing pads (in which case @LPStart is undefined).679if (CallSiteRanges.size() == 1 || LandingPadRange == nullptr) {680Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");681} else if (!Asm->isPositionIndependent()) {682// For more than one call-site ranges, LPStart must be explicitly683// specified.684// For non-PIC we can simply use the absolute value.685Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart");686Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel,687Asm->MAI->getCodePointerSize());688} else {689// For PIC mode, we Emit a PC-relative address for LPStart.690Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart");691MCContext &Context = Asm->OutStreamer->getContext();692MCSymbol *Dot = Context.createTempSymbol();693Asm->OutStreamer->emitLabel(Dot);694Asm->OutStreamer->emitValue(695MCBinaryExpr::createSub(696MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel,697Context),698MCSymbolRefExpr::create(Dot, Context), Context),699Asm->MAI->getCodePointerSize());700}701702if (HasLEB128Directives)703EmitTypeTableRefAndCallSiteTableEndRef();704else705EmitTypeTableOffsetAndCallSiteTableOffset();706707for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;708CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) {709const CallSiteEntry &S = CallSites[CallSiteIdx];710711MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel;712MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel;713714MCSymbol *BeginLabel = S.BeginLabel;715if (!BeginLabel)716BeginLabel = EHFuncBeginSym;717MCSymbol *EndLabel = S.EndLabel;718if (!EndLabel)719EndLabel = EHFuncEndSym;720721// Offset of the call site relative to the start of the procedure.722if (VerboseAsm)723Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) +724" <<");725Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding);726if (VerboseAsm)727Asm->OutStreamer->AddComment(Twine(" Call between ") +728BeginLabel->getName() + " and " +729EndLabel->getName());730Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding);731732// Offset of the landing pad relative to the start of the landing pad733// fragment.734if (!S.LPad) {735if (VerboseAsm)736Asm->OutStreamer->AddComment(" has no landing pad");737Asm->emitCallSiteValue(0, CallSiteEncoding);738} else {739if (VerboseAsm)740Asm->OutStreamer->AddComment(Twine(" jumps to ") +741S.LPad->LandingPadLabel->getName());742Asm->emitCallSiteOffset(S.LPad->LandingPadLabel,743LandingPadRange->FragmentBeginLabel,744CallSiteEncoding);745}746747// Offset of the first associated action record, relative to the start748// of the action table. This value is biased by 1 (1 indicates the start749// of the action table), and 0 indicates that there are no actions.750if (VerboseAsm) {751if (S.Action == 0)752Asm->OutStreamer->AddComment(" On action: cleanup");753else754Asm->OutStreamer->AddComment(" On action: " +755Twine((S.Action - 1) / 2 + 1));756}757Asm->emitULEB128(S.Action);758}759}760Asm->OutStreamer->emitLabel(CstEndLabel);761}762763// Emit the Action Table.764int Entry = 0;765for (const ActionEntry &Action : Actions) {766if (VerboseAsm) {767// Emit comments that decode the action table.768Asm->OutStreamer->AddComment(">> Action Record " + Twine(++Entry) + " <<");769}770771// Type Filter772//773// Used by the runtime to match the type of the thrown exception to the774// type of the catch clauses or the types in the exception specification.775if (VerboseAsm) {776if (Action.ValueForTypeID > 0)777Asm->OutStreamer->AddComment(" Catch TypeInfo " +778Twine(Action.ValueForTypeID));779else if (Action.ValueForTypeID < 0)780Asm->OutStreamer->AddComment(" Filter TypeInfo " +781Twine(Action.ValueForTypeID));782else783Asm->OutStreamer->AddComment(" Cleanup");784}785Asm->emitSLEB128(Action.ValueForTypeID);786787// Action Record788if (VerboseAsm) {789if (Action.Previous == unsigned(-1)) {790Asm->OutStreamer->AddComment(" No further actions");791} else {792Asm->OutStreamer->AddComment(" Continue to action " +793Twine(Action.Previous + 1));794}795}796Asm->emitSLEB128(Action.NextAction);797}798799if (HaveTTData) {800Asm->emitAlignment(Align(4));801emitTypeInfos(TTypeEncoding, TTBaseLabel);802}803804Asm->emitAlignment(Align(4));805return GCCETSym;806}807808void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) {809const MachineFunction *MF = Asm->MF;810const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();811const std::vector<unsigned> &FilterIds = MF->getFilterIds();812813const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();814815int Entry = 0;816// Emit the Catch TypeInfos.817if (VerboseAsm && !TypeInfos.empty()) {818Asm->OutStreamer->AddComment(">> Catch TypeInfos <<");819Asm->OutStreamer->addBlankLine();820Entry = TypeInfos.size();821}822823for (const GlobalValue *GV : llvm::reverse(TypeInfos)) {824if (VerboseAsm)825Asm->OutStreamer->AddComment("TypeInfo " + Twine(Entry--));826Asm->emitTTypeReference(GV, TTypeEncoding);827}828829Asm->OutStreamer->emitLabel(TTBaseLabel);830831// Emit the Exception Specifications.832if (VerboseAsm && !FilterIds.empty()) {833Asm->OutStreamer->AddComment(">> Filter TypeInfos <<");834Asm->OutStreamer->addBlankLine();835Entry = 0;836}837for (std::vector<unsigned>::const_iterator838I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) {839unsigned TypeID = *I;840if (VerboseAsm) {841--Entry;842if (isFilterEHSelector(TypeID))843Asm->OutStreamer->AddComment("FilterInfo " + Twine(Entry));844}845846Asm->emitULEB128(TypeID);847}848}849850851