diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -229,7 +229,8 @@ /// DWARF v5 Name Index header. struct Header { - uint32_t UnitLength; + uint64_t UnitLength; + dwarf::DwarfFormat Format; uint16_t Version; uint32_t CompUnitCount; uint32_t LocalTypeUnitCount; @@ -456,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; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -377,6 +377,19 @@ Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, uint64_t *Offset) { + uint64_t StartingOffset = *Offset; + // Check that we can read the unit length field. + if (!AS.isValidOffsetForDataOfSize(StartingOffset, 4)) + return createStringError(errc::illegal_byte_sequence, + "Section too small: cannot read header."); + UnitLength = AS.getU32(Offset); + if (UnitLength >= dwarf::DW_LENGTH_lo_reserved && + UnitLength != dwarf::DW_LENGTH_DWARF64) + return createStringError(errc::illegal_byte_sequence, + "Unsupported reserved unit length value"); + Format = (UnitLength == dwarf::DW_LENGTH_DWARF64) ? dwarf::DWARF64 + : dwarf::DWARF32; + // These fields are the same for 32-bit and 64-bit DWARF formats. constexpr unsigned CommonHeaderSize = 2 + // Version 2 + // Padding @@ -387,14 +400,14 @@ 4 + // Name count 4 + // Abbreviations table size 4; // Augmentation string size - static const unsigned DWARF32HeaderFixedPartSize = - dwarf::getUnitLengthFieldByteSize(dwarf::DWARF32) + CommonHeaderSize; // Check that we can read the fixed-size part. - if (!AS.isValidOffsetForDataOfSize(*Offset, DWARF32HeaderFixedPartSize)) + if (!AS.isValidOffsetForDataOfSize( + StartingOffset, + CommonHeaderSize + dwarf::getUnitLengthFieldByteSize(Format))) return createStringError(errc::illegal_byte_sequence, "Section too small: cannot read header."); - - UnitLength = AS.getU32(Offset); + if (Format == dwarf::DWARF64) + UnitLength = AS.getU64(Offset); Version = AS.getU16(Offset); // Skip padding *Offset += 2; @@ -498,9 +511,10 @@ 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; @@ -508,9 +522,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, @@ -591,20 +605,24 @@ 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); } @@ -625,7 +643,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, @@ -637,12 +655,16 @@ 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}; } diff --git a/llvm/test/DebugInfo/X86/dwarfdump-debug-names.s b/llvm/test/DebugInfo/X86/dwarfdump-debug-names.s --- a/llvm/test/DebugInfo/X86/dwarfdump-debug-names.s +++ b/llvm/test/DebugInfo/X86/dwarfdump-debug-names.s @@ -93,6 +93,46 @@ .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 { @@ -172,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: } diff --git a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt --- a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt +++ b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_unittest(DebugInfoDWARFTests DwarfGenerator.cpp DwarfUtils.cpp + DWARFAcceleratorTableTest.cpp DWARFDebugArangeSetTest.cpp DWARFDebugInfoTest.cpp DWARFDebugLineTest.cpp diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp new file mode 100644 --- /dev/null +++ b/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: cannot read header."); +} + +} // end anonymous namespace