Index: include/llvm/MC/MCContext.h =================================================================== --- include/llvm/MC/MCContext.h +++ include/llvm/MC/MCContext.h @@ -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" @@ -123,11 +125,13 @@ /// 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; + /// The sections that we generate dwarf debugging line info for when + /// generating dwarf assembly source files. + SetVector GenDwarfSections; + /// Symbols created for the start and end of each section, used for + /// generating the debug_aranges section + DenseMap GenDwarfSectionStartSyms; + DenseMap GenDwarfSectionEndSyms; /// The information gathered from labels that will have dwarf label /// entries when generating dwarf assembly source files. @@ -141,6 +145,9 @@ /// non-empty. StringRef DwarfDebugProducer; + /// The maximum version of dwarf that we should emit. + unsigned DwarfVersion; + /// Honor temporary labels, this is useful for debugging semantic /// differences between temporary and non-temporary labels (primarily on /// Darwin). @@ -363,15 +370,53 @@ void setGenDwarfForAssembly(bool Value) { GenDwarfForAssembly = Value; } unsigned getGenDwarfFileNumber() { return GenDwarfFileNumber; } unsigned nextGenDwarfFileNumber() { return ++GenDwarfFileNumber; } - const MCSection *getGenDwarfSection() { return GenDwarfSection; } - void setGenDwarfSection(const MCSection *Sec) { GenDwarfSection = Sec; } - MCSymbol *getGenDwarfSectionStartSym() { return GenDwarfSectionStartSym; } - void setGenDwarfSectionStartSym(MCSymbol *Sym) { - GenDwarfSectionStartSym = Sym; + SetVector &getGenDwarfSections() { + return GenDwarfSections; + } + void addGenDwarfSection(const MCSection *Sec) { + GenDwarfSections.insert(Sec); + } + void FinalizeDwarfSections(MCStreamer &MCOS) { + MCContext &context = MCOS.getContext(); + SetVector InvalidSections; + + for (SetVector::iterator sec = + GenDwarfSections.begin(); + sec != GenDwarfSections.end(); ++sec) { + MCOS.SwitchSection(*sec); + if (MCOS.hasInstructions()) { + MCSymbol *SectionEndSym = context.CreateTempSymbol(); + MCOS.EmitLabel(SectionEndSym); + context.setGenDwarfSectionEndSym(*sec, SectionEndSym); + } else { + InvalidSections.insert(*sec); + } + } + + for (SetVector::iterator sec = InvalidSections.begin(); + sec != InvalidSections.end(); ++sec) { + GenDwarfSections.remove(*sec); + } + } + MCSymbol *getGenDwarfSectionStartSym(const MCSection *Sec) { + DenseMap::iterator Sym = + GenDwarfSectionStartSyms.find(Sec); + if (Sym != GenDwarfSectionStartSyms.end()) + return Sym->second; + return NULL; } - MCSymbol *getGenDwarfSectionEndSym() { return GenDwarfSectionEndSym; } - void setGenDwarfSectionEndSym(MCSymbol *Sym) { - GenDwarfSectionEndSym = Sym; + void setGenDwarfSectionStartSym(const MCSection *Sec, MCSymbol *Sym) { + GenDwarfSectionStartSyms[Sec] = Sym; + } + MCSymbol *getGenDwarfSectionEndSym(const MCSection *Sec) { + DenseMap::iterator Sym = + GenDwarfSectionEndSyms.find(Sec); + if (Sym != GenDwarfSectionEndSyms.end()) + return Sym->second; + return NULL; + } + void setGenDwarfSectionEndSym(const MCSection *Sec, MCSymbol *Sym) { + GenDwarfSectionEndSyms[Sec] = Sym; } const std::vector &getMCGenDwarfLabelEntries() const { @@ -387,6 +432,9 @@ void setDwarfDebugProducer(StringRef S) { DwarfDebugProducer = S; } StringRef getDwarfDebugProducer() { return DwarfDebugProducer; } + void setDwarfVersion(unsigned v) { DwarfVersion = v; } + unsigned getDwarfVersion() const { return DwarfVersion; } + /// @} char *getSecureLogFile() { return SecureLogFile; } Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -117,6 +117,10 @@ void EmitFill(uint64_t NumBytes, uint8_t FillValue) override; void EmitZeros(uint64_t NumBytes) override; void FinishImpl() override; + + virtual bool hasInstructions() const { + return getCurrentSectionData()->hasInstructions(); + } }; } // end namespace llvm Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -716,6 +716,8 @@ virtual void FinishImpl() = 0; /// Finish - Finish emission of machine code. void Finish(); + + virtual bool hasInstructions() const { return false; } }; /// createNullStreamer - Create a dummy machine code streamer, which does Index: lib/MC/MCDwarf.cpp =================================================================== --- lib/MC/MCDwarf.cpp +++ lib/MC/MCDwarf.cpp @@ -16,7 +16,9 @@ #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/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Debug.h" @@ -432,7 +434,7 @@ // When generating dwarf for assembly source files this emits // the data for .debug_abbrev section which contains three DIEs. -static void EmitGenDwarfAbbrev(MCStreamer *MCOS) { +static void EmitGenDwarfAbbrev(MCStreamer *MCOS, bool UseRangesSection) { MCContext &context = MCOS->getContext(); MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection()); @@ -441,8 +443,12 @@ 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 (UseRangesSection) { + 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); @@ -482,13 +488,7 @@ 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); + SetVector &Sections = context.getGenDwarfSections(); MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection()); @@ -506,8 +506,8 @@ 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; @@ -531,14 +531,22 @@ 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->EmitAbsValue(Addr, AddrSize); - MCOS->EmitAbsValue(Size, AddrSize); + // Now emit the table of pairs of PointerSize'ed values for the section + // addresses and sizes. + for (SetVector::const_iterator sec = Sections.begin(); + sec != Sections.end(); sec++) { + MCSymbol* StartSymbol = context.getGenDwarfSectionStartSym(*sec); + MCSymbol* EndSymbol = context.getGenDwarfSectionEndSym(*sec); + 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->EmitAbsValue(Addr, AddrSize); + MCOS->EmitAbsValue(Size, AddrSize); + } // And finally the pair of terminating zeros. MCOS->EmitIntValue(0, AddrSize); @@ -550,7 +558,8 @@ // 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()); @@ -568,8 +577,8 @@ const MCExpr *Length = MakeStartMinusEndExpr(*MCOS, *InfoStart, *InfoEnd, 4); MCOS->EmitAbsValue(Length, 4); - // The 2 byte DWARF version, which is 2. - MCOS->EmitIntValue(2, 2); + // The 2 byte DWARF version. + MCOS->EmitIntValue(context.getDwarfVersion(), 2); // 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. @@ -597,15 +606,43 @@ 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->EmitAbsValue(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->EmitAbsValue(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 + SetVector &Sections = context.getGenDwarfSections(); + SetVector::const_iterator TextSection = Sections.begin(); + while (true) { + assert(TextSection != Sections.end() && "No text section found"); + MCOS->SwitchSection(*TextSection); + if (MCOS->hasInstructions()) break; + ++TextSection; + } + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection()); + + MCSymbol* StartSymbol = context.getGenDwarfSectionStartSym(*TextSection); + MCSymbol* EndSymbol = context.getGenDwarfSectionEndSym(*TextSection); + 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->EmitAbsValue(Start, AddrSize); + + // AT_high_pc, the last address of the default .text section. + const MCExpr *End = MCSymbolRefExpr::Create( + EndSymbol, MCSymbolRefExpr::VK_None, context); + MCOS->EmitAbsValue(End, AddrSize); + } // AT_name, the name of the source file. Reconstruct from the first directory // and file table entries. @@ -702,13 +739,58 @@ MCOS->EmitLabel(InfoEnd); } +// When generating dwarf for assembly source files this emits the data for +// .debug_ranges section. We currently only emit one range list, which spans +// all of the executable sections of this file. +static void EmitGenDwarfRanges(MCStreamer *MCOS) { + MCContext &context = MCOS->getContext(); + SetVector &Sections = context.getGenDwarfSections(); + + const MCAsmInfo *AsmInfo = context.getAsmInfo(); + int AddrSize = AsmInfo->getPointerSize(); + + for (SetVector::const_iterator sec = Sections.begin(); + sec != Sections.end(); sec++) { + MCOS->SwitchSection(*sec); + if (!MCOS->hasInstructions()) continue; + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfRangesSection()); + + MCSymbol* StartSymbol = context.getGenDwarfSectionStartSym(*sec); + MCSymbol* EndSymbol = context.getGenDwarfSectionEndSym(*sec); + 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->EmitAbsValue(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, const MCSymbol *LineSectionSymbol) { - // Create the dwarf sections in this order (.debug_line already created). MCContext &context = MCOS->getContext(); + + // If there are no line table entries then do not emit any debug sections. + if (context.getMCLineSections().empty()) + return; + + // Create the dwarf sections in this order (.debug_line already created). const MCAsmInfo *AsmInfo = context.getAsmInfo(); bool CreateDwarfSectionSymbols = AsmInfo->doesDwarfUseRelocationsAcrossSections(); @@ -716,6 +798,23 @@ LineSectionSymbol = NULL; MCSymbol *AbbrevSectionSymbol = NULL; MCSymbol *InfoSectionSymbol = NULL; + MCSymbol *RangesSectionSymbol = NULL; + + // Create end symbols for each section, and remove empty sections + MCOS->getContext().FinalizeDwarfSections(*MCOS); + + int NumSectionsWithInstructions = 0; + SetVector &Sections = MCOS->getContext().getGenDwarfSections(); + for (SetVector::const_iterator sec = Sections.begin(); + sec != Sections.end(); sec++) { + MCOS->SwitchSection(*sec); + if (MCOS->hasInstructions()) ++NumSectionsWithInstructions; + } + // We only need to use the .debug_ranges section if we have multiple + // non-empty code sections. + const bool UseRangesSection = NumSectionsWithInstructions > 1; + CreateDwarfSectionSymbols |= UseRangesSection; + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection()); if (CreateDwarfSectionSymbols) { InfoSectionSymbol = context.CreateTempSymbol(); @@ -726,20 +825,30 @@ 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.getMCLineSections().empty()) - 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); + EmitGenDwarfAbbrev(MCOS, UseRangesSection); // Output the data for .debug_info section. - EmitGenDwarfInfo(MCOS, AbbrevSectionSymbol, LineSectionSymbol); + EmitGenDwarfInfo(MCOS, AbbrevSectionSymbol, LineSectionSymbol, + RangesSectionSymbol); } // @@ -750,12 +859,13 @@ // 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.getGenDwarfSections().count(MCOS->getCurrentSection().first)) return; // The dwarf label's name does not have the symbol name's leading Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -636,10 +636,10 @@ // If we are generating dwarf for assembly source files save the initial text // section and generate a .file directive. if (getContext().getGenDwarfForAssembly()) { - getContext().setGenDwarfSection(getStreamer().getCurrentSection().first); + getContext().addGenDwarfSection(getStreamer().getCurrentSection().first); MCSymbol *SectionStartSym = getContext().CreateTempSymbol(); getStreamer().EmitLabel(SectionStartSym); - getContext().setGenDwarfSectionStartSym(SectionStartSym); + getContext().setGenDwarfSectionStartSym(getStreamer().getCurrentSection().first, SectionStartSym); getStreamer().EmitDwarfFileDirective(getContext().nextGenDwarfFileNumber(), StringRef(), getContext().getMainFileName()); @@ -1577,12 +1577,11 @@ printMessage(IDLoc, SourceMgr::DK_Note, OS.str()); } - // If we are generating dwarf for assembly source files and the current - // section is the initial text section then generate a .loc directive for - // the instruction. + // If we are generating dwarf for the current section then generate a .loc + // directive for the instruction. if (!HadError && getContext().getGenDwarfForAssembly() && - getContext().getGenDwarfSection() == - getStreamer().getCurrentSection().first) { + getContext().getGenDwarfSections().count( + getStreamer().getCurrentSection().first)) { unsigned Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer); Index: lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- lib/MC/MCParser/ELFAsmParser.cpp +++ lib/MC/MCParser/ELFAsmParser.cpp @@ -150,7 +150,7 @@ private: bool ParseSectionName(StringRef &SectionName); - bool ParseSectionArguments(bool IsPush); + bool ParseSectionArguments(bool IsPush, SMLoc loc); unsigned parseSunStyleSectionFlags(); }; @@ -356,7 +356,7 @@ bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { getStreamer().PushSection(); - if (ParseSectionArguments(/*IsPush=*/true)) { + if (ParseSectionArguments(/*IsPush=*/true, loc)) { getStreamer().PopSection(); return true; } @@ -371,11 +371,11 @@ } // FIXME: This is a work in progress. -bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { - return ParseSectionArguments(/*IsPush=*/false); +bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc loc) { + return ParseSectionArguments(/*IsPush=*/false, loc); } -bool ELFAsmParser::ParseSectionArguments(bool IsPush) { +bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { StringRef SectionName; if (ParseSectionName(SectionName)) @@ -519,10 +519,25 @@ } SectionKind Kind = computeSectionKind(Flags); - getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type, - Flags, Kind, Size, - GroupName), - Subsection); + const MCSection *ELFSection = getContext().getELFSection( + SectionName, Type, Flags, Kind, Size, GroupName); + getStreamer().SwitchSection(ELFSection, Subsection); + + if (getContext().getGenDwarfForAssembly()) { + if (!getContext().getGenDwarfSections().count(ELFSection)) { + getContext().addGenDwarfSection(ELFSection); + if (getContext().getDwarfVersion() <= 2 && + getContext().getGenDwarfSections().size() > 1) + Error(loc, "DWARF2 only supports one section per compilation unit"); + } + + if (!getContext().getGenDwarfSectionStartSym(ELFSection)) { + MCSymbol *SectionStartSymbol = getContext().CreateTempSymbol(); + getStreamer().EmitLabel(SectionStartSymbol); + getContext().setGenDwarfSectionStartSym(ELFSection, SectionStartSymbol); + } + } + return false; } Index: test/MC/ARM/dwarf-asm-multiple-sections.s =================================================================== --- /dev/null +++ test/MC/ARM/dwarf-asm-multiple-sections.s @@ -0,0 +1,74 @@ +// RUN: llvm-mc < %s -triple=armv7-linux-gnueabi -filetype=obj -o %t -g -fdebug-compilation-dir=/tmp +// RUN: llvm-dwarfdump %t | FileCheck -check-prefix DWARF %s +// RUN: llvm-objdump -r %t | FileCheck -check-prefix RELOC %s +// RUN: not llvm-mc < %s -triple=armv7-linux-gnueabi -filetype=obj -o %t -g -gdwarf-2 2>&1 | FileCheck -check-prefix VERSION %s + .section .text, "ax" +a: + mov r0, r0 + + .section foo, "ax" +b: + mov r1, r1 + +// DWARF: .debug_abbrev contents: +// DWARF: Abbrev table for offset: 0x00000000 +// DWARF: [1] DW_TAG_compile_unit DW_CHILDREN_yes +// DWARF: DW_AT_stmt_list DW_FORM_data4 +// DWARF: DW_AT_ranges DW_FORM_data4 +// DWARF: DW_AT_name DW_FORM_string +// DWARF: DW_AT_comp_dir DW_FORM_string +// DWARF: DW_AT_producer DW_FORM_string +// DWARF: DW_AT_language DW_FORM_data2 + +// DWARF: .debug_info contents: +// DWARF: 0x{{[0-9a-f]+}}: DW_TAG_compile_unit [1] +// CHECK-NOT-DWARF: DW_TAG_ +// DWARF: DW_AT_ranges [DW_FORM_data4] (0x00000000) + +// DWARF: 0x{{[0-9a-f]+}}: DW_TAG_label [2] * +// DWARF-NEXT: DW_AT_name [DW_FORM_string] ("a") + +// DWARF: 0x{{[0-9a-f]+}}: DW_TAG_label [2] * +// DWARF-NEXT: DW_AT_name [DW_FORM_string] ("b") + + +// DWARF: .debug_aranges contents: +// DWARF-NEXT: Address Range Header: length = 0x00000024, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x04, seg_size = 0x00 +// DWARF-NEXT: [0x00000000 - 0x00000004) +// DWARF-NEXT: [0x00000000 - 0x00000004) + + +// DWARF: .debug_line contents: +// DWARF: 0x0000000000000000 7 0 1 0 0 is_stmt +// DWARF-NEXT: 0x0000000000000004 7 0 1 0 0 is_stmt end_sequence +// DWARF-NEXT: 0x0000000000000000 11 0 1 0 0 is_stmt +// DWARF-NEXT: 0x0000000000000004 11 0 1 0 0 is_stmt end_sequence + + +// DWARF: .debug_ranges contents: +// DWARF: 00000000 ffffffff 00000000 +// DWARF: 00000000 00000000 00000004 +// DWARF: 00000000 ffffffff 00000000 +// DWARF: 00000000 00000000 00000004 +// DWARF: 00000000 + + + +// RELOC: RELOCATION RECORDS FOR [.rel.debug_info]: +// RELOC-NEXT: 6 R_ARM_ABS32 .debug_abbrev +// RELOC-NEXT: 12 R_ARM_ABS32 .debug_line +// RELOC-NEXT: 16 R_ARM_ABS32 .debug_ranges +// RELOC-NEXT: 79 R_ARM_ABS32 .text +// RELOC-NEXT: 97 R_ARM_ABS32 foo + +// RELOC: RELOCATION RECORDS FOR [.rel.debug_ranges]: +// RELOC-NEXT: 4 R_ARM_ABS32 .text +// RELOC-NEXT: 20 R_ARM_ABS32 foo + +// RELOC: RELOCATION RECORDS FOR [.rel.debug_aranges]: +// RELOC-NEXT: 6 R_ARM_ABS32 .debug_info +// RELOC-NEXT: 16 R_ARM_ABS32 .text +// RELOC-NEXT: 24 R_ARM_ABS32 foo + + +// VERSION: {{.*}} error: DWARF2 only supports one section per compilation unit Index: test/MC/ARM/dwarf-asm-nonstandard-section.s =================================================================== --- /dev/null +++ test/MC/ARM/dwarf-asm-nonstandard-section.s @@ -0,0 +1,57 @@ +// RUN: llvm-mc < %s -triple=armv7-linux-gnueabi -filetype=obj -o %t -g -fdebug-compilation-dir=/tmp +// RUN: llvm-dwarfdump %t | FileCheck -check-prefix DWARF %s +// RUN: llvm-objdump -r %t | FileCheck -check-prefix RELOC %s + + .section foo, "ax" +b: + mov r1, r1 + +// DWARF: .debug_abbrev contents: +// DWARF: Abbrev table for offset: 0x00000000 +// DWARF: [1] DW_TAG_compile_unit DW_CHILDREN_yes +// DWARF: DW_AT_stmt_list DW_FORM_data4 +// DWARF: DW_AT_low_pc DW_FORM_addr +// DWARF: DW_AT_high_pc DW_FORM_addr +// DWARF: DW_AT_name DW_FORM_string +// DWARF: DW_AT_comp_dir DW_FORM_string +// DWARF: DW_AT_producer DW_FORM_string +// DWARF: DW_AT_language DW_FORM_data2 + +// DWARF: .debug_info contents: +// DWARF: 0x{{[0-9a-f]+}}: DW_TAG_compile_unit [1] +// DWARF-NOT: DW_TAG_ +// DWARF: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +// DWARF: DW_AT_high_pc [DW_FORM_addr] (0x0000000000000004) + +// DWARF: 0x{{[0-9a-f]+}}: DW_TAG_label [2] * +// DWARF-NEXT: DW_AT_name [DW_FORM_string] ("b") + + +// DWARF: .debug_aranges contents: +// DWARF-NEXT: Address Range Header: length = 0x0000001c, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x04, seg_size = 0x00 +// DWARF-NEXT: [0x00000000 - 0x00000004) + + +// DWARF: .debug_line contents: +// DWARF: 0x0000000000000000 7 0 1 0 0 is_stmt +// DWARF-NEXT: 0x0000000000000004 7 0 1 0 0 is_stmt end_sequence + + +// DWARF: .debug_ranges contents: +// DWARF-NOT: {{0-9a-f}} +// DWARF: .debug_pubnames contents: + + + +// RELOC: RELOCATION RECORDS FOR [.rel.debug_info]: +// RELOC-NEXT: 6 R_ARM_ABS32 .debug_abbrev +// RELOC-NEXT: 12 R_ARM_ABS32 .debug_line +// RELOC-NEXT: 16 R_ARM_ABS32 foo +// RELOC-NEXT: 20 R_ARM_ABS32 foo +// RELOC-NEXT: 83 R_ARM_ABS32 foo + +// RELOC-NOT: RELOCATION RECORDS FOR [.rel.debug_ranges]: + +// RELOC: RELOCATION RECORDS FOR [.rel.debug_aranges]: +// RELOC-NEXT: 6 R_ARM_ABS32 .debug_info +// RELOC-NEXT: 16 R_ARM_ABS32 foo Index: test/MC/ARM/dwarf-asm-single-section.s =================================================================== --- /dev/null +++ test/MC/ARM/dwarf-asm-single-section.s @@ -0,0 +1,56 @@ +// RUN: llvm-mc < %s -triple=armv7-linux-gnueabi -filetype=obj -o %t -g -fdebug-compilation-dir=/tmp +// RUN: llvm-dwarfdump %t | FileCheck -check-prefix DWARF %s +// RUN: llvm-objdump -r %t | FileCheck -check-prefix RELOC %s + + .section .text, "ax" +a: + mov r0, r0 + + +// DWARF: .debug_abbrev contents: +// DWARF: Abbrev table for offset: 0x00000000 +// DWARF: [1] DW_TAG_compile_unit DW_CHILDREN_yes +// DWARF: DW_AT_stmt_list DW_FORM_data4 +// DWARF: DW_AT_low_pc DW_FORM_addr +// DWARF: DW_AT_high_pc DW_FORM_addr +// DWARF: DW_AT_name DW_FORM_string +// DWARF: DW_AT_comp_dir DW_FORM_string +// DWARF: DW_AT_producer DW_FORM_string +// DWARF: DW_AT_language DW_FORM_data2 + +// DWARF: .debug_info contents: +// DWARF: 0x{{[0-9a-f]+}}: DW_TAG_compile_unit [1] +// CHECK-NOT-DWARF: DW_TAG_ +// DWARF: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +// DWARF: DW_AT_high_pc [DW_FORM_addr] (0x0000000000000004) + +// DWARF: 0x{{[0-9a-f]+}}: DW_TAG_label [2] * +// DWARF-NEXT: DW_AT_name [DW_FORM_string] ("a") + + +// DWARF: .debug_aranges contents: +// DWARF-NEXT: Address Range Header: length = 0x0000001c, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x04, seg_size = 0x00 +// DWARF-NEXT: [0x00000000 - 0x00000004) + +// DWARF: .debug_line contents: +// DWARF: 0x0000000000000000 7 0 1 0 0 is_stmt +// DWARF-NEXT: 0x0000000000000004 7 0 1 0 0 is_stmt end_sequence + + +// DWARF: .debug_ranges contents: +// DWARF-NOT: {{0-9a-f}} +// DWARF: .debug_pubnames contents: + + +// RELOC: RELOCATION RECORDS FOR [.rel.debug_info]: +// RELOC-NEXT: 6 R_ARM_ABS32 .debug_abbrev +// RELOC-NEXT: 12 R_ARM_ABS32 .debug_line +// RELOC-NEXT: 16 R_ARM_ABS32 .text +// RELOC-NEXT: 20 R_ARM_ABS32 .text +// RELOC-NEXT: 83 R_ARM_ABS32 .text + +// RELOC-NOT: RELOCATION RECORDS FOR [.rel.debug_ranges]: + +// RELOC: RELOCATION RECORDS FOR [.rel.debug_aranges]: +// RELOC-NEXT: 6 R_ARM_ABS32 .debug_info +// RELOC-NEXT: 16 R_ARM_ABS32 .text Index: tools/llvm-mc/llvm-mc.cpp =================================================================== --- tools/llvm-mc/llvm-mc.cpp +++ tools/llvm-mc/llvm-mc.cpp @@ -152,6 +152,23 @@ GenDwarfForAssembly("g", cl::desc("Generate dwarf debugging info for assembly " "source files")); +enum DwarfVersionNumber { + DWARF2 = 2, + DWARF3 = 3, + DWARF4 = 4 +}; + +static cl::opt +DwarfVersion(cl::desc("Dwarf version"), + cl::init(DWARF3), + cl::values(clEnumValN(DWARF2, "gdwarf-2", + "Dwarf version 2"), + clEnumValN(DWARF3, "gdwarf-3", + "Dwarf version 3"), + clEnumValN(DWARF4, "gdwarf-4", + "Dwarf version 4"), + clEnumValEnd)); + static cl::opt DebugCompilationDir("fdebug-compilation-dir", cl::desc("Specifies the debug info's compilation dir")); @@ -394,6 +411,7 @@ Ctx.setAllowTemporaryLabels(false); Ctx.setGenDwarfForAssembly(GenDwarfForAssembly); + Ctx.setDwarfVersion(DwarfVersion); if (!DwarfDebugFlags.empty()) Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags)); if (!DwarfDebugProducer.empty())