Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -76,7 +76,7 @@ if (m_context.isDwo()) index = &llvm::getDWARFUnitIndex(m_context.GetAsLLVM(), section == DIERef::Section::DebugTypes - ? llvm::DW_SECT_TYPES + ? llvm::DW_SECT_EXT_TYPES : llvm::DW_SECT_INFO); lldb::offset_t offset = 0; while (data.ValidOffset(offset)) { Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -479,7 +479,8 @@ const DWARFDataExtractor &data = GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData(); if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) { - if (const auto *contribution = entry->getOffset(llvm::DW_SECT_LOC)) + if (const auto *contribution = entry->getOffset( + GetVersion() >= 5 ? llvm::DW_SECT_LOCLISTS : llvm::DW_SECT_EXT_LOC)) return DWARFDataExtractor(data, contribution->Offset, contribution->Length); return DWARFDataExtractor(); Index: llvm/include/llvm/BinaryFormat/Dwarf.def =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.def +++ llvm/include/llvm/BinaryFormat/Dwarf.def @@ -22,7 +22,7 @@ (defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \ defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \ defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX || \ - defined HANDLE_DW_END) + defined HANDLE_DW_END || defined HANDLE_DW_SECT) #error "Missing macro definition of HANDLE_DW*" #endif @@ -128,6 +128,10 @@ #define HANDLE_DW_END(ID, NAME) #endif +#ifndef HANDLE_DW_SECT +#define HANDLE_DW_SECT(ID, NAME) +#endif + HANDLE_DW_TAG(0x0000, null, 2, DWARF, DW_KIND_NONE) HANDLE_DW_TAG(0x0001, array_type, 2, DWARF, DW_KIND_TYPE) HANDLE_DW_TAG(0x0002, class_type, 2, DWARF, DW_KIND_TYPE) @@ -957,6 +961,15 @@ HANDLE_DW_IDX(0x04, parent) HANDLE_DW_IDX(0x05, type_hash) +// DWARF package file section identifiers. +// DWARFv5, section 7.3.5.3, table 7.1. +HANDLE_DW_SECT(1, INFO) +HANDLE_DW_SECT(3, ABBREV) +HANDLE_DW_SECT(4, LINE) +HANDLE_DW_SECT(5, LOCLISTS) +HANDLE_DW_SECT(6, STR_OFFSETS) +HANDLE_DW_SECT(7, MACRO) +HANDLE_DW_SECT(8, RNGLISTS) #undef HANDLE_DW_TAG #undef HANDLE_DW_AT @@ -981,3 +994,4 @@ #undef HANDLE_DWARF_SECTION #undef HANDLE_DW_IDX #undef HANDLE_DW_END +#undef HANDLE_DW_SECT Index: llvm/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h @@ -19,17 +19,62 @@ class raw_ostream; +/// The enum of section identifiers to be used in internal interfaces. +/// +/// Pre-standard implementation of package files defined a number of section +/// identifiers with values that clash definitions in the DWARFv5 standard. +/// See https://gcc.gnu.org/wiki/DebugFissionDWP and Section 7.3.5.3 in DWARFv5. +/// +/// The following identifiers are the same in the proposal and in DWARFv5: +/// - DW_SECT_INFO = 1 (.debug_info.dwo) +/// - DW_SECT_ABBREV = 3 (.debug_abbrev.dwo) +/// - DW_SECT_LINE = 4 (.debug_line.dwo) +/// - DW_SECT_STR_OFFSETS = 6 (.debug_str_offsets.dwo) +/// +/// The following identifiers are defined only in DWARFv5: +/// - DW_SECT_LOCLISTS = 5 (.debug_loclists.dwo) +/// - DW_SECT_RNGLISTS = 8 (.debug_rnglists.dwo) +/// +/// The following identifiers are defined only in the GNU proposal: +/// - DW_SECT_TYPES = 2 (.debug_types.dwo) +/// - DW_SECT_LOC = 5 (.debug_loc.dwo) +/// - DW_SECT_MACINFO = 7 (.debug_macinfo.dwo) +/// +/// DW_SECT_MACRO for the .debug_macro.dwo section is defined in both standards, +/// but with different values, 8 in GNU and 7 in DWARFv5. +/// +/// This enum defines constants to represent the identifiers of both sets. +/// For DWARFv5 ones, the values are the same as defined in the standard. +/// For pre-standard ones that correspond to sections being deprecated in +/// DWARFv5, the values are chosen more or less arbitrary and a tag "_EXT_" +/// is added to the names. +/// +/// The enum is intended to be used only in internal interfaces. +/// Special conversion functions should be used for the translation. enum DWARFSectionKind { - DW_SECT_INFO = 1, - DW_SECT_TYPES, - DW_SECT_ABBREV, - DW_SECT_LINE, - DW_SECT_LOC, - DW_SECT_STR_OFFSETS, - DW_SECT_MACINFO, - DW_SECT_MACRO, + /// Denotes a value read from an index section that does not correspond + /// to any of the supported standards. + DW_SECT_EXT_unknown = 0, +#define HANDLE_DW_SECT(ID, NAME) DW_SECT_##NAME = ID, +#include "llvm/BinaryFormat/Dwarf.def" + DW_SECT_EXT_TYPES = 2, + DW_SECT_EXT_LOC = 9, + DW_SECT_EXT_MACINFO = 10, }; +/// Convert the internal value for a section kind to an on-disk value. +/// +/// The conversion depends on the version of the index section. +/// IndexVersion is expected to be either 2 for pre-standard GNU proposal +/// or 5 for DWARFv5 package file. +uint32_t serializeSectionKind(DWARFSectionKind Kind, unsigned IndexVersion); + +/// Convert a value read from an index section to the internal representation. +/// +/// The conversion depends on the index section version, which is expected +/// to be either 2 for pre-standard GNU proposal or 5 for DWARFv5 package file. +DWARFSectionKind deserializeSectionKind(uint32_t Value, unsigned IndexVersion); + class DWARFUnitIndex { struct Header { uint32_t Version; @@ -72,6 +117,11 @@ DWARFSectionKind InfoColumnKind; int InfoColumn = -1; std::unique_ptr ColumnKinds; + // This is a parallel array of raw section IDs for columns of unknown kinds. + // This array is created only if there are DW_SECT_EXT_unknown items in + // ColumnKinds. The only initialized items in this array are ones with + // the same indexes as DW_SECT_EXT_unknown items in ColumnKinds. + std::unique_ptr UnknownColumnIds; std::unique_ptr Rows; mutable std::vector OffsetLookup; @@ -88,6 +138,8 @@ bool parse(DataExtractor IndexData); void dump(raw_ostream &OS) const; + uint32_t getVersion() const { return Header.Version; } + const Entry *getFromOffset(uint32_t Offset) const; const Entry *getFromHash(uint64_t Offset) const; Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -725,7 +725,7 @@ DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0); - TUIndex = std::make_unique(DW_SECT_TYPES); + TUIndex = std::make_unique(DW_SECT_EXT_TYPES); TUIndex->parse(TUIndexData); return *TUIndex; } @@ -924,7 +924,7 @@ }); NormalUnits.finishedInfoUnits(); DObj->forEachTypesSections([&](const DWARFSection &S) { - NormalUnits.addUnitsForSection(*this, S, DW_SECT_TYPES); + NormalUnits.addUnitsForSection(*this, S, DW_SECT_EXT_TYPES); }); } @@ -936,7 +936,7 @@ }); DWOUnits.finishedInfoUnits(); DObj->forEachTypesDWOSections([&](const DWARFSection &S) { - DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_TYPES, Lazy); + DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_EXT_TYPES, Lazy); }); } Index: llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -181,20 +181,17 @@ if (IsDWO) { // If we are reading a package file, we need to adjust the location list // data based on the index entries. - StringRef Data = LocSection->Data; + StringRef Data = Header.getVersion() >= 5 + ? Context.getDWARFObj().getLoclistsDWOSection().Data + : LocSection->Data; if (auto *IndexEntry = Header.getIndexEntry()) - if (const auto *C = IndexEntry->getOffset(DW_SECT_LOC)) + if (const auto *C = IndexEntry->getOffset( + Header.getVersion() >= 5 ? DW_SECT_LOCLISTS : DW_SECT_EXT_LOC)) Data = Data.substr(C->Offset, C->Length); - DWARFDataExtractor DWARFData = - Header.getVersion() >= 5 - ? DWARFDataExtractor(Context.getDWARFObj(), - Context.getDWARFObj().getLoclistsDWOSection(), - isLittleEndian, getAddressByteSize()) - : DWARFDataExtractor(Data, isLittleEndian, getAddressByteSize()); + DWARFDataExtractor DWARFData(Data, isLittleEndian, getAddressByteSize()); LocTable = std::make_unique(DWARFData, Header.getVersion()); - } else if (Header.getVersion() >= 5) { LocTable = std::make_unique( DWARFDataExtractor(Context.getDWARFObj(), @@ -276,7 +273,7 @@ FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); // Fake a unit type based on the section type. This isn't perfect, // but distinguishing compile and type units is generally enough. - if (SectionKind == DW_SECT_TYPES) + if (SectionKind == DW_SECT_EXT_TYPES) UnitType = DW_UT_type; else UnitType = DW_UT_compile; @@ -759,7 +756,7 @@ DWARFSectionKind Kind) { if (Kind == DW_SECT_INFO) return Context.getCUIndex(); - assert(Kind == DW_SECT_TYPES); + assert(Kind == DW_SECT_EXT_TYPES); return Context.getTUIndex(); } Index: llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp @@ -17,15 +17,94 @@ using namespace llvm; +namespace { + +enum class DWARFSectionKindV2 { + DW_SECT_INFO = 1, + DW_SECT_TYPES = 2, + DW_SECT_ABBREV = 3, + DW_SECT_LINE = 4, + DW_SECT_LOC = 5, + DW_SECT_STR_OFFSETS = 6, + DW_SECT_MACINFO = 7, + DW_SECT_MACRO = 8, +}; + +} // namespace + +uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind, + unsigned IndexVersion) { + if (IndexVersion == 5) { + assert(Kind >= DW_SECT_INFO && Kind <= DW_SECT_RNGLISTS && + Kind != DW_SECT_EXT_TYPES); + return static_cast(Kind); + } + assert(IndexVersion == 2); + switch (Kind) { +#define CASE(S,T) \ + case DW_SECT_##S: \ + return static_cast(DWARFSectionKindV2::DW_SECT_##T) + CASE(INFO, INFO); + CASE(EXT_TYPES, TYPES); + CASE(ABBREV, ABBREV); + CASE(LINE, LINE); + CASE(EXT_LOC, LOC); + CASE(STR_OFFSETS, STR_OFFSETS); + CASE(EXT_MACINFO, MACINFO); + CASE(MACRO, MACRO); +#undef CASE + default: + // All other section kinds have no corresponding values in v2 indexes. + llvm_unreachable("Invalid DWARFSectionKind"); + } +} + +DWARFSectionKind llvm::deserializeSectionKind(uint32_t Value, + unsigned IndexVersion) { + if (IndexVersion == 5) + return (Value >= DW_SECT_INFO && Value <= DW_SECT_RNGLISTS && + Value != DW_SECT_EXT_TYPES) + ? static_cast(Value) + : DW_SECT_EXT_unknown; + assert(IndexVersion == 2); + switch (static_cast(Value)) { +#define CASE(S,T) \ + case DWARFSectionKindV2::DW_SECT_##S: \ + return DW_SECT_##T + CASE(INFO, INFO); + CASE(TYPES, EXT_TYPES); + CASE(ABBREV, ABBREV); + CASE(LINE, LINE); + CASE(LOC, EXT_LOC); + CASE(STR_OFFSETS, STR_OFFSETS); + CASE(MACINFO, EXT_MACINFO); + CASE(MACRO, MACRO); +#undef CASE + } + return DW_SECT_EXT_unknown; +} + bool DWARFUnitIndex::Header::parse(DataExtractor IndexData, uint64_t *OffsetPtr) { + const uint64_t BeginOffset = *OffsetPtr; if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16)) return false; + // GCC Debug Fission defines the version as an unsigned 32-bit field + // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP. + // DWARFv5 defines the same space as an uhalf version field with value of 5 + // and a 2 bytes long padding, see Section 7.3.5.3. Version = IndexData.getU32(OffsetPtr); + if (Version != 2) { + *OffsetPtr = BeginOffset; + Version = IndexData.getU16(OffsetPtr); + if (Version != 5) + return false; + *OffsetPtr += 2; // Skip padding. + } NumColumns = IndexData.getU32(OffsetPtr); NumUnits = IndexData.getU32(OffsetPtr); NumBuckets = IndexData.getU32(OffsetPtr); - return Version <= 2; + return true; } void DWARFUnitIndex::Header::dump(raw_ostream &OS) const { @@ -49,6 +128,10 @@ if (!Header.parse(IndexData, &Offset)) return false; + // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo. + if (Header.Version == 5) + InfoColumnKind = DW_SECT_INFO; + if (!IndexData.isValidOffsetForDataOfSize( Offset, Header.NumBuckets * (8 + 4) + (2 * Header.NumUnits + 1) * 4 * Header.NumColumns)) @@ -76,8 +159,15 @@ // Read the Column Headers for (unsigned i = 0; i != Header.NumColumns; ++i) { - ColumnKinds[i] = static_cast(IndexData.getU32(&Offset)); - if (ColumnKinds[i] == InfoColumnKind) { + uint32_t RawSectID = IndexData.getU32(&Offset); + DWARFSectionKind Kind = deserializeSectionKind(RawSectID, Header.Version); + ColumnKinds[i] = Kind; + if (Kind == DW_SECT_EXT_unknown) { + if (!UnknownColumnIds) + UnknownColumnIds = std::make_unique(Header.NumColumns); + UnknownColumnIds[i] = RawSectID; + } + if (Kind == InfoColumnKind) { if (InfoColumn != -1) return false; InfoColumn = i; @@ -105,20 +195,21 @@ } StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) { -#define CASE(DS) \ - case DW_SECT_##DS: \ - return #DS; + switch (DS) { - CASE(INFO); - CASE(TYPES); - CASE(ABBREV); - CASE(LINE); - CASE(LOC); - CASE(STR_OFFSETS); - CASE(MACINFO); - CASE(MACRO); +#define HANDLE_DW_SECT(ID, NAME) \ + case DW_SECT_##NAME: \ + return #NAME; +#include "llvm/BinaryFormat/Dwarf.def" + case DW_SECT_EXT_TYPES: + return "TYPES"; + case DW_SECT_EXT_LOC: + return "LOC"; + case DW_SECT_EXT_MACINFO: + return "MACINFO"; + default: + llvm_unreachable("Unknown DWARFSectionKind"); } - return StringRef(); } void DWARFUnitIndex::dump(raw_ostream &OS) const { @@ -129,11 +220,12 @@ OS << "Index Signature "; for (unsigned i = 0; i != Header.NumColumns; ++i) { DWARFSectionKind Kind = ColumnKinds[i]; - StringRef Name = getColumnHeader(Kind); - if (!Name.empty()) - OS << ' ' << left_justify(Name, 24); - else - OS << format(" Unknown: %-15u", static_cast(Kind)); + if (Kind != DW_SECT_EXT_unknown) + OS << ' ' << left_justify(getColumnHeader(Kind), 24); + else { + assert(UnknownColumnIds); + OS << format(" Unknown: %-15" PRIu32, UnknownColumnIds[i]); + } } OS << "\n----- ------------------"; for (unsigned i = 0; i != Header.NumColumns; ++i) Index: llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -352,7 +352,7 @@ OS << "Verifying .debug_types Unit Header Chain...\n"; DObj.forEachTypesSections([&](const DWARFSection &S) { - NumErrors += verifyUnitSection(S, DW_SECT_TYPES); + NumErrors += verifyUnitSection(S, DW_SECT_EXT_TYPES); }); return NumErrors == 0; } Index: llvm/test/DebugInfo/X86/dwp-v2-cu-index.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwp-v2-cu-index.s @@ -0,0 +1,51 @@ +## The test checks that we can parse and dump a pre-standard CU index section. +## See https://gcc.gnu.org/wiki/DebugFissionDWP for the proposal. + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-cu-index - | \ +# RUN: FileCheck %s + +# CHECK: .debug_cu_index contents: +# CHECK-NEXT: version = 2 slots = 2 +# CHECK-EMPTY: +# CHECK-NEXT: Index Signature INFO ABBREV LINE LOC STR_OFFSETS MACINFO MACRO +# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ +# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040) [0x00005000, 0x00005050) [0x00006000, 0x00006060) [0x00007000, 0x00007070) + + .section .debug_cu_index, "", @progbits +## Header: + .long 2 # Version + .long 7 # Section count + .long 1 # Unit count + .long 2 # Slot count +## Hash Table of Signatures: + .quad 0x1100001122222222 + .quad 0 +## Parallel Table of Indexes: + .long 1 + .long 0 +## Table of Section Offsets: +## Row 0: + .long 1 # DW_SECT_INFO + .long 3 # DW_SECT_ABBREV + .long 4 # DW_SECT_LINE + .long 5 # DW_SECT_LOC + .long 6 # DW_SECT_STR_OFFSETS + .long 7 # DW_SECT_MACINFO + .long 8 # DW_SECT_MACRO +## Row 1: + .long 0x1000 # Offset in .debug_info.dwo + .long 0x2000 # Offset in .debug_abbrev.dwo + .long 0x3000 # Offset in .debug_line.dwo + .long 0x4000 # Offset in .debug_loc.dwo + .long 0x5000 # Offset in .debug_str_offsets.dwo + .long 0x6000 # Offset in .debug_macinfo.dwo + .long 0x7000 # Offset in .debug_macro.dwo +## Table of Section Sizes: + .long 0x10 # Size in .debug_info.dwo + .long 0x20 # Size in .debug_abbrev.dwo + .long 0x30 # Size in .debug_line.dwo + .long 0x40 # Size in .debug_loc.dwo + .long 0x50 # Size in .debug_str_offsets.dwo + .long 0x60 # Size in .debug_macinfo.dwo + .long 0x70 # Size in .debug_macro.dwo Index: llvm/test/DebugInfo/X86/dwp-v2-loc.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwp-v2-loc.s @@ -0,0 +1,91 @@ +## The test checks that pre-v5 compile units in package files read their +## location tables from .debug_loc.dwo sections. +## See dwp-v5-loclists.s for v5 units. + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-info -debug-loc - | \ +# RUN: FileCheck %s + +# CHECK: .debug_info.dwo contents: +# CHECK: DW_TAG_compile_unit +# CHECK-NEXT: DW_AT_GNU_dwo_id (0x1100001122222222) +# CHECK: DW_TAG_variable +# CHECK-NEXT: DW_AT_name ("a") +# CHECK-NEXT: DW_AT_location (0x00000000: +# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x0000000000000010): DW_OP_reg5 RDI) + +# CHECK: .debug_loc.dwo contents: +# CHECK-NEXT: 0x00000000: +# CHECK-NEXT: DW_LLE_startx_length (0x00000001, 0x00000010): DW_OP_reg5 RDI + +.section .debug_abbrev.dwo, "e", @progbits +.LAbbrevBegin: + .uleb128 1 # Abbreviation Code + .uleb128 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .uleb128 0x2131 # DW_AT_GNU_dwo_id + .uleb128 7 # DW_FORM_data8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .uleb128 2 # Abbreviation Code + .uleb128 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .uleb128 3 # DW_AT_name + .uleb128 8 # DW_FORM_string + .uleb128 2 # DW_AT_location + .uleb128 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) +.LAbbrevEnd: + + .section .debug_info.dwo, "e", @progbits +.LCUBegin: + .long .LCUEnd-.LCUVersion # Length of Unit +.LCUVersion: + .short 4 # Version + .long 0 # Abbrev offset + .byte 8 # Address size + .uleb128 1 # Abbrev [1] DW_TAG_compile_unit + .quad 0x1100001122222222 # DW_AT_GNU_dwo_id + .uleb128 2 # Abbrev [2] DW_TAG_variable + .asciz "a" # DW_AT_name + .long 0 # DW_AT_location + .byte 0 # End Of Children Mark +.LCUEnd: + +.section .debug_loc.dwo, "e", @progbits +.LLocBegin: + .byte 3 # DW_LLE_startx_length + .uleb128 1 # Index + .long 0x10 # Length + .short 1 # Loc expr size + .byte 85 # DW_OP_reg5 + .byte 0 # DW_LLE_end_of_list +.LLocEnd: + + .section .debug_cu_index, "", @progbits +## Header: + .long 2 # Version + .long 3 # Section count + .long 1 # Unit count + .long 2 # Slot count +## Hash Table of Signatures: + .quad 0x1100001122222222 + .quad 0 +## Parallel Table of Indexes: + .long 1 + .long 0 +## Table of Section Offsets: +## Row 0: + .long 1 # DW_SECT_INFO + .long 3 # DW_SECT_ABBREV + .long 5 # DW_SECT_LOC +## Row 1: + .long 0 # Offset in .debug_info.dwo + .long 0 # Offset in .debug_abbrev.dwo + .long 0 # Offset in .debug_loc.dwo +## Table of Section Sizes: + .long .LCUEnd-.LCUBegin # Size in .debug_info.dwo + .long .LAbbrevEnd-.LAbbrevBegin # Size in .debug_abbrev.dwo + .long .LLocEnd-.LLocBegin # Size in .debug_loc.dwo Index: llvm/test/DebugInfo/X86/dwp-v2-tu-index.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwp-v2-tu-index.s @@ -0,0 +1,42 @@ +## The test checks that we can parse and dump a pre-standard TU index section. +## See https://gcc.gnu.org/wiki/DebugFissionDWP for the proposal. + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-tu-index - | \ +# RUN: FileCheck %s + +# CHECK: .debug_tu_index contents: +# CHECK-NEXT: version = 2 slots = 2 +# CHECK-EMPTY: +# CHECK-NEXT: Index Signature TYPES ABBREV LINE STR_OFFSETS +# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------ +# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040) + + .section .debug_tu_index, "", @progbits +## Header: + .long 2 # Version + .long 4 # Section count + .long 1 # Unit count + .long 2 # Slot count +## Hash Table of Signatures: + .quad 0x1100001122222222 + .quad 0 +## Parallel Table of Indexes: + .long 1 + .long 0 +## Table of Section Offsets: +## Row 0: + .long 2 # DW_SECT_TYPES + .long 3 # DW_SECT_ABBREV + .long 4 # DW_SECT_LINE + .long 6 # DW_SECT_STR_OFFSETS +## Row 1: + .long 0x1000 # Offset in .debug_types.dwo + .long 0x2000 # Offset in .debug_abbrev.dwo + .long 0x3000 # Offset in .debug_line.dwo + .long 0x4000 # Offset in .debug_str_offsets.dwo +## Table of Section Sizes: + .long 0x10 # Size in .debug_types.dwo + .long 0x20 # Size in .debug_abbrev.dwo + .long 0x30 # Size in .debug_line.dwo + .long 0x40 # Size in .debug_str_offsets.dwo Index: llvm/test/DebugInfo/X86/dwp-v5-cu-index.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwp-v5-cu-index.s @@ -0,0 +1,52 @@ +## The test checks that we can parse and dump a CU index section that is +## compliant to the DWARFv5 standard. + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-cu-index - | \ +# RUN: FileCheck %s + +# CHECK: .debug_cu_index contents: +# CHECK-NEXT: version = 5 slots = 2 +# CHECK-EMPTY: +# CHECK-NEXT: Index Signature INFO ABBREV LINE LOCLISTS STR_OFFSETS MACRO RNGLISTS +# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ +# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040) [0x00005000, 0x00005050) [0x00006000, 0x00006060) [0x00007000, 0x00007070) + + .section .debug_cu_index, "", @progbits +## Header: + .short 5 # Version + .space 2 # Padding + .long 7 # Section count + .long 1 # Unit count + .long 2 # Slot count +## Hash Table of Signatures: + .quad 0x1100001122222222 + .quad 0 +## Parallel Table of Indexes: + .long 1 + .long 0 +## Table of Section Offsets: +## Row 0: + .long 1 # DW_SECT_INFO + .long 3 # DW_SECT_ABBREV + .long 4 # DW_SECT_LINE + .long 5 # DW_SECT_LOCLISTS + .long 6 # DW_SECT_STR_OFFSETS + .long 7 # DW_SECT_MACRO + .long 8 # DW_SECT_RNGLISTS +## Row 1: + .long 0x1000 # Offset in .debug_info.dwo + .long 0x2000 # Offset in .debug_abbrev.dwo + .long 0x3000 # Offset in .debug_line.dwo + .long 0x4000 # Offset in .debug_loclists.dwo + .long 0x5000 # Offset in .debug_str_offsets.dwo + .long 0x6000 # Offset in .debug_macro.dwo + .long 0x7000 # Offset in .debug_rnglists.dwo +## Table of Section Sizes: + .long 0x10 # Size in .debug_info.dwo + .long 0x20 # Size in .debug_abbrev.dwo + .long 0x30 # Size in .debug_line.dwo + .long 0x40 # Size in .debug_loclists.dwo + .long 0x50 # Size in .debug_str_offsets.dwo + .long 0x60 # Size in .debug_macro.dwo + .long 0x70 # Size in .debug_rnglists.dwo Index: llvm/test/DebugInfo/X86/dwp-v5-loclists.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwp-v5-loclists.s @@ -0,0 +1,103 @@ +## The test checks that v5 compile units in package files read their +## location tables from .debug_loclists.dwo sections. +## See dwp-v2-loc.s for pre-v5 units. + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-info -debug-loclists - | \ +# RUN: FileCheck %s + +# CHECK: .debug_info.dwo contents: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_TAG_variable +# CHECK-NEXT: DW_AT_name ("a") +# CHECK-NEXT: DW_AT_location (indexed (0x0) loclist = 0x00000010: +# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x0000000000000010): DW_OP_reg5 RDI) + +# CHECK: .debug_loclists.dwo contents: +# CHECK-NEXT: locations list header: +# CHECK-NEXT: offsets: [ +# CHECK-NEXT: 0x00000004 +# CHECK-NEXT: ] +# CHECK-NEXT: 0x00000010: +# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x0000000000000010): DW_OP_reg5 RDI + +.section .debug_abbrev.dwo, "e", @progbits +.LAbbrevBegin: + .uleb128 1 # Abbreviation Code + .uleb128 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .uleb128 2 # Abbreviation Code + .uleb128 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .uleb128 3 # DW_AT_name + .uleb128 8 # DW_FORM_string + .uleb128 2 # DW_AT_location + .uleb128 34 # DW_FORM_loclistx + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) +.LAbbrevEnd: + + .section .debug_info.dwo, "e", @progbits +.LCUBegin: + .long .LCUEnd-.LCUVersion # Length of Unit +.LCUVersion: + .short 5 # Version + .byte 5 # DW_UT_split_compile + .byte 8 # Address size + .long 0 # Abbrev offset + .quad 0x1100001122222222 # DWO id + .uleb128 1 # Abbrev [1] DW_TAG_compile_unit + .uleb128 2 # Abbrev [2] DW_TAG_variable + .asciz "a" # DW_AT_name + .uleb128 0 # DW_AT_location + .byte 0 # End Of Children Mark +.LCUEnd: + +.section .debug_loclists.dwo, "e", @progbits +.LLLBegin: + .long .LLLEnd-.LLLVersion # Length of Unit +.LLLVersion: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 1 # Offset entry count +.LLLBase: + .long .LLL0-.LLLBase +.LLL0: + .byte 3 # DW_LLE_startx_length + .uleb128 1 # Index + .uleb128 0x10 # Length + .uleb128 1 # Loc expr size + .byte 85 # DW_OP_reg5 + .byte 0 # DW_LLE_end_of_list +.LLLEnd: + + .section .debug_cu_index, "", @progbits +## Header: + .short 5 # Version + .space 2 # Padding + .long 3 # Section count + .long 1 # Unit count + .long 2 # Slot count +## Hash Table of Signatures: + .quad 0x1100001122222222 + .quad 0 +## Parallel Table of Indexes: + .long 1 + .long 0 +## Table of Section Offsets: +## Row 0: + .long 1 # DW_SECT_INFO + .long 3 # DW_SECT_ABBREV + .long 5 # DW_SECT_LOCLISTS +## Row 1: + .long 0 # Offset in .debug_info.dwo + .long 0 # Offset in .debug_abbrev.dwo + .long 0 # Offset in .debug_loclists.dwo +## Table of Section Sizes: + .long .LCUEnd-.LCUBegin # Size in .debug_info.dwo + .long .LAbbrevEnd-.LAbbrevBegin # Size in .debug_abbrev.dwo + .long .LLLEnd-.LLLBegin # Size in .debug_loclists.dwo Index: llvm/test/DebugInfo/X86/dwp-v5-tu-index.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwp-v5-tu-index.s @@ -0,0 +1,43 @@ +## The test checks that we can parse and dump a TU index section that is +## compliant to the DWARFv5 standard. + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-tu-index - | \ +# RUN: FileCheck %s + +# CHECK: .debug_tu_index contents: +# CHECK-NEXT: version = 5 slots = 2 +# CHECK-EMPTY: +# CHECK-NEXT: Index Signature INFO ABBREV LINE STR_OFFSETS +# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------ +# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040) + + .section .debug_tu_index, "", @progbits +## Header: + .short 5 # Version + .space 2 # Padding + .long 4 # Section count + .long 1 # Unit count + .long 2 # Slot count +## Hash Table of Signatures: + .quad 0x1100001122222222 + .quad 0 +## Parallel Table of Indexes: + .long 1 + .long 0 +## Table of Section Offsets: +## Row 0: + .long 1 # DW_SECT_INFO + .long 3 # DW_SECT_ABBREV + .long 4 # DW_SECT_LINE + .long 6 # DW_SECT_STR_OFFSETS +## Row 1: + .long 0x1000 # Offset in .debug_info.dwo + .long 0x2000 # Offset in .debug_abbrev.dwo + .long 0x3000 # Offset in .debug_line.dwo + .long 0x4000 # Offset in .debug_str_offsets.dwo +## Table of Section Sizes: + .long 0x10 # Size in .debug_info.dwo + .long 0x20 # Size in .debug_abbrev.dwo + .long 0x30 # Size in .debug_line.dwo + .long 0x40 # Size in .debug_str_offsets.dwo Index: llvm/test/tools/llvm-dwp/X86/unsupported_cu_index_version.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-dwp/X86/unsupported_cu_index_version.s @@ -0,0 +1,50 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.dwp +# RUN: not llvm-dwp %t.dwp -o %t 2>&1 | FileCheck %s + +# CHECK: error: unsupported cu_index version + +.section .debug_abbrev.dwo, "e", @progbits +.LAbbrevBegin: + .uleb128 1 # Abbreviation Code + .uleb128 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_no + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) +.LAbbrevEnd: + + .section .debug_info.dwo, "e", @progbits +.LCUBegin: + .long .LCUEnd-.LCUVersion # Length of Unit +.LCUVersion: + .short 5 # Version + .byte 5 # DW_UT_split_compile + .byte 8 # Address size + .long 0 # Abbrev offset + .quad 0x1100001122222222 # DWO id + .uleb128 1 # Abbrev [1] DW_TAG_compile_unit +.LCUEnd: + + .section .debug_cu_index, "", @progbits +## Header: + .short 5 # Version + .space 2 # Padding + .long 2 # Section count + .long 1 # Unit count + .long 2 # Slot count +## Hash Table of Signatures: + .quad 0x1100001122222222 + .quad 0 +## Parallel Table of Indexes: + .long 1 + .long 0 +## Table of Section Offsets: +## Row 0: + .long 1 # DW_SECT_INFO + .long 3 # DW_SECT_ABBREV +## Row 1: + .long 0 # Offset in .debug_info.dwo + .long 0 # Offset in .debug_abbrev.dwo +## Table of Section Sizes: + .long .LCUEnd-.LCUBegin # Size in .debug_info.dwo + .long .LAbbrevEnd-.LAbbrevBegin # Size in .debug_abbrev.dwo Index: llvm/tools/llvm-dwp/llvm-dwp.cpp =================================================================== --- llvm/tools/llvm-dwp/llvm-dwp.cpp +++ llvm/tools/llvm-dwp/llvm-dwp.cpp @@ -214,16 +214,19 @@ StringRef DWPName; }; -// Convert a section identifier into the index to use with +// Convert an internal section identifier into the index to use with // UnitIndexEntry::Contributions. -static unsigned SectionKindToIndex(DWARFSectionKind Kind) { - assert(static_cast(Kind) >= 1); - return static_cast(Kind) - 1; +static unsigned getContributionIndex(DWARFSectionKind Kind) { + // Assuming pre-standard DWP format. + assert(serializeSectionKind(Kind, 2) >= DW_SECT_INFO); + return serializeSectionKind(Kind, 2) - DW_SECT_INFO; } // Convert a UnitIndexEntry::Contributions index to the corresponding on-disk // value of the section identifier. -static unsigned IndexToOnDiskSectionId(unsigned Index) { return Index + 1; } +static unsigned getOnDiskSectionId(unsigned Index) { + return Index + DW_SECT_INFO; +} static StringRef getSubsection(StringRef Section, const DWARFUnitIndex::Entry &Entry, @@ -250,12 +253,14 @@ // Zero out the debug_info contribution Entry.Contributions[0] = {}; for (auto Kind : TUIndex.getColumnKinds()) { - auto &C = Entry.Contributions[SectionKindToIndex(Kind)]; + if (Kind == DW_SECT_EXT_unknown) + continue; + auto &C = Entry.Contributions[getContributionIndex(Kind)]; C.Offset += I->Offset; C.Length = I->Length; ++I; } - const unsigned TypesIndex = SectionKindToIndex(DW_SECT_TYPES); + const unsigned TypesIndex = getContributionIndex(DW_SECT_EXT_TYPES); auto &C = Entry.Contributions[TypesIndex]; Out.emitBytes(Types.substr( C.Offset - TUEntry.Contributions[TypesIndex].Offset, C.Length)); @@ -277,7 +282,7 @@ UnitIndexEntry Entry = CUEntry; // Zero out the debug_info contribution Entry.Contributions[0] = {}; - auto &C = Entry.Contributions[SectionKindToIndex(DW_SECT_TYPES)]; + auto &C = Entry.Contributions[getContributionIndex(DW_SECT_EXT_TYPES)]; C.Offset = TypesOffset; auto PrevOffset = Offset; // Length of the unit, including the 4 byte length field. @@ -354,7 +359,7 @@ // Write the column headers (which sections will appear in the table) for (size_t i = 0; i != ContributionOffsets.size(); ++i) if (ContributionOffsets[i]) - Out.emitIntValue(IndexToOnDiskSectionId(i), 4); + Out.emitIntValue(getOnDiskSectionId(i), 4); // Write the offsets. writeIndexTable(Out, ContributionOffsets, IndexEntries, @@ -447,8 +452,8 @@ return Error::success(); if (DWARFSectionKind Kind = SectionPair->second.second) { - auto Index = SectionKindToIndex(Kind); - if (Kind != DW_SECT_TYPES) { + auto Index = getContributionIndex(Kind); + if (Kind != DW_SECT_EXT_TYPES) { CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; ContributionOffsets[Index] += (CurEntry.Contributions[Index].Length = Contents.size()); @@ -532,10 +537,10 @@ MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection(); const StringMap> KnownSections = { {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, - {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}}, + {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}}, {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, {"debug_str.dwo", {StrSection, static_cast(0)}}, - {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}}, + {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}}, {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, {"debug_cu_index", {CUIndexSection, static_cast(0)}}, @@ -599,7 +604,7 @@ P.first->second.DWOName = ID.DWOName; addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry, - ContributionOffsets[SectionKindToIndex(DW_SECT_TYPES)]); + ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)]); continue; } @@ -607,6 +612,8 @@ DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0); if (!CUIndex.parse(CUIndexData)) return make_error("Failed to parse cu_index"); + if (CUIndex.getVersion() != 2) + return make_error("unsupported cu_index version"); for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { auto *I = E.getOffsets(); @@ -628,7 +635,9 @@ NewEntry.DWOName = ID.DWOName; NewEntry.DWPName = Input; for (auto Kind : CUIndex.getColumnKinds()) { - auto &C = NewEntry.Contributions[SectionKindToIndex(Kind)]; + if (Kind == DW_SECT_EXT_unknown) + continue; + auto &C = NewEntry.Contributions[getContributionIndex(Kind)]; C.Offset += I->Offset; C.Length = I->Length; ++I; @@ -638,13 +647,16 @@ if (!CurTypesSection.empty()) { if (CurTypesSection.size() != 1) return make_error("multiple type unit sections in .dwp file"); - DWARFUnitIndex TUIndex(DW_SECT_TYPES); + DWARFUnitIndex TUIndex(DW_SECT_EXT_TYPES); DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0); if (!TUIndex.parse(TUIndexData)) return make_error("Failed to parse tu_index"); + if (TUIndex.getVersion() != 2) + return make_error("unsupported tu_index version"); addAllTypesFromDWP( Out, TypeIndexEntries, TUIndex, TypesSection, CurTypesSection.front(), - CurEntry, ContributionOffsets[SectionKindToIndex(DW_SECT_TYPES)]); + CurEntry, + ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)]); } } @@ -655,7 +667,7 @@ TypeIndexEntries); // Lie about the type contribution - ContributionOffsets[SectionKindToIndex(DW_SECT_TYPES)] = 0; + ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)] = 0; // Unlie about the info contribution ContributionOffsets[0] = 1;