From af11c556dbcee06b4511a6c5761f4cbd543d0047 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Mon, 6 Apr 2020 21:29:22 +0700 Subject: [PATCH] [DebugInfo] Fix reading DWARFv5 type units in DWP. In DWARFv5, type units are stored in .debug_info sections, along with compilation units, and they are distinguished by the unit_type field in the header, not by the name of the section. It is impossible to associate the correct index section of a DWP file with the unit before the unit's header is read. This patch fixes reading DWARFv5 type units by parsing the header first and then applying the index entry according to the actual unit type. Differential Revision: https://reviews.llvm.org/D77552 --- llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 10 ++- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 51 ++++++++------- llvm/test/DebugInfo/X86/dwp-v5-tu.s | 76 ++++++++++++++++++++++ .../DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 2 +- 4 files changed, 111 insertions(+), 28 deletions(-) create mode 100644 llvm/test/DebugInfo/X86/dwp-v5-tu.s diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 635c437..cb9e2c3 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -70,10 +70,14 @@ class DWARFUnitHeader { 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 index 5fb3b76..31c5cc8 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -73,12 +73,15 @@ void DWARFUnitVector::addUnitsImpl( 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 @@ Optional DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { 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 @@ bool DWARFUnitHeader::extract(DWARFContext &Context, 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 @@ bool DWARFUnitHeader::extract(DWARFContext &Context, 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 index 0000000..91acb1d --- /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 index 1e7149e..c982320 100644 --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -3166,7 +3166,7 @@ TEST(DWARFDebugInfo, TestDWARF64UnitLength) { 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. -- 2.7.4