Index: include/llvm/CodeGen/DIE.h =================================================================== --- include/llvm/CodeGen/DIE.h +++ include/llvm/CodeGen/DIE.h @@ -264,6 +264,27 @@ }; //===--------------------------------------------------------------------===// +/// A container for string pool string values indexed by a unit-specific index. +/// +/// This class is used with the DW_FORM_strx form. +class DIEIndexedString { + DwarfStringPoolEntryRef S; + unsigned Index; + +public: + DIEIndexedString(const DwarfStringPoolEntryRef S, unsigned Ix) + : S(S), Index(Ix) {} + + StringRef getString() const { return S.getString(); } + unsigned getIndex() const { return Index; } + + void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const; + unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const; + + void print(raw_ostream &O) const; +}; + +//===--------------------------------------------------------------------===// /// A container for inline string values. /// /// This class is used with the DW_FORM_string form. Index: include/llvm/CodeGen/DIEValue.def =================================================================== --- include/llvm/CodeGen/DIEValue.def +++ include/llvm/CodeGen/DIEValue.def @@ -41,6 +41,7 @@ HANDLE_DIEVALUE_LARGE(Loc) HANDLE_DIEVALUE_SMALL(LocList) HANDLE_DIEVALUE_LARGE(InlineString) +HANDLE_DIEVALUE_LARGE(IndexedString) #undef HANDLE_DIEVALUE #undef HANDLE_DIEVALUE_SMALL Index: include/llvm/CodeGen/DwarfStringPoolEntry.h =================================================================== --- include/llvm/CodeGen/DwarfStringPoolEntry.h +++ include/llvm/CodeGen/DwarfStringPoolEntry.h @@ -44,6 +44,9 @@ bool operator==(const DwarfStringPoolEntryRef &X) const { return I == X.I; } bool operator!=(const DwarfStringPoolEntryRef &X) const { return I != X.I; } + bool operator<(const DwarfStringPoolEntryRef &X) const { + return getIndex() < X.getIndex(); + } }; } // end namespace llvm 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,9 @@ public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, - bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, + StringRef SS, const DWARFSection &SOS, StringRef 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, UnitSection, Entry) {} Index: include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFContext.h +++ include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -78,6 +78,9 @@ std::unique_ptr AbbrevDWO; std::unique_ptr LocDWO; + /// The maximum DWARF version of all units. + unsigned MaxVersion; + /// Read compile units from the debug_info section (if necessary) /// and store them in CUs. void parseCompileUnits(); @@ -95,7 +98,7 @@ void parseDWOTypeUnits(); public: - DWARFContext() : DIContext(CK_DWARF) {} + DWARFContext() : DIContext(CK_DWARF), MaxVersion(0) {} DWARFContext(DWARFContext &) = delete; DWARFContext &operator=(DWARFContext &) = delete; @@ -170,6 +173,13 @@ return DWOCUs[index].get(); } + unsigned getMaxVersion() const { return MaxVersion; } + + void setMaxVersionIfGreater(unsigned Version) { + if (Version > MaxVersion) + MaxVersion = Version; + } + const DWARFUnitIndex &getCUIndex(); DWARFGdbIndex &getGdbIndex(); const DWARFUnitIndex &getTUIndex(); @@ -228,6 +238,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; @@ -235,7 +250,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 StringRef getAddrSection() = 0; virtual const DWARFSection& getAppleNamesSection() = 0; @@ -283,6 +298,11 @@ StringRef GnuPubNamesSection; StringRef GnuPubTypesSection; + /// DWARF v5 + /// @{ + DWARFSection StringOffsetSection; + /// @} + // Sections for DWARF5 split dwarf proposal. DWARFSection InfoDWOSection; TypeSectionMap TypesDWOSections; @@ -290,7 +310,7 @@ DWARFSection LineDWOSection; DWARFSection LocDWOSection; StringRef StringDWOSection; - StringRef StringOffsetDWOSection; + DWARFSection StringOffsetDWOSection; DWARFSection RangeDWOSection; StringRef AddrSection; DWARFSection AppleNamesSection; @@ -335,6 +355,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; } @@ -347,7 +372,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,8 +31,9 @@ public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, - bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, + StringRef SS, const DWARFSection &SOS, StringRef 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, UnitSection, Entry) {} Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -57,7 +57,7 @@ virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, StringRef AOS, + StringRef SS, const DWARFSection &SOS, StringRef AOS, StringRef LS, bool isLittleEndian, bool isDWO) = 0; }; @@ -89,8 +89,8 @@ private: void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, - bool LE, bool IsDWO) override { + StringRef SS, const DWARFSection &SOS, StringRef AOS, + StringRef LS, bool LE, bool IsDWO) override { if (Parsed) return; const auto &Index = getDWARFUnitIndex(Context, UnitType::Section); @@ -119,7 +119,8 @@ uint32_t RangeSectionBase; StringRef LineSection; StringRef StringSection; - StringRef StringOffsetSection; + const DWARFSection &StringOffsetSection; + uint64_t StringOffsetSectionBase; StringRef AddrOffsetSection; uint32_t AddrOffsetSectionBase; bool isLittleEndian; @@ -172,8 +173,8 @@ public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO, - const DWARFUnitSectionBase &UnitSection, + const DWARFSection &SOS, StringRef AOS, StringRef LS, bool LE, + bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry = nullptr); virtual ~DWARFUnit(); @@ -182,7 +183,9 @@ StringRef getLineSection() const { return LineSection; } StringRef getStringSection() const { return StringSection; } - StringRef getStringOffsetSection() const { return StringOffsetSection; } + const DWARFSection &getStringOffsetSection() const { + return StringOffsetSection; + } void setAddrOffsetSection(StringRef AOS, uint32_t Base) { AddrOffsetSection = AOS; @@ -199,7 +202,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); @@ -210,6 +214,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 @@ -286,9 +286,12 @@ } virtual std::error_code - getBuildAttributes(ARMAttributeParser &Attributes) const { - return std::error_code(); - } + getBuildAttributes(ARMAttributeParser &Attributes) const { + 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/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIE.cpp +++ lib/CodeGen/AsmPrinter/DIE.cpp @@ -410,6 +410,7 @@ case dwarf::DW_FORM_GNU_str_index: case dwarf::DW_FORM_GNU_addr_index: case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_strx: case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return; @@ -469,6 +470,7 @@ case dwarf::DW_FORM_GNU_str_index: case dwarf::DW_FORM_GNU_addr_index: case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_strx: case dwarf::DW_FORM_udata: return getULEB128Size(Integer); case dwarf::DW_FORM_sdata: @@ -610,6 +612,32 @@ } //===----------------------------------------------------------------------===// +// DIEIndexedString Implementation +//===----------------------------------------------------------------------===// + +void DIEIndexedString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { + assert((Form == dwarf::DW_FORM_strx || Form == dwarf::DW_FORM_strx1 || + Form == dwarf::DW_FORM_strx2 || Form == dwarf::DW_FORM_strx3 || + Form == dwarf::DW_FORM_strx4) && + "Expected valid indexed string form"); + DIEInteger(getIndex()).EmitValue(AP, Form); +} + +unsigned DIEIndexedString::SizeOf(const AsmPrinter *AP, + dwarf::Form Form) const { + assert((Form == dwarf::DW_FORM_strx || Form == dwarf::DW_FORM_strx1 || + Form == dwarf::DW_FORM_strx2 || Form == dwarf::DW_FORM_strx3 || + Form == dwarf::DW_FORM_strx4) && + "Expected valid indexed string form"); + return DIEInteger(getIndex()).SizeOf(AP, Form); +} + +LLVM_DUMP_METHOD +void DIEIndexedString::print(raw_ostream &O) const { + O << "IxString: Ix = " << getIndex() << " " << getString(); +} + +//===----------------------------------------------------------------------===// // DIEInlineString Implementation //===----------------------------------------------------------------------===// void DIEInlineString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { Index: lib/CodeGen/AsmPrinter/DIEHash.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIEHash.cpp +++ lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -34,8 +34,16 @@ // Iterate through all the attributes until we find the one we're // looking for, if we can't find it return an empty string. for (const auto &V : Die.values()) - if (V.getAttribute() == Attr) - return V.getDIEString().getString(); + if (V.getAttribute() == Attr) { + switch (V.getType()) { + case DIEValue::isString: + return V.getDIEString().getString(); + case DIEValue::isIndexedString: + return V.getDIEIndexedString().getString(); + default: + llvm_unreachable("Unknown string value type"); + } + } return StringRef(""); } @@ -330,6 +338,12 @@ addULEB128(dwarf::DW_FORM_string); addString(Value.getDIEString().getString()); break; + case DIEValue::isIndexedString: + addULEB128('A'); + addULEB128(Attribute); + addULEB128(dwarf::DW_FORM_string); + addString(Value.getDIEIndexedString().getString()); + break; case DIEValue::isInlineString: addULEB128('A'); addULEB128(Attribute); Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -112,10 +112,6 @@ void addLocalLabelAddress(DIE &Die, dwarf::Attribute Attribute, const MCSymbol *Label); - /// addSectionDelta - Add a label delta attribute data and value. - DIE::value_iterator addSectionDelta(DIE &Die, dwarf::Attribute Attribute, - const MCSymbol *Hi, const MCSymbol *Lo); - DwarfCompileUnit &getCU() override { return *this; } unsigned getOrCreateSourceID(StringRef FileName, StringRef DirName) override; @@ -136,12 +132,6 @@ void attachLowHighPC(DIE &D, const MCSymbol *Begin, const MCSymbol *End); - /// addSectionLabel - Add a Dwarf section label attribute data and value. - /// - DIE::value_iterator addSectionLabel(DIE &Die, dwarf::Attribute Attribute, - const MCSymbol *Label, - const MCSymbol *Sec); - /// \brief Find DIE for the given subprogram and attach appropriate /// DW_AT_low_pc and DW_AT_high_pc attributes. If there are global /// variables in this scope then create and insert DIEs for these Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -245,17 +245,6 @@ CURanges.back().setEnd(Range.getEnd()); } -DIE::value_iterator -DwarfCompileUnit::addSectionLabel(DIE &Die, dwarf::Attribute Attribute, - const MCSymbol *Label, const MCSymbol *Sec) { - if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) - return addLabel(Die, Attribute, - DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset - : dwarf::DW_FORM_data4, - Label); - return addSectionDelta(Die, Attribute, Label, Sec); -} - void DwarfCompileUnit::initStmtList() { // Define start line table label for each Compile Unit. MCSymbol *LineTableStartSym = @@ -380,15 +369,6 @@ FinalChildren.push_back(std::move(ScopeDIE)); } -DIE::value_iterator -DwarfCompileUnit::addSectionDelta(DIE &Die, dwarf::Attribute Attribute, - const MCSymbol *Hi, const MCSymbol *Lo) { - return Die.addValue(DIEValueAllocator, Attribute, - DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset - : dwarf::DW_FORM_data4, - new (DIEValueAllocator) DIEDelta(Hi, Lo)); -} - void DwarfCompileUnit::addScopeRangeList(DIE &ScopeDIE, SmallVector Range) { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -265,6 +265,9 @@ bool HasAppleExtensionAttributes; bool HasSplitDwarf; + /// Whether to use the DWARF v5 string offsets table. + bool UseSegmentedStringOffsetsTable; + /// Separated Dwarf Variables /// In general these will all be for bits that are left in the /// original object file, rather than things that are meant @@ -518,6 +521,16 @@ /// split dwarf proposal support. bool useSplitDwarf() const { return HasSplitDwarf; } + /// Returns whether to generate a string offsets table with contributions from + /// each CU and type unit. This implies the use of DW_FORM_strx* indirect + /// references with DWARF v5 and beyond. Note that DW_FORM_GNU_str_index is + /// also an indirect reference, but it is used with a pre-DWARF v5 + /// implementation of split DWARF sections, which uses a monolithic string + /// offsets table. + bool useSegmentedStringOffsetsTable() const { + return UseSegmentedStringOffsetsTable; + } + /// Returns the Dwarf Version. uint16_t getDwarfVersion() const; Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -276,6 +276,12 @@ // GDB does not fully support the DWARF 4 representation for bitfields. UseDWARF2Bitfields = (DwarfVersion < 4) || tuneForGDB(); + // The DWARF v5 string offsets table has contributions from each compile + // and type unit each preceded by a header. The string offsets + // table used by the pre-DWARF v5 split-DWARF implementation uses + // a monolithic string offsets table without any header. + UseSegmentedStringOffsetsTable = DwarfVersion >= 5; + Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); } @@ -424,6 +430,9 @@ DIUnit->getSourceLanguage()); NewCU.addString(Die, dwarf::DW_AT_name, FN); + if (useSegmentedStringOffsetsTable()) + NewCU.initStringOffsetsSegment(); + if (!useSplitDwarf()) { NewCU.initStmtList(); @@ -1896,6 +1905,9 @@ NewCU.initStmtList(); + if (useSegmentedStringOffsetsTable()) + NewCU.initStringOffsetsSegment(); + initSkeletonUnit(CU, NewCU.getUnitDie(), std::move(OwnedUnit)); return NewCU; @@ -1928,9 +1940,13 @@ // sections. void DwarfDebug::emitDebugStrDWO() { assert(useSplitDwarf() && "No split dwarf?"); - MCSection *OffSec = Asm->getObjFileLowering().getDwarfStrOffDWOSection(); - InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(), - OffSec); + if (useSegmentedStringOffsetsTable()) { + InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection()); + } else { + MCSection *OffSec = Asm->getObjFileLowering().getDwarfStrOffDWOSection(); + InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(), + OffSec); + } } MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) { @@ -1990,6 +2006,9 @@ NewTU.setSection(Asm->getObjFileLowering().getDwarfTypesSection(Signature)); } + if (useSegmentedStringOffsetsTable()) + NewTU.initStringOffsetsSegment(); + NewTU.setType(NewTU.createTypeDIE(CTy)); if (TopLevelType) { Index: lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -40,6 +40,11 @@ TheU->emitHeader(UseOffsets); Asm->emitDwarfDIE(Die); + + // Emit the unit's contribution to the string offsets table. + if (TheU->useSegmentedStringOffsetsTable()) { + TheU->emitStringOffsets(); + } } // Compute the size and offset for each DIE. Index: lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.h +++ lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/UniqueVector.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" #include "llvm/IR/DIBuilder.h" @@ -98,6 +99,14 @@ /// corresponds to the MDNode mapped with the subprogram DIE. DenseMap ContainingTypeMap; + /// DWARF v5: Keep track of strings that are referenced by this unit, so + /// we can build its contribution to the string offsets table. + UniqueVector Strings; + + /// DWARF v5: The symbol at the start of the unit's contribution to the string + /// offsets table. + MCSymbol *StringOffsetsStartSym; + DwarfUnit(dwarf::Tag, const DICompileUnit *CU, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU); @@ -271,6 +280,14 @@ /// call insertDIE if MD is not null. DIE &createAndAddDIE(unsigned Tag, DIE &Parent, const DINode *N = nullptr); + const UniqueVector &getStrings() const { + return Strings; + } + + bool useSegmentedStringOffsetsTable() const { + return DD->useSegmentedStringOffsetsTable(); + } + /// Compute the size of a header for this unit, not including the initial /// length field. virtual unsigned getHeaderSize() const { @@ -284,10 +301,25 @@ /// Emit the header for this unit, not including the initial length field. virtual void emitHeader(bool UseOffsets) = 0; + /// Prepare the unit's contribution to the string offsets section. + void initStringOffsetsSegment(); + + /// Emit the unit's contribution to the string offsets table. + void emitStringOffsets(); + virtual DwarfCompileUnit &getCU() = 0; void constructTypeDIE(DIE &Buffer, const DICompositeType *CTy); + /// Add a label delta attribute data and value. + DIE::value_iterator addSectionDelta(DIE &Die, dwarf::Attribute Attribute, + const MCSymbol *Hi, const MCSymbol *Lo); + + /// Add a Dwarf section label attribute data and value. + DIE::value_iterator addSectionLabel(DIE &Die, dwarf::Attribute Attribute, + const MCSymbol *Label, + const MCSymbol *Sec); + protected: ~DwarfUnit(); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -18,19 +18,20 @@ #include "DwarfExpression.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Metadata.h" -#include "llvm/MC/MachineLocation.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MachineLocation.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -75,8 +76,8 @@ DwarfUnit::DwarfUnit(dwarf::Tag UnitTag, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU) : DIEUnit(A->getDwarfVersion(), A->MAI->getCodePointerSize(), UnitTag), - CUNode(Node), Asm(A), DD(DW), DU(DWU), IndexTyDie(nullptr) { -} + CUNode(Node), Asm(A), DD(DW), DU(DWU), IndexTyDie(nullptr), + StringOffsetsStartSym(nullptr) {} DwarfTypeUnit::DwarfTypeUnit(DwarfCompileUnit &CU, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU, @@ -237,9 +238,19 @@ void DwarfUnit::addString(DIE &Die, dwarf::Attribute Attribute, StringRef String) { - Die.addValue(DIEValueAllocator, Attribute, - isDwoUnit() ? dwarf::DW_FORM_GNU_str_index : dwarf::DW_FORM_strp, - DIEString(DU->getStringPool().getEntry(*Asm, String))); + auto StringPoolEntry = DU->getStringPool().getEntry(*Asm, String); + if (useSegmentedStringOffsetsTable()) { + // FIXME: Use DW_FORM_strx{1,2,3,4} + unsigned Index = Strings.insert(StringPoolEntry) - 1; + Die.addValue(DIEValueAllocator, Attribute, dwarf::DW_FORM_strx, + new (DIEValueAllocator) + DIEIndexedString(StringPoolEntry, Index)); + } else { + Die.addValue(DIEValueAllocator, Attribute, + isDwoUnit() ? dwarf::DW_FORM_GNU_str_index + : dwarf::DW_FORM_strp, + DIEString(StringPoolEntry)); + } } DIEValueList::value_iterator DwarfUnit::addLabel(DIEValueList &Die, @@ -1573,6 +1584,29 @@ } } +void DwarfUnit::emitStringOffsets() { + assert(StringOffsetsStartSym && "No Start symbol for string offset segment"); + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + MCSection *StrOffSection = isDwoUnit() ? TLOF.getDwarfStrOffDWOSection() + : TLOF.getDwarfStrOffSection(); + Asm->OutStreamer->SwitchSection(StrOffSection); + unsigned EntrySize = 4; + // TODO: DWARF64 + // The header for the contribution contains the size of the contribution + // (not including the header) and the DWARF version. + Asm->EmitInt32(Strings.size() * EntrySize); + Asm->EmitInt16(Asm->getDwarfVersion()); + Asm->EmitInt16(0); + // Define the symbol that marks the start of the contribution and is + // referenced by the unit header (DW_AT_str_offsets_base). + Asm->OutStreamer->EmitLabel(StringOffsetsStartSym); + for (const auto &Entry : Strings) + if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections() || isDwoUnit()) + Asm->OutStreamer->EmitIntValue(Entry.getOffset(), EntrySize); + else + Asm->EmitLabelReference(Entry.getSymbol(), EntrySize, true); +} + void DwarfTypeUnit::emitHeader(bool UseOffsets) { DwarfUnit::emitCommonHeader(UseOffsets, DD->useSplitDwarf() ? dwarf::DW_UT_split_type @@ -1608,3 +1642,40 @@ return nullptr; return getSection()->getBeginSymbol(); } + +DIE::value_iterator DwarfUnit::addSectionDelta(DIE &Die, + dwarf::Attribute Attribute, + const MCSymbol *Hi, + const MCSymbol *Lo) { + return Die.addValue(DIEValueAllocator, Attribute, + DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset + : dwarf::DW_FORM_data4, + new (DIEValueAllocator) DIEDelta(Hi, Lo)); +} + +DIE::value_iterator DwarfUnit::addSectionLabel(DIE &Die, + dwarf::Attribute Attribute, + const MCSymbol *Label, + const MCSymbol *Sec) { + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) + return addLabel(Die, Attribute, + DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset + : dwarf::DW_FORM_data4, + Label); + return addSectionDelta(Die, Attribute, Label, Sec); +} + +/// DWARF v5: Create the symbol that designates the start of the string offset +/// table for this unit and add a reference to it to the unit DIE. +void DwarfUnit::initStringOffsetsSegment() { + StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base"); + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + if (isDwoUnit()) + addSectionDelta(getUnitDie(), dwarf::DW_AT_str_offsets_base, + StringOffsetsStartSym, + TLOF.getDwarfStrOffDWOSection()->getBeginSymbol()); + else + addSectionLabel(getUnitDie(), dwarf::DW_AT_str_offsets_base, + StringOffsetsStartSym, + TLOF.getDwarfStrOffSection()->getBeginSymbol()); +} Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -78,6 +78,67 @@ Accel.dump(OS); } +// Dump the DWARF v5 string offsets section. It consists of per-unit +// contributions (segments) 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; + // Perform validation and extract the segment size from the header. + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 4)) + return; + uint32_t SegmentStart = Offset; + uint64_t SegmentSize = StrOffsetExt.getU32(&Offset); + // The DWARF standard mandates that the contribution size must be + // less than 0xfffffff0. Since 0xffffffff indicates DWARF64, we + // reject the range from 0xfffffff0 to 0xfffffffe. + if (SegmentSize > 0xfffffff0 && SegmentSize < 0xffffffff) + return; + if (SegmentSize == 0xffffffff) { + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 8)) + return; + Format = DWARF64; + SegmentSize = StrOffsetExt.getU64(&Offset); + } + // Before we start dumping the actual string offsets, we're expecting a + // version number and padding (a total of 4 bytes), so we validate for + // SegmentSize + 4. + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, SegmentSize + 4)) + return; + + Version = StrOffsetExt.getU16(&Offset); + Offset += 2; + OS << format("0x%8.8x: ", SegmentStart); + OS << "Segment size = " << SegmentSize << ", Version = " << Version << "\n"; + + uint32_t SegmentBase = Offset; + while (Offset - SegmentBase < SegmentSize) { + uint64_t StringOffset = 0; + RelocAddrMap::const_iterator AI = Section.Relocs.find(Offset); + if (AI != Section.Relocs.end()) + StringOffset += AI->second.second; + OS << format("0x%8.8x: ", Offset); + if (Format == DWARF32) { + StringOffset += StrOffsetExt.getU32(&Offset); + OS << format("%8.8x\n", StringOffset); + } else { + StringOffset += StrOffsetExt.getU64(&Offset); + 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) { @@ -248,16 +309,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 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)); + } } } @@ -723,6 +797,10 @@ data = UncompressedSections.back(); } + // Map platform specific debug section names to DWARF standard section + // names. + name = Obj.mapDebugSectionName(name); + // Compressed sections names in GNU style starts from ".z", // at this point section is decompressed and we drop compression prefix. name = name.substr( @@ -768,18 +846,20 @@ // TODO: Add support for relocations in other sections as needed. // Record relocations for the debug_info and debug_line sections. - RelocAddrMap *Map = StringSwitch(RelSecName) - .Case("debug_info", &InfoSection.Relocs) - .Case("debug_loc", &LocSection.Relocs) - .Case("debug_info.dwo", &InfoDWOSection.Relocs) - .Case("debug_line", &LineSection.Relocs) - .Case("debug_ranges", &RangeSection.Relocs) - .Case("apple_names", &AppleNamesSection.Relocs) - .Case("apple_types", &AppleTypesSection.Relocs) - .Case("apple_namespaces", &AppleNamespacesSection.Relocs) - .Case("apple_namespac", &AppleNamespacesSection.Relocs) - .Case("apple_objc", &AppleObjCSection.Relocs) - .Default(nullptr); + RelocAddrMap *Map = + StringSwitch(RelSecName) + .Case("debug_info", &InfoSection.Relocs) + .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("apple_names", &AppleNamesSection.Relocs) + .Case("apple_types", &AppleTypesSection.Relocs) + .Case("apple_namespaces", &AppleNamespacesSection.Relocs) + .Case("apple_namespac", &AppleNamespacesSection.Relocs) + .Case("apple_objc", &AppleObjCSection.Relocs) + .Default(nullptr); if (!Map) { // Find debug_types relocs by section rather than name as there are // multiple, comdat grouped, debug_types sections. @@ -856,6 +936,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) @@ -867,7 +948,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) .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); @@ -416,6 +417,7 @@ break; case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: + case DW_FORM_strx: Value.uval = data.getULEB128(offset_ptr); break; default: @@ -520,6 +522,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); @@ -598,10 +601,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/DWARFTypeUnit.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -24,7 +24,10 @@ return false; TypeHash = debug_info.getU64(offset_ptr); TypeOffset = debug_info.getU32(offset_ptr); - return TypeOffset < getLength(); + // TypeOffset is relative to the beginning of the header, + // so we have to account for the leading length field. + unsigned SizeOfLength = getFormat() == dwarf::DwarfFormat::DWARF64 ? 12 : 4; + return TypeOffset < getLength() + SizeOfLength; } void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) { 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,20 +49,18 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, - bool LE, bool IsDWO, + StringRef SS, const DWARFSection &SOS, StringRef 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(); + if (IndexEntry) + if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) + StringOffsetSectionBase = C->Offset; } DWARFUnit::~DWARFUnit() = default; @@ -77,17 +76,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.second; + 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 +126,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 +252,11 @@ setBaseAddress(*BaseAddr); AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0); RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); + // Pre-DWARF v5 split-dwarf implementation derive their string offset + // section start from the index table. Make sure we don't overwrite it when + // we look for the str_offsets_base attribute and don't find it. + StringOffsetSectionBase = toSectionOffset( + UnitDie.find(DW_AT_str_offsets_base), StringOffsetSectionBase); // 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"); @@ -553,6 +556,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); @@ -569,7 +577,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 = @@ -691,6 +698,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 | @@ -745,7 +757,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,14 @@ return make_error("Unrecognized MachO magic number", object_error::invalid_file_type); } + +StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const { + return StringSwitch(Name) + .Case("__debug_abbrev", ".debug_abbrev") + .Case("__debug_info", ".debug_info") + .Case("__debug_line", ".debug_line") + .Case("__debug_frame", ".debug_frame") + .Case("__debug_str", ".debug_str") + .Case("__debug_str_offs", ".debug_str_offsets") + .Default(Name); +} Index: test/DebugInfo/Generic/string-offsets-multiple-cus.ll =================================================================== --- test/DebugInfo/Generic/string-offsets-multiple-cus.ll +++ test/DebugInfo/Generic/string-offsets-multiple-cus.ll @@ -0,0 +1,203 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump - | FileCheck --check-prefix=DEFAULT \ +; RUN: --check-prefix=BOTH %s +; RUN: %llc_dwarf -filetype=obj -generate-type-units < %s | llvm-dwarfdump - | \ +; RUN: FileCheck --check-prefix=TYPEUNITS --check-prefix=BOTH %s +; +; Check the correct handling of multiple compile and type units with regard to the +; string offset section. +; +; Constructed from the following sources: +; +; int aglob; +; struct A { +; int i; +; float f; +; }; +; +; void afunc(int i) +; { +; A a; +; } +; +; b.cpp: +; int bglob; +; +; void bfunc(int i) +; { +; } +; +; int cglob; +; void cfunc(int j) +; { +; } +; +; +; Check that all 3 compile units have the correct DW_AT_str_offsets_base attributes +; with the correct offsets. +; +; CU 1 +; BOTH: .debug_info contents: +; BOTH-NOT: .contents: +; BOTH: DW_TAG_compile_unit +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU1_STROFF:[0-9a-f]+]]) +; +; CU 2 +; BOTH-NOT: contents: +; BOTH: DW_TAG_compile_unit +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU2_STROFF:[0-9a-f]+]]) +; BOTH-NOT: NULL +; BOTH: DW_TAG_variable +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_name [DW_FORM_strx] ( indexed (00000003) string = "bglob") +; +; CU 3 +; BOTH-NOT: contents: +; BOTH: DW_TAG_compile_unit +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[CU3_STROFF:[0-9a-f]+]]) +; BOTH-NOT: NULL +; BOTH: DW_TAG_variable +; BOTH-NOT: {{DW_TAG|NULL}} +; BOTH: DW_AT_name [DW_FORM_strx] ( indexed (00000003) string = "cglob") +; +; Verify that type units have the proper DW_AT_str_offsets_base attribute and +; a segment in the .debug_str_offsets section. +; +; TYPEUNITS: .debug_types contents: +; TYPEUNITS-NOT: contents: +; TYPEUNITS: DW_TAG_type_unit +; TYPEUNITS-NOT: {{DW_TAG|NULL}} +; TYPEUNITS: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x[[TU_STROFF:[0-9]+]]) +; TYPEUNITS-NOT: NULL +; TYPEUNITS: DW_TAG_member +; TYPEUNITS-NOT: NULL +; TYPEUNITS: DW_TAG_member +; TYPEUNITS-NOT: {{DW_TAG|NULL}} +; TYPEUNITS: DW_AT_name [DW_FORM_strx] ( indexed (00000002) string = "f") +; +; BOTH: .debug_str contents: +; BOTH-NOT: contents: +; BOTH: 0x[[BGLOBOFF:[0-9a-f]+]]: "bglob" +; +; Check the .debug_str_offsets section +; DEFAULT: .debug_str_offsets contents: +; DEFAULT-NEXT: 0x00000000: Segment size = 48, Version = 5 +; DEFAULT-NEXT: 0x[[CU1_STROFF]]: +; DEFAULT: 0x00000038: Segment size = 28, Version = 5 +; DEFAULT-NEXT: 0x[[CU2_STROFF]]: +; DEFAULT-NEXT: {{.*:}} +; DEFAULT-NEXT: {{.*:}} +; The string with index 3 in segment 1 should be "bglob" +; DEFAULT-NEXT: {{.*:}} [[BGLOBOFF]] +; DEFAULT: 0x0000005c: Segment size = 28, Version = 5 +; DEFAULT-NEXT: 0x[[CU3_STROFF]]: + +; TYPEUNITS: .debug_str_offsets contents: +; TYPEUNITS-NEXT: 0x00000000: Segment size = 20, Version = 5 +; TYPEUNITS-NEXT: 0x[[TU_STROFF]]: +; TYPEUNITS: 0x0000001c: Segment size = 36, Version = 5 +; TYPEUNITS-NEXT: 0x[[CU1_STROFF]]: +; TYPEUNITS: 0x00000048: Segment size = 32, Version = 5 +; TYPEUNITS-NEXT: 0x[[CU2_STROFF]]: +; TYPEUNITS-NEXT: {{.*:}} +; TYPEUNITS-NEXT: {{.*:}} +; The string with index 3 in segment 1 should be "bglob" +; TYPEUNITS-NEXT: {{.*:}} [[BGLOBOFF]] +; TYPEUNITS: 0x00000070: Segment size = 32, Version = 5 +; TYPEUNITS-NEXT: 0x[[CU3_STROFF]]: + + +; ModuleID = 'test.bc' +source_filename = "llvm-link" +; target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +; target triple = "x86_64-unknown-linux-gnu" + +%struct.A = type { i32, float } + +@aglob = global i32 0, align 4, !dbg !0 +@bglob = global i32 0, align 4, !dbg !7 +@cglob = global i32 0, align 4, !dbg !12 + +; Function Attrs: noinline nounwind uwtable +define void @_Z5afunci(i32 %i) #0 !dbg !20 { +entry: + %i.addr = alloca i32, align 4 + %a = alloca %struct.A, align 4 + store i32 %i, i32* %i.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !23, metadata !24), !dbg !25 + call void @llvm.dbg.declare(metadata %struct.A* %a, metadata !26, metadata !24), !dbg !32 + ret void, !dbg !33 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: noinline nounwind uwtable +define void @_Z5bfunci(i32 %i) #0 !dbg !34 { +entry: + %i.addr = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !35, metadata !24), !dbg !36 + ret void, !dbg !37 +} + +; Function Attrs: noinline nounwind uwtable +define void @_Z5cfunci(i32 %j) #0 !dbg !38 { +entry: + %j.addr = alloca i32, align 4 + store i32 %j, i32* %j.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %j.addr, metadata !39, metadata !24), !dbg !40 + ret void, !dbg !41 +} + +attributes #0 = { noinline nounwind uwtable } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!2, !9, !14} +!llvm.ident = !{!17, !17, !17} +!llvm.module.flags = !{!18, !19} + +!0 = !DIGlobalVariableExpression(var: !1) +!1 = distinct !DIGlobalVariable(name: "aglob", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 5.0.0 (trunk 300143)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "a.cpp", directory: "/home/test/debuginfo/DWARF5/LTO") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !DIGlobalVariableExpression(var: !8) +!8 = distinct !DIGlobalVariable(name: "bglob", scope: !9, file: !10, line: 1, type: !6, isLocal: false, isDefinition: true) +!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !10, producer: "clang version 5.0.0 (trunk 300143)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !11) +!10 = !DIFile(filename: "b.cpp", directory: "/home/test/debuginfo/DWARF5/LTO") +!11 = !{!7} +!12 = !DIGlobalVariableExpression(var: !13) +!13 = distinct !DIGlobalVariable(name: "cglob", scope: !14, file: !15, line: 1, type: !6, isLocal: false, isDefinition: true) +!14 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !15, producer: "clang version 5.0.0 (trunk 300143)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !16) +!15 = !DIFile(filename: "c.cpp", directory: "/home/test/debuginfo/DWARF5/LTO") +!16 = !{!12} +!17 = !{!"clang version 5.0.0 (trunk 300143)"} +!18 = !{i32 2, !"Dwarf Version", i32 5} +!19 = !{i32 2, !"Debug Info Version", i32 3} +!20 = distinct !DISubprogram(name: "afunc", linkageName: "_Z5afunci", scope: !3, file: !3, line: 8, type: !21, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4) +!21 = !DISubroutineType(types: !22) +!22 = !{null, !6} +!23 = !DILocalVariable(name: "i", arg: 1, scope: !20, file: !3, line: 8, type: !6) +!24 = !DIExpression() +!25 = !DILocation(line: 8, column: 16, scope: !20) +!26 = !DILocalVariable(name: "a", scope: !20, file: !3, line: 10, type: !27) +!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 3, size: 64, elements: !28, identifier: "_ZTS1A") +!28 = !{!29, !30} +!29 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !27, file: !3, line: 4, baseType: !6, size: 32) +!30 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !27, file: !3, line: 5, baseType: !31, size: 32, offset: 32) +!31 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!32 = !DILocation(line: 10, column: 5, scope: !20) +!33 = !DILocation(line: 11, column: 1, scope: !20) +!34 = distinct !DISubprogram(name: "bfunc", linkageName: "_Z5bfunci", scope: !10, file: !10, line: 3, type: !21, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !9, variables: !4) +!35 = !DILocalVariable(name: "i", arg: 1, scope: !34, file: !10, line: 3, type: !6) +!36 = !DILocation(line: 3, column: 16, scope: !34) +!37 = !DILocation(line: 5, column: 1, scope: !34) +!38 = distinct !DISubprogram(name: "cfunc", linkageName: "_Z5cfunci", scope: !15, file: !15, line: 3, type: !21, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !14, variables: !4) +!39 = !DILocalVariable(name: "j", arg: 1, scope: !38, file: !15, line: 3, type: !6) +!40 = !DILocation(line: 3, column: 16, scope: !38) +!41 = !DILocation(line: 5, column: 1, scope: !38) Index: test/DebugInfo/Generic/string-offsets-table.ll =================================================================== --- test/DebugInfo/Generic/string-offsets-table.ll +++ test/DebugInfo/Generic/string-offsets-table.ll @@ -0,0 +1,144 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump - | FileCheck --check-prefix=MONOLITHIC %s +; RUN: %llc_dwarf -split-dwarf-file=foo.dwo -filetype=obj < %s | llvm-dwarfdump - \ +; RUN: | FileCheck --check-prefix=SPLIT %s + +; Test the proper emission of the DWARF v5 string offsets table. +; We test both default (monolithic) dwarf generation and splitting into *.dwo sections. +; +; Constructed from the following source with +; clang -S -emit-llvm -gdwarf-5: +; +; int aglob; +; +; struct A { +; int i; +; float f; +; }; +; +; void afunc(int i) +; { +; A a; +; } + +; Check the DW_AT_str_offsets_base attribute in .debug_abbrev +; MONOLITHIC: .debug_abbrev contents: +; MONOLITHIC-NOT: contents: +; MONOLITHIC: DW_TAG_compile_unit +; MONOLITHIC-NOT: DW_TAG +; MONOLITHIC: DW_AT_str_offsets_base DW_FORM_sec_offset + +; Check that indexed strings come out correctly and that the DW_str_offsets_base attribute +; is there. +; MONOLITHIC: .debug_info contents: +; MONOLITHIC-NOT: contents: +; MONOLITHIC: DW_TAG_compile_unit +; MONOLITHIC-NOT: {{DW_TAG|NULL}} +; MONOLITHIC: DW_AT_producer [DW_FORM_strx] ( indexed (00000000) string = "clang{{.*}}") +; MONOLITHIC-NOT: {{DW_TAG|NULL}} +; MONOLITHIC: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +; MONOLITHIC-NOT: {{DW_TAG|NULL}} +; MONOLITHIC: DW_AT_comp_dir [DW_FORM_strx] ( indexed (00000002) string = "/home/{{.*}}") +; MONOLITHIC-NOT: NULL +; MONOLITHIC: DW_TAG_subprogram +; MONOLITHIC-NOT: {{DW_TAG|NULL}} +; MONOLITHIC: DW_AT_linkage_name [DW_FORM_strx] ( indexed (00000005) string = "_Z5afunci") + +; Verify that the .debug_str_offsets section is there and +; that it starts with an 8-byte header, followed by relocatable +; offsets into the .debug_str section. +; MONOLITHIC: .debug_str_offsets contents: +; MONOLITHIC-NEXT: 0x00000000: Segment size = 48, Version = 5 +; MONOLITHIC-NEXT: 0x00000008: 00000000 +; MONOLITHIC-NEXT: 0x0000000c: 00000023 +; MONOLITHIC-NEXT: 0x00000010: 00000029 +; +; For split dwarf, verify first that the skeleton unit has the DW_AT_str_offsets_base +; attribute and that there is a .debug_str_offsets section with a proper header. +; +; SPLIT: .debug_info contents: +; SPLIT-NEXT: 0x00000000: Compile Unit:{{.*}}DW_UT_skeleton +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_compile_unit +; SPLIT-NOT: {{DW_TAG|contents:}} +; SPLIT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +; +; Check the split CU in .debug_info.dwo for a DW_AT_str_offsets_base attribute. +; SPLIT: .debug_info.dwo contents: +; SPLIT-NEXT: 0x00000000: Compile Unit:{{.*}}DW_UT_split_compile +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_compile_unit +; SPLIT-NOT: {{DW_TAG|NULL}} +; SPLIT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +; +; Check for a couple of indexed strings. +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_variable +; SPLIT-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000003) string = "aglob") +; SPLIT-NOT: contents: +; SPLIT: DW_TAG_subprogram +; SPLIT-NOT: {{DW_TAG|NULL}} +; SPLIT: DW_AT_linkage_name [DW_FORM_strx] ( indexed (00000005) string = "_Z5afunci") +; +; Check the string_offsets sections: .debug_str_offsets and .debug_str_offsets.dwo +; SPLIT: .debug_str_offsets contents: +; SPLIT-NEXT: 0x00000000: Segment size = 8, Version = 5 +; SPLIT-NEXT: 0x00000008: 00000000 +; SPLIT-NEXT: 0x0000000c: 00000008 +; SPLIT: .debug_str_offsets.dwo contents: +; SPLIT-NEXT: 0x00000000: Segment size = 48, Version = 5 +; SPLIT-NEXT: 0x00000008: 00000000 +; SPLIT-NEXT: 0x0000000c: 00000008 +; SPLIT-NEXT: 0x00000010: 0000002b +; +; ModuleID = 'a.cpp' +source_filename = "a.cpp" + +%struct.A = type { i32, float } + +@aglob = global i32 0, align 4, !dbg !0 + +; Function Attrs: noinline nounwind uwtable +define void @_Z5afunci(i32 %i) #0 !dbg !10 { +entry: + %i.addr = alloca i32, align 4 + %a = alloca %struct.A, align 4 + store i32 %i, i32* %i.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !13, metadata !14), !dbg !15 + call void @llvm.dbg.declare(metadata %struct.A* %a, metadata !16, metadata !14), !dbg !22 + ret void, !dbg !23 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind uwtable } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8} +!llvm.ident = !{!9} + +!0 = !DIGlobalVariableExpression(var: !1) +!1 = distinct !DIGlobalVariable(name: "aglob", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 5.0.0 (trunk 300364)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "a.cpp", directory: "/home/test/debuginfo/DWARF5") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 5} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{!"clang version 5.0.0 (trunk 300364)"} +!10 = distinct !DISubprogram(name: "afunc", linkageName: "_Z5afunci", scope: !3, file: !3, line: 8, type: !11, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !6} +!13 = !DILocalVariable(name: "i", arg: 1, scope: !10, file: !3, line: 8, type: !6) +!14 = !DIExpression() +!15 = !DILocation(line: 8, column: 16, scope: !10) +!16 = !DILocalVariable(name: "a", scope: !10, file: !3, line: 10, type: !17) +!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 3, size: 64, elements: !18, identifier: "_ZTS1A") +!18 = !{!19, !20} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !17, file: !3, line: 4, baseType: !6, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !17, file: !3, line: 5, baseType: !21, size: 32, offset: 32) +!21 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!22 = !DILocation(line: 10, column: 5, scope: !10) +!23 = !DILocation(line: 11, column: 1, scope: !10) 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.elf-x86-64 + + .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.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.elf-x86-64 | 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: Segment size = 12, Version = 5 +CHECK-NEXT: 0x00000008: 00000000 +CHECK-NEXT: 0x0000000c: 00000018 +CHECK-NEXT: 0x00000010: 00000027 +CHECK-NEXT: 0x00000014: Segment size = 12, Version = 5 +CHECK-NEXT: 0x0000001c: 00000000 +CHECK-NEXT: 0x00000020: 00000036 +CHECK-NEXT: 0x00000024: 00000045 +CHECK-NEXT: 0x00000028: Segment size = 8, Version = 5 +CHECK-NEXT: 0x00000030: 00000054 +CHECK-NEXT: 0x00000034: 0000005e + +CHECK: .debug_str_offsets.dwo contents: +CHECK-NEXT: 0x00000000: Segment size = 12, Version = 5 +CHECK-NEXT: 0x00000008: 00000000 +CHECK-NEXT: 0x0000000c: 0000001e +CHECK-NEXT: 0x00000010: 00000034 +CHECK-NEXT: 0x00000014: Segment 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;