diff --git a/lld/ELF/DWARF.h b/lld/ELF/DWARF.h index f168ab3f786d..a2a206b15bfb 100644 --- a/lld/ELF/DWARF.h +++ b/lld/ELF/DWARF.h @@ -11,6 +11,7 @@ #define LLD_ELF_DWARF_H #include "InputFiles.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Object/ELF.h" @@ -27,8 +28,9 @@ template class LLDDwarfObj final : public llvm::DWARFObject { public: explicit LLDDwarfObj(ObjFile *Obj); - const llvm::DWARFSection &getInfoSection() const override { - return InfoSection; + void forEachInfoSections( + llvm::function_ref F) const override { + F(InfoSection); } const llvm::DWARFSection &getRangeSection() const override { diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h index 8e582da3172e..5a808b0ec6a9 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -33,7 +33,8 @@ public: virtual ArrayRef getSectionNames() const { return {}; } virtual bool isLittleEndian() const = 0; virtual uint8_t getAddressSize() const { llvm_unreachable("unimplemented"); } - virtual const DWARFSection &getInfoSection() const { return Dummy; } + virtual void + forEachInfoSections(function_ref F) const {} virtual void forEachTypesSections(function_ref F) const {} virtual StringRef getAbbrevSection() const { return ""; } @@ -53,7 +54,8 @@ public: virtual StringRef getGnuPubNamesSection() const { return ""; } virtual StringRef getGnuPubTypesSection() const { return ""; } virtual const DWARFSection &getStringOffsetSection() const { return Dummy; } - virtual const DWARFSection &getInfoDWOSection() const { return Dummy; } + virtual void + forEachInfoDWOSections(function_ref F) const {} virtual void forEachTypesDWOSections(function_ref F) const {} virtual StringRef getAbbrevDWOSection() const { return ""; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 00e37d7b7c5b..99cf9b985c00 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -351,20 +351,22 @@ void DWARFContext::dump( DObj->getAbbrevDWOSection())) getDebugAbbrevDWO()->dump(OS); - auto dumpDebugInfo = [&](unit_iterator_range Units) { - if (DumpOffset) - getDIEForOffset(DumpOffset.getValue()) - .dump(OS, 0, DumpOpts.noImplicitRecursion()); + auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) { + OS << '\n' << Name << " contents:\n"; + if (DumpOffset = DumpOffsets[DIDT_ID_DebugInfo]) + for (const auto &U : Units) + U->getDIEForOffset(DumpOffset.getValue()) + .dump(OS, 0, DumpOpts.noImplicitRecursion()); else for (const auto &U : Units) U->dump(OS, DumpOpts); }; - if (shouldDump(Explicit, ".debug_info", DIDT_ID_DebugInfo, - DObj->getInfoSection().Data)) - dumpDebugInfo(info_section_units()); - if (shouldDump(ExplicitDWO, ".debug_info.dwo", DIDT_ID_DebugInfo, - DObj->getInfoDWOSection().Data)) - dumpDebugInfo(dwo_info_section_units()); + if ((DumpType & DIDT_DebugInfo)) { + if (Explicit || getNumCompileUnits()) + dumpDebugInfo(".debug_info", info_section_units()); + if (ExplicitDWO || getNumDWOCompileUnits()) + dumpDebugInfo(".debug_info.dwo", dwo_info_section_units()); + } auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) { OS << '\n' << Name << " contents:\n"; @@ -872,7 +874,9 @@ Expected DWARFContext::getLineTableForUnit( void DWARFContext::parseNormalUnits() { if (!NormalUnits.empty()) return; - NormalUnits.addUnitsForSection(*this, DObj->getInfoSection(), DW_SECT_INFO); + DObj->forEachInfoSections([&](const DWARFSection &S) { + NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO); + }); NormalUnits.finishedInfoUnits(); DObj->forEachTypesSections([&](const DWARFSection &S) { NormalUnits.addUnitsForSection(*this, S, DW_SECT_TYPES); @@ -882,8 +886,9 @@ void DWARFContext::parseNormalUnits() { void DWARFContext::parseDWOUnits(bool Lazy) { if (!DWOUnits.empty()) return; - DWOUnits.addUnitsForDWOSection(*this, DObj->getInfoDWOSection(), DW_SECT_INFO, - Lazy); + DObj->forEachInfoDWOSections([&](const DWARFSection &S) { + DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy); + }); DWOUnits.finishedInfoUnits(); DObj->forEachTypesDWOSections([&](const DWARFSection &S) { DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_TYPES, Lazy); @@ -1235,20 +1240,20 @@ class DWARFObjInMemory final : public DWARFObject { const object::ObjectFile *Obj = nullptr; std::vector SectionNames; - using TypeSectionMap = MapVector>; - TypeSectionMap TypesSections; - TypeSectionMap TypesDWOSections; + InfoSectionMap InfoSections; + InfoSectionMap TypesSections; + InfoSectionMap InfoDWOSections; + InfoSectionMap TypesDWOSections; - DWARFSectionMap InfoSection; DWARFSectionMap LocSection; DWARFSectionMap LocListsSection; DWARFSectionMap LineSection; DWARFSectionMap RangeSection; DWARFSectionMap RnglistsSection; DWARFSectionMap StringOffsetSection; - DWARFSectionMap InfoDWOSection; DWARFSectionMap LineDWOSection; DWARFSectionMap LocDWOSection; DWARFSectionMap StringOffsetDWOSection; @@ -1263,14 +1268,12 @@ class DWARFObjInMemory final : public DWARFObject { DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { return StringSwitch(Name) - .Case("debug_info", &InfoSection) .Case("debug_loc", &LocSection) .Case("debug_loclists", &LocListsSection) .Case("debug_line", &LineSection) .Case("debug_str_offsets", &StringOffsetSection) .Case("debug_ranges", &RangeSection) .Case("debug_rnglists", &RnglistsSection) - .Case("debug_info.dwo", &InfoDWOSection) .Case("debug_loc.dwo", &LocDWOSection) .Case("debug_line.dwo", &LineDWOSection) .Case("debug_names", &DebugNamesSection) @@ -1359,6 +1362,16 @@ public: for (const auto &SecIt : Sections) { if (StringRef *SectionData = mapSectionToMember(SecIt.first())) *SectionData = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_info") + // Find debug_info and debug_types data by section rather than name as + // there are multiple, comdat grouped, of these sections. + InfoSections[SectionRef()].Data = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_info.dwo") + InfoDWOSections[SectionRef()].Data = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_types") + TypesSections[SectionRef()].Data = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_types.dwo") + TypesDWOSections[SectionRef()].Data = SecIt.second->getBuffer(); } } DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L, @@ -1413,9 +1426,13 @@ public: // FIXME: Use the other dwo range section when we emit it. RangeDWOSection.Data = Data; } + } else if (Name == "debug_info") { + // Find debug_info and debug_types data by section rather than name as + // there are multiple, comdat grouped, of these sections. + InfoSections[Section].Data = Data; + } else if (Name == "debug_info.dwo") { + InfoDWOSections[Section].Data = Data; } else if (Name == "debug_types") { - // Find debug_types data by section rather than name as there are - // multiple, comdat grouped, debug_types sections. TypesSections[Section].Data = Data; } else if (Name == "debug_types.dwo") { TypesDWOSections[Section].Data = Data; @@ -1450,9 +1467,16 @@ public: DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName); RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr; if (!Map) { - // Find debug_types relocs by section rather than name as there are - // multiple, comdat grouped, debug_types sections. - if (RelSecName == "debug_types") + // Find debug_info and debug_types relocs by section rather than name + // as there are multiple, comdat grouped, of these sections. + if (RelSecName == "debug_info") + Map = &static_cast(InfoSections[*RelocatedSection]) + .Relocs; + else if (RelSecName == "debug_info.dwo") + Map = &static_cast( + InfoDWOSections[*RelocatedSection]) + .Relocs; + else if (RelSecName == "debug_types") Map = &static_cast(TypesSections[*RelocatedSection]) .Relocs; @@ -1550,8 +1574,10 @@ public: StringRef getLineStringSection() const override { return LineStringSection; } // Sections for DWARF5 split dwarf proposal. - const DWARFSection &getInfoDWOSection() const override { - return InfoDWOSection; + void forEachInfoDWOSections( + function_ref F) const override { + for (auto &P : InfoDWOSections) + F(P.second); } void forEachTypesDWOSections( function_ref F) const override { @@ -1598,7 +1624,11 @@ public: StringRef getFileName() const override { return FileName; } uint8_t getAddressSize() const override { return AddressSize; } - const DWARFSection &getInfoSection() const override { return InfoSection; } + void forEachInfoSections( + function_ref F) const override { + for (auto &P : InfoSections) + F(P.second); + } void forEachTypesSections( function_ref F) const override { for (auto &P : TypesSections) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 128bd0651ba4..f8370178b627 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -364,15 +364,18 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, bool DWARFVerifier::handleDebugInfo() { const DWARFObject &DObj = DCtx.getDWARFObj(); + unsigned NumErrors = 0; OS << "Verifying .debug_info Unit Header Chain...\n"; - unsigned result = verifyUnitSection(DObj.getInfoSection(), DW_SECT_INFO); + DObj.forEachInfoSections([&](const DWARFSection &S) { + NumErrors += verifyUnitSection(S, DW_SECT_INFO); + }); OS << "Verifying .debug_types Unit Header Chain...\n"; DObj.forEachTypesSections([&](const DWARFSection &S) { - result += verifyUnitSection(S, DW_SECT_TYPES); + NumErrors += verifyUnitSection(S, DW_SECT_TYPES); }); - return result == 0; + return NumErrors == 0; } unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, @@ -551,6 +554,7 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue) { const DWARFObject &DObj = DCtx.getDWARFObj(); + auto DieCU = Die.getDwarfUnit(); unsigned NumErrors = 0; const auto Form = AttrValue.Value.getForm(); switch (Form) { @@ -563,7 +567,6 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, Optional RefVal = AttrValue.Value.getAsReference(); assert(RefVal); if (RefVal) { - auto DieCU = Die.getDwarfUnit(); auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); auto CUOffset = AttrValue.Value.getRawUValue(); if (CUOffset >= CUSize) { @@ -588,7 +591,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, Optional RefVal = AttrValue.Value.getAsReference(); assert(RefVal); if (RefVal) { - if (*RefVal >= DObj.getInfoSection().Data.size()) { + if (*RefVal >= DieCU->getInfoSection().Data.size()) { ++NumErrors; error() << "DW_FORM_ref_addr offset beyond .debug_info " "bounds:\n"; diff --git a/llvm/test/DebugInfo/X86/dwarfdump-header.s b/llvm/test/DebugInfo/X86/dwarfdump-header.s index 7daba5f69612..daf03614f9da 100644 --- a/llvm/test/DebugInfo/X86/dwarfdump-header.s +++ b/llvm/test/DebugInfo/X86/dwarfdump-header.s @@ -152,6 +152,38 @@ CU_split_5_end: # CHECK-NEXT: DW_AT_producer {{.*}} "Handmade DWO producer" # CHECK-NEXT: DW_AT_name {{.*}} "V5_dwo_compile_unit" +# Now a DWARF v5 type unit, which goes in a .debug_info.dwo comdat. +# Note there will not be another ".debug_info.dwo contents:" line, even though +# there is a separate ELF section header; it's dumped along with the previous +# unit as if they were in a single section. + + .section .debug_info.dwo,"G",@progbits,5555,comdat +# CHECK-NOT: .debug_info.dwo + +# DWARF v5 split type unit header. +TU_split_5_start: + .long TU_split_5_end-TU_split_5_version # Length of Unit +TU_split_5_version: + .short 5 # DWARF version number + .byte 6 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev.dwo # Offset Into Abbrev. Section + .quad 0x8899aabbccddeeff # Type Signature + .long TU_split_5_type-TU_split_5_start # Type offset +# The type-unit DIE, which has a name. + .byte 2 + .long dwo_TU_5 +# The type DIE, which has a name. +TU_split_5_type: + .byte 3 + .long dwo_TU_5 + .byte 0 # NULL + .byte 0 # NULL +TU_split_5_end: + +# CHECK: 0x00000000: Type Unit: length = 0x00000020 version = 0x0005 unit_type = DW_UT_split_type abbr_offset = 0x0000 addr_size = 0x08 name = 'V5_split_type_unit' type_signature = 0x8899aabbccddeeff type_offset = 0x001d (next unit at 0x00000024) +# CHECK: 0x00000018: DW_TAG_type_unit + .section .debug_types,"",@progbits # CHECK-LABEL: .debug_types contents: @@ -178,34 +210,6 @@ TU_4_end: # CHECK: 0x00000000: Type Unit: length = 0x0000001f version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 name = 'V4_type_unit' type_signature = 0x0011223344556677 type_offset = 0x001c (next unit at 0x00000023) # CHECK: 0x00000017: DW_TAG_type_unit - .section .debug_types.dwo,"",@progbits -# FIXME: DWARF v5 wants type units in .debug_info[.dwo] not .debug_types[.dwo]. -# CHECK: .debug_types.dwo contents: - -# DWARF v5 split type unit header. -TU_split_5_start: - .long TU_split_5_end-TU_split_5_version # Length of Unit -TU_split_5_version: - .short 5 # DWARF version number - .byte 6 # DWARF Unit Type - .byte 8 # Address Size (in bytes) - .long .debug_abbrev.dwo # Offset Into Abbrev. Section - .quad 0x8899aabbccddeeff # Type Signature - .long TU_split_5_type-TU_split_5_start # Type offset -# The type-unit DIE, which has a name. - .byte 2 - .long dwo_TU_5 -# The type DIE, which has a name. -TU_split_5_type: - .byte 3 - .long dwo_TU_5 - .byte 0 # NULL - .byte 0 # NULL -TU_split_5_end: - -# CHECK: 0x00000000: Type Unit: length = 0x00000020 version = 0x0005 unit_type = DW_UT_split_type abbr_offset = 0x0000 addr_size = 0x08 name = 'V5_split_type_unit' type_signature = 0x8899aabbccddeeff type_offset = 0x001d (next unit at 0x00000024) -# CHECK: 0x00000018: DW_TAG_type_unit - .section .debug_line,"",@progbits # CHECK-LABEL: .debug_line contents: