Index: include/llvm/DebugInfo/DIContext.h =================================================================== --- include/llvm/DebugInfo/DIContext.h +++ include/llvm/DebugInfo/DIContext.h @@ -135,6 +135,7 @@ DIDT_GnuPubnames, DIDT_GnuPubtypes, DIDT_Str, + DIDT_StrOffsets, DIDT_StrDwo, DIDT_StrOffsetsDwo, DIDT_AppleNames, Index: include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -19,8 +19,8 @@ public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, const DWARFSection *AOS, - StringRef LS, bool LE, bool IsDWO, + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, Index: include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFContext.h +++ include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -71,6 +71,9 @@ std::unique_ptr AbbrevDWO; std::unique_ptr LocDWO; + /// The maximum DWARF version of all units. + unsigned MaxVersion; + struct DWOFile { object::OwningBinary File; std::unique_ptr Context; @@ -96,7 +99,7 @@ void parseDWOTypeUnits(); public: - DWARFContext() : DIContext(CK_DWARF) {} + DWARFContext() : DIContext(CK_DWARF), MaxVersion(0) {} DWARFContext(DWARFContext &) = delete; DWARFContext &operator=(DWARFContext &) = delete; @@ -178,6 +181,13 @@ /// Get a DIE given an exact offset. DWARFDie getDIEForOffset(uint32_t Offset); + unsigned getMaxVersion() const { return MaxVersion; } + + void setMaxVersionIfGreater(unsigned Version) { + if (Version > MaxVersion) + MaxVersion = Version; + } + const DWARFUnitIndex &getCUIndex(); DWARFGdbIndex &getGdbIndex(); const DWARFUnitIndex &getTUIndex(); @@ -237,6 +247,11 @@ virtual StringRef getGnuPubNamesSection() = 0; virtual StringRef getGnuPubTypesSection() = 0; + /// DWARF v5 + /// @{ + virtual const DWARFSection &getStringOffsetSection() = 0; + /// @} + // Sections for DWARF5 split dwarf proposal. virtual const DWARFSection &getInfoDWOSection() = 0; virtual const TypeSectionMap &getTypesDWOSections() = 0; @@ -244,7 +259,7 @@ virtual const DWARFSection &getLineDWOSection() = 0; virtual const DWARFSection &getLocDWOSection() = 0; virtual StringRef getStringDWOSection() = 0; - virtual StringRef getStringOffsetDWOSection() = 0; + virtual const DWARFSection &getStringOffsetDWOSection() = 0; virtual const DWARFSection &getRangeDWOSection() = 0; virtual const DWARFSection &getAddrSection() = 0; virtual const DWARFSection& getAppleNamesSection() = 0; @@ -295,6 +310,11 @@ StringRef GnuPubNamesSection; StringRef GnuPubTypesSection; + /// DWARF v5 + /// @{ + DWARFSection StringOffsetSection; + /// @} + // Sections for DWARF5 split dwarf proposal. DWARFSection InfoDWOSection; TypeSectionMap TypesDWOSections; @@ -302,7 +322,7 @@ DWARFSection LineDWOSection; DWARFSection LocDWOSection; StringRef StringDWOSection; - StringRef StringOffsetDWOSection; + DWARFSection StringOffsetDWOSection; DWARFSection RangeDWOSection; DWARFSection AddrSection; DWARFSection AppleNamesSection; @@ -353,6 +373,11 @@ const DWARFSection& getAppleNamespacesSection() override { return AppleNamespacesSection; } const DWARFSection& getAppleObjCSection() override { return AppleObjCSection; } + // DWARF v5 + const DWARFSection &getStringOffsetSection() override { + return StringOffsetSection; + } + // Sections for DWARF5 split dwarf proposal. const DWARFSection &getInfoDWOSection() override { return InfoDWOSection; } @@ -365,7 +390,7 @@ const DWARFSection &getLocDWOSection() override { return LocDWOSection; } StringRef getStringDWOSection() override { return StringDWOSection; } - StringRef getStringOffsetDWOSection() override { + const DWARFSection &getStringOffsetDWOSection() override { return StringOffsetDWOSection; } Index: include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -31,7 +31,7 @@ public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, const DWARFSection *AOS, + StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -57,8 +57,9 @@ virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, const DWARFSection *AOS, - StringRef LS, bool isLittleEndian, bool isDWO) = 0; + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, StringRef LS, + bool isLittleEndian, bool isDWO) = 0; }; const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, @@ -89,7 +90,7 @@ private: void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, const DWARFSection *AOS, + StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, StringRef LS, bool LE, bool IsDWO) override { if (Parsed) return; @@ -119,7 +120,8 @@ uint32_t RangeSectionBase; StringRef LineSection; StringRef StringSection; - StringRef StringOffsetSection; + const DWARFSection &StringOffsetSection; + uint64_t StringOffsetSectionBase = 0; const DWARFSection *AddrOffsetSection; uint32_t AddrOffsetSectionBase; bool isLittleEndian; @@ -162,8 +164,8 @@ public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, - StringRef SOS, const DWARFSection *AOS, StringRef LS, bool LE, - bool IsDWO, const DWARFUnitSectionBase &UnitSection, + const DWARFSection &SOS, const DWARFSection *AOS, StringRef LS, + bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry = nullptr); virtual ~DWARFUnit(); @@ -172,7 +174,9 @@ StringRef getLineSection() const { return LineSection; } StringRef getStringSection() const { return StringSection; } - StringRef getStringOffsetSection() const { return StringOffsetSection; } + const DWARFSection &getStringOffsetSection() const { + return StringOffsetSection; + } void setAddrOffsetSection(const DWARFSection *AOS, uint32_t Base) { AddrOffsetSection = AOS; @@ -189,7 +193,8 @@ bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const; // FIXME: Result should be uint64_t in DWARF64. - bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const; + bool getStringOffsetSectionItem(uint32_t Index, uint64_t &Result) const; + uint64_t getStringOffsetSectionRelocation(uint32_t Index) const; DataExtractor getDebugInfoExtractor() const { return DataExtractor(InfoSection.Data, isLittleEndian, AddrSize); @@ -200,6 +205,9 @@ } const RelocAddrMap *getRelocMap() const { return &InfoSection.Relocs; } + const RelocAddrMap &getStringOffsetsRelocMap() const { + return StringOffsetSection.Relocs; + } bool extract(DataExtractor debug_info, uint32_t* offset_ptr); Index: include/llvm/MC/MCObjectFileInfo.h =================================================================== --- include/llvm/MC/MCObjectFileInfo.h +++ include/llvm/MC/MCObjectFileInfo.h @@ -109,6 +109,9 @@ MCSection *DwarfLineDWOSection; MCSection *DwarfLocDWOSection; MCSection *DwarfStrOffDWOSection; + + /// The DWARF v5 string offset and address table sections. + MCSection *DwarfStrOffSection; MCSection *DwarfAddrSection; // These are for Fission DWP files. @@ -260,6 +263,7 @@ MCSection *getDwarfLineDWOSection() const { return DwarfLineDWOSection; } MCSection *getDwarfLocDWOSection() const { return DwarfLocDWOSection; } MCSection *getDwarfStrOffDWOSection() const { return DwarfStrOffDWOSection; } + MCSection *getDwarfStrOffSection() const { return DwarfStrOffSection; } MCSection *getDwarfAddrSection() const { return DwarfAddrSection; } MCSection *getDwarfCUIndexSection() const { return DwarfCUIndexSection; } MCSection *getDwarfTUIndexSection() const { return DwarfTUIndexSection; } Index: include/llvm/Object/MachO.h =================================================================== --- include/llvm/Object/MachO.h +++ include/llvm/Object/MachO.h @@ -549,6 +549,8 @@ bool isRelocatableObject() const override; + StringRef mapDebugSectionName(StringRef Name) const override; + bool hasPageZeroSegment() const { return HasPageZeroSegment; } static bool classof(const Binary *v) { Index: include/llvm/Object/ObjectFile.h =================================================================== --- include/llvm/Object/ObjectFile.h +++ include/llvm/Object/ObjectFile.h @@ -290,6 +290,9 @@ return std::error_code(); } + /// Maps a debug section name to a standard DWARF section name. + virtual StringRef mapDebugSectionName(StringRef Name) const { return Name; } + /// True if this is a relocatable object (.o/.obj). virtual bool isRelocatableObject() const = 0; Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -81,6 +81,69 @@ Accel.dump(OS); } +// Dump the DWARF v5 string offsets section. It consists of per-unit +// contributions of string offsets, each preceded by a header describing +// its size. +static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName, + const DWARFSection &Section, + bool LittleEndian) { + if (Section.Data.empty()) + return; + OS << "\n." << SectionName << " contents:\n"; + DataExtractor StrOffsetExt(Section.Data, LittleEndian, 0); + uint32_t Offset = 0; + uint64_t SectionSize = Section.Data.size(); + + while (Offset < SectionSize) { + unsigned Version = 0; + DwarfFormat Format = DWARF32; + unsigned EntrySize = 4; + // Perform validation and extract the segment size from the header. + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 4)) + return; + uint32_t ContributionStart = Offset; + uint64_t ContributionSize = StrOffsetExt.getU32(&Offset); + // A contribution size of 0xffffffff indicates DWARF64, with the actual size + // in the following 8 bytes. Otherwise, the DWARF standard mandates that + // the contribution size must be at most 0xfffffff0. + if (ContributionSize == 0xffffffff) { + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 8)) + return; + Format = DWARF64; + EntrySize = 8; + ContributionSize = StrOffsetExt.getU64(&Offset); + } else if (ContributionSize > 0xfffffff0) + return; + + // We must ensure that we don't read a partial record at the end, so we + // validate for a multiple of EntrySize. Also, we're expecting a version + // number and padding, which adds an additional 4 bytes. + uint64_t ValidationSize = + 4 + ((ContributionSize + EntrySize - 1) & (-(uint64_t)EntrySize)); + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, ValidationSize)) + return; + + Version = StrOffsetExt.getU16(&Offset); + Offset += 2; + OS << format("0x%8.8x: ", ContributionStart); + OS << "Contribution size = " << ContributionSize + << ", Version = " << Version << "\n"; + + uint32_t ContributionBase = Offset; + while (Offset - ContributionBase < ContributionSize) { + uint64_t StringOffset = 0; + OS << format("0x%8.8x: ", Offset); + StringOffset = + getRelocatedValue(StrOffsetExt, EntrySize, &Offset, &Section.Relocs); + if (Format == DWARF32) { + OS << format("%8.8x\n", StringOffset); + } else { + OS << format("%16.16x\n", StringOffset); + } + } + } +} + void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, bool SummarizeTypes) { if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { @@ -251,16 +314,29 @@ true /* GnuStyle */) .dump("debug_gnu_pubtypes", OS); - if ((DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) && - !getStringOffsetDWOSection().empty()) { - OS << "\n.debug_str_offsets.dwo contents:\n"; - DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(), - 0); - offset = 0; - uint64_t size = getStringOffsetDWOSection().size(); - while (offset < size) { - OS << format("0x%8.8x: ", offset); - OS << format("%8.8x\n", strOffsetExt.getU32(&offset)); + if (DumpType == DIDT_All || DumpType == DIDT_StrOffsets) + dumpStringOffsetsSection(OS, "debug_str_offsets", getStringOffsetSection(), + isLittleEndian()); + + if (DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) { + // If we have at least one unit with DWARF v5 or greater, we assume that + // the DWO string offsets section is formatted like the regular DWARF v5 + // string offsets section, i.e. a series of contributions by compile and + // type units, each preceded by a header. Otherwise, we treat it as a + // monolithic sequence of string offsets. + if (getMaxVersion() >= 5) + dumpStringOffsetsSection(OS, "debug_str_offsets.dwo", + getStringOffsetDWOSection(), isLittleEndian()); + else if (!getStringOffsetDWOSection().Data.empty()) { + OS << "\n.debug_str_offsets.dwo contents:\n"; + DataExtractor strOffsetExt(getStringOffsetDWOSection().Data, + isLittleEndian(), 0); + offset = 0; + uint64_t size = getStringOffsetDWOSection().Data.size(); + while (offset < size) { + OS << format("0x%8.8x: ", offset); + OS << format("%8.8x\n", strOffsetExt.getU32(&offset)); + } } } @@ -1093,6 +1169,10 @@ TypesDWOSections[Section].Data = data; } + // Map platform specific debug section names to DWARF standard section + // names. + name = Obj.mapDebugSectionName(name); + if (RelocatedSection == Obj.section_end()) continue; @@ -1125,6 +1205,7 @@ .Case("debug_loc", &LocSection.Relocs) .Case("debug_info.dwo", &InfoDWOSection.Relocs) .Case("debug_line", &LineSection.Relocs) + .Case("debug_str_offsets", &StringOffsetSection.Relocs) .Case("debug_ranges", &RangeSection.Relocs) .Case("debug_addr", &AddrSection.Relocs) .Case("apple_names", &AppleNamesSection.Relocs) @@ -1194,6 +1275,7 @@ .Case("debug_frame", &DebugFrameSection) .Case("eh_frame", &EHFrameSection) .Case("debug_str", &StringSection) + .Case("debug_str_offsets", &StringOffsetSection.Data) .Case("debug_ranges", &RangeSection.Data) .Case("debug_macinfo", &MacinfoSection) .Case("debug_pubnames", &PubNamesSection) @@ -1205,7 +1287,7 @@ .Case("debug_loc.dwo", &LocDWOSection.Data) .Case("debug_line.dwo", &LineDWOSection.Data) .Case("debug_str.dwo", &StringDWOSection) - .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) + .Case("debug_str_offsets.dwo", &StringOffsetDWOSection.Data) .Case("debug_addr", &AddrSection.Data) .Case("apple_names", &AppleNamesSection.Data) .Case("apple_types", &AppleTypesSection.Data) Index: lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -301,6 +301,7 @@ return (FC == FC_Address); case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: + case DW_FORM_strx: return (FC == FC_String); case DW_FORM_implicit_const: return (FC == FC_Constant); @@ -415,6 +416,7 @@ break; case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: + case DW_FORM_strx: Value.uval = Data.getULEB128(OffsetPtr); break; default: @@ -542,6 +544,7 @@ OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue); dumpString(OS); break; + case DW_FORM_strx: case DW_FORM_GNU_str_index: OS << format(" indexed (%8.8x) string = ", (uint32_t)UValue); dumpString(OS); @@ -620,10 +623,11 @@ if (Form == DW_FORM_GNU_strp_alt || U == nullptr) return None; uint32_t Offset = Value.uval; - if (Form == DW_FORM_GNU_str_index) { - uint32_t StrOffset; + if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx) { + uint64_t StrOffset; if (!U->getStringOffsetSectionItem(Offset, StrOffset)) return None; + StrOffset += U->getStringOffsetSectionRelocation(Offset); Offset = StrOffset; } if (const char *Str = U->getStringExtractor().getCStr(&Offset)) { Index: lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFUnit.cpp +++ lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -33,8 +33,9 @@ void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) { parseImpl(C, Section, C.getDebugAbbrev(), &C.getRangeSection(), - C.getStringSection(), StringRef(), &C.getAddrSection(), - C.getLineSection().Data, C.isLittleEndian(), false); + C.getStringSection(), C.getStringOffsetSection(), + &C.getAddrSection(), C.getLineSection().Data, C.isLittleEndian(), + false); } void DWARFUnitSectionBase::parseDWO(DWARFContext &C, @@ -48,19 +49,14 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, const DWARFSection *AOS, - StringRef LS, bool LE, bool IsDWO, + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry) : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS), - LineSection(LS), StringSection(SS), StringOffsetSection([&]() { - if (IndexEntry) - if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) - return SOS.slice(C->Offset, C->Offset + C->Length); - return SOS; - }()), - AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO), - UnitSection(UnitSection), IndexEntry(IndexEntry) { + LineSection(LS), StringSection(SS), StringOffsetSection(SOS), + StringOffsetSectionBase(0), AddrOffsetSection(AOS), isLittleEndian(LE), + isDWO(IsDWO), UnitSection(UnitSection), IndexEntry(IndexEntry) { clear(); } @@ -77,17 +73,25 @@ } bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index, - uint32_t &Result) const { - // FIXME: string offset section entries are 8-byte for DWARF64. - const uint32_t ItemSize = 4; - uint32_t Offset = Index * ItemSize; - if (StringOffsetSection.size() < Offset + ItemSize) + uint64_t &Result) const { + unsigned ItemSize = getFormat() == DWARF64 ? 8 : 4; + uint32_t Offset = StringOffsetSectionBase + Index * ItemSize; + if (StringOffsetSection.Data.size() < Offset + ItemSize) return false; - DataExtractor DA(StringOffsetSection, isLittleEndian, 0); - Result = DA.getU32(&Offset); + DataExtractor DA(StringOffsetSection.Data, isLittleEndian, 0); + Result = ItemSize == 4 ? DA.getU32(&Offset) : DA.getU64(&Offset); return true; } +uint64_t DWARFUnit::getStringOffsetSectionRelocation(uint32_t Index) const { + unsigned ItemSize = getFormat() == DWARF64 ? 8 : 4; + uint64_t ByteOffset = StringOffsetSectionBase + Index * ItemSize; + RelocAddrMap::const_iterator AI = getStringOffsetsRelocMap().find(ByteOffset); + if (AI != getStringOffsetsRelocMap().end()) + return AI->second.Value; + return 0; +} + bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); @@ -119,6 +123,9 @@ if (!LengthOK || !VersionOK || !AddrSizeOK) return false; + // Keep track of the highest DWARF version we encounter across all units. + Context.setMaxVersionIfGreater(Version); + Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); return Abbrevs != nullptr; } @@ -242,6 +249,17 @@ setBaseAddress(*BaseAddr); AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0); RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); + + // In general, we derive the offset of the unit's contibution to the + // debug_str_offsets{.dwo} section from the unit DIE's + // DW_AT_str_offsets_base attribute. In dwp files we add to it the offset + // we get from the index table. + StringOffsetSectionBase = + toSectionOffset(UnitDie.find(DW_AT_str_offsets_base), 0); + if (IndexEntry) + if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) + StringOffsetSectionBase += C->Offset; + // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for // skeleton CU DIE, so that DWARF users not aware of it are not broken. } Index: lib/MC/MCObjectFileInfo.cpp =================================================================== --- lib/MC/MCObjectFileInfo.cpp +++ lib/MC/MCObjectFileInfo.cpp @@ -241,6 +241,9 @@ DwarfStrSection = Ctx->getMachOSection("__DWARF", "__debug_str", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "info_string"); + DwarfStrOffSection = + Ctx->getMachOSection("__DWARF", "__debug_str_offs", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "section_str_off"); DwarfLocSection = Ctx->getMachOSection("__DWARF", "__debug_loc", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "section_debug_loc"); @@ -557,6 +560,11 @@ DwarfAccelTypesSection = Ctx->getELFSection(".apple_types", ELF::SHT_PROGBITS, 0); + // String Offset and Address Sections + DwarfStrOffSection = + Ctx->getELFSection(".debug_str_offsets", DebugSecType, 0); + DwarfAddrSection = Ctx->getELFSection(".debug_addr", DebugSecType, 0); + // Fission Sections DwarfInfoDWOSection = Ctx->getELFSection(".debug_info.dwo", DebugSecType, 0); @@ -573,7 +581,6 @@ Ctx->getELFSection(".debug_loc.dwo", DebugSecType, 0); DwarfStrOffDWOSection = Ctx->getELFSection(".debug_str_offsets.dwo", DebugSecType, 0); - DwarfAddrSection = Ctx->getELFSection(".debug_addr", DebugSecType, 0); // DWP Sections DwarfCUIndexSection = @@ -695,6 +702,11 @@ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata(), "info_string"); + DwarfStrOffSection = Ctx->getCOFFSection( + ".debug_str_offsets", + COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata(), "section_str_off"); DwarfLocSection = Ctx->getCOFFSection( ".debug_loc", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | @@ -749,7 +761,7 @@ ".debug_str_offsets.dwo", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, - SectionKind::getMetadata()); + SectionKind::getMetadata(), "section_str_off_dwo"); DwarfAddrSection = Ctx->getCOFFSection( ".debug_addr", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | Index: lib/Object/MachOObjectFile.cpp =================================================================== --- lib/Object/MachOObjectFile.cpp +++ lib/Object/MachOObjectFile.cpp @@ -4310,3 +4310,9 @@ return make_error("Unrecognized MachO magic number", object_error::invalid_file_type); } + +StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const { + return StringSwitch(Name) + .Case("debug_str_offs", "debug_str_offsets") + .Default(Name); +} Index: test/DebugInfo/Inputs/dwarfdump-str-offsets-dwp.s =================================================================== --- test/DebugInfo/Inputs/dwarfdump-str-offsets-dwp.s +++ test/DebugInfo/Inputs/dwarfdump-str-offsets-dwp.s @@ -0,0 +1,277 @@ +# Test object to verify that dwarfdump handles dwp files with DWARF v5 string +# offset tables. We have 2 CUs and 2 TUs, where it is assumed that +# CU1 and TU1 came from one object file, CU2 and TU2 from a second object +# file. +# +# To generate the test object: +# llvm-mc -triple x86_64-unknown-linux dwarfdump-str-offsets-dwp.s -filetype=obj \ +# -o dwarfdump-str_offsets-dwp.x86_64.o + + .section .debug_str.dwo,"MS",@progbits,1 +str_producer: + .asciz "Handmade DWARF producer" +str_CU1: + .asciz "Compile_Unit_1" +str_CU1_dir: + .asciz "/home/test/CU1" +str_CU2: + .asciz "Compile_Unit_2" +str_CU2_dir: + .asciz "/home/test/CU2" +str_TU1: + .asciz "Type_Unit_1" +str_TU1_type: + .asciz "MyStruct_1" +str_TU2: + .asciz "Type_Unit_2" +str_TU2_type: + .asciz "MyStruct_2" + + .section .debug_str_offsets.dwo,"",@progbits +# Object files 1's portion of the .debug_str_offsets.dwo section. +.debug_str_offsets_object_file1: + +# CU1's contribution (from object file 1) +.debug_str_offsets_start_CU1: + .long .debug_str_offsets_end_CU1-.debug_str_offsets_base_CU1 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base_CU1: + .long str_producer-.debug_str.dwo + .long str_CU1-.debug_str.dwo + .long str_CU1_dir-.debug_str.dwo +.debug_str_offsets_end_CU1: + +# TU1's contribution (from object file 1) +.debug_str_offsets_start_TU1: + .long .debug_str_offsets_end_TU1-.debug_str_offsets_base_TU1 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base_TU1: + .long str_TU1-.debug_str.dwo + .long str_TU1_type-.debug_str.dwo +.debug_str_offsets_end_TU1: + +# Object files 2's portion of the .debug_str_offsets.dwo section. +.debug_str_offsets_object_file2: + +# CU2's contribution (from object file 2) +.debug_str_offsets_start_CU2: + .long .debug_str_offsets_end_CU2-.debug_str_offsets_base_CU2 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base_CU2: + .long str_producer-.debug_str.dwo + .long str_CU2-.debug_str.dwo + .long str_CU2_dir-.debug_str.dwo +.debug_str_offsets_end_CU2: + +# TU2's contribution (from object file 2) +.debug_str_offsets_start_TU2: + .long .debug_str_offsets_end_TU2-.debug_str_offsets_base_TU2 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base_TU2: + .long str_TU2-.debug_str.dwo + .long str_TU2_type-.debug_str.dwo +.debug_str_offsets_end_TU2: + + +# Abbrevs are shared for all compile and type units + .section .debug_abbrev.dwo,"",@progbits + .byte 0x01 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x00 # DW_CHILDREN_no + .byte 0x25 # DW_AT_producer + .byte 0x1a # DW_FORM_strx + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x72 # DW_AT_str_offsets_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x02 # Abbrev code + .byte 0x41 # DW_TAG_type_unit + .byte 0x01 # DW_CHILDREN_yes + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x72 # DW_AT_str_offsets_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x03 # Abbrev code + .byte 0x13 # DW_TAG_structure_type + .byte 0x00 # DW_CHILDREN_no (no members) + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) +abbrev_end: + + .section .debug_info.dwo,"",@progbits + +# DWARF v5 CU header. +CU1_5_start: + .long CU1_5_end-CU1_5_version # Length of Unit +CU1_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev.dwo # Offset Into Abbrev. Section +# The compile-unit DIE, which has a DW_AT_producer, DW_AT_name, +# DW_AT_str_offsets and DW_AT_compdir. + .byte 1 # Abbreviation code + .byte 0 # The index of the producer string + .byte 1 # The index of the CU name string +# The DW_AT_str_offsets_base attribute for CU1 contains the offset of CU1's +# contribution relative to the start of object file 1's portion of the +# .debug_str_offsets section. + .long .debug_str_offsets_base_CU1-.debug_str_offsets_object_file1 + .byte 2 # The index of the comp dir string + .byte 0 # NULL +CU1_5_end: + +CU2_5_start: + .long CU2_5_end-CU2_5_version # Length of Unit +CU2_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev.dwo # Offset Into Abbrev. Section +# The compile-unit DIE, which has a DW_AT_producer, DW_AT_name, +# DW_AT_str_offsets and DW_AT_compdir. + .byte 1 # Abbreviation code + .byte 0 # The index of the producer string + .byte 1 # The index of the CU name string +# The DW_AT_str_offsets_base attribute for CU2 contains the offset of CU2's +# contribution relative to the start of object file 2's portion of the +# .debug_str_offsets section. + .long .debug_str_offsets_base_CU2-.debug_str_offsets_object_file2 + .byte 2 # The index of the comp dir string + .byte 0 # NULL +CU2_5_end: + + .section .debug_types.dwo,"",@progbits +# DWARF v5 Type unit header. +TU1_5_start: + .long TU1_5_end-TU1_5_version # Length of Unit +TU1_5_version: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev.dwo # Offset Into Abbrev. Section + .quad 0x0011223344556677 # Type Signature + .long TU1_5_type-TU1_5_start # Type offset +# The type-unit DIE, which has a name. + .byte 2 # Abbreviation code + .byte 0 # Index of the unit type name string +# The DW_AT_str_offsets_base attribute for TU1 contains the offset of TU1's +# contribution relative to the start of object file 1's portion of the +# .debug_str_offsets section. + .long .debug_str_offsets_base_TU1-.debug_str_offsets_object_file1 +# The type DIE, which has a name. +TU1_5_type: + .byte 3 # Abbreviation code + .byte 1 # Index of the type name string + .byte 0 # NULL + .byte 0 # NULL +TU1_5_end: + +TU2_5_start: + .long TU2_5_end-TU2_5_version # Length of Unit +TU2_5_version: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev.dwo # Offset Into Abbrev. Section + .quad 0x00aabbccddeeff99 # Type Signature + .long TU2_5_type-TU2_5_start # Type offset +# The type-unit DIE, which has a name. + .byte 2 # Abbreviation code + .byte 0 # Index of the unit type name string +# The DW_AT_str_offsets_base attribute for TU2 contains the offset of TU2's +# contribution relative to the start of object file 2's portion of the +# .debug_str_offsets section. + .long .debug_str_offsets_base_TU2-.debug_str_offsets_object_file2 +# The type DIE, which has a name. +TU2_5_type: + .byte 3 # Abbreviation code + .byte 1 # Index of the type name string + .byte 0 # NULL + .byte 0 # NULL +TU2_5_end: + + .section .debug_cu_index,"",@progbits + # The index header + .long 2 # Version + .long 3 # Columns of contribution matrix + .long 2 # number of units + .long 2 # number of hash buckets in table + + # The signatures for both CUs. + .quad 0xddeeaaddbbaabbee # signature 1 + .quad 0xff00ffeeffaaff00 # signature 2 + # The indexes for both CUs. + .long 1 # index 1 + .long 2 # index 2 + # The sections to which both CUs contribute. + .long 1 # DW_SECT_INFO + .long 3 # DW_SECT_ABBREV + .long 6 # DW_SECT_STR_OFFSETS + + # The starting offsets of both CU's contributions to info, + # abbrev and string offsets table. + .long CU1_5_start-.debug_info.dwo + .long 0 + .long .debug_str_offsets_object_file1-.debug_str_offsets.dwo + .long CU2_5_start-.debug_info.dwo + .long 0 + .long .debug_str_offsets_object_file2-.debug_str_offsets.dwo + + # The lengths of both CU's contributions to info, abbrev and + # string offsets table. + .long CU1_5_end-CU1_5_start + .long abbrev_end-.debug_abbrev.dwo + .long .debug_str_offsets_end_CU1-.debug_str_offsets_start_CU1 + .long CU2_5_end-CU2_5_start + .long abbrev_end-.debug_abbrev.dwo + .long .debug_str_offsets_end_CU2-.debug_str_offsets_start_CU2 + + .section .debug_tu_index,"",@progbits + # The index header + .long 2 # Version + .long 3 # Columns of contribution matrix + .long 2 # number of units + .long 2 # number of hash buckets in table + + # The signatures for both TUs. + .quad 0xeeaaddbbaabbeedd # signature 1 + .quad 0x00ffeeffaaff00ff # signature 2 + # The indexes for both TUs. + .long 1 # index 1 + .long 2 # index 2 + # The sections to which both TUs contribute. + .long 2 # DW_SECT_TYPES + .long 3 # DW_SECT_ABBREV + .long 6 # DW_SECT_STR_OFFSETS + + # The starting offsets of both TU's contributions to info, + # abbrev and string offsets table. + .long TU1_5_start-.debug_types.dwo + .long 0 + .long .debug_str_offsets_object_file1-.debug_str_offsets.dwo + .long TU2_5_start-.debug_types.dwo + .long 0 + .long .debug_str_offsets_object_file2-.debug_str_offsets.dwo + + # The lengths of both TU's contributions to info, abbrev and + # string offsets table. + .long TU1_5_end-TU1_5_start + .long abbrev_end-.debug_abbrev.dwo + .long .debug_str_offsets_end_TU1-.debug_str_offsets_start_TU1 + .long TU2_5_end-TU2_5_start + .long abbrev_end-.debug_abbrev.dwo + .long .debug_str_offsets_end_TU2-.debug_str_offsets_start_TU2 Index: test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-1.s =================================================================== --- test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-1.s +++ test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-1.s @@ -0,0 +1,11 @@ +# Test object to verify that llvm-dwarfdump handles an invalid string offsets +# table. +# +# To generate the test object: +# llvm-mc -triple x86_64-unknown-linux dwarfdump-str-offsets-invalid-1.s -filetype=obj \ +# -o dwarfdump-str-offsets-invalid-1.elf-x86-64 + +# Every unit contributes to the string_offsets table. + .section .debug_str_offsets,"",@progbits +# A degenerate section, not enough for a single contribution size. + .byte 2 Index: test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-2.s =================================================================== --- test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-2.s +++ test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-2.s @@ -0,0 +1,13 @@ +# Test object to verify that llvm-dwarfdump handles an invalid string offsets +# table. +# +# To generate the test object: +# llvm-mc -triple x86_64-unknown-linux dwarfdump-str-offsets-invalid-2.s -filetype=obj \ +# -o dwarfdump-str-offsets-invalid-2.x86_64.o + +# Every unit contributes to the string_offsets table. + .section .debug_str_offsets,"",@progbits +# A degenerate section with fewer bytes than required for a DWARF64 size. + .long 0xffffffff + .long 0 + .short 4 Index: test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-3.s =================================================================== --- test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-3.s +++ test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-3.s @@ -0,0 +1,65 @@ +# Test object to verify that llvm-dwarfdump handles an invalid string offsets +# table. +# +# To generate the test object: +# llvm-mc -triple x86_64-unknown-linux dwarfdump-str-offsets-invalid-3.s -filetype=obj \ +# -o dwarfdump-str-offsets-invalid-3.x86_64.o + + .section .debug_str,"MS",@progbits,1 +str_producer: + .asciz "Handmade DWARF producer" +str_CU1: + .asciz "Compile_Unit_1" +str_CU1_dir: + .asciz "/home/test/CU1" +str_CU2: + .asciz "Compile_Unit_2" +str_CU2_dir: + .asciz "/home/test/CU2" +str_TU: + .asciz "Type_Unit" +str_TU_type: + .asciz "MyStruct" + + .section .debug_str.dwo,"MS",@progbits,1 +dwo_str_CU_5_producer: + .asciz "Handmade split DWARF producer" +dwo_str_CU_5_name: + .asciz "V5_split_compile_unit" +dwo_str_CU_5_comp_dir: + .asciz "/home/test/splitCU" +dwo_str_TU_5: + .asciz "V5_split_type_unit" +dwo_str_TU_5_type: + .asciz "V5_split_Mystruct" + +# Every unit contributes to the string_offsets table. + .section .debug_str_offsets,"",@progbits +# CU1's contribution +# Invalid length + .long 0xfffffffe + .long .debug_str_offsets_segment0_end-.debug_str_offsets_base0 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base0: + .long str_producer + .long str_CU1 + .long str_CU1_dir +.debug_str_offsets_segment0_end: +# CU2's contribution + .long .debug_str_offsets_segment1_end-.debug_str_offsets_base1 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base1: + .long str_producer + .long str_CU2 + .long str_CU2_dir +.debug_str_offsets_segment1_end: +# The TU's contribution + .long .debug_str_offsets_segment2_end-.debug_str_offsets_base2 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base2: + .long str_TU + .long str_TU_type +.debug_str_offsets_segment2_end: Index: test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-4.s =================================================================== --- test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-4.s +++ test/DebugInfo/Inputs/dwarfdump-str-offsets-invalid-4.s @@ -0,0 +1,26 @@ +# Test object to verify that llvm-dwarfdump handles an invalid string offsets +# table. +# +# To generate the test object: +# llvm-mc -triple x86_64-unknown-linux dwarfdump-str-offsets-invalid-4.s -filetype=obj \ +# -o dwarfdump-str-offsets-invalid-4.x86_64.o + + .section .debug_str,"MS",@progbits,1 +str_producer: + .asciz "Handmade DWARF producer" +str_CU1: + .asciz "Compile_Unit_1" + +# Every unit contributes to the string_offsets table. + .section .debug_str_offsets,"",@progbits +# CU1's contribution +# The length is not a multiple of 4. Check that we don't read off the +# end. + .long .debug_str_offsets_segment0_end-.debug_str_offsets_base0 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base0: + .long str_producer + .long str_CU1 + .byte 0 +.debug_str_offsets_segment0_end: Index: test/DebugInfo/Inputs/dwarfdump-str-offsets.s =================================================================== --- test/DebugInfo/Inputs/dwarfdump-str-offsets.s +++ test/DebugInfo/Inputs/dwarfdump-str-offsets.s @@ -0,0 +1,250 @@ +# Test object to verify dwarfdump handles v5 string offset tables. +# We have 2 v5 CUs, a v5 TU, and a split v5 CU and TU. +# +# To generate the test object: +# llvm-mc -triple x86_64-unknown-linux dwarfdump-str-offsets.s -filetype=obj \ +# -o dwarfdump-str-offsets.x86_64.o + + .section .debug_str,"MS",@progbits,1 +str_producer: + .asciz "Handmade DWARF producer" +str_CU1: + .asciz "Compile_Unit_1" +str_CU1_dir: + .asciz "/home/test/CU1" +str_CU2: + .asciz "Compile_Unit_2" +str_CU2_dir: + .asciz "/home/test/CU2" +str_TU: + .asciz "Type_Unit" +str_TU_type: + .asciz "MyStruct" + +# Every unit contributes to the string_offsets table. + .section .debug_str_offsets,"",@progbits +# CU1's contribution + .long .debug_str_offsets_segment0_end-.debug_str_offsets_base0 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base0: + .long str_producer + .long str_CU1 + .long str_CU1_dir +.debug_str_offsets_segment0_end: +# CU2's contribution + .long .debug_str_offsets_segment1_end-.debug_str_offsets_base1 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base1: + .long str_producer + .long str_CU2 + .long str_CU2_dir +.debug_str_offsets_segment1_end: +# The TU's contribution + .long .debug_str_offsets_segment2_end-.debug_str_offsets_base2 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base2: + .long str_TU + .long str_TU_type +.debug_str_offsets_segment2_end: + + .section .debug_str.dwo,"MS",@progbits,1 +dwo_str_CU_5_producer: + .asciz "Handmade split DWARF producer" +dwo_str_CU_5_name: + .asciz "V5_split_compile_unit" +dwo_str_CU_5_comp_dir: + .asciz "/home/test/splitCU" +dwo_str_TU_5: + .asciz "V5_split_type_unit" +dwo_str_TU_5_type: + .asciz "V5_split_Mystruct" + + .section .debug_str_offsets.dwo,"",@progbits +# The split CU's contribution + .long .debug_dwo_str_offsets_segment0_end-.debug_dwo_str_offsets_base0 + .short 5 # DWARF version + .short 0 # Padding +.debug_dwo_str_offsets_base0: + .long dwo_str_CU_5_producer-.debug_str.dwo + .long dwo_str_CU_5_name-.debug_str.dwo + .long dwo_str_CU_5_comp_dir-.debug_str.dwo +.debug_dwo_str_offsets_segment0_end: +# The split TU's contribution + .long .debug_dwo_str_offsets_segment1_end-.debug_dwo_str_offsets_base1 + .short 5 # DWARF version + .short 0 # Padding +.debug_dwo_str_offsets_base1: + .long dwo_str_TU_5-.debug_str.dwo + .long dwo_str_TU_5_type-.debug_str.dwo +.debug_dwo_str_offsets_segment1_end: + +# All CUs/TUs use the same abbrev section for simplicity. + .section .debug_abbrev,"",@progbits + .byte 0x01 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x00 # DW_CHILDREN_no + .byte 0x25 # DW_AT_producer + .byte 0x1a # DW_FORM_strx + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x72 # DW_AT_str_offsets_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x1b # DW_AT_comp_dir + .byte 0x1a # DW_FORM_strx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x02 # Abbrev code + .byte 0x41 # DW_TAG_type_unit + .byte 0x01 # DW_CHILDREN_yes + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x72 # DW_AT_str_offsets_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x03 # Abbrev code + .byte 0x13 # DW_TAG_structure_type + .byte 0x00 # DW_CHILDREN_no (no members) + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) + +# And a .dwo copy for the .dwo sections. + .section .debug_abbrev.dwo,"",@progbits + .byte 0x01 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x00 # DW_CHILDREN_no + .byte 0x25 # DW_AT_producer + .byte 0x1a # DW_FORM_strx + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x72 # DW_AT_str_offsets_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x1b # DW_AT_comp_dir + .byte 0x1a # DW_FORM_strx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x02 # Abbrev code + .byte 0x41 # DW_TAG_type_unit + .byte 0x01 # DW_CHILDREN_yes + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x72 # DW_AT_str_offsets_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x03 # Abbrev code + .byte 0x13 # DW_TAG_structure_type + .byte 0x00 # DW_CHILDREN_no (no members) + .byte 0x03 # DW_AT_name + .byte 0x1a # DW_FORM_strx + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) + + .section .debug_info,"",@progbits + +# DWARF v5 CU header. + .long CU1_5_end-CU1_5_version # Length of Unit +CU1_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has a DW_AT_producer, DW_AT_name, +# DW_AT_str_offsets and DW_AT_compdir. + .byte 1 # Abbreviation code + .byte 0 # The index of the producer string + .byte 1 # The index of the CU name string + .long .debug_str_offsets_base0 + .byte 2 # The index of the comp dir string + .byte 0 # NULL +CU1_5_end: + +# DWARF v5 CU header + .long CU2_5_end-CU2_5_version # Length of Unit +CU2_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has a DW_AT_producer, DW_AT_name, +# DW_AT_str_offsets and DW_AT_compdir. + .byte 1 # Abbreviation code + .byte 0 # The index of the producer string + .byte 1 # The index of the CU name string + .long .debug_str_offsets_base1 + .byte 2 # The index of the comp dir string + .byte 0 # NULL +CU2_5_end: + + .section .debug_types,"",@progbits +# DWARF v5 Type unit header. +TU_5_start: + .long TU_5_end-TU_5_version # Length of Unit +TU_5_version: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad 0x0011223344556677 # Type Signature + .long TU_5_type-TU_5_start # Type offset +# The type-unit DIE, which has a name. + .byte 2 # Abbreviation code + .byte 0 # Index of the unit type name string + .long .debug_str_offsets_base2 # offset into the str_offsets section +# The type DIE, which has a name. +TU_5_type: + .byte 3 # Abbreviation code + .byte 1 # Index of the type name string + .byte 0 # NULL + .byte 0 # NULL +TU_5_end: + + .section .debug_info.dwo,"",@progbits + +# DWARF v5 split CU header. + .long CU_split_5_end-CU_split_5_version # Length of Unit +CU_split_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev.dwo # Offset Into Abbrev Section +# The compile-unit DIE, which has a DW_AT_producer, DW_AT_name, +# DW_AT_str_offsets and DW_AT_compdir. + .byte 1 # Abbreviation code + .byte 0 # The index of the producer string + .byte 1 # The index of the CU name string + .long .debug_dwo_str_offsets_base0-.debug_str_offsets.dwo + .byte 2 # The index of the comp dir string + .byte 0 # NULL +CU_split_5_end: + + .section .debug_types.dwo,"",@progbits + +# DWARF v5 split type unit header. +TU_split_5_start: + .long TU_split_5_end-TU_split_5_version # Length of Unit +TU_split_5_version: + .short 5 # DWARF version number + .byte 6 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev.dwo # Offset Into Abbrev Section + .quad 0x8899aabbccddeeff # Type Signature + .long TU_split_5_type-TU_split_5_start # Type offset +# The type-unit DIE, which has a name. + .byte 2 # Abbreviation code + .byte 0 # The index of the type unit name string + .long .debug_dwo_str_offsets_base1-.debug_str_offsets.dwo +# The type DIE, which has a name. +TU_split_5_type: + .byte 3 # Abbreviation code + .byte 1 # The index of the type name string + .byte 0 # NULL + .byte 0 # NULL +TU_split_5_end: Index: test/DebugInfo/dwarfdump-str-offsets-invalid.test =================================================================== --- test/DebugInfo/dwarfdump-str-offsets-invalid.test +++ test/DebugInfo/dwarfdump-str-offsets-invalid.test @@ -0,0 +1,9 @@ +; Verify that llvm-dwarfdump handles invalid string offset tables. + +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-str-offsets-invalid-1.x86_64.o | FileCheck %s +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-str-offsets-invalid-2.x86_64.o | FileCheck %s +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-str-offsets-invalid-3.x86_64.o | FileCheck %s +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-str-offsets-invalid-4.x86_64.o | FileCheck %s + +CHECK: .debug_str_offsets contents: +CHECK-NOT: 0x[0-9a-f]* Index: test/DebugInfo/dwarfdump-str-offsets.test =================================================================== --- test/DebugInfo/dwarfdump-str-offsets.test +++ test/DebugInfo/dwarfdump-str-offsets.test @@ -0,0 +1,76 @@ +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-str-offsets.x86_64.o | FileCheck %s + +; We are using a hand-constructed object file and are interest in the correct +; diplay of the DW_str_offsetsbase attribute, the correct display of strings +; and the dump of the .debug_str_offsets[.dwo] table. +; +; Abbreviation for DW_AT_str_offsets_base +CHECK: .debug_abbrev contents: +CHECK-NOT: contents: +CHECK: DW_TAG_compile_unit +CHECK-NOT: DW_TAG +CHECK: DW_AT_str_offsets_base DW_FORM_sec_offset + +; Verify that strings are displayed correctly as indexed strings +CHECK: .debug_info contents: +CHECK-NOT: contents: +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer [DW_FORM_strx] ( indexed (00000000) string = "Handmade DWARF producer") +CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "Compile_Unit_1") +CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strx] ( indexed (00000002) string = "/home/test/CU1") + +; Second compile unit (b.cpp) +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer [DW_FORM_strx] ( indexed (00000000) string = "Handmade DWARF producer") +CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "Compile_Unit_2") +CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x0000001c) +CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strx] ( indexed (00000002) string = "/home/test/CU2") + +; The split CU +CHECK: .debug_info.dwo contents: +CHECK-NOT: contents: +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer [DW_FORM_strx] ( indexed (00000000) string = "Handmade split DWARF producer") +CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "V5_split_compile_unit") +CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strx] ( indexed (00000002) string = "/home/test/splitCU") + +; The type unit +CHECK: .debug_types contents: +CHECK: DW_TAG_type_unit +CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000000) string = "Type_Unit") +CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000030) +CHECK: DW_TAG_structure_type +CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "MyStruct") + +; The split type unit +CHECK: .debug_types.dwo contents: +CHECK: DW_TAG_type_unit +CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000000) string = "V5_split_type_unit") +CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x0000001c) +CHECK: DW_TAG_structure_type +CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "V5_split_Mystruct") + +; The .debug_str_offsets section +CHECK: .debug_str_offsets contents: +CHECK-NEXT: 0x00000000: Contribution size = 12, Version = 5 +CHECK-NEXT: 0x00000008: 00000000 +CHECK-NEXT: 0x0000000c: 00000018 +CHECK-NEXT: 0x00000010: 00000027 +CHECK-NEXT: 0x00000014: Contribution size = 12, Version = 5 +CHECK-NEXT: 0x0000001c: 00000000 +CHECK-NEXT: 0x00000020: 00000036 +CHECK-NEXT: 0x00000024: 00000045 +CHECK-NEXT: 0x00000028: Contribution size = 8, Version = 5 +CHECK-NEXT: 0x00000030: 00000054 +CHECK-NEXT: 0x00000034: 0000005e + +CHECK: .debug_str_offsets.dwo contents: +CHECK-NEXT: 0x00000000: Contribution size = 12, Version = 5 +CHECK-NEXT: 0x00000008: 00000000 +CHECK-NEXT: 0x0000000c: 0000001e +CHECK-NEXT: 0x00000010: 00000034 +CHECK-NEXT: 0x00000014: Contribution size = 8, Version = 5 +CHECK-NEXT: 0x0000001c: 00000047 +CHECK-NEXT: 0x00000020: 0000005a Index: tools/llvm-dwarfdump/llvm-dwarfdump.cpp =================================================================== --- tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -67,6 +67,7 @@ clEnumValN(DIDT_GnuPubnames, "gnu_pubnames", ".debug_gnu_pubnames"), clEnumValN(DIDT_GnuPubtypes, "gnu_pubtypes", ".debug_gnu_pubtypes"), clEnumValN(DIDT_Str, "str", ".debug_str"), + clEnumValN(DIDT_StrOffsets, "str_offsets", ".debug_str_offsets"), clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"), clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", ".debug_str_offsets.dwo"), Index: tools/obj2yaml/dwarf2yaml.cpp =================================================================== --- tools/obj2yaml/dwarf2yaml.cpp +++ tools/obj2yaml/dwarf2yaml.cpp @@ -203,6 +203,7 @@ case dwarf::DW_FORM_line_strp: case dwarf::DW_FORM_strp_sup: case dwarf::DW_FORM_GNU_str_index: + case dwarf::DW_FORM_strx: if (auto Val = FormValue.getValue().getAsCStringOffset()) NewValue.Value = Val.getValue(); break;