diff --git a/lld/ELF/DWARF.h b/lld/ELF/DWARF.h --- a/lld/ELF/DWARF.h +++ b/lld/ELF/DWARF.h @@ -56,11 +56,11 @@ return addrSection; } - const llvm::DWARFSection &getGnuPubnamesSection() const override { + const LLDDWARFSection &getGnuPubnamesSection() const override { return gnuPubnamesSection; } - const llvm::DWARFSection &getGnuPubtypesSection() const override { + const LLDDWARFSection &getGnuPubtypesSection() const override { return gnuPubtypesSection; } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -2705,12 +2705,15 @@ static std::vector readPubNamesAndTypes(const LLDDwarfObj &obj, const std::vector &cus) { - const DWARFSection &pubNames = obj.getGnuPubnamesSection(); - const DWARFSection &pubTypes = obj.getGnuPubtypesSection(); + const LLDDWARFSection &pubNames = obj.getGnuPubnamesSection(); + const LLDDWARFSection &pubTypes = obj.getGnuPubtypesSection(); std::vector ret; - for (const DWARFSection *pub : {&pubNames, &pubTypes}) { - DWARFDebugPubTable table(obj, *pub, config->isLE, true); + for (const LLDDWARFSection *pub : {&pubNames, &pubTypes}) { + DWARFDataExtractor data(obj, *pub, config->isLE, config->wordsize); + DWARFDebugPubTable table; + if (Error e = table.extract(data, /*GnuStyle=*/true)) + warn(toString(pub->sec) + ": " + toString(std::move(e))); for (const DWARFDebugPubTable::Set &set : table.getData()) { // The value written into the constant pool is kind << 24 | cuIndex. As we // don't know how many compilation units precede this object to compute diff --git a/lld/test/ELF/gdb-index-invalid-pubnames.s b/lld/test/ELF/gdb-index-invalid-pubnames.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/gdb-index-invalid-pubnames.s @@ -0,0 +1,26 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t +# RUN: ld.lld --gdb-index %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: warning: {{.*}}(.debug_gnu_pubnames): unexpected end of data at offset 0x1 while reading [0x0, 0x4) + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.LCUBegin: + .long .LUnitEnd-.LUnitBegin # Length of Unit +.LUnitBegin: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit +.LUnitEnd: + + .section .debug_gnu_pubnames,"",@progbits + .byte 0 diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h @@ -12,6 +12,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFObject.h" #include #include @@ -67,11 +68,12 @@ /// gnu styled tables contains additional information. /// This flag determines whether or not section we parse is debug_gnu* table. - bool GnuStyle; + bool GnuStyle = false; public: - DWARFDebugPubTable(const DWARFObject &Obj, const DWARFSection &Sec, - bool LittleEndian, bool GnuStyle); + DWARFDebugPubTable() = default; + + Error extract(DWARFDataExtractor Data, bool GnuStyle); void dump(raw_ostream &OS) const; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -336,6 +336,14 @@ } } +static void dumpPubTableSection(raw_ostream &OS, DIDumpOptions DumpOpts, + DWARFDataExtractor Data, bool GnuStyle) { + DWARFDebugPubTable Table; + if (Error E = Table.extract(Data, GnuStyle)) + DumpOpts.RecoverableErrorHandler(std::move(E)); + Table.dump(OS); +} + void DWARFContext::dump( raw_ostream &OS, DIDumpOptions DumpOpts, std::array, DIDT_ID_Count> DumpOffsets) { @@ -626,26 +634,32 @@ } if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames, - DObj->getPubnamesSection().Data)) - DWARFDebugPubTable(*DObj, DObj->getPubnamesSection(), isLittleEndian(), false) - .dump(OS); + DObj->getPubnamesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getPubnamesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false); + } if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes, - DObj->getPubtypesSection().Data)) - DWARFDebugPubTable(*DObj, DObj->getPubtypesSection(), isLittleEndian(), false) - .dump(OS); + DObj->getPubtypesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getPubtypesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false); + } if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames, - DObj->getGnuPubnamesSection().Data)) - DWARFDebugPubTable(*DObj, DObj->getGnuPubnamesSection(), isLittleEndian(), - true /* GnuStyle */) - .dump(OS); + DObj->getGnuPubnamesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubnamesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true); + } if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes, - DObj->getGnuPubtypesSection().Data)) - DWARFDebugPubTable(*DObj, DObj->getGnuPubtypesSection(), isLittleEndian(), - true /* GnuStyle */) - .dump(OS); + DObj->getGnuPubtypesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubtypesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true); + } if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets, DObj->getStrOffsetsSection().Data)) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp @@ -18,34 +18,32 @@ using namespace llvm; using namespace dwarf; -DWARFDebugPubTable::DWARFDebugPubTable(const DWARFObject &Obj, - const DWARFSection &Sec, - bool LittleEndian, bool GnuStyle) - : GnuStyle(GnuStyle) { - DWARFDataExtractor PubNames(Obj, Sec, LittleEndian, 0); - uint64_t Offset = 0; - while (PubNames.isValidOffset(Offset)) { +Error DWARFDebugPubTable::extract(DWARFDataExtractor Data, bool GnuStyle) { + this->GnuStyle = GnuStyle; + Sets.clear(); + DataExtractor::Cursor C(0); + while (C && Data.isValidOffset(C.tell())) { Sets.push_back({}); Set &SetData = Sets.back(); - std::tie(SetData.Length, SetData.Format) = - PubNames.getInitialLength(&Offset); + std::tie(SetData.Length, SetData.Format) = Data.getInitialLength(C); const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(SetData.Format); - SetData.Version = PubNames.getU16(&Offset); - SetData.Offset = PubNames.getRelocatedValue(OffsetSize, &Offset); - SetData.Size = PubNames.getUnsigned(&Offset, OffsetSize); + SetData.Version = Data.getU16(C); + SetData.Offset = Data.getRelocatedValue(C, OffsetSize); + SetData.Size = Data.getUnsigned(C, OffsetSize); - while (Offset < Sec.Data.size()) { - uint64_t DieRef = PubNames.getUnsigned(&Offset, OffsetSize); + while (C) { + uint64_t DieRef = Data.getUnsigned(C, OffsetSize); if (DieRef == 0) break; - uint8_t IndexEntryValue = GnuStyle ? PubNames.getU8(&Offset) : 0; - StringRef Name = PubNames.getCStrRef(&Offset); + uint8_t IndexEntryValue = GnuStyle ? Data.getU8(C) : 0; + StringRef Name = Data.getCStrRef(C); SetData.Entries.push_back( {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name}); } } + return C.takeError(); } void DWARFDebugPubTable::dump(raw_ostream &OS) const { diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_pub_tables_invalid.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_pub_tables_invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_pub_tables_invalid.s @@ -0,0 +1,26 @@ +# RUN: llvm-mc -triple x86_64 %s -filetype=obj -o %t +# RUN: not llvm-dwarfdump -v %t 2>&1 | FileCheck %s + +# CHECK: .debug_pubnames contents: +# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4) + +# CHECK: .debug_pubtypes contents: +# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4) + +# CHECK: .debug_gnu_pubnames contents: +# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4) + +# CHECK: .debug_gnu_pubtypes contents: +# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4) + + .section .debug_pubnames,"",@progbits + .byte 0 + + .section .debug_pubtypes,"",@progbits + .byte 0 + + .section .debug_gnu_pubnames,"",@progbits + .byte 0 + + .section .debug_gnu_pubtypes,"",@progbits + .byte 0