diff --git a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h --- a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h +++ b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h @@ -28,23 +28,22 @@ struct Data; struct PubSection; -Error emitDebugAbbrev(raw_ostream &OS, const Data &DI); -Error emitDebugStr(raw_ostream &OS, const Data &DI); - -Error emitDebugAranges(raw_ostream &OS, const Data &DI); -Error emitDebugRanges(raw_ostream &OS, const Data &DI); -Error emitDebugPubnames(raw_ostream &OS, const Data &DI); -Error emitDebugPubtypes(raw_ostream &OS, const Data &DI); -Error emitDebugGNUPubnames(raw_ostream &OS, const Data &DI); -Error emitDebugGNUPubtypes(raw_ostream &OS, const Data &DI); -Error emitDebugInfo(raw_ostream &OS, const Data &DI); -Error emitDebugLine(raw_ostream &OS, const Data &DI); -Error emitDebugAddr(raw_ostream &OS, const Data &DI); -Error emitDebugStrOffsets(raw_ostream &OS, const Data &DI); -Error emitDebugRnglists(raw_ostream &OS, const Data &DI); -Error emitDebugLoclists(raw_ostream &OS, const Data &DI); - -std::function +Error emitDebugAbbrev(raw_ostream &OS, Data &DI); +Error emitDebugStr(raw_ostream &OS, Data &DI); +Error emitDebugAranges(raw_ostream &OS, Data &DI); +Error emitDebugRanges(raw_ostream &OS, Data &DI); +Error emitDebugPubnames(raw_ostream &OS, Data &DI); +Error emitDebugPubtypes(raw_ostream &OS, Data &DI); +Error emitDebugGNUPubnames(raw_ostream &OS, Data &DI); +Error emitDebugGNUPubtypes(raw_ostream &OS, Data &DI); +Error emitDebugInfo(raw_ostream &OS, Data &DI); +Error emitDebugLine(raw_ostream &OS, Data &DI); +Error emitDebugAddr(raw_ostream &OS, Data &DI); +Error emitDebugStrOffsets(raw_ostream &OS, Data &DI); +Error emitDebugRnglists(raw_ostream &OS, Data &DI); +Error emitDebugLoclists(raw_ostream &OS, Data &DI); + +std::function getDWARFEmitterByName(StringRef SecName); Expected>> emitDebugSections(StringRef YAMLString, diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h --- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h +++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h @@ -21,6 +21,7 @@ #include "llvm/ObjectYAML/YAML.h" #include "llvm/Support/YAMLTraits.h" #include +#include #include namespace llvm { @@ -40,6 +41,7 @@ }; struct AbbrevTable { + Optional ID; std::vector Table; }; @@ -110,6 +112,7 @@ uint16_t Version; Optional AddrSize; llvm::dwarf::UnitType Type; // Added in DWARF 5 + Optional AbbrevTableID; yaml::Hex64 AbbrOffset; std::vector Entries; }; @@ -228,6 +231,10 @@ bool isEmpty() const; SetVector getNonEmptySectionNames() const; + Expected getAbbrevTableIndexByID(uint64_t ID); + +private: + std::unordered_map AbbrevTableID2Index; }; } // end namespace DWARFYAML diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp --- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp +++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp @@ -85,7 +85,7 @@ OS, IsLittleEndian)); } -Error DWARFYAML::emitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) { +Error DWARFYAML::emitDebugStr(raw_ostream &OS, DWARFYAML::Data &DI) { for (auto Str : DI.DebugStrings) { OS.write(Str.data(), Str.size()); OS.write('\0'); @@ -94,7 +94,7 @@ return Error::success(); } -Error DWARFYAML::emitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) { +Error DWARFYAML::emitDebugAbbrev(raw_ostream &OS, DWARFYAML::Data &DI) { uint64_t AbbrevCode = 0; for (const DWARFYAML::AbbrevTable &AbbrevTable : DI.DebugAbbrev) { for (const DWARFYAML::Abbrev &AbbrevDecl : AbbrevTable.Table) { @@ -121,7 +121,7 @@ return Error::success(); } -Error DWARFYAML::emitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) { +Error DWARFYAML::emitDebugAranges(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.DebugAranges && "unexpected emitDebugAranges() call"); for (auto Range : *DI.DebugAranges) { uint8_t AddrSize; @@ -170,7 +170,7 @@ return Error::success(); } -Error DWARFYAML::emitDebugRanges(raw_ostream &OS, const DWARFYAML::Data &DI) { +Error DWARFYAML::emitDebugRanges(raw_ostream &OS, DWARFYAML::Data &DI) { const size_t RangesOffset = OS.tell(); uint64_t EntryIndex = 0; for (auto DebugRanges : DI.DebugRanges) { @@ -224,29 +224,29 @@ return Error::success(); } -Error DWARFYAML::emitDebugPubnames(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugPubnames(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.PubNames && "unexpected emitDebugPubnames() call"); return emitPubSection(OS, *DI.PubNames, DI.IsLittleEndian); } -Error DWARFYAML::emitDebugPubtypes(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugPubtypes(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.PubTypes && "unexpected emitDebugPubtypes() call"); return emitPubSection(OS, *DI.PubTypes, DI.IsLittleEndian); } -Error DWARFYAML::emitDebugGNUPubnames(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugGNUPubnames(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.GNUPubNames && "unexpected emitDebugGNUPubnames() call"); return emitPubSection(OS, *DI.GNUPubNames, DI.IsLittleEndian, /*IsGNUStyle=*/true); } -Error DWARFYAML::emitDebugGNUPubtypes(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugGNUPubtypes(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.GNUPubTypes && "unexpected emitDebugGNUPubtypes() call"); return emitPubSection(OS, *DI.GNUPubTypes, DI.IsLittleEndian, /*IsGNUStyle=*/true); } -static Expected writeDIE(ArrayRef AbbrevTable, +static Expected writeDIE(DWARFYAML::Data &DI, uint64_t AbbrevTableID, const dwarf::FormParams &Params, const DWARFYAML::Entry &Entry, raw_ostream &OS, bool IsLittleEndian) { @@ -256,12 +256,12 @@ if (AbbrCode == 0 || Entry.Values.empty()) return OS.tell() - EntryBegin; - if (AbbrevTable.empty()) - return createStringError( - errc::invalid_argument, - "non-empty compilation unit should have an associated abbrev table"); - - ArrayRef AbbrevDecls(AbbrevTable[0].Table); + Expected AbbrevTableIndexOrErr = + DI.getAbbrevTableIndexByID(AbbrevTableID); + if (!AbbrevTableIndexOrErr) + return AbbrevTableIndexOrErr.takeError(); + ArrayRef AbbrevDecls( + DI.DebugAbbrev[*AbbrevTableIndexOrErr].Table); if (AbbrCode > AbbrevDecls.size()) return createStringError( @@ -383,8 +383,9 @@ return OS.tell() - EntryBegin; } -Error DWARFYAML::emitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { - for (const DWARFYAML::Unit &Unit : DI.CompileUnits) { +Error DWARFYAML::emitDebugInfo(raw_ostream &OS, DWARFYAML::Data &DI) { + for (uint64_t I = 0; I < DI.CompileUnits.size(); ++I) { + const DWARFYAML::Unit &Unit = DI.CompileUnits[I]; uint8_t AddrSize; if (Unit.AddrSize) AddrSize = *Unit.AddrSize; @@ -402,9 +403,11 @@ std::string EntryBuffer; raw_string_ostream EntryBufferOS(EntryBuffer); + uint64_t AbbrevTableID = Unit.AbbrevTableID.getValueOr(I); for (const DWARFYAML::Entry &Entry : Unit.Entries) { - if (Expected EntryLength = writeDIE( - DI.DebugAbbrev, Params, Entry, EntryBufferOS, DI.IsLittleEndian)) + if (Expected EntryLength = + writeDIE(DI, AbbrevTableID, Params, Entry, EntryBufferOS, + DI.IsLittleEndian)) Length += *EntryLength; else return EntryLength.takeError(); @@ -440,7 +443,7 @@ encodeULEB128(File.Length, OS); } -Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) { +Error DWARFYAML::emitDebugLine(raw_ostream &OS, DWARFYAML::Data &DI) { for (const auto &LineTable : DI.DebugLines) { writeInitialLength(LineTable.Format, LineTable.Length, OS, DI.IsLittleEndian); @@ -530,7 +533,7 @@ return Error::success(); } -Error DWARFYAML::emitDebugAddr(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugAddr(raw_ostream &OS, DWARFYAML::Data &DI) { for (const AddrTableEntry &TableEntry : DI.DebugAddr) { uint8_t AddrSize; if (TableEntry.AddrSize) @@ -571,7 +574,7 @@ return Error::success(); } -Error DWARFYAML::emitDebugStrOffsets(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugStrOffsets(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.DebugStrOffsets && "unexpected emitDebugStrOffsets() call"); for (const DWARFYAML::StringOffsetsTable &Table : *DI.DebugStrOffsets) { uint64_t Length; @@ -895,23 +898,23 @@ return Error::success(); } -Error DWARFYAML::emitDebugRnglists(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugRnglists(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.DebugRnglists && "unexpected emitDebugRnglists() call"); return writeDWARFLists( OS, *DI.DebugRnglists, DI.IsLittleEndian, DI.Is64BitAddrSize); } -Error DWARFYAML::emitDebugLoclists(raw_ostream &OS, const Data &DI) { +Error DWARFYAML::emitDebugLoclists(raw_ostream &OS, DWARFYAML::Data &DI) { assert(DI.DebugLoclists && "unexpected emitDebugRnglists() call"); return writeDWARFLists( OS, *DI.DebugLoclists, DI.IsLittleEndian, DI.Is64BitAddrSize); } -std::function +std::function DWARFYAML::getDWARFEmitterByName(StringRef SecName) { auto EmitFunc = - StringSwitch< - std::function>(SecName) + StringSwitch>( + SecName) .Case("debug_abbrev", DWARFYAML::emitDebugAbbrev) .Case("debug_addr", DWARFYAML::emitDebugAddr) .Case("debug_aranges", DWARFYAML::emitDebugAranges) @@ -926,7 +929,7 @@ .Case("debug_rnglists", DWARFYAML::emitDebugRnglists) .Case("debug_str", DWARFYAML::emitDebugStr) .Case("debug_str_offsets", DWARFYAML::emitDebugStrOffsets) - .Default([&](raw_ostream &, const DWARFYAML::Data &) { + .Default([&](raw_ostream &, DWARFYAML::Data &) { return createStringError(errc::not_supported, SecName + " is not supported"); }); @@ -935,7 +938,7 @@ } static Error -emitDebugSectionImpl(const DWARFYAML::Data &DI, StringRef Sec, +emitDebugSectionImpl(DWARFYAML::Data &DI, StringRef Sec, StringMap> &OutputBuffers) { std::string Data; raw_string_ostream DebugInfoStream(Data); diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp --- a/llvm/lib/ObjectYAML/DWARFYAML.cpp +++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp @@ -13,6 +13,8 @@ #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" namespace llvm { @@ -53,6 +55,31 @@ return SecNames; } +Expected DWARFYAML::Data::getAbbrevTableIndexByID(uint64_t ID) { + if (AbbrevTableID2Index.empty()) { + for (auto &AbbrevTable : enumerate(DebugAbbrev)) { + // If the abbrev table's ID isn't specified, we use the index as its ID. + uint64_t AbbrevTableID = + AbbrevTable.value().ID.getValueOr(AbbrevTable.index()); + auto It = + AbbrevTableID2Index.insert({AbbrevTableID, AbbrevTable.index()}); + if (!It.second) + return createStringError( + errc::invalid_argument, + "the ID (%" PRIu64 ") of abbrev table with index %" PRIu64 + " has been used by abbrev table with index %" PRIu64, + AbbrevTableID, AbbrevTable.index(), It.first->second); + } + } + + auto It = AbbrevTableID2Index.find(ID); + if (It == AbbrevTableID2Index.end()) + return createStringError(errc::invalid_argument, + "cannot find abbrev table whose ID is %" PRIu64, + ID); + return It->second; +} + namespace yaml { void MappingTraits::mapping(IO &IO, DWARFYAML::Data &DWARF) { @@ -80,6 +107,7 @@ void MappingTraits::mapping( IO &IO, DWARFYAML::AbbrevTable &AbbrevTable) { + IO.mapOptional("ID", AbbrevTable.ID); IO.mapOptional("Table", AbbrevTable.Table); } @@ -153,6 +181,7 @@ IO.mapRequired("Version", Unit.Version); if (Unit.Version >= 5) IO.mapRequired("UnitType", Unit.Type); + IO.mapOptional("AbbrevTableID", Unit.AbbrevTableID); IO.mapRequired("AbbrOffset", Unit.AbbrOffset); IO.mapOptional("AddrSize", Unit.AddrSize); IO.mapOptional("Entries", Unit.Entries); diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -939,7 +939,7 @@ template Expected emitDWARF(typename ELFT::Shdr &SHeader, StringRef Name, - const DWARFYAML::Data &DWARF, + DWARFYAML::Data &DWARF, ContiguousBlobAccumulator &CBA) { // We are unable to predict the size of debug data, so we request to write 0 // bytes. This should always return us an output stream unless CBA is already diff --git a/llvm/test/ObjectYAML/MachO/DWARF-debug_abbrev.yaml b/llvm/test/ObjectYAML/MachO/DWARF-debug_abbrev.yaml --- a/llvm/test/ObjectYAML/MachO/DWARF-debug_abbrev.yaml +++ b/llvm/test/ObjectYAML/MachO/DWARF-debug_abbrev.yaml @@ -1,4 +1,7 @@ -# RUN: yaml2obj %s | obj2yaml | FileCheck %s +## a) Test that yaml2obj is able to emit the __debug_abbrev section and obj2yaml is +## able to convert it back. + +# RUN: yaml2obj --docnum=1 %s | obj2yaml | FileCheck %s --- !mach-o FileHeader: @@ -420,3 +423,70 @@ #CHECK: Attributes: #CHECK: - Attribute: DW_AT_type #CHECK: Form: DW_FORM_ref4 + + +## b) Test that yaml2obj emits an error message when there are non-empty compilation +## units and multiple abbrev tables are assigned the same ID. + +# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=ID-COLLISION + +# ID-COLLISION: yaml2obj: error: the ID (1) of abbrev table with index 1 has been used by abbrev table with index 0 + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x0000000A + ncmds: 1 + sizeofcmds: 232 + flags: 0x00000000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: __DWARF + vmaddr: 0x00 + vmsize: 0x00 + fileoff: 0x00 + filesize: 0x00 + maxprot: 0 + initprot: 0 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x00 + size: 24 + offset: 528 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x00 + size: 64 + offset: 1070 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 +DWARF: + debug_abbrev: + - ID: 1 + - ID: 1 + debug_info: + - Version: 4 + AbbrOffset: 0x00 + Entries: + - AbbrCode: 1 + Values: + - Value: 0x1234 diff --git a/llvm/test/ObjectYAML/MachO/DWARF-debug_info.yaml b/llvm/test/ObjectYAML/MachO/DWARF-debug_info.yaml --- a/llvm/test/ObjectYAML/MachO/DWARF-debug_info.yaml +++ b/llvm/test/ObjectYAML/MachO/DWARF-debug_info.yaml @@ -514,6 +514,7 @@ # DWARF32: debug_info: # DWARF32-NEXT: - Length: 0x0000000000000075 # DWARF32-NEXT: Version: 4 +# DWARF32-NEXT: AbbrevTableID: 0 # DWARF32-NEXT: AbbrOffset: 0 # DWARF32-NEXT: AddrSize: 8 # DWARF32-NEXT: Entries: @@ -583,6 +584,7 @@ # DWARF32-YAML: debug_info: # DWARF32-YAML-NEXT: - Length: 0x000000000000000C # DWARF32-YAML-NEXT: Version: 4 +# DWARF32-YAML-NEXT: AbbrevTableID: 0 # DWARF32-YAML-NEXT: AbbrOffset: 0 # DWARF32-YAML-NEXT: AddrSize: 8 # DWARF32-YAML-NEXT: Entries: @@ -666,9 +668,237 @@ # DWARF64-YAML-NEXT: - Format: DWARF64 # DWARF64-YAML-NEXT: Length: 0x000000000000000C # DWARF64-YAML-NEXT: Version: 4 +# DWARF64-YAML-NEXT: AbbrevTableID: 0 # DWARF64-YAML-NEXT: AbbrOffset: 0 # DWARF64-YAML-NEXT: AddrSize: 8 # DWARF64-YAML-NEXT: Entries: # DWARF64-YAML-NEXT: - AbbrCode: 0x00000001 # DWARF64-YAML-NEXT: Values: # DWARF64-YAML-NEXT: - Value: 0x0000000000001234 + +## c) Test that yaml2obj is able to generate compilation units according to the +## associated abbrev table that is referenced by the 'AbbrevTableID' and obj2yaml +## is able to convert it back. + +# RUN: yaml2obj --docnum=3 %s | obj2yaml | FileCheck %s --check-prefix=MULTI-TABLES + +# MULTI-TABLES: DWARF: +# MULTI-TABLES-NEXT: debug_abbrev: +# MULTI-TABLES-NEXT: - ID: 0 +# MULTI-TABLES-NEXT: Table: +# MULTI-TABLES-NEXT: - Code: 0x0000000000000001 +# MULTI-TABLES-NEXT: Tag: DW_TAG_compile_unit +# MULTI-TABLES-NEXT: Children: DW_CHILDREN_no +# MULTI-TABLES-NEXT: Attributes: +# MULTI-TABLES-NEXT: - Attribute: DW_AT_low_pc +# MULTI-TABLES-NEXT: Form: DW_FORM_addr +# MULTI-TABLES-NEXT: - ID: 1 +# MULTI-TABLES-NEXT: Table: +# MULTI-TABLES-NEXT: - Code: 0x0000000000000001 +# MULTI-TABLES-NEXT: Tag: DW_TAG_compile_unit +# MULTI-TABLES-NEXT: Children: DW_CHILDREN_no +# MULTI-TABLES-NEXT: Attributes: +# MULTI-TABLES-NEXT: - Attribute: DW_AT_low_pc +# MULTI-TABLES-NEXT: Form: DW_FORM_data4 +# MULTI-TABLES-NEXT: - ID: 2 +# MULTI-TABLES-NEXT: Table: +# MULTI-TABLES-NEXT: - Code: 0x0000000000000001 +# MULTI-TABLES-NEXT: Tag: DW_TAG_compile_unit +# MULTI-TABLES-NEXT: Children: DW_CHILDREN_no +# MULTI-TABLES-NEXT: Attributes: +# MULTI-TABLES-NEXT: - Attribute: DW_AT_low_pc +# MULTI-TABLES-NEXT: Form: DW_FORM_udata +# MULTI-TABLES-NEXT: debug_info: +# MULTI-TABLES-NEXT: - Length: 0x000000000000000C +# MULTI-TABLES-NEXT: Version: 4 +# MULTI-TABLES-NEXT: AbbrevTableID: 1 +# MULTI-TABLES-NEXT: AbbrOffset: 0x0000000000000008 +# MULTI-TABLES-NEXT: AddrSize: 8 +# MULTI-TABLES-NEXT: Entries: +# MULTI-TABLES-NEXT: - AbbrCode: 0x00000001 +# MULTI-TABLES-NEXT: Values: +# MULTI-TABLES-NEXT: - Value: 0x0000000000001234 +# MULTI-TABLES-NEXT: - Length: 0x000000000000000C +# MULTI-TABLES-NEXT: Version: 4 +# MULTI-TABLES-NEXT: AbbrevTableID: 1 +# MULTI-TABLES-NEXT: AbbrOffset: 0x0000000000000008 +# MULTI-TABLES-NEXT: AddrSize: 8 +# MULTI-TABLES-NEXT: Entries: +# MULTI-TABLES-NEXT: - AbbrCode: 0x00000001 +# MULTI-TABLES-NEXT: Values: +# MULTI-TABLES-NEXT: - Value: 0x0000000000004321 +# MULTI-TABLES-NEXT: - Length: 0x0000000000000010 +# MULTI-TABLES-NEXT: Version: 4 +# MULTI-TABLES-NEXT: AbbrevTableID: 0 +# MULTI-TABLES-NEXT: AbbrOffset: 0x0000000000000000 +# MULTI-TABLES-NEXT: AddrSize: 8 +# MULTI-TABLES-NEXT: Entries: +# MULTI-TABLES-NEXT: - AbbrCode: 0x00000001 +# MULTI-TABLES-NEXT: Values: +# MULTI-TABLES-NEXT: - Value: 0x0000000000005678 +# MULTI-TABLES-NEXT: ... + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x0000000A + ncmds: 1 + sizeofcmds: 232 + flags: 0x00000000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: __DWARF + vmaddr: 0x00 + vmsize: 0x00 + fileoff: 0x00 + filesize: 0x00 + maxprot: 0 + initprot: 0 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x00 + size: 24 + offset: 528 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x00 + size: 64 + offset: 1070 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 +DWARF: + debug_abbrev: + - Table: + - Code: 1 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - ID: 2 + Table: + - Code: 1 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_low_pc + Form: DW_FORM_data4 + - ID: 1 + Table: + - Code: 1 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_low_pc + Form: DW_FORM_udata + debug_info: + - Version: 4 + AbbrevTableID: 2 + AbbrOffset: 8 + Entries: + - AbbrCode: 1 + Values: + - Value: 0x1234 + - Version: 4 + AbbrevTableID: 2 + AbbrOffset: 8 + Entries: + - AbbrCode: 1 + Values: + - Value: 0x4321 + - Version: 4 + AbbrevTableID: 0 + AbbrOffset: 0 + Entries: + - AbbrCode: 1 + Values: + - Value: 0x5678 + - Version: 4 + AbbrevTableID: 1 + AbbrOffset: 16 + Entries: + - AbbrCode: 1 + Values: + - Value: 0x8765 + +## d) Test that yaml2obj emits an error message when a compilation unit doesn't have +## an associated abbrev table. + +# RUN: not yaml2obj --docnum=4 %s 2>&1 | FileCheck %s --check-prefix=MISSING-ABBREV + +# MISSING-ABBREV: yaml2obj: error: cannot find abbrev table whose ID is 0 + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x0000000A + ncmds: 1 + sizeofcmds: 232 + flags: 0x00000000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: __DWARF + vmaddr: 0x00 + vmsize: 0x00 + fileoff: 0x00 + filesize: 0x00 + maxprot: 0 + initprot: 0 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x00 + size: 24 + offset: 528 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x00 + size: 64 + offset: 1070 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 +DWARF: + debug_info: + - Version: 4 + AbbrOffset: 0x00 + Entries: + - AbbrCode: 1 + Values: + - Value: 0x1234 diff --git a/llvm/test/ObjectYAML/MachO/DWARF5-debug_info.yaml b/llvm/test/ObjectYAML/MachO/DWARF5-debug_info.yaml --- a/llvm/test/ObjectYAML/MachO/DWARF5-debug_info.yaml +++ b/llvm/test/ObjectYAML/MachO/DWARF5-debug_info.yaml @@ -515,6 +515,7 @@ # DWARF32-NEXT: - Length: 0x0000000000000076 # DWARF32-NEXT: Version: 5 # DWARF32-NEXT: UnitType: DW_UT_compile +# DWARF32-NEXT: AbbrevTableID: 0 # DWARF32-NEXT: AbbrOffset: 0 # DWARF32-NEXT: AddrSize: 8 # DWARF32-NEXT: Entries: @@ -585,6 +586,7 @@ # DWARF32-YAML-NEXT: - Length: 0x000000000000000C # DWARF32-YAML-NEXT: Version: 5 # DWARF32-YAML-NEXT: UnitType: DW_UT_compile +# DWARF32-YAML-NEXT: AbbrevTableID: 0 # DWARF32-YAML-NEXT: AbbrOffset: 0x0000000000000000 # DWARF32-YAML-NEXT: AddrSize: 8 # DWARF32-YAML-NEXT: Entries: @@ -670,6 +672,7 @@ # DWARF64-YAML-NEXT: Length: 0x0000000000000014 # DWARF64-YAML-NEXT: Version: 5 # DWARF64-YAML-NEXT: UnitType: DW_UT_compile +# DWARF64-YAML-NEXT: AbbrevTableID: 0 # DWARF64-YAML-NEXT: AbbrOffset: 0x0000000000000000 # DWARF64-YAML-NEXT: AddrSize: 8 # DWARF64-YAML-NEXT: Entries: diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-abbrev.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-abbrev.yaml --- a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-abbrev.yaml +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-abbrev.yaml @@ -314,3 +314,28 @@ - Tag: DW_TAG_subprogram Children: DW_CHILDREN_no Attributes: [] + +## i) Test that yaml2obj emits an error message when there are non-empty compilation units +## and multiple abbrev tables are assigned the same ID. + +## RUN: not yaml2obj --docnum=9 %s 2>&1 | FileCheck %s --check-prefix=ID-COLLISION + +# ID-COLLISION: yaml2obj: error: the ID (1) of abbrev table with index 1 has been used by abbrev table with index 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_abbrev: + - ID: 1 + - ID: 1 + debug_info: + - Version: 4 + AbbrOffset: 0x00 + Entries: + - AbbrCode: 1 + Values: + - Value: 0x1234 diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-info.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-info.yaml --- a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-info.yaml +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-info.yaml @@ -207,11 +207,12 @@ - Attribute: 0x01 Form: DW_FORM_addrx4 ## 0x2c debug_info: - - Length: 0x1234 - Version: 5 - UnitType: DW_UT_type - AbbrOffset: 0x1234 - AddrSize: 4 + - Length: 0x1234 + Version: 5 + UnitType: DW_UT_type + AbbrevTableID: 0 + AbbrOffset: 0x1234 + AddrSize: 4 Entries: - AbbrCode: 1 Values: @@ -272,6 +273,7 @@ Version: 5 ## Test another unit type. UnitType: DW_UT_compile + AbbrevTableID: 0 AbbrOffset: 0x1234 AddrSize: 4 Entries: @@ -280,6 +282,7 @@ - Length: 0x5678 ## Test DWARFv4 Version: 4 + AbbrevTableID: 0 AbbrOffset: 0x5678 AddrSize: 4 Entries: @@ -901,7 +904,7 @@ ## RUN: not yaml2obj --docnum=16 %s 2>&1 | FileCheck %s --check-prefix=NO-ABBREV -# NO-ABBREV: yaml2obj: error: non-empty compilation unit should have an associated abbrev table +# NO-ABBREV: yaml2obj: error: cannot find abbrev table whose ID is 0 --- !ELF FileHeader: diff --git a/llvm/tools/obj2yaml/dwarf2yaml.cpp b/llvm/tools/obj2yaml/dwarf2yaml.cpp --- a/llvm/tools/obj2yaml/dwarf2yaml.cpp +++ b/llvm/tools/obj2yaml/dwarf2yaml.cpp @@ -23,6 +23,7 @@ void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) { auto AbbrevSetPtr = DCtx.getDebugAbbrev(); if (AbbrevSetPtr) { + uint64_t AbbrevTableID = 0; for (auto AbbrvDeclSet : *AbbrevSetPtr) { Y.DebugAbbrev.emplace_back(); for (auto AbbrvDecl : AbbrvDeclSet.second) { @@ -39,6 +40,7 @@ AttAbrv.Value = Attribute.getImplicitConstValue(); Abbrv.Attributes.push_back(AttAbrv); } + Y.DebugAbbrev.back().ID = AbbrevTableID++; Y.DebugAbbrev.back().Table.push_back(Abbrv); } } @@ -172,6 +174,14 @@ NewUnit.Version = CU->getVersion(); if (NewUnit.Version >= 5) NewUnit.Type = (dwarf::UnitType)CU->getUnitType(); + const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev(); + NewUnit.AbbrevTableID = std::distance( + DebugAbbrev->begin(), + std::find_if( + DebugAbbrev->begin(), DebugAbbrev->end(), + [&](const std::pair &P) { + return P.first == CU->getAbbreviations()->getOffset(); + })); NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset(); NewUnit.AddrSize = CU->getAddressByteSize(); for (auto DIE : CU->dies()) { 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 @@ -2487,6 +2487,7 @@ - Value: 0x0000000000000000 - Length: 16 Version: 4 + AbbrevTableID: 0 AbbrOffset: 0 AddrSize: 8 Entries: