Skip to content

Commit

Permalink
Emit DWARF info for all code section in an assembly file
Browse files Browse the repository at this point in the history
Currently, when using llvm as an assembler, DWARF debug information is only
generated for the .text section. This patch modifies this so that DWARF info
is emitted for all executable sections.

llvm-svn: 211273
  • Loading branch information
ostannard committed Jun 19, 2014
1 parent f7693f4 commit 8b27308
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 70 deletions.
9 changes: 9 additions & 0 deletions llvm/include/llvm/ADT/MapVector.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,15 @@ class MapVector {
Map.erase(Pos);
Vector.pop_back();
}

/// \brief Remove the element given by Iterator.
/// Returns an iterator to the element following the one which was removed,
/// which may be end().
typename VectorType::iterator erase(typename VectorType::iterator Iterator) {
typename MapType::iterator MapIterator = Map.find(Iterator->first);
Map.erase(MapIterator);
return Vector.erase(Iterator);
}
};

}
Expand Down
29 changes: 16 additions & 13 deletions llvm/include/llvm/MC/MCContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
#define LLVM_MC_MCCONTEXT_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/SectionKind.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
Expand Down Expand Up @@ -129,11 +131,10 @@ namespace llvm {
/// assembly source files.
unsigned GenDwarfFileNumber;

/// The default initial text section that we generate dwarf debugging line
/// info for when generating dwarf assembly source files.
const MCSection *GenDwarfSection;
/// Symbols created for the start and end of this section.
MCSymbol *GenDwarfSectionStartSym, *GenDwarfSectionEndSym;
/// Symbols created for the start and end of each section, used for
/// generating the .debug_ranges and .debug_aranges sections.
MapVector<const MCSection *, std::pair<MCSymbol *, MCSymbol *> >
SectionStartEndSyms;

/// The information gathered from labels that will have dwarf label
/// entries when generating dwarf assembly source files.
Expand Down Expand Up @@ -374,16 +375,18 @@ namespace llvm {
void setGenDwarfFileNumber(unsigned FileNumber) {
GenDwarfFileNumber = FileNumber;
}
const MCSection *getGenDwarfSection() { return GenDwarfSection; }
void setGenDwarfSection(const MCSection *Sec) { GenDwarfSection = Sec; }
MCSymbol *getGenDwarfSectionStartSym() { return GenDwarfSectionStartSym; }
void setGenDwarfSectionStartSym(MCSymbol *Sym) {
GenDwarfSectionStartSym = Sym;
MapVector<const MCSection *, std::pair<MCSymbol *, MCSymbol *> > &
getGenDwarfSectionSyms() {
return SectionStartEndSyms;
}
MCSymbol *getGenDwarfSectionEndSym() { return GenDwarfSectionEndSym; }
void setGenDwarfSectionEndSym(MCSymbol *Sym) {
GenDwarfSectionEndSym = Sym;
std::pair<MapVector<const MCSection *,
std::pair<MCSymbol *, MCSymbol *> >::iterator,
bool>
addGenDwarfSection(const MCSection *Sec) {
return SectionStartEndSyms.insert(
std::make_pair(Sec, std::make_pair(nullptr, nullptr)));
}
void finalizeDwarfSections(MCStreamer &MCOS);
const std::vector<MCGenDwarfLabelEntry> &getMCGenDwarfLabelEntries() const {
return MCGenDwarfLabelEntries;
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/MC/MCObjectStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ class MCObjectStreamer : public MCStreamer {
void EmitFill(uint64_t NumBytes, uint8_t FillValue) override;
void EmitZeros(uint64_t NumBytes) override;
void FinishImpl() override;

virtual bool mayHaveInstructions() const {
return getCurrentSectionData()->hasInstructions();
}
};

} // end namespace llvm
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,8 @@ class MCStreamer {
virtual void FinishImpl() = 0;
/// Finish - Finish emission of machine code.
void Finish();

virtual bool mayHaveInstructions() const { return true; }
};

/// createNullStreamer - Create a dummy machine code streamer, which does
Expand Down
23 changes: 23 additions & 0 deletions llvm/lib/MC/MCContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,29 @@ bool MCContext::isValidDwarfFileNumber(unsigned FileNumber, unsigned CUID) {
return !MCDwarfFiles[FileNumber].Name.empty();
}

/// finalizeDwarfSections - Emit end symbols for each non-empty code section.
/// Also remove empty sections from SectionStartEndSyms, to avoid generating
/// useless debug info for them.
void MCContext::finalizeDwarfSections(MCStreamer &MCOS) {
MCContext &context = MCOS.getContext();

auto sec = SectionStartEndSyms.begin();
while (sec != SectionStartEndSyms.end()) {
assert(sec->second.first && "Start symbol must be set by now");
MCOS.SwitchSection(sec->first);
if (MCOS.mayHaveInstructions()) {
MCSymbol *SectionEndSym = context.CreateTempSymbol();
MCOS.EmitLabel(SectionEndSym);
sec->second.second = SectionEndSym;
++sec;
} else {
MapVector<const MCSection *, std::pair<MCSymbol *, MCSymbol *> >::iterator
to_erase = sec;
sec = SectionStartEndSyms.erase(to_erase);
}
}
}

void MCContext::FatalError(SMLoc Loc, const Twine &Msg) const {
// If we have a source manager and a location, use it. Otherwise just
// use the generic report_fatal_error().
Expand Down
174 changes: 134 additions & 40 deletions llvm/lib/MC/MCDwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#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"
Expand Down Expand Up @@ -518,8 +519,12 @@ static void EmitGenDwarfAbbrev(MCStreamer *MCOS) {
MCOS->EmitULEB128IntValue(dwarf::DW_TAG_compile_unit);
MCOS->EmitIntValue(dwarf::DW_CHILDREN_yes, 1);
EmitAbbrev(MCOS, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4);
EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr);
if (MCOS->getContext().getGenDwarfSectionSyms().size() > 1) {
EmitAbbrev(MCOS, dwarf::DW_AT_ranges, 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);
Expand Down Expand Up @@ -552,20 +557,14 @@ static void EmitGenDwarfAbbrev(MCStreamer *MCOS) {
}

// When generating dwarf for assembly source files this emits the data for
// .debug_aranges section. Which contains a header and a table of pairs of
// PointerSize'ed values for the address and size of section(s) with line table
// entries (just the default .text in our case) and a terminating pair of zeros.
// .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();

// Create a symbol at the end of the section that we are creating the dwarf
// debugging info to use later in here as part of the expression to calculate
// the size of the section for the table.
MCOS->SwitchSection(context.getGenDwarfSection());
MCSymbol *SectionEndSym = context.CreateTempSymbol();
MCOS->EmitLabel(SectionEndSym);
context.setGenDwarfSectionEndSym(SectionEndSym);
auto &Sections = context.getGenDwarfSectionSyms();

MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());

Expand All @@ -583,8 +582,8 @@ static void EmitGenDwarfAranges(MCStreamer *MCOS,
Length += Pad;

// Add the size of the pair of PointerSize'ed values for the address and size
// of the one default .text section we have in the table.
Length += 2 * AddrSize;
// of each section we have in the table.
Length += 2 * AddrSize * Sections.size();
// And the pair of terminating zeros.
Length += 2 * AddrSize;

Expand All @@ -608,14 +607,21 @@ static void EmitGenDwarfAranges(MCStreamer *MCOS,
for(int i = 0; i < Pad; i++)
MCOS->EmitIntValue(0, 1);

// Now emit the table of pairs of PointerSize'ed values for the section(s)
// address and size, in our case just the one default .text section.
const MCExpr *Addr = MCSymbolRefExpr::Create(
context.getGenDwarfSectionStartSym(), MCSymbolRefExpr::VK_None, context);
const MCExpr *Size = MakeStartMinusEndExpr(*MCOS,
*context.getGenDwarfSectionStartSym(), *SectionEndSym, 0);
MCOS->EmitValue(Addr, AddrSize);
MCOS->EmitAbsValue(Size, AddrSize);
// Now emit the table of pairs of PointerSize'ed values for the section
// addresses and sizes.
for (const auto &sec : Sections) {
MCSymbol* StartSymbol = sec.second.first;
MCSymbol* EndSymbol = sec.second.second;
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);
MCOS->EmitAbsValue(Size, AddrSize);
}

// And finally the pair of terminating zeros.
MCOS->EmitIntValue(0, AddrSize);
Expand All @@ -627,7 +633,8 @@ static void EmitGenDwarfAranges(MCStreamer *MCOS,
// DIE and a list of label DIEs.
static void EmitGenDwarfInfo(MCStreamer *MCOS,
const MCSymbol *AbbrevSectionSymbol,
const MCSymbol *LineSectionSymbol) {
const MCSymbol *LineSectionSymbol,
const MCSymbol *RangesSectionSymbol) {
MCContext &context = MCOS->getContext();

MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection());
Expand Down Expand Up @@ -674,15 +681,37 @@ static void EmitGenDwarfInfo(MCStreamer *MCOS,
MCOS->EmitIntValue(0, 4);
}

// AT_low_pc, the first address of the default .text section.
const MCExpr *Start = MCSymbolRefExpr::Create(
context.getGenDwarfSectionStartSym(), MCSymbolRefExpr::VK_None, context);
MCOS->EmitValue(Start, AddrSize);
if (RangesSectionSymbol) {
// There are multiple sections containing code, so we must use the
// .debug_ranges sections.

// AT_high_pc, the last address of the default .text section.
const MCExpr *End = MCSymbolRefExpr::Create(
context.getGenDwarfSectionEndSym(), MCSymbolRefExpr::VK_None, context);
MCOS->EmitValue(End, AddrSize);
// 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->second.first;
MCSymbol* EndSymbol = TextSection->second.second;
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.
Expand Down Expand Up @@ -766,13 +795,51 @@ static void EmitGenDwarfInfo(MCStreamer *MCOS,
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 (const auto sec : Sections) {

MCSymbol* StartSymbol = sec.second.first;
MCSymbol* EndSymbol = sec.second.second;
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);
MCOS->EmitAbsValue(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) {
// Create the dwarf sections in this order (.debug_line already created).
MCContext &context = MCOS->getContext();

// Create the dwarf sections in this order (.debug_line already created).
const MCAsmInfo *AsmInfo = context.getAsmInfo();
bool CreateDwarfSectionSymbols =
AsmInfo->doesDwarfUseRelocationsAcrossSections();
Expand All @@ -781,6 +848,22 @@ void MCGenDwarfInfo::Emit(MCStreamer *MCOS) {
LineSectionSymbol = MCOS->getDwarfLineTableSymbol(0);
MCSymbol *AbbrevSectionSymbol = nullptr;
MCSymbol *InfoSectionSymbol = nullptr;
MCSymbol *RangesSectionSymbol = NULL;

// 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 need to use the .debug_ranges section if we have multiple
// code sections.
const bool UseRangesSection =
MCOS->getContext().getGenDwarfSectionSyms().size() > 1;
CreateDwarfSectionSymbols |= UseRangesSection;

MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection());
if (CreateDwarfSectionSymbols) {
InfoSectionSymbol = context.CreateTempSymbol();
Expand All @@ -791,20 +874,30 @@ void MCGenDwarfInfo::Emit(MCStreamer *MCOS) {
AbbrevSectionSymbol = context.CreateTempSymbol();
MCOS->EmitLabel(AbbrevSectionSymbol);
}
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());
if (UseRangesSection) {
MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfRangesSection());
if (CreateDwarfSectionSymbols) {
RangesSectionSymbol = context.CreateTempSymbol();
MCOS->EmitLabel(RangesSectionSymbol);
}
}

// If there are no line table entries then do not emit any section contents.
if (!context.hasMCLineSections())
return;
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);
EmitGenDwarfInfo(MCOS, AbbrevSectionSymbol, LineSectionSymbol,
RangesSectionSymbol);
}

//
Expand All @@ -815,12 +908,13 @@ void MCGenDwarfInfo::Emit(MCStreamer *MCOS) {
//
void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS,
SourceMgr &SrcMgr, SMLoc &Loc) {
// We won't create dwarf labels for temporary symbols or symbols not in
// the default text.
// We won't create dwarf labels for temporary symbols.
if (Symbol->isTemporary())
return;
MCContext &context = MCOS->getContext();
if (context.getGenDwarfSection() != MCOS->getCurrentSection().first)
// 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
Expand Down

0 comments on commit 8b27308

Please sign in to comment.