diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -70,10 +70,14 @@ public: /// Parse a unit header from \p debug_info starting at \p offset_ptr. + /// Note that \p SectionKind is used as a hint to guess the unit type + /// for DWARF formats prior to DWARFv5. In DWARFv5 the unit type is + /// explicitly defined in the header and the hint is ignored. bool extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, - uint64_t *offset_ptr, DWARFSectionKind Kind = DW_SECT_INFO, - const DWARFUnitIndex *Index = nullptr, - const DWARFUnitIndex::Entry *Entry = nullptr); + uint64_t *offset_ptr, DWARFSectionKind SectionKind); + // For units in DWARF Package File, remember the index entry and update + // the abbreviation offset read by extract(). + bool applyIndexEntry(const DWARFUnitIndex::Entry *Entry); uint64_t getOffset() const { return Offset; } const dwarf::FormParams &getFormParams() const { return FormParams; } uint16_t getVersion() const { return FormParams.Version; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -73,12 +73,15 @@ DWARFDataExtractor Data(Obj, InfoSection, LE, 0); if (!Data.isValidOffset(Offset)) return nullptr; - const DWARFUnitIndex *Index = nullptr; - if (IsDWO) - Index = &getDWARFUnitIndex(Context, SectionKind); DWARFUnitHeader Header; - if (!Header.extract(Context, Data, &Offset, SectionKind, Index, - IndexEntry)) + if (!Header.extract(Context, Data, &Offset, SectionKind)) + return nullptr; + if (!IndexEntry && IsDWO) { + const DWARFUnitIndex &Index = getDWARFUnitIndex( + Context, Header.isTypeUnit() ? DW_SECT_EXT_TYPES : DW_SECT_INFO); + IndexEntry = Index.getFromOffset(Header.getOffset()); + } + if (IndexEntry && !Header.applyIndexEntry(IndexEntry)) return nullptr; std::unique_ptr U; if (Header.isTypeUnit()) @@ -251,14 +254,10 @@ bool DWARFUnitHeader::extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, uint64_t *offset_ptr, - DWARFSectionKind SectionKind, - const DWARFUnitIndex *Index, - const DWARFUnitIndex::Entry *Entry) { + DWARFSectionKind SectionKind) { Offset = *offset_ptr; Error Err = Error::success(); - IndexEntry = Entry; - if (!IndexEntry && Index) - IndexEntry = Index->getFromOffset(*offset_ptr); + IndexEntry = nullptr; std::tie(Length, FormParams.Format) = debug_info.getInitialLength(offset_ptr, &Err); FormParams.Version = debug_info.getU16(offset_ptr, &Err); @@ -288,19 +287,6 @@ if (errorToBool(std::move(Err))) return false; - if (IndexEntry) { - if (AbbrOffset) - return false; - auto *UnitContrib = IndexEntry->getContribution(); - if (!UnitContrib || - UnitContrib->Length != (Length + getUnitLengthFieldByteSize())) - return false; - auto *AbbrEntry = IndexEntry->getContribution(DW_SECT_ABBREV); - if (!AbbrEntry) - return false; - AbbrOffset = AbbrEntry->Offset; - } - // Header fields all parsed, capture the size of this unit header. assert(*offset_ptr - Offset <= 255 && "unexpected header size"); Size = uint8_t(*offset_ptr - Offset); @@ -324,6 +310,23 @@ return true; } +bool DWARFUnitHeader::applyIndexEntry(const DWARFUnitIndex::Entry *Entry) { + assert(Entry); + assert(!IndexEntry); + IndexEntry = Entry; + if (AbbrOffset) + return false; + auto *UnitContrib = IndexEntry->getContribution(); + if (!UnitContrib || + UnitContrib->Length != (getLength() + getUnitLengthFieldByteSize())) + return false; + auto *AbbrEntry = IndexEntry->getContribution(DW_SECT_ABBREV); + if (!AbbrEntry) + return false; + AbbrOffset = AbbrEntry->Offset; + return true; +} + // Parse the rangelist table header, including the optional array of offsets // following it (DWARF v5 and later). template diff --git a/llvm/test/DebugInfo/X86/dwp-v5-tu.s b/llvm/test/DebugInfo/X86/dwp-v5-tu.s new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/dwp-v5-tu.s @@ -0,0 +1,76 @@ +## The test checks that we can read DWARFv5 type units in DWP files. + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -debug-info - | \ +# RUN: FileCheck %s + +# CHECK: .debug_info.dwo contents: +# CHECK: Type Unit: +# CHECK: DW_TAG_type_unit +# CHECK-NEXT: DW_AT_visibility (DW_VIS_local) +# CHECK: DW_TAG_structure_type +# CHECK-NEXT: DW_AT_name ("foo") + + .section .debug_abbrev.dwo, "e", @progbits +## Reserve some space in the section so that the abbreviation table for the type +## unit does not start at the beginning of the section and thus the base offset +## from the index section should be added to find the correct offset. + .space 16 +.LAbbrevBegin: + .uleb128 1 # Abbrev code + .uleb128 0x41 # DW_TAG_type_unit + .byte 1 # DW_CHILDREN_yes + .uleb128 0x17 # DW_AT_visibility + .uleb128 0x0b # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .uleb128 2 # Abbrev code + .uleb128 0x13 # DW_TAG_structure_type + .byte 0 # DW_CHILDREN_no + .uleb128 0x03 # DW_AT_name + .uleb128 0x08 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) +.LAbbrevEnd: + + .section .debug_info.dwo, "e", @progbits +.LTUBegin: + .long .LTUEnd-.LTUVersion # Length of Unit +.LTUVersion: + .short 5 # DWARF version number + .byte 6 # DW_UT_split_type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad 0x1100001122222222 # Type Signature + .long .LTUType-.LTUBegin # Type offset + .uleb128 1 # Abbrev [1] DW_TAG_type_unit + .byte 1 # DW_AT_visibility +.LTUType: + .uleb128 2 # Abbrev [2] DW_TAG_structure_type + .asciz "foo" # DW_AT_name +.LTUEnd: + + .section .debug_tu_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 .LAbbrevBegin-.debug_abbrev.dwo # Offset in .debug_abbrev.dwo +## Table of Section Sizes: + .long .LTUEnd-.LTUBegin # Size in .debug_info.dwo + .long .LAbbrevEnd-.LAbbrevBegin # Size in .debug_abbrev.dwo diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -3166,7 +3166,7 @@ DWARFDataExtractor Data(Obj, Sec, /* IsLittleEndian = */ true, /* AddressSize = */ 4); uint64_t Offset = 0; - EXPECT_FALSE(Header.extract(*Context, Data, &Offset)); + EXPECT_FALSE(Header.extract(*Context, Data, &Offset, DW_SECT_INFO)); // Header.extract() returns false because there is not enough space // in the section for the declared length. Anyway, we can check that // the properties are read correctly.