//
//===----------------------------------------------------------------------===//
//
-// This file contains support for writing dwarf exception info into asm files.
+// This file contains support for writing DWARF exception info into asm files.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLocation.h"
-#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCStreamer.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
using namespace llvm;
static TimerGroup &getDwarfTimerGroup() {
- static TimerGroup DwarfTimerGroup("Dwarf Exception");
+ static TimerGroup DwarfTimerGroup("DWARF Exception");
return DwarfTimerGroup;
}
shouldEmitTableModule(false), shouldEmitMovesModule(false),
ExceptionTimer(0) {
if (TimePassesIsEnabled)
- ExceptionTimer = new Timer("Dwarf Exception Writer",
+ ExceptionTimer = new Timer("DWARF Exception Writer",
getDwarfTimerGroup());
}
delete ExceptionTimer;
}
+/// SizeOfEncodedValue - Return the size of the encoding in bytes.
unsigned DwarfException::SizeOfEncodedValue(unsigned Encoding) {
if (Encoding == dwarf::DW_EH_PE_omit)
return 0;
return 8;
}
- llvm_unreachable("Invalid encoded value.");
+ assert(0 && "Invalid encoded value.");
return 0;
}
/// EmitCIE - Emit a Common Information Entry (CIE). This holds information that
/// is shared among many Frame Description Entries. There is at least one CIE
/// in every non-empty .debug_frame section.
-void DwarfException::EmitCIE(const Function *Personality, unsigned Index) {
+void DwarfException::EmitCIE(const Function *PersonalityFn, unsigned Index) {
// Size and sign of stack growth.
int stackGrowth =
Asm->TM.getFrameInfo()->getStackGrowthDirection() ==
TargetFrameInfo::StackGrowsUp ?
TD->getPointerSize() : -TD->getPointerSize();
+ const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
+
// Begin eh frame section.
- Asm->OutStreamer.SwitchSection(Asm->getObjFileLowering().getEHFrameSection());
+ Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection());
if (MAI->is_EHSymbolPrivate())
O << MAI->getPrivateGlobalPrefix();
-
O << "EH_frame" << Index << ":\n";
+
EmitLabel("section_eh_frame", Index);
// Define base labels.
Asm->EOL("CIE Version");
// The personality presence indicates that language specific information will
- // show up in the eh frame.
-
- // FIXME: Don't hardcode these encodings.
+ // show up in the eh frame. Find out how we are supposed to lower the
+ // personality function reference:
+ const MCExpr *PersonalityRef = 0;
+ bool IsPersonalityIndirect = false, IsPersonalityPCRel = false;
+ if (PersonalityFn) {
+ // FIXME: HANDLE STATIC CODEGEN MODEL HERE.
+
+ // In non-static mode, ask the object file how to represent this reference.
+ PersonalityRef =
+ TLOF.getSymbolForDwarfGlobalReference(PersonalityFn, Asm->Mang,
+ Asm->MMI,
+ IsPersonalityIndirect,
+ IsPersonalityPCRel);
+ }
+
unsigned PerEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
- if (Personality && MAI->getNeedsIndirectEncoding())
+ if (IsPersonalityIndirect)
PerEncoding |= dwarf::DW_EH_PE_indirect;
unsigned LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
unsigned FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
unsigned AugmentationSize = 0;
char *APtr = Augmentation + 1;
- if (Personality) {
+ if (PersonalityRef) {
// There is a personality function.
*APtr++ = 'P';
AugmentationSize += 1 + SizeOfEncodedValue(PerEncoding);
Asm->EOL("Personality", PerEncoding);
// If there is a personality, we need to indicate the function's location.
- if (Personality) {
- PrintRelDirective(true);
- O << MAI->getPersonalityPrefix();
- Asm->EmitExternalGlobal((const GlobalVariable *)(Personality));
- O << MAI->getPersonalitySuffix();
- if (strcmp(MAI->getPersonalitySuffix(), "+4@GOTPCREL"))
- O << "-" << MAI->getPCSymbol();
+ if (PersonalityRef) {
+ // If the reference to the personality function symbol is not already
+ // pc-relative, then we need to subtract our current address from it. Do
+ // this by emitting a label and subtracting it from the expression we
+ // already have. This is equivalent to emitting "foo - .", but we have to
+ // emit the label for "." directly.
+ if (!IsPersonalityPCRel) {
+ SmallString<64> Name;
+ raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix()
+ << "personalityref_addr" << Asm->getFunctionNumber() << "_" << Index;
+ MCSymbol *DotSym = Asm->OutContext.GetOrCreateSymbol(Name.str());
+ Asm->OutStreamer.EmitLabel(DotSym);
+
+ PersonalityRef =
+ MCBinaryExpr::CreateSub(PersonalityRef,
+ MCSymbolRefExpr::Create(DotSym,Asm->OutContext),
+ Asm->OutContext);
+ }
+
+ O << MAI->getData32bitsDirective();
+ PersonalityRef->print(O, MAI);
Asm->EOL("Personality");
Asm->EmitInt8(LSDAEncoding);
// 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);
+ Asm->EmitAlignment(TD->getPointerSize() == 4 ? 2 : 3, 0, 0, false);
EmitLabel("eh_frame_common_end", Index);
Asm->EOL();
/// 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
+/// with a next action of zero. If no type id is found then 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.
+/// catches in the function. This tables is reverse indexed base 1.
void DwarfException::EmitExceptionTable() {
const std::vector<GlobalVariable *> &TypeInfos = MMI->getTypeInfos();
const std::vector<unsigned> &FilterIds = MMI->getFilterIds();
// landing pad site.
SmallVector<ActionEntry, 32> Actions;
SmallVector<unsigned, 64> FirstActions;
- unsigned SizeActions = ComputeActionsTable(LandingPads, Actions, FirstActions);
+ unsigned SizeActions = ComputeActionsTable(LandingPads, Actions,
+ FirstActions);
// 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 when using Dwarf exception handling.
+ // try-ranges for them need be deduced when using DWARF exception handling.
RangeMapType PadMap;
for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
const LandingPadInfo *LandingPad = LandingPads[i];
// 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
+ const unsigned SiteStartSize = SizeOfEncodedValue(dwarf::DW_EH_PE_udata4);
+ const unsigned SiteLengthSize = SizeOfEncodedValue(dwarf::DW_EH_PE_udata4);
+ const unsigned LandingPadSize = SizeOfEncodedValue(dwarf::DW_EH_PE_udata4);
+ bool IsSJLJ = MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
+ bool HaveTTData = IsSJLJ ? (!TypeInfos.empty() || !FilterIds.empty()) : true;
unsigned SizeSites;
- bool HaveTTData = (MAI->getExceptionHandlingType() == ExceptionHandling::SjLj)
- ? (!TypeInfos.empty() || !FilterIds.empty()) : true;
-
-
- if (MAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
+ if (IsSJLJ)
SizeSites = 0;
- } else
+ else
SizeSites = CallSites.size() *
(SiteStartSize + SiteLengthSize + LandingPadSize);
+
for (unsigned i = 0, e = CallSites.size(); i < e; ++i) {
SizeSites += MCAsmInfo::getULEB128Size(CallSites[i].Action);
- if (MAI->getExceptionHandlingType() == ExceptionHandling::SjLj)
+ if (IsSJLJ)
SizeSites += MCAsmInfo::getULEB128Size(i);
}
- // Type infos.
- const unsigned TypeInfoSize = TD->getPointerSize(); // DW_EH_PE_absptr
- unsigned SizeTypes = TypeInfos.size() * TypeInfoSize;
-
- unsigned TypeOffset = sizeof(int8_t) + // Call site format
- MCAsmInfo::getULEB128Size(SizeSites) + // Call-site table length
- SizeSites + SizeActions + SizeTypes;
-
- unsigned TotalSize = sizeof(int8_t) + // LPStart format
- sizeof(int8_t) + // TType format
- (HaveTTData ?
- MCAsmInfo::getULEB128Size(TypeOffset) : 0) + // TType base offset
- TypeOffset;
-
- unsigned SizeAlign = (4 - TotalSize) & 3;
- // Begin the exception table.
+ // Type infos.
const MCSection *LSDASection = Asm->getObjFileLowering().getLSDASection();
- Asm->OutStreamer.SwitchSection(LSDASection);
- 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");
- }
+ unsigned TTypeFormat;
+ unsigned TypeFormatSize;
- EmitLabel("exception", SubprogramCount);
- if (MAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
- SmallString<16> LSDAName;
- raw_svector_ostream(LSDAName) << MAI->getPrivateGlobalPrefix() <<
- "_LSDA_" << Asm->getFunctionNumber();
- O << LSDAName.str() << ":\n";
- }
-
- // Emit the header.
- Asm->EmitInt8(dwarf::DW_EH_PE_omit);
- Asm->EOL("@LPStart format", dwarf::DW_EH_PE_omit);
-
-#if 0
- if (TypeInfos.empty() && FilterIds.empty()) {
- // If there are no typeinfos or filters, there is nothing to emit, optimize
- // by specifying the "omit" encoding.
- Asm->EmitInt8(dwarf::DW_EH_PE_omit);
- Asm->EOL("@TType format", dwarf::DW_EH_PE_omit);
+ if (!HaveTTData) {
+ // For SjLj exceptions, if there is no TypeInfo, then we just explicitly say
+ // that we're omitting that bit.
+ TTypeFormat = dwarf::DW_EH_PE_omit;
+ TypeFormatSize = SizeOfEncodedValue(dwarf::DW_EH_PE_absptr);
} else {
// Okay, we have actual filters or typeinfos to emit. As such, we need to
// pick a type encoding for them. We're about to emit a list of pointers to
// mode, this reference will require a relocation by the dynamic linker.
//
// Because of this, we have a couple of options:
+ //
// 1) If we are in -static mode, we can always use an absolute reference
// from the LSDA, because the static linker will resolve it.
+ //
// 2) Otherwise, if the LSDA section is writable, we can output the direct
// reference to the typeinfo and allow the dynamic linker to relocate
// it. Since it is in a writable section, the dynamic linker won't
// have a problem.
+ //
// 3) Finally, if we're in PIC mode and the LDSA section isn't writable,
// we need to use some form of indirection. For example, on Darwin,
// we can output a statically-relocatable reference to a dyld stub. The
// need to tell the personality function of the unwinder to indirect
// through the dyld stub.
//
- // FIXME: When this is actually implemented, we'll have to emit the stubs
+ // FIXME: When (3) is actually implemented, we'll have to emit the stubs
// somewhere. This predicate should be moved to a shared location that is
// in target-independent code.
//
- if (LSDASection->isWritable() ||
- Asm->TM.getRelocationModel() == Reloc::Static) {
- Asm->EmitInt8(DW_EH_PE_absptr);
- Asm->EOL("TType format (DW_EH_PE_absptr)");
- } else {
- Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4);
- Asm->EOL("TType format (DW_EH_PE_pcrel | DW_EH_PE_indirect"
- " | DW_EH_PE_sdata4)");
- }
- Asm->EmitULEB128Bytes(TypeOffset);
- Asm->EOL("TType base offset");
+ if (LSDASection->getKind().isWriteable() ||
+ Asm->TM.getRelocationModel() == Reloc::Static)
+ TTypeFormat = dwarf::DW_EH_PE_absptr;
+ else
+ TTypeFormat = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
+ dwarf::DW_EH_PE_sdata4;
+
+ TypeFormatSize = SizeOfEncodedValue(TTypeFormat);
}
-#else
- // For SjLj exceptions, if there is no TypeInfo, then we just explicitly
- // say that we're omitting that bit.
- // FIXME: does this apply to Dwarf also? The above #if 0 implies yes?
- if (!HaveTTData) {
- Asm->EmitInt8(dwarf::DW_EH_PE_omit);
- Asm->EOL("@TType format", dwarf::DW_EH_PE_omit);
- } else {
- Asm->EmitInt8(dwarf::DW_EH_PE_absptr);
- Asm->EOL("@TType format", dwarf::DW_EH_PE_absptr);
- Asm->EmitULEB128Bytes(TypeOffset);
+
+ // Begin the exception table.
+ Asm->OutStreamer.SwitchSection(LSDASection);
+ Asm->EmitAlignment(2, 0, 0, false);
+
+ O << "GCC_except_table" << SubprogramCount << ":\n";
+
+ // The type infos need to be aligned. GCC does this by inserting padding just
+ // before the type infos. However, this changes the size of the exception
+ // table, so you need to take this into account when you output the exception
+ // table size. However, the size is output using a variable length encoding.
+ // So by increasing the size by inserting padding, you may increase the number
+ // of bytes used for writing the size. If it increases, say by one byte, then
+ // you now need to output one less byte of padding to get the type infos
+ // aligned. However this decreases the size of the exception table. This
+ // changes the value you have to output for the exception table size. Due to
+ // the variable length encoding, the number of bytes used for writing the
+ // length may decrease. If so, you then have to increase the amount of
+ // padding. And so on. If you look carefully at the GCC code you will see that
+ // it indeed does this in a loop, going on and on until the values stabilize.
+ // We chose another solution: don't output padding inside the table like GCC
+ // does, instead output it before the table.
+ unsigned SizeTypes = TypeInfos.size() * TypeFormatSize;
+ unsigned TyOffset = sizeof(int8_t) + // Call site format
+ MCAsmInfo::getULEB128Size(SizeSites) + // Call-site table length
+ SizeSites + SizeActions + SizeTypes;
+ unsigned TotalSize = sizeof(int8_t) + // LPStart format
+ sizeof(int8_t) + // TType format
+ (HaveTTData ?
+ MCAsmInfo::getULEB128Size(TyOffset) : 0) + // TType base offset
+ TyOffset;
+ unsigned SizeAlign = (4 - TotalSize) & 3;
+
+ for (unsigned i = 0; i != SizeAlign; ++i) {
+ Asm->EmitInt8(0);
+ Asm->EOL("Padding");
+ }
+
+ EmitLabel("exception", SubprogramCount);
+
+ if (IsSJLJ) {
+ SmallString<16> LSDAName;
+ raw_svector_ostream(LSDAName) << MAI->getPrivateGlobalPrefix() <<
+ "_LSDA_" << Asm->getFunctionNumber();
+ O << LSDAName.str() << ":\n";
+ }
+
+ // Emit the header.
+ Asm->EmitInt8(dwarf::DW_EH_PE_omit);
+ Asm->EOL("@LPStart format", dwarf::DW_EH_PE_omit);
+
+ Asm->EmitInt8(TTypeFormat);
+ Asm->EOL("@TType format", TTypeFormat);
+
+ if (HaveTTData) {
+ Asm->EmitULEB128Bytes(TyOffset);
Asm->EOL("@TType base offset");
}
-#endif
- // SjLj Exception handilng
- if (MAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
+ // SjLj Exception handling
+ if (IsSJLJ) {
Asm->EmitInt8(dwarf::DW_EH_PE_udata4);
Asm->EOL("Call site format", dwarf::DW_EH_PE_udata4);
Asm->EmitULEB128Bytes(SizeSites);
// * The first action record for that call site.
//
// A missing entry in the call-site table indicates that a call is not
- // supposed to throw. Such calls include:
- //
- // * Calls to destructors within cleanup code. C++ semantics forbids these
- // calls to throw.
- // * Calls to intrinsic routines in the standard library which are known
- // not to throw (sin, memcpy, et al).
- //
- // If the runtime does not find the call-site entry for a given call, it
- // will call `terminate()'.
+ // supposed to throw.
// Emit the landing pad call site table.
Asm->EmitInt8(dwarf::DW_EH_PE_udata4);
Asm->EOL("Next action");
}
- // Emit the Catch Clauses. The code for the catch clauses following the same
- // try is similar to a switch statement. The catch clause action record
- // informs the runtime about the type of a catch clause and about the
- // associated switch value.
- //
- // Action Record Fields:
- //
- // * Filter Value
- // Positive value, starting at 1. Index in the types table of the
- // __typeinfo for the catch-clause type. 1 is the first word preceding
- // TTBase, 2 is the second word, and so on. Used by the runtime to check
- // if the thrown exception type matches the catch-clause type. Back-end
- // generated switch statements check against this value.
- //
- // * Next
- // Signed offset, in bytes from the start of this field, to the next
- // chained action record, or zero if none.
- //
- // The order of the action records determined by the next field is the order
- // of the catch clauses as they appear in the source code, and must be kept in
- // the same order. As a result, changing the order of the catch clause would
- // change the semantics of the program.
+ // Emit the Catch TypeInfos.
for (std::vector<GlobalVariable *>::const_reverse_iterator
I = TypeInfos.rbegin(), E = TypeInfos.rend(); I != E; ++I) {
const GlobalVariable *GV = *I;
PrintRelDirective();
if (GV) {
- std::string GLN;
- O << Asm->getGlobalLinkName(GV, GLN);
+ O << Asm->Mang->getMangledName(GV);
} else {
O << "0x0";
}
Asm->EOL("TypeInfo");
}
- // Emit the Type Table.
+ // Emit the Exception Specifications.
for (std::vector<unsigned>::const_iterator
I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) {
unsigned TypeID = *I;
Asm->EmitULEB128Bytes(TypeID);
- Asm->EOL("Filter TypeInfo index");
+ if (TypeID != 0)
+ Asm->EOL("Exception specification");
+ else
+ Asm->EOL();
}
Asm->EmitAlignment(2, 0, 0, false);
const std::vector<Function *> Personalities = MMI->getPersonalities();
- for (unsigned i = 0, e = Personalities.size(); i < e; ++i)
- EmitCIE(Personalities[i], i);
+ for (unsigned I = 0, E = Personalities.size(); I < E; ++I)
+ EmitCIE(Personalities[I], I);
for (std::vector<FunctionEHFrameInfo>::iterator
I = EHFrames.begin(), E = EHFrames.end(); I != E; ++I)
ExceptionTimer->stopTimer();
}
-/// BeginFunction - Gather pre-function exception information. Assumes being
-/// emitted immediately after the function entry point.
+/// BeginFunction - Gather pre-function exception information. Assumes it's
+/// being emitted immediately after the function entry point.
void DwarfException::BeginFunction(MachineFunction *MF) {
+ if (!MMI || !MAI->doesSupportExceptionHandling()) return;
+
if (TimePassesIsEnabled)
ExceptionTimer->startTimer();
this->MF = MF;
shouldEmitTable = shouldEmitMoves = false;
- if (MMI && MAI->doesSupportExceptionHandling()) {
- // Map all labels and get rid of any dead landing pads.
- MMI->TidyLandingPads();
+ // 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().empty())
- shouldEmitTable = true;
+ // If any landing pads survive, we need an EH table.
+ if (!MMI->getLandingPads().empty())
+ shouldEmitTable = true;
- // See if we need frame move info.
- if (!MF->getFunction()->doesNotThrow() || UnwindTablesMandatory)
- shouldEmitMoves = 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);
- }
+ if (shouldEmitMoves || shouldEmitTable)
+ // Assumes in correct section after the entry point.
+ EmitLabel("eh_func_begin", ++SubprogramCount);
shouldEmitTableModule |= shouldEmitTable;
shouldEmitMovesModule |= shouldEmitMoves;
EmitLabel("eh_func_end", SubprogramCount);
EmitExceptionTable();
+ std::string FunctionEHName =
+ Asm->Mang->getMangledName(MF->getFunction(), ".eh",
+ Asm->MAI->is_EHSymbolPrivate());
+
// Save EH frame information
- EHFrames.push_back(FunctionEHFrameInfo(getAsm()->getCurrentFunctionEHName(MF),
- SubprogramCount,
+ EHFrames.push_back(FunctionEHFrameInfo(FunctionEHName, SubprogramCount,
MMI->getPersonalityIndex(),
MF->getFrameInfo()->hasCalls(),
!MMI->getLandingPads().empty(),