summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Mitton <richard@codersnotes.com>2013-09-19 23:21:01 +0000
committerRichard Mitton <richard@codersnotes.com>2013-09-19 23:21:01 +0000
commit5cc319a42a914b24b164a94d9a563c728a7a4026 (patch)
tree2101b566f8fb8e3eea815cf1e29fc86c632a322a
parent70e0b047be83cbaca06c0cc72e508667bcd5e95f (diff)
downloadllvm-5cc319a42a914b24b164a94d9a563c728a7a4026.tar.gz
llvm-5cc319a42a914b24b164a94d9a563c728a7a4026.tar.bz2
llvm-5cc319a42a914b24b164a94d9a563c728a7a4026.tar.xz
Added support for generate DWARF .debug_aranges sections automatically.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191052 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/MC/MCELFStreamer.h2
-rw-r--r--include/llvm/MC/MCStreamer.h19
-rw-r--r--include/llvm/Support/Dwarf.h3
-rw-r--r--lib/CodeGen/AsmPrinter/AsmPrinter.cpp3
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp14
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.cpp206
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.h15
-rw-r--r--lib/MC/MCAsmStreamer.cpp11
-rw-r--r--lib/MC/MCELFStreamer.cpp16
-rw-r--r--lib/MC/MCMachOStreamer.cpp6
-rw-r--r--lib/MC/MCNullStreamer.cpp2
-rw-r--r--lib/MC/MCPureStreamer.cpp2
-rw-r--r--lib/MC/MCStreamer.cpp15
-rw-r--r--lib/MC/WinCOFFStreamer.cpp2
-rw-r--r--lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp2
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp2
-rw-r--r--test/DebugInfo/dwarf-aranges.ll94
-rw-r--r--test/DebugInfo/multiple-aranges.ll65
18 files changed, 453 insertions, 26 deletions
diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h
index bff0cbad5b..76369ccb23 100644
--- a/include/llvm/MC/MCELFStreamer.h
+++ b/include/llvm/MC/MCELFStreamer.h
@@ -85,6 +85,8 @@ public:
virtual void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned);
+ virtual void Flush();
+
virtual void FinishImpl();
/// @}
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index cd297a4d9d..8cb5c49323 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/include/llvm/MC/MCStreamer.h
@@ -86,6 +86,10 @@ private:
MCSymbol *LastSymbol;
+ // SymbolOrdering - Tracks an index to represent the order
+ // a symbol was emitted in. Zero means we did not emit that symbol.
+ DenseMap<const MCSymbol *, unsigned> SymbolOrdering;
+
/// SectionStack - This is stack of current and previous section
/// values saved by PushSection.
SmallVector<std::pair<MCSectionSubPair, MCSectionSubPair>, 4> SectionStack;
@@ -185,6 +189,12 @@ public:
return MCSectionSubPair();
}
+ /// GetSymbolOrder - Returns an index to represent the order
+ /// a symbol was emitted in. (zero if we did not emit that symbol)
+ unsigned GetSymbolOrder(const MCSymbol *Sym) const {
+ return SymbolOrdering.lookup(Sym);
+ }
+
/// ChangeSection - Update streamer for a new active section.
///
/// This is called by PopSection and SwitchSection, if the current
@@ -264,6 +274,12 @@ public:
/// InitToTextSection - Create a text section and switch the streamer to it.
virtual void InitToTextSection() = 0;
+ /// AssignSection - Sets the symbol's section.
+ ///
+ /// Each emitted symbol will be tracked in the ordering table,
+ /// so we can sort on them later.
+ void AssignSection(MCSymbol *Symbol, const MCSection *Section);
+
/// EmitLabel - Emit a label for @p Symbol into the current section.
///
/// This corresponds to an assembler statement such as:
@@ -620,6 +636,9 @@ public:
/// these methods there.
virtual void EmitTCEntry(const MCSymbol &S);
+ /// Flush - Causes any cached state to be written out.
+ virtual void Flush() {}
+
/// FinishImpl - Streamer specific finalization.
virtual void FinishImpl() = 0;
/// Finish - Finish emission of machine code.
diff --git a/include/llvm/Support/Dwarf.h b/include/llvm/Support/Dwarf.h
index 7b87c6a90d..d924788057 100644
--- a/include/llvm/Support/Dwarf.h
+++ b/include/llvm/Support/Dwarf.h
@@ -59,7 +59,8 @@ enum LLVMConstants {
DWARF_VERSION = 4, // Default dwarf version we output.
DW_CIE_VERSION = 1, // Common frame information version.
DW_PUBTYPES_VERSION = 2, // Section version number for .debug_pubtypes.
- DW_PUBNAMES_VERSION = 2 // Section version number for .debug_pubnames.
+ DW_PUBNAMES_VERSION = 2, // Section version number for .debug_pubnames.
+ DW_ARANGES_VERSION = 2 // Section version number for .debug_aranges.
};
// Special ID values that distinguish a CIE from a FDE in DWARF CFI.
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index d0173f6316..e66237706b 100644
--- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -881,6 +881,9 @@ bool AsmPrinter::doFinalization(Module &M) {
if (!ModuleFlags.empty())
getObjFileLowering().emitModuleFlags(OutStreamer, ModuleFlags, Mang, TM);
+ // Make sure we wrote out everything we need.
+ OutStreamer.Flush();
+
// Finalize debug and EH information.
if (DE) {
{
diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 4893c25c09..2638b3150f 100644
--- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -181,6 +181,12 @@ void CompileUnit::addLabel(DIE *Die, uint16_t Attribute, uint16_t Form,
const MCSymbol *Label) {
DIEValue *Value = new (DIEValueAllocator) DIELabel(Label);
Die->addValue(Attribute, Form, Value);
+
+ SymbolCU Entry;
+ Entry.CU = this;
+ Entry.Sym = Label;
+
+ DD->addLabel(Entry);
}
/// addLabelAddress - Add a dwarf label attribute data and value using
@@ -188,6 +194,14 @@ void CompileUnit::addLabel(DIE *Die, uint16_t Attribute, uint16_t Form,
///
void CompileUnit::addLabelAddress(DIE *Die, uint16_t Attribute,
MCSymbol *Label) {
+ if (Label) {
+ SymbolCU Entry;
+ Entry.CU = this;
+ Entry.Sym = Label;
+
+ DD->addLabel(Entry);
+ }
+
if (!DD->useSplitDwarf()) {
if (Label != NULL) {
DIEValue *Value = new (DIEValueAllocator) DIELabel(Label);
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index a8ebf45e6e..f45e2f2431 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -924,7 +924,7 @@ void DwarfDebug::beginModule() {
MMI->setDebugInfoAvailability(true);
// Prime section data.
- SectionMap.insert(Asm->getObjFileLowering().getTextSection());
+ SectionMap[Asm->getObjFileLowering().getTextSection()];
}
// Attach DW_AT_inline attribute with inlined subprogram DIEs.
@@ -1077,16 +1077,39 @@ void DwarfDebug::finalizeModuleInfo() {
}
void DwarfDebug::endSections() {
- // Standard sections final addresses.
- Asm->OutStreamer.SwitchSection(Asm->getObjFileLowering().getTextSection());
- Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("text_end"));
- Asm->OutStreamer.SwitchSection(Asm->getObjFileLowering().getDataSection());
- Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("data_end"));
+ // Filter labels by section.
+ for (size_t n = 0; n < Labels.size(); n++) {
+ const SymbolCU &SCU = Labels[n];
+ if (SCU.Sym->isInSection()) {
+ // Make a note of this symbol and it's section.
+ const MCSection *Section = &SCU.Sym->getSection();
+ if (!Section->getKind().isMetadata())
+ SectionMap[Section].push_back(SCU);
+ } else {
+ // Some symbols (e.g. common/bss on mach-o) can have no section but still
+ // appear in the output. This sucks as we rely on sections to build
+ // arange spans. We can do it without, but it's icky.
+ SectionMap[NULL].push_back(SCU);
+ }
+ }
+
+ // Add terminating symbols for each section.
+ for (SectionMapType::iterator it = SectionMap.begin(); it != SectionMap.end();
+ it++) {
+ const MCSection *Section = it->first;
+ MCSymbol *Sym = NULL;
- // End text sections.
- for (unsigned I = 0, E = SectionMap.size(); I != E; ++I) {
- Asm->OutStreamer.SwitchSection(SectionMap[I]);
- Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("section_end", I+1));
+ if (Section) {
+ Sym = Asm->GetTempSymbol(Section->getLabelEndName());
+ Asm->OutStreamer.SwitchSection(Section);
+ Asm->OutStreamer.EmitLabel(Sym);
+ }
+
+ // Insert a final terminator.
+ SymbolCU Entry;
+ Entry.CU = NULL;
+ Entry.Sym = Sym;
+ SectionMap[Section].push_back(Entry);
}
}
@@ -2659,11 +2682,172 @@ void DwarfDebug::emitDebugLoc() {
}
}
-// Emit visible names into a debug aranges section.
+struct SymbolCUSorter {
+ SymbolCUSorter(const MCStreamer &s) : Streamer(s) {}
+ const MCStreamer &Streamer;
+
+ bool operator() (const SymbolCU &A, const SymbolCU &B) {
+ unsigned IA = A.Sym ? Streamer.GetSymbolOrder(A.Sym) : 0;
+ unsigned IB = B.Sym ? Streamer.GetSymbolOrder(B.Sym) : 0;
+
+ // Symbols with no order assigned should be placed at the end.
+ // (e.g. section end labels)
+ if (IA == 0)
+ IA = (unsigned)(-1);
+ if (IB == 0)
+ IB = (unsigned)(-1);
+ return IA < IB;
+ }
+};
+
+static bool SectionSort(const MCSection *A, const MCSection *B) {
+ std::string LA = (A ? A->getLabelBeginName() : "");
+ std::string LB = (B ? B->getLabelBeginName() : "");
+ return LA < LB;
+}
+
+static bool CUSort(const CompileUnit *A, const CompileUnit *B) {
+ return (A->getUniqueID() < B->getUniqueID());
+}
+
+struct ArangeSpan {
+ const MCSymbol *Start, *End;
+};
+
+// Emit a debug aranges section, containing a CU lookup for any
+// address we can tie back to a CU.
void DwarfDebug::emitDebugARanges() {
// Start the dwarf aranges section.
Asm->OutStreamer
.SwitchSection(Asm->getObjFileLowering().getDwarfARangesSection());
+
+ typedef DenseMap<CompileUnit *, std::vector<ArangeSpan> > SpansType;
+
+ SpansType Spans;
+
+ // Build a list of sections used.
+ std::vector<const MCSection *> Sections;
+ for (SectionMapType::iterator it = SectionMap.begin(); it != SectionMap.end();
+ it++) {
+ const MCSection *Section = it->first;
+ Sections.push_back(Section);
+ }
+
+ // Sort the sections into order.
+ // This is only done to ensure consistent output order across different runs.
+ std::sort(Sections.begin(), Sections.end(), SectionSort);
+
+ // Build a set of address spans, sorted by CU.
+ for (size_t SecIdx=0;SecIdx<Sections.size();SecIdx++) {
+ const MCSection *Section = Sections[SecIdx];
+ SmallVector<SymbolCU, 8> &List = SectionMap[Section];
+ if (List.size() < 2)
+ continue;
+
+ // Sort the symbols by offset within the section.
+ SymbolCUSorter sorter(Asm->OutStreamer);
+ std::sort(List.begin(), List.end(), sorter);
+
+ // If we have no section (e.g. common), just write out
+ // individual spans for each symbol.
+ if (Section == NULL) {
+ for (size_t n = 0; n < List.size(); n++) {
+ const SymbolCU &Cur = List[n];
+
+ ArangeSpan Span;
+ Span.Start = Cur.Sym;
+ Span.End = NULL;
+ if (Cur.CU)
+ Spans[Cur.CU].push_back(Span);
+ }
+ } else {
+ // Build spans between each label.
+ const MCSymbol *StartSym = List[0].Sym;
+ for (size_t n = 1; n < List.size(); n++) {
+ const SymbolCU &Prev = List[n - 1];
+ const SymbolCU &Cur = List[n];
+
+ // Try and build the longest span we can within the same CU.
+ if (Cur.CU != Prev.CU) {
+ ArangeSpan Span;
+ Span.Start = StartSym;
+ Span.End = Cur.Sym;
+ Spans[Prev.CU].push_back(Span);
+ StartSym = Cur.Sym;
+ }
+ }
+ }
+ }
+
+ const MCSection *ISec = Asm->getObjFileLowering().getDwarfInfoSection();
+ unsigned PtrSize = Asm->getDataLayout().getPointerSize();
+
+ // Build a list of CUs used.
+ std::vector<CompileUnit *> CUs;
+ for (SpansType::iterator it = Spans.begin(); it != Spans.end(); it++) {
+ CompileUnit *CU = it->first;
+ CUs.push_back(CU);
+ }
+
+ // Sort the CU list (again, to ensure consistent output order).
+ std::sort(CUs.begin(), CUs.end(), CUSort);
+
+ // Emit an arange table for each CU we used.
+ for (size_t CUIdx=0;CUIdx<CUs.size();CUIdx++) {
+ CompileUnit *CU = CUs[CUIdx];
+ std::vector<ArangeSpan> &List = Spans[CU];
+
+ // Emit size of content not including length itself.
+ unsigned ContentSize
+ = sizeof(int16_t) // DWARF ARange version number
+ + sizeof(int32_t) // Offset of CU in the .debug_info section
+ + sizeof(int8_t) // Pointer Size (in bytes)
+ + sizeof(int8_t); // Segment Size (in bytes)
+
+ unsigned TupleSize = PtrSize * 2;
+
+ // 7.20 in the Dwarf specs requires the table to be aligned to a tuple.
+ unsigned Padding = 0;
+ while (((sizeof(int32_t) + ContentSize + Padding) % TupleSize) != 0)
+ Padding++;
+
+ ContentSize += Padding;
+ ContentSize += (List.size() + 1) * TupleSize;
+
+ // For each compile unit, write the list of spans it covers.
+ Asm->OutStreamer.AddComment("Length of ARange Set");
+ Asm->EmitInt32(ContentSize);
+ Asm->OutStreamer.AddComment("DWARF Arange version number");
+ Asm->EmitInt16(dwarf::DW_ARANGES_VERSION);
+ Asm->OutStreamer.AddComment("Offset Into Debug Info Section");
+ Asm->EmitSectionOffset(
+ Asm->GetTempSymbol(ISec->getLabelBeginName(), CU->getUniqueID()),
+ DwarfInfoSectionSym);
+ Asm->OutStreamer.AddComment("Address Size (in bytes)");
+ Asm->EmitInt8(PtrSize);
+ Asm->OutStreamer.AddComment("Segment Size (in bytes)");
+ Asm->EmitInt8(0);
+
+ for (unsigned n = 0; n < Padding; n++)
+ Asm->EmitInt8(0xff);
+
+ for (unsigned n = 0; n < List.size(); n++) {
+ const ArangeSpan &Span = List[n];
+ Asm->EmitLabelReference(Span.Start, PtrSize);
+
+ // Calculate the size as being from the span start to it's end.
+ // If we have no valid end symbol, then we just cover the first byte.
+ // (this sucks, but I can't seem to figure out how to get the size)
+ if (Span.End)
+ Asm->EmitLabelDifference(Span.End, Span.Start, PtrSize);
+ else
+ Asm->OutStreamer.EmitIntValue(1, PtrSize);
+ }
+
+ Asm->OutStreamer.AddComment("ARange terminator");
+ Asm->OutStreamer.EmitIntValue(0, PtrSize);
+ Asm->OutStreamer.EmitIntValue(0, PtrSize);
+ }
}
// Emit visible names into a debug ranges section.
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 5a03e9fb58..8fe60c77be 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -300,6 +300,12 @@ public:
unsigned getCUOffset(DIE *Die);
};
+/// \brief Helper used to pair up a symbol and it's DWARF compile unit.
+struct SymbolCU {
+ const MCSymbol *Sym;
+ CompileUnit *CU;
+};
+
/// \brief Collects and handles dwarf debug information.
class DwarfDebug {
// Target of Dwarf emission.
@@ -332,8 +338,12 @@ class DwarfDebug {
// separated by a zero byte, mapped to a unique id.
StringMap<unsigned, BumpPtrAllocator&> SourceIdMap;
+ // List of all labels used in the output.
+ std::vector<SymbolCU> Labels;
+
// Provides a unique id per text section.
- SetVector<const MCSection*> SectionMap;
+ typedef DenseMap<const MCSection *, SmallVector<SymbolCU, 8> > SectionMapType;
+ SectionMapType SectionMap;
// List of arguments for current function.
SmallVector<DbgVariable *, 8> CurrentFnArguments;
@@ -669,6 +679,9 @@ public:
/// type units.
void addTypeUnitType(DIE *Die) { TypeUnits.push_back(Die); }
+ /// \brief Add a label so that arange data can be generated for it.
+ void addLabel(SymbolCU SCU) { Labels.push_back(SCU); }
+
/// \brief Look up the source id with the given directory and source file
/// names. If none currently exists, create a new id and insert it in the
/// SourceIds map.
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index 2456d8de82..e57025e101 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -533,6 +533,9 @@ void MCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment) {
+ const MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
+ AssignSection(Symbol, Section);
+
OS << "\t.comm\t" << *Symbol << ',' << Size;
if (ByteAlignment != 0) {
if (MAI->getCOMMDirectiveAlignmentIsInBytes())
@@ -549,6 +552,9 @@ void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
/// @param Size - The size of the common symbol.
void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlign) {
+ const MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
+ AssignSection(Symbol, Section);
+
OS << "\t.lcomm\t" << *Symbol << ',' << Size;
if (ByteAlign > 1) {
switch (MAI->getLCOMMDirectiveAlignmentType()) {
@@ -568,6 +574,9 @@ void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
uint64_t Size, unsigned ByteAlignment) {
+ if (Symbol)
+ AssignSection(Symbol, Section);
+
// Note: a .zerofill directive does not switch sections.
OS << ".zerofill ";
@@ -588,6 +597,8 @@ void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
// e.g. _a.
void MCAsmStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
uint64_t Size, unsigned ByteAlignment) {
+ AssignSection(Symbol, Section);
+
assert(Symbol != NULL && "Symbol shouldn't be NULL!");
// Instead of using the Section we'll just use the shortcut.
// This is a mach-o specific directive and section.
diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp
index a04352a8b2..0ed040d5be 100644
--- a/lib/MC/MCELFStreamer.cpp
+++ b/lib/MC/MCELFStreamer.cpp
@@ -272,7 +272,8 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
ELF::SHF_WRITE |
ELF::SHF_ALLOC,
SectionKind::getBSS());
- Symbol->setSection(*Section);
+
+ AssignSection(Symbol, Section);
struct LocalCommon L = {&SD, Size, ByteAlignment};
LocalCommons.push_back(L);
@@ -527,9 +528,7 @@ void MCELFStreamer::EmitBundleUnlock() {
SD->setBundleLockState(MCSectionData::NotBundleLocked);
}
-void MCELFStreamer::FinishImpl() {
- EmitFrames(NULL, true);
-
+void MCELFStreamer::Flush() {
for (std::vector<LocalCommon>::const_iterator i = LocalCommons.begin(),
e = LocalCommons.end();
i != e; ++i) {
@@ -550,8 +549,17 @@ void MCELFStreamer::FinishImpl() {
SectData.setAlignment(ByteAlignment);
}
+ LocalCommons.clear();
+}
+
+void MCELFStreamer::FinishImpl() {
+ EmitFrames(NULL, true);
+
+ Flush();
+
this->MCObjectStreamer::FinishImpl();
}
+
void MCELFStreamer::EmitTCEntry(const MCSymbol &S) {
// Creates a R_PPC64_TOC relocation
MCObjectStreamer::EmitSymbolValue(&S, 8);
diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp
index e628461f1d..2c4707f58c 100644
--- a/lib/MC/MCMachOStreamer.cpp
+++ b/lib/MC/MCMachOStreamer.cpp
@@ -123,7 +123,7 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
// isSymbolLinkerVisible uses the section.
- Symbol->setSection(*getCurrentSection().first);
+ AssignSection(Symbol, getCurrentSection().first);
// We have to create a new fragment if this is an atom defining symbol,
// fragments cannot span atoms.
if (getAssembler().isSymbolLinkerVisible(*Symbol))
@@ -327,6 +327,8 @@ void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
// FIXME: Darwin 'as' does appear to allow redef of a .comm by itself.
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
+ AssignSection(Symbol, NULL);
+
MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
SD.setExternal(true);
SD.setCommon(Size, ByteAlignment);
@@ -363,7 +365,7 @@ void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
MCFragment *F = new MCFillFragment(0, 0, Size, &SectData);
SD.setFragment(F);
- Symbol->setSection(*Section);
+ AssignSection(Symbol, Section);
// Update the maximum alignment on the zero fill section if necessary.
if (ByteAlignment > SectData.getAlignment())
diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp
index 87a7db69cd..2ddc4f0f71 100644
--- a/lib/MC/MCNullStreamer.cpp
+++ b/lib/MC/MCNullStreamer.cpp
@@ -37,7 +37,7 @@ namespace {
virtual void EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
assert(getCurrentSection().first &&"Cannot emit before setting section!");
- Symbol->setSection(*getCurrentSection().first);
+ AssignSection(Symbol, getCurrentSection().first);
}
virtual void EmitDebugLabel(MCSymbol *Symbol) {
EmitLabel(Symbol);
diff --git a/lib/MC/MCPureStreamer.cpp b/lib/MC/MCPureStreamer.cpp
index c6c772c6e2..a83caf6080 100644
--- a/lib/MC/MCPureStreamer.cpp
+++ b/lib/MC/MCPureStreamer.cpp
@@ -121,7 +121,7 @@ void MCPureStreamer::EmitLabel(MCSymbol *Symbol) {
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
assert(getCurrentSection().first && "Cannot emit before setting section!");
- Symbol->setSection(*getCurrentSection().first);
+ AssignSection(Symbol, getCurrentSection().first);
MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp
index c2a20f9ca6..4ffde67476 100644
--- a/lib/MC/MCStreamer.cpp
+++ b/lib/MC/MCStreamer.cpp
@@ -191,17 +191,28 @@ void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
MCSymbol *EHSymbol) {
}
+void MCStreamer::AssignSection(MCSymbol *Symbol, const MCSection *Section) {
+ if (Section)
+ Symbol->setSection(*Section);
+ else
+ Symbol->setUndefined();
+
+ // As we emit symbols into a section, track the order so that they can
+ // be sorted upon later. Zero is reserved to mean 'unemitted'.
+ SymbolOrdering[Symbol] = 1 + SymbolOrdering.size();
+}
+
void MCStreamer::EmitLabel(MCSymbol *Symbol) {
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
assert(getCurrentSection().first && "Cannot emit before setting section!");
- Symbol->setSection(*getCurrentSection().first);
+ AssignSection(Symbol, getCurrentSection().first);
LastSymbol = Symbol;
}
void MCStreamer::EmitDebugLabel(MCSymbol *Symbol) {
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
assert(getCurrentSection().first && "Cannot emit before setting section!");
- Symbol->setSection(*getCurrentSection().first);
+ AssignSection(Symbol, getCurrentSection().first);
LastSymbol = Symbol;
}
diff --git a/lib/MC/WinCOFFStreamer.cpp b/lib/MC/WinCOFFStreamer.cpp
index 3f0449dc46..dd98aa5f30 100644
--- a/lib/MC/WinCOFFStreamer.cpp
+++ b/lib/MC/WinCOFFStreamer.cpp
@@ -164,7 +164,7 @@ void WinCOFFStreamer::AddCommonSymbol(MCSymbol *Symbol, uint64_t Size,
SymbolData.setExternal(External);
- Symbol->setSection(*Section);
+ AssignSection(Symbol, Section);
if (ByteAlignment != 1)
new MCAlignFragment(ByteAlignment, 0, 0, ByteAlignment, &SectionData);
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index 104e4d242d..8e2be8185e 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -129,7 +129,7 @@ private:
MCELF::SetType(SD, ELF::STT_NOTYPE);
MCELF::SetBinding(SD, ELF::STB_LOCAL);
SD.setExternal(false);
- Symbol->setSection(*getCurrentSection().first);
+ AssignSection(Symbol, getCurrentSection().first);
const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext());
Symbol->setVariableValue(Value);
diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index 6b9820565b..37a80d5b8c 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -183,7 +183,7 @@ private:
MCELF::SetType(SD, ELF::STT_NOTYPE);
MCELF::SetBinding(SD, ELF::STB_LOCAL);
SD.setExternal(false);
- Symbol->setSection(*getCurrentSection().first);
+ AssignSection(Symbol, getCurrentSection().first);
const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext());
Symbol->setVariableValue(Value);
diff --git a/test/DebugInfo/dwarf-aranges.ll b/test/DebugInfo/dwarf-aranges.ll
new file mode 100644
index 0000000000..eae5c790d8
--- /dev/null
+++ b/test/DebugInfo/dwarf-aranges.ll
@@ -0,0 +1,94 @@
+; RUN: llc < %s | FileCheck -check-prefix=CHECK-HEADER %s
+; RUN: llc < %s | FileCheck -check-prefix=CHECK-CODE %s
+; RUN: llc < %s | FileCheck -check-prefix=CHECK-DATA %s
+; RUN: llc < %s | FileCheck -check-prefix=CHECK-BSS %s
+; RUN: llc < %s | FileCheck -check-prefix=CHECK-CUSTOM %s
+
+
+; -- header --
+; CHECK-HEADER: .short 2 # DWARF Arange version number
+; CHECK-HEADER-NEXT: .long .L.debug_info_begin0
+; CHECK-HEADER-NEXT: .byte 8 # Address Size (in bytes)
+; CHECK-HEADER-NEXT: .byte 0 # Segment Size (in bytes)
+; -- alignment --
+; CHECK-HEADER-NEXT: .byte
+; CHECK-HEADER-NEXT: .byte
+; CHECK-HEADER-NEXT: .byte
+; CHECK-HEADER-NEXT: .byte
+; -- finish --
+; CHECK-HEADER: # ARange terminator
+
+
+; CHECK-CODE: .short 2 # DWARF Arange version number
+; CHECK-CODE: .quad .Lfunc_begin0
+; CHECK-CODE: # ARange terminator
+
+; CHECK-DATA: .short 2 # DWARF Arange version number
+; CHECK-DATA: .quad some_data
+; CHECK-DATA-NEXT: -some_data
+; CHECK-DATA-NEXT: .quad
+; CHECK-DATA: # ARange terminator
+
+; CHECK-BSS: .short 2 # DWARF Arange version number
+; CHECK-BSS: .quad some_bss
+; CHECK-BSS-NEXT: -some_bss
+; CHECK-BSS-NEXT: .quad
+; CHECK-BSS: # ARange terminator
+
+; CHECK-CUSTOM: .short 2 # DWARF Arange version number
+; CHECK-CUSTOM: .quad some_other
+; CHECK-CUSTOM-NEXT: -some_other
+; CHECK-CUSTOM-NEXT: .quad
+; CHECK-CUSTOM: # ARange terminator
+
+
+
+
+; -- source code --
+; Generated from: "clang -c -g -emit-llvm"
+;
+; int some_data = 4;
+; int some_bss;
+; int some_other __attribute__ ((section ("strangesection"))) = 5;
+;
+; void some_code()
+; {
+; some_bss += some_data + some_other;
+; }
+
+target triple = "x86_64-unknown-linux-gnu"
+
+@some_data = global i32 4, align 4
+@some_other = global i32 5, section "strangesection", align 4
+@some_bss = common global i32 0, align 4
+
+define void @some_code() {
+entry:
+ %0 = load i32* @some_data, align 4, !dbg !14
+ %1 = load i32* @some_other, align 4, !dbg !14
+ %add = add nsw i32 %0, %1, !dbg !14
+ %2 = load i32* @some_bss, align 4, !dbg !14
+ %add1 = add nsw i32 %2, %add, !dbg !14
+ store i32 %add1, i32* @some_bss, align 4, !dbg !14
+ ret void, !dbg !15
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!13}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.4 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !8, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/home/kayamon/test.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"test.c", metadata !"/home/kayamon"}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"some_code", metadata !"some_code", metadata !"", i32 5, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 0, i1 false, void ()* @some_code, null, null, metadata !2, i32 6} ; [ DW_TAG_subprogram ] [line 5] [def] [scope 6] [some_code]
+!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [/home/kayamon/test.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{null}
+!8 = metadata !{metadata !9, metadata !11, metadata !12}
+!9 = metadata !{i32 786484, i32 0, null, metadata !"some_data", metadata !"some_data", metadata !"", metadata !5, i32 1, metadata !10, i32 0, i32 1, i32* @some_data, null} ; [ DW_TAG_variable ] [some_data] [line 1] [def]
+!10 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!11 = metadata !{i32 786484, i32 0, null, metadata !"some_other", metadata !"some_other", metadata !"", metadata !5, i32 3, metadata !10, i32 0, i32 1, i32* @some_other, null} ; [ DW_TAG_variable ] [some_other] [line 3] [def]
+!12 = metadata !{i32 786484, i32 0, null, metadata !"some_bss", metadata !"some_bss", metadata !"", metadata !5, i32 2, metadata !10, i32 0, i32 1, i32* @some_bss, null} ; [ DW_TAG_variable ] [some_bss] [line 2] [def]
+!13 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!14 = metadata !{i32 7, i32 0, metadata !4, null}
+!15 = metadata !{i32 8, i32 0, metadata !4, null} ; [ DW_TAG_imported_declaration ]
diff --git a/test/DebugInfo/multiple-aranges.ll b/test/DebugInfo/multiple-aranges.ll
new file mode 100644
index 0000000000..08c4fa6684
--- /dev/null
+++ b/test/DebugInfo/multiple-aranges.ll
@@ -0,0 +1,65 @@
+; RUN: llc < %s | FileCheck %s
+
+; First CU
+; CHECK: .long 44 # Length of ARange Set
+; CHECK-NEXT: .short 2 # DWARF Arange version number
+; CHECK-NEXT: .long .L.debug_info_begin0 # Offset Into Debug Info Section
+; CHECK-NEXT: .byte 8 # Address Size (in bytes)
+; CHECK-NEXT: .byte 0 # Segment Size (in bytes)
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .quad kittens
+; CHECK-NEXT: .Lset0 = rainbows-kittens
+; CHECK-NEXT: .quad .Lset0
+; CHECK-NEXT: .quad 0 # ARange terminator
+; CHECK-NEXT: .quad 0
+
+; Second CU
+; CHECK-NEXT: .long 44 # Length of ARange Set
+; CHECK-NEXT: .short 2 # DWARF Arange version number
+; CHECK-NEXT: .long .L.debug_info_begin1 # Offset Into Debug Info Section
+; CHECK-NEXT: .byte 8 # Address Size (in bytes)
+; CHECK-NEXT: .byte 0 # Segment Size (in bytes)
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .byte 255
+; CHECK-NEXT: .quad rainbows
+; CHECK-NEXT: .Lset1 = .L.data_end-rainbows
+; CHECK-NEXT: .quad .Lset1
+; CHECK-NEXT: .quad 0 # ARange terminator
+; CHECK-NEXT: .quad 0
+
+
+; Generated from: clang -c -g -emit-llvm
+; llvm-link test1.bc test2.bc -o test.bc
+; test1.c: int kittens = 4;
+; test2.c: int rainbows = 5;
+
+
+
+
+; ModuleID = 'test.bc'
+target triple = "x86_64-unknown-linux-gnu"
+
+@kittens = global i32 4, align 4
+@rainbows = global i32 5, align 4
+
+!llvm.dbg.cu = !{!0, !7}
+!llvm.module.flags = !{!12}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.4 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !2, metadata !3, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/home/kayamon/test1.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"test1.c", metadata !"/home/kayamon"}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786484, i32 0, null, metadata !"kittens", metadata !"kittens", metadata !"", metadata !5, i32 1, metadata !6, i32 0, i32 1, i32* @kittens, null} ; [ DW_TAG_variable ] [kittens] [line 1] [def]
+!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [/home/kayamon/test1.c]
+!6 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!7 = metadata !{i32 786449, metadata !8, i32 12, metadata !"clang version 3.4 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !2, metadata !9, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/home/kayamon/test2.c] [DW_LANG_C99]
+!8 = metadata !{metadata !"test2.c", metadata !"/home/kayamon"}
+!9 = metadata !{metadata !10}
+!10 = metadata !{i32 786484, i32 0, null, metadata !"rainbows", metadata !"rainbows", metadata !"", metadata !11, i32 1, metadata !6, i32 0, i32 1, i32* @rainbows, null} ; [ DW_TAG_variable ] [rainbows] [line 1] [def]
+!11 = metadata !{i32 786473, metadata !8} ; [ DW_TAG_file_type ] [/home/kayamon/test2.c]
+!12 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}