Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -34,9 +34,6 @@ : DWARFUnit(Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, UnitSection) {} - uint32_t getHeaderSize() const override { - return DWARFUnit::getHeaderSize() + 12; - } uint64_t getTypeHash() const { return getHeader().getTypeHash(); } uint32_t getTypeOffset() const { return getHeader().getTypeOffset(); } Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -59,9 +59,15 @@ uint64_t TypeHash = 0; uint32_t TypeOffset = 0; + // For v5 split or skeleton compile units only. + Optional DWOId; + // Unit type as parsed, or derived from the section kind. uint8_t UnitType = 0; + // Size as parsed. uint8_t for compactness. + uint8_t Size = 0; + public: /// Parse a unit header from \p debug_info starting at \p offset_ptr. bool extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, @@ -78,6 +84,11 @@ } uint32_t getLength() const { return Length; } uint64_t getAbbrOffset() const { return AbbrOffset; } + Optional getDWOId() const { return DWOId; } + void setDWOId(uint64_t Id) { + assert((!DWOId || *DWOId == Id) && "setting DWOId to a different value"); + DWOId = Id; + } const DWARFUnitIndex::Entry *getIndexEntry() const { return IndexEntry; } uint64_t getTypeHash() const { return TypeHash; } uint32_t getTypeOffset() const { return TypeOffset; } @@ -85,6 +96,7 @@ bool isTypeUnit() const { return UnitType == dwarf::DW_UT_type || UnitType == dwarf::DW_UT_split_type; } + uint8_t getSize() const { return Size; } // FIXME: Support DWARF64. uint32_t getNextUnitOffset() const { return Offset + Length + 4; } }; @@ -289,8 +301,8 @@ protected: const DWARFUnitHeader &getHeader() const { return Header; } - /// Size in bytes of the unit header. - virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; } + /// Size in bytes of the parsed unit header. + uint32_t getHeaderSize() const { return Header.getSize(); } /// Find the unit's contribution to the string offsets table and determine its /// length and form. The given offset is expected to be derived from the unit @@ -430,7 +442,8 @@ } const char *getCompilationDir(); - Optional getDWOId(); + Optional getDWOId() const { return getHeader().getDWOId(); } + void setDWOId(uint64_t NewID) { Header.setDWOId(NewID); } /// Return a vector of address ranges resulting from a (possibly encoded) /// range list starting at a given offset in the appropriate ranges section. Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -83,6 +83,9 @@ DenseMap AbstractSPDies; DenseMap> AbstractVariables; + /// DWO ID for correlating skeleton and split units. + uint64_t DWOId = 0; + /// Construct a DIE for the given DbgVariable without initializing the /// DbgVariable's DIE reference. DIE *constructVariableDIEImpl(const DbgVariable &DV, bool Abstract); @@ -219,6 +222,13 @@ /// Set the skeleton unit associated with this unit. void setSkeleton(DwarfCompileUnit &Skel) { Skeleton = &Skel; } + unsigned getHeaderSize() const override { + // DWARF v5 added the DWO ID to the header for split/skeleton units. + unsigned DWOIdSize = + DD->getDwarfVersion() >= 5 && DD->useSplitDwarf() ? sizeof(uint64_t) + : 0; + return DwarfUnit::getHeaderSize() + DWOIdSize; + } unsigned getLength() { return sizeof(uint32_t) + // Length field getHeaderSize() + getUnitDie().getSize(); @@ -290,6 +300,9 @@ void setBaseAddress(const MCSymbol *Base) { BaseAddress = Base; } const MCSymbol *getBaseAddress() const { return BaseAddress; } + uint64_t getDWOId() const { return DWOId; } + void setDWOId(uint64_t DwoId) { DWOId = DwoId; } + bool hasDwarfPubSections() const; }; Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -855,6 +855,8 @@ : DD->useSplitDwarf() ? dwarf::DW_UT_skeleton : dwarf::DW_UT_compile; DwarfUnit::emitCommonHeader(UseOffsets, UT); + if (DD->getDwarfVersion() >= 5 && UT != dwarf::DW_UT_compile) + Asm->emitInt64(getDWOId()); } bool DwarfCompileUnit::hasDwarfPubSections() const { Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -747,11 +747,15 @@ // Emit a unique identifier for this CU. uint64_t ID = DIEHash(Asm).computeCUSignature(DWOName, TheCU.getUnitDie()); - TheCU.addUInt(TheCU.getUnitDie(), dwarf::DW_AT_GNU_dwo_id, - dwarf::DW_FORM_data8, ID); - SkCU->addUInt(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id, - dwarf::DW_FORM_data8, ID); - + if (getDwarfVersion() >= 5) { + TheCU.setDWOId(ID); + SkCU->setDWOId(ID); + } else { + TheCU.addUInt(TheCU.getUnitDie(), dwarf::DW_AT_GNU_dwo_id, + dwarf::DW_FORM_data8, ID); + SkCU->addUInt(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id, + dwarf::DW_FORM_data8, ID); + } // We don't keep track of which addresses are used in which CU so this // is a bit pessimistic under LTO. if (!AddrPool.isEmpty()) { Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp @@ -22,9 +22,10 @@ if (getVersion() >= 5) OS << " unit_type = " << dwarf::UnitTypeString(getUnitType()); OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) - << " addr_size = " << format("0x%02x", getAddressByteSize()) - << " (next unit at " << format("0x%08x", getNextUnitOffset()) - << ")\n"; + << " addr_size = " << format("0x%02x", getAddressByteSize()); + if (getVersion() >= 5 && getUnitType() != dwarf::DW_UT_compile) + OS << " DWO_id = " << format("0x%016" PRIx64, *getDWOId()); + OS << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; if (DWARFDie CUDie = getUnitDIE(false)) CUDie.dump(OS, 0, DumpOpts); Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -561,9 +561,19 @@ // probably only one unless this is something like LTO - though an in-process // built/cached lookup table could be used in that case to improve repeated // lookups of different CUs in the DWO. - for (const auto &DWOCU : dwo_compile_units()) + for (const auto &DWOCU : dwo_compile_units()) { + // Might not have parsed DWO ID yet. + if (!DWOCU->getDWOId()) { + if (Optional DWOId = + toUnsigned(DWOCU->getUnitDIE().find(DW_AT_GNU_dwo_id))) + DWOCU->setDWOId(*DWOId); + else + // No DWO ID? + continue; + } if (DWOCU->getDWOId() == Hash) return DWOCU.get(); + } return nullptr; } Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -130,15 +130,22 @@ return false; AbbrOffset = AbbrEntry->Offset; } - bool TypeOffsetOK = true; if (isTypeUnit()) { TypeHash = debug_info.getU64(offset_ptr); TypeOffset = debug_info.getU32(offset_ptr); - // Type offset is unit-relative; should be after the header and before - // the end of the current unit. - TypeOffsetOK = TypeOffset >= *offset_ptr - Offset && - TypeOffset < getLength() + SizeOfLength; - } + } else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton) + DWOId = debug_info.getU64(offset_ptr); + + // Header fields all parsed, capture the size of this unit header. + assert(*offset_ptr - Offset <= 255 && "unexpected header size"); + Size = uint8_t(*offset_ptr - Offset); + + // Type offset is unit-relative; should be after the header and before + // the end of the current unit. + bool TypeOffsetOK = + !isTypeUnit() + ? true + : TypeOffset >= Size && TypeOffset < getLength() + SizeOfLength; bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8; @@ -197,10 +204,6 @@ return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr); } -Optional DWARFUnit::getDWOId() { - return toUnsigned(getUnitDIE().find(DW_AT_GNU_dwo_id)); -} - void DWARFUnit::extractDIEsToVector( bool AppendCUDie, bool AppendNonCUDies, std::vector &Dies) const { @@ -269,6 +272,8 @@ // If CU DIE was just parsed, copy several attribute values from it. if (!HasCUDie) { DWARFDie UnitDie = getUnitDIE(); + if (Optional DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id))) + Header.setDWOId(*DWOId); if (!isDWO) { assert(AddrOffsetSectionBase == 0); assert(RangeSectionBase == 0); Index: llvm/trunk/test/CodeGen/X86/dwarf-headers.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/dwarf-headers.ll +++ llvm/trunk/test/CodeGen/X86/dwarf-headers.ll @@ -19,9 +19,10 @@ ; RUN: llvm-dwarfdump -v %t.dwo | FileCheck %s --check-prefix=DWO-5 ; Looking for DWARF headers to be generated correctly. -; There are 7 variants: v4 CU, v4 TU, v5 (normal/skeleton/split) CU, -; v5 (normal/split) TU. The v5 CU variants and TU variants differ -; only in the type-unit code. +; There are 8 variants with 5 formats: v4 CU, v4 TU, v5 normal/partial CU, +; v5 skeleton/split CU, v5 normal/split TU. Some v5 variants differ only +; in the unit_type code, and the skeleton/split CU differs from normal/partial +; by having one extra field (dwo_id). ; (v2 thru v4 CUs are all the same, and TUs were invented in v4, ; so we don't bother checking older versions.) @@ -73,11 +74,13 @@ ; ; O-5: .debug_info contents: ; O-5: 0x00000000: Compile Unit: {{.*}} version = 0x0005 unit_type = DW_UT_skeleton abbr_offset -; O-5: 0x0000000c: DW_TAG_compile_unit +; O-5-SAME: DWO_id = 0x4ed74084f749d96b +; O-5: 0x00000014: DW_TAG_compile_unit ; ; DWO-5: .debug_info.dwo contents: ; DWO-5: 0x00000000: Compile Unit: {{.*}} version = 0x0005 unit_type = DW_UT_split_compile abbr_offset -; DWO-5: 0x0000000c: DW_TAG_compile_unit +; DWO-5-SAME: DWO_id = 0x4ed74084f749d96b +; DWO-5: 0x00000014: DW_TAG_compile_unit ; ; FIXME: V5 wants type units in .debug_info.dwo not .debug_types.dwo. ; DWO-5: .debug_types.dwo contents: Index: llvm/trunk/test/DebugInfo/X86/dwarfdump-header.s =================================================================== --- llvm/trunk/test/DebugInfo/X86/dwarfdump-header.s +++ llvm/trunk/test/DebugInfo/X86/dwarfdump-header.s @@ -137,6 +137,7 @@ .byte 5 # DWARF Unit Type .byte 8 # Address Size (in bytes) .long .debug_abbrev.dwo # Offset Into Abbrev. Section + .quad 0x5a # DWO ID # The split compile-unit DIE, with DW_AT_producer, DW_AT_name, DW_AT_stmt_list. .byte 1 .long dwo_producer @@ -145,8 +146,8 @@ .byte 0 # NULL CU_split_5_end: -# CHECK: 0x00000000: Compile Unit: length = 0x00000016 version = 0x0005 unit_type = DW_UT_split_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x0000001a) -# CHECK: 0x0000000c: DW_TAG_compile_unit +# CHECK: 0x00000000: Compile Unit: length = 0x0000001e version = 0x0005 unit_type = DW_UT_split_compile abbr_offset = 0x0000 addr_size = 0x08 DWO_id = 0x000000000000005a (next unit at 0x00000022) +# CHECK: 0x00000014: DW_TAG_compile_unit # CHECK-NEXT: DW_AT_producer {{.*}} "Handmade DWO producer" # CHECK-NEXT: DW_AT_name {{.*}} "V5_dwo_compile_unit"