llvm/lib/MC/MCDwarf.cpp
Adrian Prantl 52f8d91dde Don't crash when compiling inline assembler containing .file directives.
Removing the assertion is  safe to do because any module level inline
assembly is always emitted first via AsmPrinter::doInitialization().

http://reviews.llvm.org/D16101
rdar://22690666

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263033 91177308-0d34-0410-b5e6-96231b3b80d8
2016-03-09 17:32:56 +00:00

1587 lines
56 KiB
C++

//===- lib/MC/MCDwarf.cpp - MCDwarf implementation ------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/MC/MCDwarf.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/config.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) {
unsigned MinInsnLength = Context.getAsmInfo()->getMinInstAlignment();
if (MinInsnLength == 1)
return AddrDelta;
if (AddrDelta % MinInsnLength != 0) {
// TODO: report this error, but really only once.
;
}
return AddrDelta / MinInsnLength;
}
//
// This is called when an instruction is assembled into the specified section
// and if there is information from the last .loc directive that has yet to have
// a line entry made for it is made.
//
void MCDwarfLineEntry::Make(MCObjectStreamer *MCOS, MCSection *Section) {
if (!MCOS->getContext().getDwarfLocSeen())
return;
// Create a symbol at in the current section for use in the line entry.
MCSymbol *LineSym = MCOS->getContext().createTempSymbol();
// Set the value of the symbol to use for the MCDwarfLineEntry.
MCOS->EmitLabel(LineSym);
// Get the current .loc info saved in the context.
const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc();
// Create a (local) line entry with the symbol and the current .loc info.
MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
// clear DwarfLocSeen saying the current .loc info is now used.
MCOS->getContext().clearDwarfLocSeen();
// Add the line entry to this section's entries.
MCOS->getContext()
.getMCDwarfLineTable(MCOS->getContext().getDwarfCompileUnitID())
.getMCLineSections()
.addLineEntry(LineEntry, Section);
}
//
// This helper routine returns an expression of End - Start + IntVal .
//
static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS,
const MCSymbol &Start,
const MCSymbol &End,
int IntVal) {
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
const MCExpr *Res =
MCSymbolRefExpr::create(&End, Variant, MCOS.getContext());
const MCExpr *RHS =
MCSymbolRefExpr::create(&Start, Variant, MCOS.getContext());
const MCExpr *Res1 =
MCBinaryExpr::create(MCBinaryExpr::Sub, Res, RHS, MCOS.getContext());
const MCExpr *Res2 =
MCConstantExpr::create(IntVal, MCOS.getContext());
const MCExpr *Res3 =
MCBinaryExpr::create(MCBinaryExpr::Sub, Res1, Res2, MCOS.getContext());
return Res3;
}
//
// This emits the Dwarf line table for the specified section from the entries
// in the LineSection.
//
static inline void
EmitDwarfLineTable(MCObjectStreamer *MCOS, MCSection *Section,
const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {
unsigned FileNum = 1;
unsigned LastLine = 1;
unsigned Column = 0;
unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
unsigned Isa = 0;
unsigned Discriminator = 0;
MCSymbol *LastLabel = nullptr;
// Loop through each MCDwarfLineEntry and encode the dwarf line number table.
for (auto it = LineEntries.begin(),
ie = LineEntries.end();
it != ie; ++it) {
if (FileNum != it->getFileNum()) {
FileNum = it->getFileNum();
MCOS->EmitIntValue(dwarf::DW_LNS_set_file, 1);
MCOS->EmitULEB128IntValue(FileNum);
}
if (Column != it->getColumn()) {
Column = it->getColumn();
MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1);
MCOS->EmitULEB128IntValue(Column);
}
if (Discriminator != it->getDiscriminator()) {
Discriminator = it->getDiscriminator();
unsigned Size = getULEB128Size(Discriminator);
MCOS->EmitIntValue(dwarf::DW_LNS_extended_op, 1);
MCOS->EmitULEB128IntValue(Size + 1);
MCOS->EmitIntValue(dwarf::DW_LNE_set_discriminator, 1);
MCOS->EmitULEB128IntValue(Discriminator);
}
if (Isa != it->getIsa()) {
Isa = it->getIsa();
MCOS->EmitIntValue(dwarf::DW_LNS_set_isa, 1);
MCOS->EmitULEB128IntValue(Isa);
}
if ((it->getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) {
Flags = it->getFlags();
MCOS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1);
}
if (it->getFlags() & DWARF2_FLAG_BASIC_BLOCK)
MCOS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1);
if (it->getFlags() & DWARF2_FLAG_PROLOGUE_END)
MCOS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1);
if (it->getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN)
MCOS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1);
int64_t LineDelta = static_cast<int64_t>(it->getLine()) - LastLine;
MCSymbol *Label = it->getLabel();
// At this point we want to emit/create the sequence to encode the delta in
// line numbers and the increment of the address from the previous Label
// and the current Label.
const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo();
MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label,
asmInfo->getPointerSize());
LastLine = it->getLine();
LastLabel = Label;
}
// Emit a DW_LNE_end_sequence for the end of the section.
// Use the section end label to compute the address delta and use INT64_MAX
// as the line delta which is the signal that this is actually a
// DW_LNE_end_sequence.
MCSymbol *SectionEnd = MCOS->endSection(Section);
// Switch back the dwarf line section, in case endSection had to switch the
// section.
MCContext &Ctx = MCOS->getContext();
MCOS->SwitchSection(Ctx.getObjectFileInfo()->getDwarfLineSection());
const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
AsmInfo->getPointerSize());
}
//
// This emits the Dwarf file and the line tables.
//
void MCDwarfLineTable::Emit(MCObjectStreamer *MCOS,
MCDwarfLineTableParams Params) {
MCContext &context = MCOS->getContext();
auto &LineTables = context.getMCDwarfLineTables();
// Bail out early so we don't switch to the debug_line section needlessly and
// in doing so create an unnecessary (if empty) section.
if (LineTables.empty())
return;
// Switch to the section where the table will be emitted into.
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection());
// Handle the rest of the Compile Units.
for (const auto &CUIDTablePair : LineTables)
CUIDTablePair.second.EmitCU(MCOS, Params);
}
void MCDwarfDwoLineTable::Emit(MCStreamer &MCOS,
MCDwarfLineTableParams Params) const {
MCOS.EmitLabel(Header.Emit(&MCOS, Params, None).second);
}
std::pair<MCSymbol *, MCSymbol *>
MCDwarfLineTableHeader::Emit(MCStreamer *MCOS,
MCDwarfLineTableParams Params) const {
static const char StandardOpcodeLengths[] = {
0, // length of DW_LNS_copy
1, // length of DW_LNS_advance_pc
1, // length of DW_LNS_advance_line
1, // length of DW_LNS_set_file
1, // length of DW_LNS_set_column
0, // length of DW_LNS_negate_stmt
0, // length of DW_LNS_set_basic_block
0, // length of DW_LNS_const_add_pc
1, // length of DW_LNS_fixed_advance_pc
0, // length of DW_LNS_set_prologue_end
0, // length of DW_LNS_set_epilogue_begin
1 // DW_LNS_set_isa
};
assert(array_lengthof(StandardOpcodeLengths) >=
(Params.DWARF2LineOpcodeBase - 1U));
return Emit(MCOS, Params, makeArrayRef(StandardOpcodeLengths,
Params.DWARF2LineOpcodeBase - 1));
}
static const MCExpr *forceExpAbs(MCStreamer &OS, const MCExpr* Expr) {
MCContext &Context = OS.getContext();
assert(!isa<MCSymbolRefExpr>(Expr));
if (Context.getAsmInfo()->hasAggressiveSymbolFolding())
return Expr;
MCSymbol *ABS = Context.createTempSymbol();
OS.EmitAssignment(ABS, Expr);
return MCSymbolRefExpr::create(ABS, Context);
}
static void emitAbsValue(MCStreamer &OS, const MCExpr *Value, unsigned Size) {
const MCExpr *ABS = forceExpAbs(OS, Value);
OS.EmitValue(ABS, Size);
}
std::pair<MCSymbol *, MCSymbol *>
MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
ArrayRef<char> StandardOpcodeLengths) const {
MCContext &context = MCOS->getContext();
// Create a symbol at the beginning of the line table.
MCSymbol *LineStartSym = Label;
if (!LineStartSym)
LineStartSym = context.createTempSymbol();
// Set the value of the symbol, as we are at the start of the line table.
MCOS->EmitLabel(LineStartSym);
// Create a symbol for the end of the section (to be set when we get there).
MCSymbol *LineEndSym = context.createTempSymbol();
// The first 4 bytes is the total length of the information for this
// compilation unit (not including these 4 bytes for the length).
emitAbsValue(*MCOS,
MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym, 4), 4);
// Next 2 bytes is the Version, which is Dwarf 2.
MCOS->EmitIntValue(2, 2);
// Create a symbol for the end of the prologue (to be set when we get there).
MCSymbol *ProEndSym = context.createTempSymbol(); // Lprologue_end
// Length of the prologue, is the next 4 bytes. Which is the start of the
// section to the end of the prologue. Not including the 4 bytes for the
// total length, the 2 bytes for the version, and these 4 bytes for the
// length of the prologue.
emitAbsValue(
*MCOS,
MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym, (4 + 2 + 4)), 4);
// Parameters of the state machine, are next.
MCOS->EmitIntValue(context.getAsmInfo()->getMinInstAlignment(), 1);
MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1);
MCOS->EmitIntValue(Params.DWARF2LineBase, 1);
MCOS->EmitIntValue(Params.DWARF2LineRange, 1);
MCOS->EmitIntValue(StandardOpcodeLengths.size() + 1, 1);
// Standard opcode lengths
for (char Length : StandardOpcodeLengths)
MCOS->EmitIntValue(Length, 1);
// Put out the directory and file tables.
// First the directory table.
for (unsigned i = 0; i < MCDwarfDirs.size(); i++) {
MCOS->EmitBytes(MCDwarfDirs[i]); // the DirectoryName
MCOS->EmitBytes(StringRef("\0", 1)); // the null term. of the string
}
MCOS->EmitIntValue(0, 1); // Terminate the directory list
// Second the file table.
for (unsigned i = 1; i < MCDwarfFiles.size(); i++) {
assert(!MCDwarfFiles[i].Name.empty());
MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName
MCOS->EmitBytes(StringRef("\0", 1)); // the null term. of the string
// the Directory num
MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex);
MCOS->EmitIntValue(0, 1); // last modification timestamp (always 0)
MCOS->EmitIntValue(0, 1); // filesize (always 0)
}
MCOS->EmitIntValue(0, 1); // Terminate the file list
// This is the end of the prologue, so set the value of the symbol at the
// end of the prologue (that was used in a previous expression).
MCOS->EmitLabel(ProEndSym);
return std::make_pair(LineStartSym, LineEndSym);
}
void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS,
MCDwarfLineTableParams Params) const {
MCSymbol *LineEndSym = Header.Emit(MCOS, Params).second;
// Put out the line tables.
for (const auto &LineSec : MCLineSections.getMCLineEntries())
EmitDwarfLineTable(MCOS, LineSec.first, LineSec.second);
// This is the end of the section, so set the value of the symbol at the end
// of this section (that was used in a previous expression).
MCOS->EmitLabel(LineEndSym);
}
unsigned MCDwarfLineTable::getFile(StringRef &Directory, StringRef &FileName,
unsigned FileNumber) {
return Header.getFile(Directory, FileName, FileNumber);
}
unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory,
StringRef &FileName,
unsigned FileNumber) {
if (Directory == CompilationDir)
Directory = "";
if (FileName.empty()) {
FileName = "<stdin>";
Directory = "";
}
assert(!FileName.empty());
if (FileNumber == 0) {
// File numbers start with 1 and/or after any file numbers
// allocated by inline-assembler .file directives.
FileNumber = MCDwarfFiles.empty() ? 1 : MCDwarfFiles.size();
SmallString<256> Buffer;
auto IterBool = SourceIdMap.insert(
std::make_pair((Directory + Twine('\0') + FileName).toStringRef(Buffer),
FileNumber));
if (!IterBool.second)
return IterBool.first->second;
}
// Make space for this FileNumber in the MCDwarfFiles vector if needed.
MCDwarfFiles.resize(FileNumber + 1);
// Get the new MCDwarfFile slot for this FileNumber.
MCDwarfFile &File = MCDwarfFiles[FileNumber];
// It is an error to use see the same number more than once.
if (!File.Name.empty())
return 0;
if (Directory.empty()) {
// Separate the directory part from the basename of the FileName.
StringRef tFileName = sys::path::filename(FileName);
if (!tFileName.empty()) {
Directory = sys::path::parent_path(FileName);
if (!Directory.empty())
FileName = tFileName;
}
}
// Find or make an entry in the MCDwarfDirs vector for this Directory.
// Capture directory name.
unsigned DirIndex;
if (Directory.empty()) {
// For FileNames with no directories a DirIndex of 0 is used.
DirIndex = 0;
} else {
DirIndex = 0;
for (unsigned End = MCDwarfDirs.size(); DirIndex < End; DirIndex++) {
if (Directory == MCDwarfDirs[DirIndex])
break;
}
if (DirIndex >= MCDwarfDirs.size())
MCDwarfDirs.push_back(Directory);
// The DirIndex is one based, as DirIndex of 0 is used for FileNames with
// no directories. MCDwarfDirs[] is unlike MCDwarfFiles[] in that the
// directory names are stored at MCDwarfDirs[DirIndex-1] where FileNames
// are stored at MCDwarfFiles[FileNumber].Name .
DirIndex++;
}
File.Name = FileName;
File.DirIndex = DirIndex;
// return the allocated FileNumber.
return FileNumber;
}
/// Utility function to emit the encoding to a streamer.
void MCDwarfLineAddr::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
int64_t LineDelta, uint64_t AddrDelta) {
MCContext &Context = MCOS->getContext();
SmallString<256> Tmp;
raw_svector_ostream OS(Tmp);
MCDwarfLineAddr::Encode(Context, Params, LineDelta, AddrDelta, OS);
MCOS->EmitBytes(OS.str());
}
/// Given a special op, return the address skip amount (in units of
/// DWARF2_LINE_MIN_INSN_LENGTH).
static uint64_t SpecialAddr(MCDwarfLineTableParams Params, uint64_t op) {
return (op - Params.DWARF2LineOpcodeBase) / Params.DWARF2LineRange;
}
/// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params,
int64_t LineDelta, uint64_t AddrDelta,
raw_ostream &OS) {
uint64_t Temp, Opcode;
bool NeedCopy = false;
// The maximum address skip amount that can be encoded with a special op.
uint64_t MaxSpecialAddrDelta = SpecialAddr(Params, 255);
// Scale the address delta by the minimum instruction length.
AddrDelta = ScaleAddrDelta(Context, AddrDelta);
// A LineDelta of INT64_MAX is a signal that this is actually a
// DW_LNE_end_sequence. We cannot use special opcodes here, since we want the
// end_sequence to emit the matrix entry.
if (LineDelta == INT64_MAX) {
if (AddrDelta == MaxSpecialAddrDelta)
OS << char(dwarf::DW_LNS_const_add_pc);
else if (AddrDelta) {
OS << char(dwarf::DW_LNS_advance_pc);
encodeULEB128(AddrDelta, OS);
}
OS << char(dwarf::DW_LNS_extended_op);
OS << char(1);
OS << char(dwarf::DW_LNE_end_sequence);
return;
}
// Bias the line delta by the base.
Temp = LineDelta - Params.DWARF2LineBase;
// If the line increment is out of range of a special opcode, we must encode
// it with DW_LNS_advance_line.
if (Temp >= Params.DWARF2LineRange ||
Temp + Params.DWARF2LineOpcodeBase > 255) {
OS << char(dwarf::DW_LNS_advance_line);
encodeSLEB128(LineDelta, OS);
LineDelta = 0;
Temp = 0 - Params.DWARF2LineBase;
NeedCopy = true;
}
// Use DW_LNS_copy instead of a "line +0, addr +0" special opcode.
if (LineDelta == 0 && AddrDelta == 0) {
OS << char(dwarf::DW_LNS_copy);
return;
}
// Bias the opcode by the special opcode base.
Temp += Params.DWARF2LineOpcodeBase;
// Avoid overflow when addr_delta is large.
if (AddrDelta < 256 + MaxSpecialAddrDelta) {
// Try using a special opcode.
Opcode = Temp + AddrDelta * Params.DWARF2LineRange;
if (Opcode <= 255) {
OS << char(Opcode);
return;
}
// Try using DW_LNS_const_add_pc followed by special op.
Opcode = Temp + (AddrDelta - MaxSpecialAddrDelta) * Params.DWARF2LineRange;
if (Opcode <= 255) {
OS << char(dwarf::DW_LNS_const_add_pc);
OS << char(Opcode);
return;
}
}
// Otherwise use DW_LNS_advance_pc.
OS << char(dwarf::DW_LNS_advance_pc);
encodeULEB128(AddrDelta, OS);
if (NeedCopy)
OS << char(dwarf::DW_LNS_copy);
else {
assert(Temp <= 255 && "Buggy special opcode encoding.");
OS << char(Temp);
}
}
// Utility function to write a tuple for .debug_abbrev.
static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) {
MCOS->EmitULEB128IntValue(Name);
MCOS->EmitULEB128IntValue(Form);
}
// When generating dwarf for assembly source files this emits
// the data for .debug_abbrev section which contains three DIEs.
static void EmitGenDwarfAbbrev(MCStreamer *MCOS) {
MCContext &context = MCOS->getContext();
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection());
// DW_TAG_compile_unit DIE abbrev (1).
MCOS->EmitULEB128IntValue(1);
MCOS->EmitULEB128IntValue(dwarf::DW_TAG_compile_unit);
MCOS->EmitIntValue(dwarf::DW_CHILDREN_yes, 1);
EmitAbbrev(MCOS, dwarf::DW_AT_stmt_list, context.getDwarfVersion() >= 4
? dwarf::DW_FORM_sec_offset
: dwarf::DW_FORM_data4);
if (context.getGenDwarfSectionSyms().size() > 1 &&
context.getDwarfVersion() >= 3) {
EmitAbbrev(MCOS, dwarf::DW_AT_ranges, context.getDwarfVersion() >= 4
? dwarf::DW_FORM_sec_offset
: dwarf::DW_FORM_data4);
} else {
EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr);
}
EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string);
if (!context.getCompilationDir().empty())
EmitAbbrev(MCOS, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string);
StringRef DwarfDebugFlags = context.getDwarfDebugFlags();
if (!DwarfDebugFlags.empty())
EmitAbbrev(MCOS, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string);
EmitAbbrev(MCOS, dwarf::DW_AT_producer, dwarf::DW_FORM_string);
EmitAbbrev(MCOS, dwarf::DW_AT_language, dwarf::DW_FORM_data2);
EmitAbbrev(MCOS, 0, 0);
// DW_TAG_label DIE abbrev (2).
MCOS->EmitULEB128IntValue(2);
MCOS->EmitULEB128IntValue(dwarf::DW_TAG_label);
MCOS->EmitIntValue(dwarf::DW_CHILDREN_yes, 1);
EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string);
EmitAbbrev(MCOS, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data4);
EmitAbbrev(MCOS, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data4);
EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
EmitAbbrev(MCOS, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag);
EmitAbbrev(MCOS, 0, 0);
// DW_TAG_unspecified_parameters DIE abbrev (3).
MCOS->EmitULEB128IntValue(3);
MCOS->EmitULEB128IntValue(dwarf::DW_TAG_unspecified_parameters);
MCOS->EmitIntValue(dwarf::DW_CHILDREN_no, 1);
EmitAbbrev(MCOS, 0, 0);
// Terminate the abbreviations for this compilation unit.
MCOS->EmitIntValue(0, 1);
}
// When generating dwarf for assembly source files this emits the data for
// .debug_aranges section. This section contains a header and a table of pairs
// of PointerSize'ed values for the address and size of section(s) with line
// table entries.
static void EmitGenDwarfAranges(MCStreamer *MCOS,
const MCSymbol *InfoSectionSymbol) {
MCContext &context = MCOS->getContext();
auto &Sections = context.getGenDwarfSectionSyms();
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());
// This will be the length of the .debug_aranges section, first account for
// the size of each item in the header (see below where we emit these items).
int Length = 4 + 2 + 4 + 1 + 1;
// Figure the padding after the header before the table of address and size
// pairs who's values are PointerSize'ed.
const MCAsmInfo *asmInfo = context.getAsmInfo();
int AddrSize = asmInfo->getPointerSize();
int Pad = 2 * AddrSize - (Length & (2 * AddrSize - 1));
if (Pad == 2 * AddrSize)
Pad = 0;
Length += Pad;
// Add the size of the pair of PointerSize'ed values for the address and size
// of each section we have in the table.
Length += 2 * AddrSize * Sections.size();
// And the pair of terminating zeros.
Length += 2 * AddrSize;
// Emit the header for this section.
// The 4 byte length not including the 4 byte value for the length.
MCOS->EmitIntValue(Length - 4, 4);
// The 2 byte version, which is 2.
MCOS->EmitIntValue(2, 2);
// The 4 byte offset to the compile unit in the .debug_info from the start
// of the .debug_info.
if (InfoSectionSymbol)
MCOS->EmitSymbolValue(InfoSectionSymbol, 4,
asmInfo->needsDwarfSectionOffsetDirective());
else
MCOS->EmitIntValue(0, 4);
// The 1 byte size of an address.
MCOS->EmitIntValue(AddrSize, 1);
// The 1 byte size of a segment descriptor, we use a value of zero.
MCOS->EmitIntValue(0, 1);
// Align the header with the padding if needed, before we put out the table.
for(int i = 0; i < Pad; i++)
MCOS->EmitIntValue(0, 1);
// Now emit the table of pairs of PointerSize'ed values for the section
// addresses and sizes.
for (MCSection *Sec : Sections) {
const MCSymbol *StartSymbol = Sec->getBeginSymbol();
MCSymbol *EndSymbol = Sec->getEndSymbol(context);
assert(StartSymbol && "StartSymbol must not be NULL");
assert(EndSymbol && "EndSymbol must not be NULL");
const MCExpr *Addr = MCSymbolRefExpr::create(
StartSymbol, MCSymbolRefExpr::VK_None, context);
const MCExpr *Size = MakeStartMinusEndExpr(*MCOS,
*StartSymbol, *EndSymbol, 0);
MCOS->EmitValue(Addr, AddrSize);
emitAbsValue(*MCOS, Size, AddrSize);
}
// And finally the pair of terminating zeros.
MCOS->EmitIntValue(0, AddrSize);
MCOS->EmitIntValue(0, AddrSize);
}
// When generating dwarf for assembly source files this emits the data for
// .debug_info section which contains three parts. The header, the compile_unit
// DIE and a list of label DIEs.
static void EmitGenDwarfInfo(MCStreamer *MCOS,
const MCSymbol *AbbrevSectionSymbol,
const MCSymbol *LineSectionSymbol,
const MCSymbol *RangesSectionSymbol) {
MCContext &context = MCOS->getContext();
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection());
// Create a symbol at the start and end of this section used in here for the
// expression to calculate the length in the header.
MCSymbol *InfoStart = context.createTempSymbol();
MCOS->EmitLabel(InfoStart);
MCSymbol *InfoEnd = context.createTempSymbol();
// First part: the header.
// The 4 byte total length of the information for this compilation unit, not
// including these 4 bytes.
const MCExpr *Length = MakeStartMinusEndExpr(*MCOS, *InfoStart, *InfoEnd, 4);
emitAbsValue(*MCOS, Length, 4);
// The 2 byte DWARF version.
MCOS->EmitIntValue(context.getDwarfVersion(), 2);
const MCAsmInfo &AsmInfo = *context.getAsmInfo();
// The 4 byte offset to the debug abbrevs from the start of the .debug_abbrev,
// it is at the start of that section so this is zero.
if (AbbrevSectionSymbol == nullptr)
MCOS->EmitIntValue(0, 4);
else
MCOS->EmitSymbolValue(AbbrevSectionSymbol, 4,
AsmInfo.needsDwarfSectionOffsetDirective());
const MCAsmInfo *asmInfo = context.getAsmInfo();
int AddrSize = asmInfo->getPointerSize();
// The 1 byte size of an address.
MCOS->EmitIntValue(AddrSize, 1);
// Second part: the compile_unit DIE.
// The DW_TAG_compile_unit DIE abbrev (1).
MCOS->EmitULEB128IntValue(1);
// DW_AT_stmt_list, a 4 byte offset from the start of the .debug_line section,
// which is at the start of that section so this is zero.
if (LineSectionSymbol)
MCOS->EmitSymbolValue(LineSectionSymbol, 4,
AsmInfo.needsDwarfSectionOffsetDirective());
else
MCOS->EmitIntValue(0, 4);
if (RangesSectionSymbol) {
// There are multiple sections containing code, so we must use the
// .debug_ranges sections.
// AT_ranges, the 4 byte offset from the start of the .debug_ranges section
// to the address range list for this compilation unit.
MCOS->EmitSymbolValue(RangesSectionSymbol, 4);
} else {
// If we only have one non-empty code section, we can use the simpler
// AT_low_pc and AT_high_pc attributes.
// Find the first (and only) non-empty text section
auto &Sections = context.getGenDwarfSectionSyms();
const auto TextSection = Sections.begin();
assert(TextSection != Sections.end() && "No text section found");
MCSymbol *StartSymbol = (*TextSection)->getBeginSymbol();
MCSymbol *EndSymbol = (*TextSection)->getEndSymbol(context);
assert(StartSymbol && "StartSymbol must not be NULL");
assert(EndSymbol && "EndSymbol must not be NULL");
// AT_low_pc, the first address of the default .text section.
const MCExpr *Start = MCSymbolRefExpr::create(
StartSymbol, MCSymbolRefExpr::VK_None, context);
MCOS->EmitValue(Start, AddrSize);
// AT_high_pc, the last address of the default .text section.
const MCExpr *End = MCSymbolRefExpr::create(
EndSymbol, MCSymbolRefExpr::VK_None, context);
MCOS->EmitValue(End, AddrSize);
}
// AT_name, the name of the source file. Reconstruct from the first directory
// and file table entries.
const SmallVectorImpl<std::string> &MCDwarfDirs = context.getMCDwarfDirs();
if (MCDwarfDirs.size() > 0) {
MCOS->EmitBytes(MCDwarfDirs[0]);
MCOS->EmitBytes(sys::path::get_separator());
}
const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles =
MCOS->getContext().getMCDwarfFiles();
MCOS->EmitBytes(MCDwarfFiles[1].Name);
MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
// AT_comp_dir, the working directory the assembly was done in.
if (!context.getCompilationDir().empty()) {
MCOS->EmitBytes(context.getCompilationDir());
MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
}
// AT_APPLE_flags, the command line arguments of the assembler tool.
StringRef DwarfDebugFlags = context.getDwarfDebugFlags();
if (!DwarfDebugFlags.empty()){
MCOS->EmitBytes(DwarfDebugFlags);
MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
}
// AT_producer, the version of the assembler tool.
StringRef DwarfDebugProducer = context.getDwarfDebugProducer();
if (!DwarfDebugProducer.empty())
MCOS->EmitBytes(DwarfDebugProducer);
else
MCOS->EmitBytes(StringRef("llvm-mc (based on LLVM " PACKAGE_VERSION ")"));
MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
// AT_language, a 4 byte value. We use DW_LANG_Mips_Assembler as the dwarf2
// draft has no standard code for assembler.
MCOS->EmitIntValue(dwarf::DW_LANG_Mips_Assembler, 2);
// Third part: the list of label DIEs.
// Loop on saved info for dwarf labels and create the DIEs for them.
const std::vector<MCGenDwarfLabelEntry> &Entries =
MCOS->getContext().getMCGenDwarfLabelEntries();
for (const auto &Entry : Entries) {
// The DW_TAG_label DIE abbrev (2).
MCOS->EmitULEB128IntValue(2);
// AT_name, of the label without any leading underbar.
MCOS->EmitBytes(Entry.getName());
MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
// AT_decl_file, index into the file table.
MCOS->EmitIntValue(Entry.getFileNumber(), 4);
// AT_decl_line, source line number.
MCOS->EmitIntValue(Entry.getLineNumber(), 4);
// AT_low_pc, start address of the label.
const MCExpr *AT_low_pc = MCSymbolRefExpr::create(Entry.getLabel(),
MCSymbolRefExpr::VK_None, context);
MCOS->EmitValue(AT_low_pc, AddrSize);
// DW_AT_prototyped, a one byte flag value of 0 saying we have no prototype.
MCOS->EmitIntValue(0, 1);
// The DW_TAG_unspecified_parameters DIE abbrev (3).
MCOS->EmitULEB128IntValue(3);
// Add the NULL DIE terminating the DW_TAG_unspecified_parameters DIE's.
MCOS->EmitIntValue(0, 1);
}
// Add the NULL DIE terminating the Compile Unit DIE's.
MCOS->EmitIntValue(0, 1);
// Now set the value of the symbol at the end of the info section.
MCOS->EmitLabel(InfoEnd);
}
// When generating dwarf for assembly source files this emits the data for
// .debug_ranges section. We only emit one range list, which spans all of the
// executable sections of this file.
static void EmitGenDwarfRanges(MCStreamer *MCOS) {
MCContext &context = MCOS->getContext();
auto &Sections = context.getGenDwarfSectionSyms();
const MCAsmInfo *AsmInfo = context.getAsmInfo();
int AddrSize = AsmInfo->getPointerSize();
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfRangesSection());
for (MCSection *Sec : Sections) {
const MCSymbol *StartSymbol = Sec->getBeginSymbol();
MCSymbol *EndSymbol = Sec->getEndSymbol(context);
assert(StartSymbol && "StartSymbol must not be NULL");
assert(EndSymbol && "EndSymbol must not be NULL");
// Emit a base address selection entry for the start of this section
const MCExpr *SectionStartAddr = MCSymbolRefExpr::create(
StartSymbol, MCSymbolRefExpr::VK_None, context);
MCOS->EmitFill(AddrSize, 0xFF);
MCOS->EmitValue(SectionStartAddr, AddrSize);
// Emit a range list entry spanning this section
const MCExpr *SectionSize = MakeStartMinusEndExpr(*MCOS,
*StartSymbol, *EndSymbol, 0);
MCOS->EmitIntValue(0, AddrSize);
emitAbsValue(*MCOS, SectionSize, AddrSize);
}
// Emit end of list entry
MCOS->EmitIntValue(0, AddrSize);
MCOS->EmitIntValue(0, AddrSize);
}
//
// When generating dwarf for assembly source files this emits the Dwarf
// sections.
//
void MCGenDwarfInfo::Emit(MCStreamer *MCOS) {
MCContext &context = MCOS->getContext();
// Create the dwarf sections in this order (.debug_line already created).
const MCAsmInfo *AsmInfo = context.getAsmInfo();
bool CreateDwarfSectionSymbols =
AsmInfo->doesDwarfUseRelocationsAcrossSections();
MCSymbol *LineSectionSymbol = nullptr;
if (CreateDwarfSectionSymbols)
LineSectionSymbol = MCOS->getDwarfLineTableSymbol(0);
MCSymbol *AbbrevSectionSymbol = nullptr;
MCSymbol *InfoSectionSymbol = nullptr;
MCSymbol *RangesSectionSymbol = nullptr;
// Create end symbols for each section, and remove empty sections
MCOS->getContext().finalizeDwarfSections(*MCOS);
// If there are no sections to generate debug info for, we don't need
// to do anything
if (MCOS->getContext().getGenDwarfSectionSyms().empty())
return;
// We only use the .debug_ranges section if we have multiple code sections,
// and we are emitting a DWARF version which supports it.
const bool UseRangesSection =
MCOS->getContext().getGenDwarfSectionSyms().size() > 1 &&
MCOS->getContext().getDwarfVersion() >= 3;
CreateDwarfSectionSymbols |= UseRangesSection;
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection());
if (CreateDwarfSectionSymbols) {
InfoSectionSymbol = context.createTempSymbol();
MCOS->EmitLabel(InfoSectionSymbol);
}
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection());
if (CreateDwarfSectionSymbols) {
AbbrevSectionSymbol = context.createTempSymbol();
MCOS->EmitLabel(AbbrevSectionSymbol);
}
if (UseRangesSection) {
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfRangesSection());
if (CreateDwarfSectionSymbols) {
RangesSectionSymbol = context.createTempSymbol();
MCOS->EmitLabel(RangesSectionSymbol);
}
}
assert((RangesSectionSymbol != NULL) || !UseRangesSection);
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());
// Output the data for .debug_aranges section.
EmitGenDwarfAranges(MCOS, InfoSectionSymbol);
if (UseRangesSection)
EmitGenDwarfRanges(MCOS);
// Output the data for .debug_abbrev section.
EmitGenDwarfAbbrev(MCOS);
// Output the data for .debug_info section.
EmitGenDwarfInfo(MCOS, AbbrevSectionSymbol, LineSectionSymbol,
RangesSectionSymbol);
}
//
// When generating dwarf for assembly source files this is called when symbol
// for a label is created. If this symbol is not a temporary and is in the
// section that dwarf is being generated for, save the needed info to create
// a dwarf label.
//
void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS,
SourceMgr &SrcMgr, SMLoc &Loc) {
// We won't create dwarf labels for temporary symbols.
if (Symbol->isTemporary())
return;
MCContext &context = MCOS->getContext();
// We won't create dwarf labels for symbols in sections that we are not
// generating debug info for.
if (!context.getGenDwarfSectionSyms().count(MCOS->getCurrentSection().first))
return;
// The dwarf label's name does not have the symbol name's leading
// underbar if any.
StringRef Name = Symbol->getName();
if (Name.startswith("_"))
Name = Name.substr(1, Name.size()-1);
// Get the dwarf file number to be used for the dwarf label.
unsigned FileNumber = context.getGenDwarfFileNumber();
// Finding the line number is the expensive part which is why we just don't
// pass it in as for some symbols we won't create a dwarf label.
unsigned CurBuffer = SrcMgr.FindBufferContainingLoc(Loc);
unsigned LineNumber = SrcMgr.FindLineNumber(Loc, CurBuffer);
// We create a temporary symbol for use for the AT_high_pc and AT_low_pc
// values so that they don't have things like an ARM thumb bit from the
// original symbol. So when used they won't get a low bit set after
// relocation.
MCSymbol *Label = context.createTempSymbol();
MCOS->EmitLabel(Label);
// Create and entry for the info and add it to the other entries.
MCOS->getContext().addMCGenDwarfLabelEntry(
MCGenDwarfLabelEntry(Name, FileNumber, LineNumber, Label));
}
static int getDataAlignmentFactor(MCStreamer &streamer) {
MCContext &context = streamer.getContext();
const MCAsmInfo *asmInfo = context.getAsmInfo();
int size = asmInfo->getCalleeSaveStackSlotSize();
if (asmInfo->isStackGrowthDirectionUp())
return size;
else
return -size;
}
static unsigned getSizeForEncoding(MCStreamer &streamer,
unsigned symbolEncoding) {
MCContext &context = streamer.getContext();
unsigned format = symbolEncoding & 0x0f;
switch (format) {
default: llvm_unreachable("Unknown Encoding");
case dwarf::DW_EH_PE_absptr:
case dwarf::DW_EH_PE_signed:
return context.getAsmInfo()->getPointerSize();
case dwarf::DW_EH_PE_udata2:
case dwarf::DW_EH_PE_sdata2:
return 2;
case dwarf::DW_EH_PE_udata4:
case dwarf::DW_EH_PE_sdata4:
return 4;
case dwarf::DW_EH_PE_udata8:
case dwarf::DW_EH_PE_sdata8:
return 8;
}
}
static void emitFDESymbol(MCObjectStreamer &streamer, const MCSymbol &symbol,
unsigned symbolEncoding, bool isEH) {
MCContext &context = streamer.getContext();
const MCAsmInfo *asmInfo = context.getAsmInfo();
const MCExpr *v = asmInfo->getExprForFDESymbol(&symbol,
symbolEncoding,
streamer);
unsigned size = getSizeForEncoding(streamer, symbolEncoding);
if (asmInfo->doDwarfFDESymbolsUseAbsDiff() && isEH)
emitAbsValue(streamer, v, size);
else
streamer.EmitValue(v, size);
}
static void EmitPersonality(MCStreamer &streamer, const MCSymbol &symbol,
unsigned symbolEncoding) {
MCContext &context = streamer.getContext();
const MCAsmInfo *asmInfo = context.getAsmInfo();
const MCExpr *v = asmInfo->getExprForPersonalitySymbol(&symbol,
symbolEncoding,
streamer);
unsigned size = getSizeForEncoding(streamer, symbolEncoding);
streamer.EmitValue(v, size);
}
namespace {
class FrameEmitterImpl {
int CFAOffset = 0;
int InitialCFAOffset = 0;
bool IsEH;
MCObjectStreamer &Streamer;
public:
FrameEmitterImpl(bool IsEH, MCObjectStreamer &Streamer)
: IsEH(IsEH), Streamer(Streamer) {}
/// Emit the unwind information in a compact way.
void EmitCompactUnwind(const MCDwarfFrameInfo &frame);
const MCSymbol &EmitCIE(const MCSymbol *personality,
unsigned personalityEncoding, const MCSymbol *lsda,
bool IsSignalFrame, unsigned lsdaEncoding,
bool IsSimple);
void EmitFDE(const MCSymbol &cieStart, const MCDwarfFrameInfo &frame,
bool LastInSection, const MCSymbol &SectionStart);
void EmitCFIInstructions(ArrayRef<MCCFIInstruction> Instrs,
MCSymbol *BaseLabel);
void EmitCFIInstruction(const MCCFIInstruction &Instr);
};
} // end anonymous namespace
static void emitEncodingByte(MCObjectStreamer &Streamer, unsigned Encoding) {
Streamer.EmitIntValue(Encoding, 1);
}
void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) {
int dataAlignmentFactor = getDataAlignmentFactor(Streamer);
auto *MRI = Streamer.getContext().getRegisterInfo();
switch (Instr.getOperation()) {
case MCCFIInstruction::OpRegister: {
unsigned Reg1 = Instr.getRegister();
unsigned Reg2 = Instr.getRegister2();
if (!IsEH) {
Reg1 = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg1, true), false);
Reg2 = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg2, true), false);
}
Streamer.EmitIntValue(dwarf::DW_CFA_register, 1);
Streamer.EmitULEB128IntValue(Reg1);
Streamer.EmitULEB128IntValue(Reg2);
return;
}
case MCCFIInstruction::OpWindowSave: {
Streamer.EmitIntValue(dwarf::DW_CFA_GNU_window_save, 1);
return;
}
case MCCFIInstruction::OpUndefined: {
unsigned Reg = Instr.getRegister();
Streamer.EmitIntValue(dwarf::DW_CFA_undefined, 1);
Streamer.EmitULEB128IntValue(Reg);
return;
}
case MCCFIInstruction::OpAdjustCfaOffset:
case MCCFIInstruction::OpDefCfaOffset: {
const bool IsRelative =
Instr.getOperation() == MCCFIInstruction::OpAdjustCfaOffset;
Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1);
if (IsRelative)
CFAOffset += Instr.getOffset();
else
CFAOffset = -Instr.getOffset();
Streamer.EmitULEB128IntValue(CFAOffset);
return;
}
case MCCFIInstruction::OpDefCfa: {
unsigned Reg = Instr.getRegister();
if (!IsEH)
Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false);
Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1);
Streamer.EmitULEB128IntValue(Reg);
CFAOffset = -Instr.getOffset();
Streamer.EmitULEB128IntValue(CFAOffset);
return;
}
case MCCFIInstruction::OpDefCfaRegister: {
unsigned Reg = Instr.getRegister();
if (!IsEH)
Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false);
Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1);
Streamer.EmitULEB128IntValue(Reg);
return;
}
case MCCFIInstruction::OpOffset:
case MCCFIInstruction::OpRelOffset: {
const bool IsRelative =
Instr.getOperation() == MCCFIInstruction::OpRelOffset;
unsigned Reg = Instr.getRegister();
if (!IsEH)
Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false);
int Offset = Instr.getOffset();
if (IsRelative)
Offset -= CFAOffset;
Offset = Offset / dataAlignmentFactor;
if (Offset < 0) {
Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1);
Streamer.EmitULEB128IntValue(Reg);
Streamer.EmitSLEB128IntValue(Offset);
} else if (Reg < 64) {
Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1);
Streamer.EmitULEB128IntValue(Offset);
} else {
Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1);
Streamer.EmitULEB128IntValue(Reg);
Streamer.EmitULEB128IntValue(Offset);
}
return;
}
case MCCFIInstruction::OpRememberState:
Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1);
return;
case MCCFIInstruction::OpRestoreState:
Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1);
return;
case MCCFIInstruction::OpSameValue: {
unsigned Reg = Instr.getRegister();
Streamer.EmitIntValue(dwarf::DW_CFA_same_value, 1);
Streamer.EmitULEB128IntValue(Reg);
return;
}
case MCCFIInstruction::OpRestore: {
unsigned Reg = Instr.getRegister();
if (!IsEH)
Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false);
Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1);
return;
}
case MCCFIInstruction::OpGnuArgsSize: {
Streamer.EmitIntValue(dwarf::DW_CFA_GNU_args_size, 1);
Streamer.EmitULEB128IntValue(Instr.getOffset());
return;
}
case MCCFIInstruction::OpEscape:
Streamer.EmitBytes(Instr.getValues());
return;
}
llvm_unreachable("Unhandled case in switch");
}
/// Emit frame instructions to describe the layout of the frame.
void FrameEmitterImpl::EmitCFIInstructions(ArrayRef<MCCFIInstruction> Instrs,
MCSymbol *BaseLabel) {
for (unsigned i = 0, N = Instrs.size(); i < N; ++i) {
const MCCFIInstruction &Instr = Instrs[i];
MCSymbol *Label = Instr.getLabel();
// Throw out move if the label is invalid.
if (Label && !Label->isDefined()) continue; // Not emitted, in dead code.
// Advance row if new location.
if (BaseLabel && Label) {
MCSymbol *ThisSym = Label;
if (ThisSym != BaseLabel) {
Streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym);
BaseLabel = ThisSym;
}
}
EmitCFIInstruction(Instr);
}
}
/// Emit the unwind information in a compact way.
void FrameEmitterImpl::EmitCompactUnwind(const MCDwarfFrameInfo &Frame) {
MCContext &Context = Streamer.getContext();
const MCObjectFileInfo *MOFI = Context.getObjectFileInfo();
// range-start range-length compact-unwind-enc personality-func lsda
// _foo LfooEnd-_foo 0x00000023 0 0
// _bar LbarEnd-_bar 0x00000025 __gxx_personality except_tab1
//
// .section __LD,__compact_unwind,regular,debug
//
// # compact unwind for _foo
// .quad _foo
// .set L1,LfooEnd-_foo
// .long L1
// .long 0x01010001
// .quad 0
// .quad 0
//
// # compact unwind for _bar
// .quad _bar
// .set L2,LbarEnd-_bar
// .long L2
// .long 0x01020011
// .quad __gxx_personality
// .quad except_tab1
uint32_t Encoding = Frame.CompactUnwindEncoding;
if (!Encoding) return;
bool DwarfEHFrameOnly = (Encoding == MOFI->getCompactUnwindDwarfEHFrameOnly());
// The encoding needs to know we have an LSDA.
if (!DwarfEHFrameOnly && Frame.Lsda)
Encoding |= 0x40000000;
// Range Start
unsigned FDEEncoding = MOFI->getFDEEncoding();
unsigned Size = getSizeForEncoding(Streamer, FDEEncoding);
Streamer.EmitSymbolValue(Frame.Begin, Size);
// Range Length
const MCExpr *Range = MakeStartMinusEndExpr(Streamer, *Frame.Begin,
*Frame.End, 0);
emitAbsValue(Streamer, Range, 4);
// Compact Encoding
Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_udata4);
Streamer.EmitIntValue(Encoding, Size);
// Personality Function
Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_absptr);
if (!DwarfEHFrameOnly && Frame.Personality)
Streamer.EmitSymbolValue(Frame.Personality, Size);
else
Streamer.EmitIntValue(0, Size); // No personality fn
// LSDA
Size = getSizeForEncoding(Streamer, Frame.LsdaEncoding);
if (!DwarfEHFrameOnly && Frame.Lsda)
Streamer.EmitSymbolValue(Frame.Lsda, Size);
else
Streamer.EmitIntValue(0, Size); // No LSDA
}
static unsigned getCIEVersion(bool IsEH, unsigned DwarfVersion) {
if (IsEH)
return 1;
switch (DwarfVersion) {
case 2:
return 1;
case 3:
return 3;
case 4:
case 5:
return 4;
}
llvm_unreachable("Unknown version");
}
const MCSymbol &FrameEmitterImpl::EmitCIE(const MCSymbol *personality,
unsigned personalityEncoding,
const MCSymbol *lsda,
bool IsSignalFrame,
unsigned lsdaEncoding,
bool IsSimple) {
MCContext &context = Streamer.getContext();
const MCRegisterInfo *MRI = context.getRegisterInfo();
const MCObjectFileInfo *MOFI = context.getObjectFileInfo();
MCSymbol *sectionStart = context.createTempSymbol();
Streamer.EmitLabel(sectionStart);
MCSymbol *sectionEnd = context.createTempSymbol();
// Length
const MCExpr *Length =
MakeStartMinusEndExpr(Streamer, *sectionStart, *sectionEnd, 4);
emitAbsValue(Streamer, Length, 4);
// CIE ID
unsigned CIE_ID = IsEH ? 0 : -1;
Streamer.EmitIntValue(CIE_ID, 4);
// Version
uint8_t CIEVersion = getCIEVersion(IsEH, context.getDwarfVersion());
Streamer.EmitIntValue(CIEVersion, 1);
// Augmentation String
SmallString<8> Augmentation;
if (IsEH) {
Augmentation += "z";
if (personality)
Augmentation += "P";
if (lsda)
Augmentation += "L";
Augmentation += "R";
if (IsSignalFrame)
Augmentation += "S";
Streamer.EmitBytes(Augmentation);
}
Streamer.EmitIntValue(0, 1);
if (CIEVersion >= 4) {
// Address Size
Streamer.EmitIntValue(context.getAsmInfo()->getPointerSize(), 1);
// Segment Descriptor Size
Streamer.EmitIntValue(0, 1);
}
// Code Alignment Factor
Streamer.EmitULEB128IntValue(context.getAsmInfo()->getMinInstAlignment());
// Data Alignment Factor
Streamer.EmitSLEB128IntValue(getDataAlignmentFactor(Streamer));
// Return Address Register
if (CIEVersion == 1) {
assert(MRI->getRARegister() <= 255 &&
"DWARF 2 encodes return_address_register in one byte");
Streamer.EmitIntValue(MRI->getDwarfRegNum(MRI->getRARegister(), IsEH), 1);
} else {
Streamer.EmitULEB128IntValue(
MRI->getDwarfRegNum(MRI->getRARegister(), IsEH));
}
// Augmentation Data Length (optional)
unsigned augmentationLength = 0;
if (IsEH) {
if (personality) {
// Personality Encoding
augmentationLength += 1;
// Personality
augmentationLength += getSizeForEncoding(Streamer, personalityEncoding);
}
if (lsda)
augmentationLength += 1;
// Encoding of the FDE pointers
augmentationLength += 1;
Streamer.EmitULEB128IntValue(augmentationLength);
// Augmentation Data (optional)
if (personality) {
// Personality Encoding
emitEncodingByte(Streamer, personalityEncoding);
// Personality
EmitPersonality(Streamer, *personality, personalityEncoding);
}
if (lsda)
emitEncodingByte(Streamer, lsdaEncoding);
// Encoding of the FDE pointers
emitEncodingByte(Streamer, MOFI->getFDEEncoding());
}
// Initial Instructions
const MCAsmInfo *MAI = context.getAsmInfo();
if (!IsSimple) {
const std::vector<MCCFIInstruction> &Instructions =
MAI->getInitialFrameState();
EmitCFIInstructions(Instructions, nullptr);
}
InitialCFAOffset = CFAOffset;
// Padding
Streamer.EmitValueToAlignment(IsEH ? 4 : MAI->getPointerSize());
Streamer.EmitLabel(sectionEnd);
return *sectionStart;
}
void FrameEmitterImpl::EmitFDE(const MCSymbol &cieStart,
const MCDwarfFrameInfo &frame,
bool LastInSection,
const MCSymbol &SectionStart) {
MCContext &context = Streamer.getContext();
MCSymbol *fdeStart = context.createTempSymbol();
MCSymbol *fdeEnd = context.createTempSymbol();
const MCObjectFileInfo *MOFI = context.getObjectFileInfo();
CFAOffset = InitialCFAOffset;
// Length
const MCExpr *Length = MakeStartMinusEndExpr(Streamer, *fdeStart, *fdeEnd, 0);
emitAbsValue(Streamer, Length, 4);
Streamer.EmitLabel(fdeStart);
// CIE Pointer
const MCAsmInfo *asmInfo = context.getAsmInfo();
if (IsEH) {
const MCExpr *offset =
MakeStartMinusEndExpr(Streamer, cieStart, *fdeStart, 0);
emitAbsValue(Streamer, offset, 4);
} else if (!asmInfo->doesDwarfUseRelocationsAcrossSections()) {
const MCExpr *offset =
MakeStartMinusEndExpr(Streamer, SectionStart, cieStart, 0);
emitAbsValue(Streamer, offset, 4);
} else {
Streamer.EmitSymbolValue(&cieStart, 4);
}
// PC Begin
unsigned PCEncoding =
IsEH ? MOFI->getFDEEncoding() : (unsigned)dwarf::DW_EH_PE_absptr;
unsigned PCSize = getSizeForEncoding(Streamer, PCEncoding);
emitFDESymbol(Streamer, *frame.Begin, PCEncoding, IsEH);
// PC Range
const MCExpr *Range =
MakeStartMinusEndExpr(Streamer, *frame.Begin, *frame.End, 0);
emitAbsValue(Streamer, Range, PCSize);
if (IsEH) {
// Augmentation Data Length
unsigned augmentationLength = 0;
if (frame.Lsda)
augmentationLength += getSizeForEncoding(Streamer, frame.LsdaEncoding);
Streamer.EmitULEB128IntValue(augmentationLength);
// Augmentation Data
if (frame.Lsda)
emitFDESymbol(Streamer, *frame.Lsda, frame.LsdaEncoding, true);
}
// Call Frame Instructions
EmitCFIInstructions(frame.Instructions, frame.Begin);
// Padding
// The size of a .eh_frame section has to be a multiple of the alignment
// since a null CIE is interpreted as the end. Old systems overaligned
// .eh_frame, so we do too and account for it in the last FDE.
unsigned Align = LastInSection ? asmInfo->getPointerSize() : PCSize;
Streamer.EmitValueToAlignment(Align);
Streamer.EmitLabel(fdeEnd);
}
namespace {
struct CIEKey {
static const CIEKey getEmptyKey() {
return CIEKey(nullptr, 0, -1, false, false);
}
static const CIEKey getTombstoneKey() {
return CIEKey(nullptr, -1, 0, false, false);
}
CIEKey(const MCSymbol *Personality, unsigned PersonalityEncoding,
unsigned LsdaEncoding, bool IsSignalFrame, bool IsSimple)
: Personality(Personality), PersonalityEncoding(PersonalityEncoding),
LsdaEncoding(LsdaEncoding), IsSignalFrame(IsSignalFrame),
IsSimple(IsSimple) {}
const MCSymbol *Personality;
unsigned PersonalityEncoding;
unsigned LsdaEncoding;
bool IsSignalFrame;
bool IsSimple;
};
} // anonymous namespace
namespace llvm {
template <> struct DenseMapInfo<CIEKey> {
static CIEKey getEmptyKey() { return CIEKey::getEmptyKey(); }
static CIEKey getTombstoneKey() { return CIEKey::getTombstoneKey(); }
static unsigned getHashValue(const CIEKey &Key) {
return static_cast<unsigned>(
hash_combine(Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding,
Key.IsSignalFrame, Key.IsSimple));
}
static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) {
return LHS.Personality == RHS.Personality &&
LHS.PersonalityEncoding == RHS.PersonalityEncoding &&
LHS.LsdaEncoding == RHS.LsdaEncoding &&
LHS.IsSignalFrame == RHS.IsSignalFrame &&
LHS.IsSimple == RHS.IsSimple;
}
};
} // namespace llvm
void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB,
bool IsEH) {
Streamer.generateCompactUnwindEncodings(MAB);
MCContext &Context = Streamer.getContext();
const MCObjectFileInfo *MOFI = Context.getObjectFileInfo();
FrameEmitterImpl Emitter(IsEH, Streamer);
ArrayRef<MCDwarfFrameInfo> FrameArray = Streamer.getDwarfFrameInfos();
// Emit the compact unwind info if available.
bool NeedsEHFrameSection = !MOFI->getSupportsCompactUnwindWithoutEHFrame();
if (IsEH && MOFI->getCompactUnwindSection()) {
bool SectionEmitted = false;
for (unsigned i = 0, n = FrameArray.size(); i < n; ++i) {
const MCDwarfFrameInfo &Frame = FrameArray[i];
if (Frame.CompactUnwindEncoding == 0) continue;
if (!SectionEmitted) {
Streamer.SwitchSection(MOFI->getCompactUnwindSection());
Streamer.EmitValueToAlignment(Context.getAsmInfo()->getPointerSize());
SectionEmitted = true;
}
NeedsEHFrameSection |=
Frame.CompactUnwindEncoding ==
MOFI->getCompactUnwindDwarfEHFrameOnly();
Emitter.EmitCompactUnwind(Frame);
}
}
if (!NeedsEHFrameSection) return;
MCSection &Section =
IsEH ? *const_cast<MCObjectFileInfo *>(MOFI)->getEHFrameSection()
: *MOFI->getDwarfFrameSection();
Streamer.SwitchSection(&Section);
MCSymbol *SectionStart = Context.createTempSymbol();
Streamer.EmitLabel(SectionStart);
DenseMap<CIEKey, const MCSymbol *> CIEStarts;
const MCSymbol *DummyDebugKey = nullptr;
bool CanOmitDwarf = MOFI->getOmitDwarfIfHaveCompactUnwind();
for (auto I = FrameArray.begin(), E = FrameArray.end(); I != E;) {
const MCDwarfFrameInfo &Frame = *I;
++I;
if (CanOmitDwarf && Frame.CompactUnwindEncoding !=
MOFI->getCompactUnwindDwarfEHFrameOnly())
// Don't generate an EH frame if we don't need one. I.e., it's taken care
// of by the compact unwind encoding.
continue;
CIEKey Key(Frame.Personality, Frame.PersonalityEncoding,
Frame.LsdaEncoding, Frame.IsSignalFrame, Frame.IsSimple);
const MCSymbol *&CIEStart = IsEH ? CIEStarts[Key] : DummyDebugKey;
if (!CIEStart)
CIEStart = &Emitter.EmitCIE(Frame.Personality, Frame.PersonalityEncoding,
Frame.Lsda, Frame.IsSignalFrame,
Frame.LsdaEncoding, Frame.IsSimple);
Emitter.EmitFDE(*CIEStart, Frame, I == E, *SectionStart);
}
}
void MCDwarfFrameEmitter::EmitAdvanceLoc(MCObjectStreamer &Streamer,
uint64_t AddrDelta) {
MCContext &Context = Streamer.getContext();
SmallString<256> Tmp;
raw_svector_ostream OS(Tmp);
MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OS);
Streamer.EmitBytes(OS.str());
}
void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context,
uint64_t AddrDelta,
raw_ostream &OS) {
// Scale the address delta by the minimum instruction length.
AddrDelta = ScaleAddrDelta(Context, AddrDelta);
if (AddrDelta == 0) {
} else if (isUIntN(6, AddrDelta)) {
uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta;
OS << Opcode;
} else if (isUInt<8>(AddrDelta)) {
OS << uint8_t(dwarf::DW_CFA_advance_loc1);
OS << uint8_t(AddrDelta);
} else if (isUInt<16>(AddrDelta)) {
OS << uint8_t(dwarf::DW_CFA_advance_loc2);
if (Context.getAsmInfo()->isLittleEndian())
support::endian::Writer<support::little>(OS).write<uint16_t>(AddrDelta);
else
support::endian::Writer<support::big>(OS).write<uint16_t>(AddrDelta);
} else {
assert(isUInt<32>(AddrDelta));
OS << uint8_t(dwarf::DW_CFA_advance_loc4);
if (Context.getAsmInfo()->isLittleEndian())
support::endian::Writer<support::little>(OS).write<uint32_t>(AddrDelta);
else
support::endian::Writer<support::big>(OS).write<uint32_t>(AddrDelta);
}
}