Index: llvm/include/llvm/BinaryFormat/Dwarf.h =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.h +++ llvm/include/llvm/BinaryFormat/Dwarf.h @@ -532,6 +532,17 @@ Optional LanguageLowerBound(SourceLanguage L); +/// The size of a reference determined by the DWARF 32/64-bit format. +inline uint8_t getDwarfOffsetByteSize(DwarfFormat Format) { + switch (Format) { + case DwarfFormat::DWARF32: + return 4; + case DwarfFormat::DWARF64: + return 8; + } + llvm_unreachable("Invalid Format value"); +} + /// A helper struct providing information about the byte size of DW_FORM /// values that vary in size depending on the DWARF version, address byte /// size, or DWARF32/DWARF64. @@ -551,13 +562,7 @@ /// The size of a reference is determined by the DWARF 32/64-bit format. uint8_t getDwarfOffsetByteSize() const { - switch (Format) { - case DwarfFormat::DWARF32: - return 4; - case DwarfFormat::DWARF64: - return 8; - } - llvm_unreachable("Invalid Format value"); + return dwarf::getDwarfOffsetByteSize(Format); } explicit operator bool() const { return Version && AddrSize; } Index: llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -222,11 +222,16 @@ /// referenced by the name table and interpreted with the help of the /// abbreviation table. class DWARFDebugNames : public DWARFAcceleratorTable { - /// The fixed-size part of a DWARF v5 Name Index header - struct HeaderPOD { - uint32_t UnitLength; +public: + class NameIndex; + class NameIterator; + class ValueIterator; + + /// DWARF v5 Name Index header. + struct Header { + uint64_t UnitLength; + dwarf::DwarfFormat Format; uint16_t Version; - uint16_t Padding; uint32_t CompUnitCount; uint32_t LocalTypeUnitCount; uint32_t ForeignTypeUnitCount; @@ -234,15 +239,6 @@ uint32_t NameCount; uint32_t AbbrevTableSize; uint32_t AugmentationStringSize; - }; - -public: - class NameIndex; - class NameIterator; - class ValueIterator; - - /// DWARF v5 Name Index header. - struct Header : public HeaderPOD { SmallString<8> AugmentationString; Error extract(const DWARFDataExtractor &AS, uint64_t *Offset); @@ -461,7 +457,10 @@ Error extract(); uint64_t getUnitOffset() const { return Base; } - uint64_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; } + uint64_t getNextUnitOffset() const { + return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) + + Hdr.UnitLength; + } void dump(ScopedPrinter &W) const; friend class DWARFDebugNames; Index: llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -366,7 +366,6 @@ DictScope HeaderScope(W, "Header"); W.printHex("Length", UnitLength); W.printNumber("Version", Version); - W.printHex("Padding", Padding); W.printNumber("CU count", CompUnitCount); W.printNumber("Local TU count", LocalTypeUnitCount); W.printNumber("Foreign TU count", ForeignTypeUnitCount); @@ -377,15 +376,43 @@ } Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, - uint64_t *Offset) { + uint64_t *Offset) { + static const unsigned CommonHeaderSize = 2 + // Version + 2 + // Padding + 4 + // CU count + 4 + // Local TU count + 4 + // Foreign TU count + 4 + // Bucket count + 4 + // Name count + 4 + // Abbreviations table size + 4; // Augmentation string size + static const unsigned DWARF32HeaderSize = + dwarf::getUnitLengthFieldByteSize(dwarf::DWARF32) + CommonHeaderSize; // Check that we can read the fixed-size part. - if (!AS.isValidOffset(*Offset + sizeof(HeaderPOD) - 1)) + if (!AS.isValidOffsetForDataOfSize(*Offset, DWARF32HeaderSize)) return createStringError(errc::illegal_byte_sequence, "Section too small: cannot read header."); + Format = dwarf::DWARF32; UnitLength = AS.getU32(Offset); + if (UnitLength == dwarf::DW_LENGTH_DWARF64) { + // Check again as the header is larger for DWARF64. + static const unsigned DWARF64HeaderSize = + dwarf::getUnitLengthFieldByteSize(dwarf::DWARF64) + CommonHeaderSize; + // Subtract 4 as we've already read one uword. + if (!AS.isValidOffsetForDataOfSize(*Offset, DWARF64HeaderSize - 4)) + return createStringError( + errc::illegal_byte_sequence, + "Section too small for DWARF64: cannot read header."); + Format = dwarf::DWARF64; + UnitLength = AS.getU64(Offset); + } else if (UnitLength >= dwarf::DW_LENGTH_lo_reserved) { + return createStringError(errc::illegal_byte_sequence, + "Unsupported reserved unit length value"); + } Version = AS.getU16(Offset); - Padding = AS.getU16(Offset); + // Skip padding + *Offset += 2; CompUnitCount = AS.getU32(Offset); LocalTypeUnitCount = AS.getU32(Offset); ForeignTypeUnitCount = AS.getU32(Offset); @@ -486,9 +513,11 @@ if (Error E = Hdr.extract(AS, &Offset)) return E; + const unsigned SectionOffsetSize = + dwarf::getDwarfOffsetByteSize(Hdr.Format); CUsBase = Offset; - Offset += Hdr.CompUnitCount * 4; - Offset += Hdr.LocalTypeUnitCount * 4; + Offset += Hdr.CompUnitCount * SectionOffsetSize; + Offset += Hdr.LocalTypeUnitCount * SectionOffsetSize; Offset += Hdr.ForeignTypeUnitCount * 8; BucketsBase = Offset; Offset += Hdr.BucketCount * 4; @@ -496,9 +525,9 @@ if (Hdr.BucketCount > 0) Offset += Hdr.NameCount * 4; StringOffsetsBase = Offset; - Offset += Hdr.NameCount * 4; + Offset += Hdr.NameCount * SectionOffsetSize; EntryOffsetsBase = Offset; - Offset += Hdr.NameCount * 4; + Offset += Hdr.NameCount * SectionOffsetSize; if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize)) return createStringError(errc::illegal_byte_sequence, @@ -579,20 +608,27 @@ uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const { assert(CU < Hdr.CompUnitCount); - uint64_t Offset = CUsBase + 4 * CU; - return Section.AccelSection.getRelocatedValue(4, &Offset); + const unsigned SectionOffsetSize = + dwarf::getDwarfOffsetByteSize(Hdr.Format); + uint64_t Offset = CUsBase + SectionOffsetSize * CU; + return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); } uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const { assert(TU < Hdr.LocalTypeUnitCount); - uint64_t Offset = CUsBase + 4 * (Hdr.CompUnitCount + TU); - return Section.AccelSection.getRelocatedValue(4, &Offset); + const unsigned SectionOffsetSize = + dwarf::getDwarfOffsetByteSize(Hdr.Format); + uint64_t Offset = CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU); + return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); } uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const { assert(TU < Hdr.ForeignTypeUnitCount); + const unsigned SectionOffsetSize = + dwarf::getDwarfOffsetByteSize(Hdr.Format); uint64_t Offset = - CUsBase + 4 * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU; + CUsBase + + SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU; return Section.AccelSection.getU64(&Offset); } @@ -613,7 +649,7 @@ Entry E(*this, *AbbrevIt); - dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; + dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format}; for (auto &Value : E.Values) { if (!Value.extractValue(AS, Offset, FormParams)) return createStringError(errc::io_error, @@ -625,12 +661,17 @@ DWARFDebugNames::NameTableEntry DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const { assert(0 < Index && Index <= Hdr.NameCount); - uint64_t StringOffsetOffset = StringOffsetsBase + 4 * (Index - 1); - uint64_t EntryOffsetOffset = EntryOffsetsBase + 4 * (Index - 1); + const unsigned SectionOffsetSize = + dwarf::getDwarfOffsetByteSize(Hdr.Format); + uint64_t StringOffsetOffset = + StringOffsetsBase + SectionOffsetSize * (Index - 1); + uint64_t EntryOffsetOffset = + EntryOffsetsBase + SectionOffsetSize * (Index - 1); const DWARFDataExtractor &AS = Section.AccelSection; - uint64_t StringOffset = AS.getRelocatedValue(4, &StringOffsetOffset); - uint64_t EntryOffset = AS.getU32(&EntryOffsetOffset); + uint64_t StringOffset = + AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset); + uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize); EntryOffset += EntriesBase; return {Section.StringSection, Index, StringOffset, EntryOffset}; } Index: llvm/test/DebugInfo/X86/dwarfdump-debug-names.s =================================================================== --- llvm/test/DebugInfo/X86/dwarfdump-debug-names.s +++ llvm/test/DebugInfo/X86/dwarfdump-debug-names.s @@ -93,12 +93,51 @@ .long 0 # End of list: bar .p2align 2 .Lnames_end1: + + .long 0xffffffff # DWARF64 mark + .quad .Lnames_end2-.Lnames_start2 # Length +.Lnames_start2: + .short 5 # Version + .space 2 # Padding + .long 1 # CU count + .long 1 # Local TU count + .long 1 # Foreign TU count + .long 1 # Bucket count + .long 1 # Name count + .long .Lnames_abbrev_end2-.Lnames_abbrev_start2 # Abbreviations table size + .long 0 # Augmentation string size + .quad 0xcc00cccccccc # CU0 offset + .quad 0xaa00aaaaaaaa # Local TU0 offset + .quad 0xffffff00ffffffff # Foreign TU2 signature + .long 1 # Bucket 0 + .long 0xb887389 # Hash in Bucket 0 + .quad .Linfo_string0 # String in Bucket 0: foo + .quad .Lnames3-.Lnames_entries2 # Offset in Bucket 0 +.Lnames_abbrev_start2: + .byte 0x01 # Abbrev code + .byte 0x24 # DW_TAG_base_type + .byte 0x02 # DW_IDX_type_unit + .byte 0x06 # DW_FORM_data4 + .byte 0x05 # DW_IDX_type_hash + .byte 0x07 # DW_FORM_data8 + .byte 0x00 # End of abbrev + .byte 0x00 # End of abbrev + .byte 0x00 # End of abbrev list +.Lnames_abbrev_end2: +.Lnames_entries2: +.Lnames3: + .byte 0x01 # Abbrev code + .long 1 # DW_IDX_type_unit + .quad 0xff03ffffffff # DW_IDX_type_hash + .byte 0x00 # End of list: foo + .p2align 2 +.Lnames_end2: + # CHECK: .debug_names contents: # CHECK-NEXT: Name Index @ 0x0 { # CHECK-NEXT: Header { # CHECK-NEXT: Length: 0x60 # CHECK-NEXT: Version: 5 -# CHECK-NEXT: Padding: 0x0 # CHECK-NEXT: CU count: 1 # CHECK-NEXT: Local TU count: 0 # CHECK-NEXT: Foreign TU count: 0 @@ -144,7 +183,6 @@ # CHECK-NEXT: Header { # CHECK-NEXT: Length: 0x44 # CHECK-NEXT: Version: 5 -# CHECK-NEXT: Padding: 0x0 # CHECK-NEXT: CU count: 1 # CHECK-NEXT: Local TU count: 0 # CHECK-NEXT: Foreign TU count: 0 @@ -174,3 +212,44 @@ # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } +# CHECK-NEXT: Name Index @ 0xac { +# CHECK-NEXT: Header { +# CHECK-NEXT: Length: 0x68 +# CHECK-NEXT: Version: 5 +# CHECK-NEXT: CU count: 1 +# CHECK-NEXT: Local TU count: 1 +# CHECK-NEXT: Foreign TU count: 1 +# CHECK-NEXT: Bucket count: 1 +# CHECK-NEXT: Name count: 1 +# CHECK-NEXT: Abbreviations table size: 0x9 +# CHECK-NEXT: Augmentation: '' +# CHECK-NEXT: } +# CHECK-NEXT: Compilation Unit offsets [ +# CHECK-NEXT: CU[0]: 0xcc00cccccccc +# CHECK-NEXT: ] +# CHECK-NEXT: Local Type Unit offsets [ +# CHECK-NEXT: LocalTU[0]: 0xaa00aaaaaaaa +# CHECK-NEXT: ] +# CHECK-NEXT: Foreign Type Unit signatures [ +# CHECK-NEXT: ForeignTU[0]: 0xffffff00ffffffff +# CHECK-NEXT: ] +# CHECK-NEXT: Abbreviations [ +# CHECK-NEXT: Abbreviation 0x1 { +# CHECK-NEXT: Tag: DW_TAG_base_type +# CHECK-NEXT: DW_IDX_type_unit: DW_FORM_data4 +# CHECK-NEXT: DW_IDX_type_hash: DW_FORM_data8 +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: Bucket 0 [ +# CHECK-NEXT: Name 1 { +# CHECK-NEXT: Hash: 0xB887389 +# CHECK-NEXT: String: 0x00000000 "foo" +# CHECK-NEXT: Entry @ 0x111 { +# CHECK-NEXT: Abbrev: 0x1 +# CHECK-NEXT: Tag: DW_TAG_base_type +# CHECK-NEXT: DW_IDX_type_unit: 0x00000001 +# CHECK-NEXT: DW_IDX_type_hash: 0x0000ff03ffffffff +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } Index: llvm/unittests/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- llvm/unittests/DebugInfo/DWARF/CMakeLists.txt +++ llvm/unittests/DebugInfo/DWARF/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_unittest(DebugInfoDWARFTests DwarfGenerator.cpp DwarfUtils.cpp + DWARFAcceleratorTableTest.cpp DWARFDebugInfoTest.cpp DWARFDebugLineTest.cpp DWARFDieTest.cpp Index: llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp @@ -0,0 +1,52 @@ +//===- DWARFAcceleratorTableTest.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +void ExpectDebugNamesExtractError(StringRef NamesSecData, StringRef StrSecData, + const char *ErrorMessage) { + DWARFSection NamesDWARFSection; + NamesDWARFSection.Data = NamesSecData; + StringMap> Sections; + auto Context = DWARFContext::create(Sections, /* AddrSize = */ 4, + /* isLittleEndian = */ true); + DWARFDataExtractor NamesExtractor(Context->getDWARFObj(), NamesDWARFSection, + /* isLittleEndian = */ true, + /* AddrSize = */ 4); + DataExtractor StrExtractor(StrSecData, + /* isLittleEndian = */ true, + /* AddrSize = */ 4); + DWARFDebugNames Table(NamesExtractor, StrExtractor); + Error E = Table.extract(); + ASSERT_TRUE(E.operator bool()); + EXPECT_STREQ(ErrorMessage, toString(std::move(E)).c_str()); +} + +TEST(DWARFDebugNames, ReservedUnitLength) { + static const char NamesSecData[64] = + "\xf0\xff\xff\xff"; // Reserved unit length value + ExpectDebugNamesExtractError(StringRef(NamesSecData, sizeof(NamesSecData)), + StringRef(), + "Unsupported reserved unit length value"); +} + +TEST(DWARFDebugNames, TooSmallForDWARF64) { + // DWARF64 header takes at least 44 bytes. + static const char NamesSecData[43] = "\xff\xff\xff\xff"; // DWARF64 mark + ExpectDebugNamesExtractError( + StringRef(NamesSecData, sizeof(NamesSecData)), StringRef(), + "Section too small for DWARF64: cannot read header."); +} + +} // end anonymous namespace