diff --git a/llvm/test/tools/llvm-dwp/Inputs/incompatible_versions/v4.s b/llvm/test/tools/llvm-dwp/Inputs/incompatible_versions/v4.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwp/Inputs/incompatible_versions/v4.s @@ -0,0 +1,18 @@ + .section .debug_str.dwo,"eMS",@progbits,1 +.Linfo_string0: + .asciz "main" # string offset=0 + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end1-.Ldebug_info_dwo_start1 # Length of Unit +.Ldebug_info_dwo_start1: + .short 4 # DWARF version number + .long 0 # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 9 # Abbrev [9] 0xb:0x37 DW_TAG_compile_unit +.Ldebug_info_dwo_end1: + .section .debug_abbrev.dwo,"e",@progbits + .byte 9 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .ascii "\261B" # DW_AT_GNU_dwo_id diff --git a/llvm/test/tools/llvm-dwp/Inputs/incompatible_versions/v5.s b/llvm/test/tools/llvm-dwp/Inputs/incompatible_versions/v5.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwp/Inputs/incompatible_versions/v5.s @@ -0,0 +1,9 @@ + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end1-.Ldebug_info_dwo_start1 # Length of Unit +.Ldebug_info_dwo_start1: + .short 5 # DWARF version number + .byte 5 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad 4176978386676692168 +.Ldebug_info_dwo_end1: diff --git a/llvm/test/tools/llvm-dwp/X86/unsupported_cu_index_version.s b/llvm/test/tools/llvm-dwp/X86/incompatible_cu_index_versions.s rename from llvm/test/tools/llvm-dwp/X86/unsupported_cu_index_version.s rename to llvm/test/tools/llvm-dwp/X86/incompatible_cu_index_versions.s --- a/llvm/test/tools/llvm-dwp/X86/unsupported_cu_index_version.s +++ b/llvm/test/tools/llvm-dwp/X86/incompatible_cu_index_versions.s @@ -1,7 +1,7 @@ # RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.dwp # RUN: not llvm-dwp %t.dwp -o %t 2>&1 | FileCheck %s -# CHECK: error: unsupported cu_index version: 5 (only version 2 is supported) +# CHECK: error: incompatible cu_index versions, found 2 and expecting 5 .section .debug_info.dwo, "e", @progbits .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit .Ldebug_info_dwo_start0: @@ -10,10 +10,11 @@ .byte 8 # Address Size (in bytes) .long 0 # Offset Into Abbrev. Section .quad -346972125991005518 + .byte 0 # Abbrev [9] 0xb:0x37 DW_TAG_compile_unit .Ldebug_info_dwo_end0: .section .debug_cu_index, "", @progbits ## Header: - .short 5 # Version + .short 2 # Version .space 2 # Padding .long 2 # Section count .long 1 # Unit count diff --git a/llvm/test/tools/llvm-dwp/X86/unsupported_tu_index_version.s b/llvm/test/tools/llvm-dwp/X86/incompatible_tu_index_versions.s rename from llvm/test/tools/llvm-dwp/X86/unsupported_tu_index_version.s rename to llvm/test/tools/llvm-dwp/X86/incompatible_tu_index_versions.s --- a/llvm/test/tools/llvm-dwp/X86/unsupported_tu_index_version.s +++ b/llvm/test/tools/llvm-dwp/X86/incompatible_tu_index_versions.s @@ -5,7 +5,7 @@ ## of version 2 and a TU index of version 5. A valid TU is not required, but ## the .debug_types.dwo section should not be empty. -# CHECK: error: unsupported tu_index version: 5 (only version 2 is supported) +# CHECK: error: incompatible tu_index versions, found 5 and expecting 2 .section .debug_abbrev.dwo, "e", @progbits .LAbbrevBegin: diff --git a/llvm/test/tools/llvm-dwp/X86/incompatible_unit_version.test b/llvm/test/tools/llvm-dwp/X86/incompatible_unit_version.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwp/X86/incompatible_unit_version.test @@ -0,0 +1,7 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux %p/../Inputs/incompatible_versions/v5.s -filetype=obj -o %t5.o \ +# RUN: -split-dwarf-file=%t5.dwo -dwarf-version=5 +# RUN: llvm-mc -triple x86_64-unknown-linux %p/../Inputs/incompatible_versions/v4.s -filetype=obj -o %t4.o \ +# RUN: -split-dwarf-file=%t4.dwo -dwarf-version=4 +# RUN: not llvm-dwp %t4.dwo %t5.dwo -o %t.dwp + +# CHECK: error: incompatible DWARF compile unit versions: 4 and 5 \ No newline at end of file diff --git a/llvm/test/tools/llvm-dwp/X86/info-v5.s b/llvm/test/tools/llvm-dwp/X86/info-v5.s --- a/llvm/test/tools/llvm-dwp/X86/info-v5.s +++ b/llvm/test/tools/llvm-dwp/X86/info-v5.s @@ -9,7 +9,7 @@ #CHECK: 0x00000000: Compile Unit: length = 0x00000050, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_compile, abbr_offset = 0x0000, addr_size = 0x08, DWO_id = [[DWOID:.*]] (next unit at 0x00000054) # CHECK-DAG: .debug_cu_index contents: -# CHECK: version = 2, units = 1, slots = 2 +# CHECK: version = 5, units = 1, slots = 2 # CHECK: Index Signature INFO ABBREV # CHECK: 1 [[DWOID]] [0x00000000, 0x00000054) [0x00000000, 0x0000002a) diff --git a/llvm/test/tools/llvm-dwp/X86/tu_units_v5.s b/llvm/test/tools/llvm-dwp/X86/tu_units_v5.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwp/X86/tu_units_v5.s @@ -0,0 +1,55 @@ +# This test checks if llvm-dwp can correctly generate the tu index section (v5). + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o \ +# RUN: -split-dwarf-file=%t.dwo -dwarf-version=5 +# RUN: llvm-dwp %t.dwo -o %t.dwp +# RUN: llvm-dwarfdump -debug-info -debug-tu-index %t.dwp | FileCheck %s + +# CHECK-DAG: .debug_info.dwo contents: +# CHECK: 0x00000000: Type Unit: length = 0x0000001c, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_type, abbr_offset = 0x0000, addr_size = 0x08, name = '', type_signature = [[TUID1:.*]], type_offset = 0x001f (next unit at 0x00000020) +# CHECK: 0x00000020: Type Unit: length = 0x0000001c, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_type, abbr_offset = 0x0000, addr_size = 0x08, name = '', type_signature = [[TUID2:.*]], type_offset = 0x001f (next unit at 0x00000040) +# CHECK_DAG: .debug_tu_index contents: +# CHECK: version = 5, units = 2, slots = 4 +# CHECK: Index Signature INFO ABBREV STR_OFFSETS +# CHECK: 1 [[TUID1]] [0x00000000, 0x00000020) [0x00000000, 0x00000009) [0x00000000, 0x00000004) +# CHECK: 4 [[TUID2]] [0x00000020, 0x00000040) [0x00000000, 0x00000009) [0x00000000, 0x00000004) + + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit +.Ldebug_info_dwo_start0: + .short 5 # DWARF version number + .byte 6 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad 5657452045627120676 # Type Signature + .long 31 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x1c DW_TAG_type_unit + .short 33 # DW_AT_language + .long 0 # DW_AT_stmt_list + .byte 0 # End Of Children Mark +.Ldebug_info_dwo_end0: + .long .Ldebug_info_dwo_end1-.Ldebug_info_dwo_start1 # Length of Unit +.Ldebug_info_dwo_start1: + .short 5 # DWARF version number + .byte 6 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad -8528522068957683993 # Type Signature + .long 31 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x25 DW_TAG_type_unit + .short 33 # DW_AT_language + .long 0 # DW_AT_stmt_list + .byte 0 # End Of Children Mark +.Ldebug_info_dwo_end1: + .section .debug_str_offsets.dwo,"e",@progbits + .long 0 + .section .debug_abbrev.dwo,"e",@progbits + .byte 1 # Abbreviation Code + .byte 65 # DW_TAG_type_unit + .byte 0 # DW_CHILDREN_yes + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) \ No newline at end of file diff --git a/llvm/test/tools/llvm-dwp/X86/type_dedup_v5.s b/llvm/test/tools/llvm-dwp/X86/type_dedup_v5.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwp/X86/type_dedup_v5.s @@ -0,0 +1,29 @@ +# This test checks if llvm-dwp can deduplicate tu units (v5). + +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o \ +# RUN: -split-dwarf-file=%t.dwo -dwarf-version=5 +# RUN: llvm-dwp %t.dwo -o %t.dwp +# RUN: llvm-dwarfdump -debug-info -debug-tu-index %t.dwp | FileCheck %s + +# CHECK_DAG: .debug_tu_index contents: +# CHECK: version = 5, units = 1, slots = 2 + + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit +.Ldebug_info_dwo_start0: + .short 5 # DWARF version number + .byte 6 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad 5657452045627120676 # Type Signature + .long 31 # Type DIE Offset +.Ldebug_info_dwo_end0: + .long .Ldebug_info_dwo_end1-.Ldebug_info_dwo_start1 # Length of Unit +.Ldebug_info_dwo_start1: + .short 5 # DWARF version number + .byte 6 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad 5657452045627120676 # Type Signature + .long 31 # Type DIE Offset +.Ldebug_info_dwo_end1: diff --git a/llvm/tools/llvm-dwp/llvm-dwp.cpp b/llvm/tools/llvm-dwp/llvm-dwp.cpp --- a/llvm/tools/llvm-dwp/llvm-dwp.cpp +++ b/llvm/tools/llvm-dwp/llvm-dwp.cpp @@ -77,9 +77,10 @@ return 8; // unit length: 4 bytes, version: 2 bytes, padding: 2 bytes. } -// Holds data for Skeleton and Split Compilation Unit Headers as defined in -// Dwarf 5 specification, 7.5.1.2 and Dwarf 4 specification 7.5.1.1. -struct CompileUnitHeader { +// Holds data for Skeleton, Split Compilation, and Type Unit Headers (only in +// v5) as defined in Dwarf 5 specification, 7.5.1.2, 7.5.1.3 and Dwarf 4 +// specification 7.5.1.1. +struct InfoSectionUnitHeader { // unit_length field. Note that the type is uint64_t even in 32-bit dwarf. uint64_t Length = 0; @@ -109,10 +110,12 @@ }; // Parse and return the header of the compile unit. -static Expected parseCompileUnitHeader(StringRef Info) { - CompileUnitHeader Header; - Error Err = Error::success(); +static Expected +parseInfoSectionUnitHeader(StringRef Info) { + InfoSectionUnitHeader Header; uint64_t Offset = 0; + + Error Err = Error::success(); DWARFDataExtractor InfoData(Info, true, 0); std::tie(Header.Length, Header.Format) = InfoData.getInitialLength(&Offset, &Err); @@ -150,6 +153,10 @@ Header.AddrSize = InfoData.getU8(&Offset); Header.DebugAbbrevOffset = InfoData.getU32(&Offset); Header.Signature = InfoData.getU64(&Offset); + if (Header.UnitType == dwarf::DW_UT_split_type) { + // Type offset. + InfoData.getU32(&Offset); + } } else { // Note that, address_size and debug_abbrev_offset fields have switched // places between dwarf version 4 and 5. @@ -165,7 +172,7 @@ MCSection *StrOffsetSection, StringRef CurStrSection, StringRef CurStrOffsetSection, - const CompileUnitHeader &Header) { + uint16_t Version) { // Could possibly produce an error or warning if one of these was non-null but // the other was null. if (CurStrSection.empty() || CurStrOffsetSection.empty()) @@ -186,7 +193,7 @@ Out.SwitchSection(StrOffsetSection); - uint64_t HeaderSize = debugStrOffsetsHeaderSize(Data, Header.Version); + uint64_t HeaderSize = debugStrOffsetsHeaderSize(Data, Version); uint64_t Offset = 0; uint64_t Size = CurStrOffsetSection.size(); // FIXME: This can be caused by bad input and should be handled as such. @@ -259,14 +266,10 @@ return StrData.getCStr(&StrOffset); } -static Expected getCUIdentifiers(StringRef Abbrev, - StringRef Info, - StringRef StrOffsets, - StringRef Str) { - Expected HeaderOrError = parseCompileUnitHeader(Info); - if (!HeaderOrError) - return HeaderOrError.takeError(); - CompileUnitHeader &Header = *HeaderOrError; +static Expected +getCUIdentifiers(InfoSectionUnitHeader &Header, StringRef Abbrev, + StringRef Info, StringRef StrOffsets, StringRef Str) { + DataExtractor InfoData(Info, true, 0); uint64_t Offset = Header.HeaderSize; if (Header.Version >= 5 && Header.UnitType != dwarf::DW_UT_split_compile) @@ -274,7 +277,6 @@ std::string("unit type DW_UT_split_compile type not found in " "debug_info header. Unexpected unit type 0x" + utostr(Header.UnitType) + " found")); - CompileUnitIdentifiers ID; uint32_t AbbrCode = InfoData.getULEB128(&Offset); @@ -336,10 +338,10 @@ // Convert an internal section identifier into the index to use with // UnitIndexEntry::Contributions. -static unsigned getContributionIndex(DWARFSectionKind Kind) { - // Assuming the pre-standard DWP format. - assert(serializeSectionKind(Kind, 2) >= DW_SECT_INFO); - return serializeSectionKind(Kind, 2) - DW_SECT_INFO; +static unsigned getContributionIndex(DWARFSectionKind Kind, + uint32_t IndexVersion) { + assert(serializeSectionKind(Kind, IndexVersion) >= DW_SECT_INFO); + return serializeSectionKind(Kind, IndexVersion) - DW_SECT_INFO; } // Convert a UnitIndexEntry::Contributions index to the corresponding on-disk @@ -357,10 +359,12 @@ return Section.substr(Off->Offset, Off->Length); } -static void addAllTypesFromDWP( - MCStreamer &Out, MapVector &TypeIndexEntries, - const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types, - const UnitIndexEntry &TUEntry, uint32_t &TypesOffset) { +static void +addAllTypesFromDWP(MCStreamer &Out, + MapVector &TypeIndexEntries, + const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, + StringRef Types, const UnitIndexEntry &TUEntry, + uint32_t &TypesOffset, unsigned TypesContributionIndex) { Out.SwitchSection(OutputTypes); for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) { auto *I = E.getContributions(); @@ -375,25 +379,25 @@ for (auto Kind : TUIndex.getColumnKinds()) { if (!isSupportedSectionKind(Kind)) continue; - auto &C = Entry.Contributions[getContributionIndex(Kind)]; + auto &C = + Entry.Contributions[getContributionIndex(Kind, TUIndex.getVersion())]; C.Offset += I->Offset; C.Length = I->Length; ++I; } - unsigned TypesIndex = getContributionIndex(DW_SECT_EXT_TYPES); - auto &C = Entry.Contributions[TypesIndex]; + auto &C = Entry.Contributions[TypesContributionIndex]; Out.emitBytes(Types.substr( - C.Offset - TUEntry.Contributions[TypesIndex].Offset, C.Length)); + C.Offset - TUEntry.Contributions[TypesContributionIndex].Offset, + C.Length)); C.Offset = TypesOffset; TypesOffset += C.Length; } } -static void addAllTypes(MCStreamer &Out, - MapVector &TypeIndexEntries, - MCSection *OutputTypes, - const std::vector &TypesSections, - const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { +static void addAllTypesFromTypesSection( + MCStreamer &Out, MapVector &TypeIndexEntries, + MCSection *OutputTypes, const std::vector &TypesSections, + const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { for (StringRef Types : TypesSections) { Out.SwitchSection(OutputTypes); uint64_t Offset = 0; @@ -402,7 +406,7 @@ UnitIndexEntry Entry = CUEntry; // Zero out the debug_info contribution Entry.Contributions[0] = {}; - auto &C = Entry.Contributions[getContributionIndex(DW_SECT_EXT_TYPES)]; + auto &C = Entry.Contributions[getContributionIndex(DW_SECT_EXT_TYPES, 2)]; C.Offset = TypesOffset; auto PrevOffset = Offset; // Length of the unit, including the 4 byte length field. @@ -434,10 +438,10 @@ Out.emitIntValue(E.second.Contributions[i].*Field, 4); } -static void -writeIndex(MCStreamer &Out, MCSection *Section, - ArrayRef ContributionOffsets, - const MapVector &IndexEntries) { +static void writeIndex(MCStreamer &Out, MCSection *Section, + ArrayRef ContributionOffsets, + const MapVector &IndexEntries, + uint32_t IndexVersion) { if (IndexEntries.empty()) return; @@ -463,7 +467,7 @@ } Out.SwitchSection(Section); - Out.emitIntValue(2, 4); // Version + Out.emitIntValue(IndexVersion, 4); // Version Out.emitIntValue(Columns, 4); // Columns Out.emitIntValue(IndexEntries.size(), 4); // Num Units Out.emitIntValue(Buckets.size(), 4); // Num Buckets @@ -540,13 +544,15 @@ const StringMap> &KnownSections, const MCSection *StrSection, const MCSection *StrOffsetSection, const MCSection *TypesSection, const MCSection *CUIndexSection, - const MCSection *TUIndexSection, const SectionRef &Section, MCStreamer &Out, + const MCSection *TUIndexSection, const MCSection *InfoSection, + const SectionRef &Section, MCStreamer &Out, std::deque> &UncompressedSections, uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry, StringRef &CurStrSection, StringRef &CurStrOffsetSection, - std::vector &CurTypesSection, StringRef &InfoSection, - StringRef &AbbrevSection, StringRef &CurCUIndexSection, - StringRef &CurTUIndexSection) { + std::vector &CurTypesSection, + std::vector &CurInfoSection, StringRef &AbbrevSection, + StringRef &CurCUIndexSection, StringRef &CurTUIndexSection, + std::vector> &SectionLength) { if (Section.isBSS()) return Error::success(); @@ -573,22 +579,12 @@ return Error::success(); if (DWARFSectionKind Kind = SectionPair->second.second) { - auto Index = getContributionIndex(Kind); - if (Kind != DW_SECT_EXT_TYPES) { - CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; - ContributionOffsets[Index] += - (CurEntry.Contributions[Index].Length = Contents.size()); + if (Kind != DW_SECT_EXT_TYPES && Kind != DW_SECT_INFO) { + SectionLength.push_back(std::make_pair(Kind, Contents.size())); } - switch (Kind) { - case DW_SECT_INFO: - InfoSection = Contents; - break; - case DW_SECT_ABBREV: + if (Kind == DW_SECT_ABBREV) { AbbrevSection = Contents; - break; - default: - break; } } @@ -603,6 +599,8 @@ CurCUIndexSection = Contents; else if (OutSection == TUIndexSection) CurTUIndexSection = Contents; + else if (OutSection == InfoSection) + CurInfoSection.push_back(Contents); else { Out.SwitchSection(OutSection); Out.emitBytes(Contents); @@ -656,8 +654,9 @@ MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection(); MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection(); MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection(); + MCSection *const InfoSection = MCOFI.getDwarfInfoDWOSection(); const StringMap> KnownSections = { - {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, + {"debug_info.dwo", {InfoSection, DW_SECT_INFO}}, {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}}, {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, {"debug_str.dwo", {StrSection, static_cast(0)}}, @@ -671,6 +670,8 @@ MapVector TypeIndexEntries; uint32_t ContributionOffsets[8] = {}; + uint16_t Version = 0; + uint32_t IndexVersion = 0; DWPStringPool Strings(Out, StrSection); @@ -692,66 +693,140 @@ StringRef CurStrSection; StringRef CurStrOffsetSection; std::vector CurTypesSection; - StringRef InfoSection; + std::vector CurInfoSection; StringRef AbbrevSection; StringRef CurCUIndexSection; StringRef CurTUIndexSection; + std::vector> SectionLength; + for (const auto &Section : Obj.sections()) if (auto Err = handleSection( KnownSections, StrSection, StrOffsetSection, TypesSection, - CUIndexSection, TUIndexSection, Section, Out, + CUIndexSection, TUIndexSection, InfoSection, Section, Out, UncompressedSections, ContributionOffsets, CurEntry, - CurStrSection, CurStrOffsetSection, CurTypesSection, InfoSection, - AbbrevSection, CurCUIndexSection, CurTUIndexSection)) + CurStrSection, CurStrOffsetSection, CurTypesSection, + CurInfoSection, AbbrevSection, CurCUIndexSection, + CurTUIndexSection, SectionLength)) return Err; - if (InfoSection.empty()) + if (CurInfoSection.empty()) continue; - Expected CompileUnitHeaderOrErr = - parseCompileUnitHeader(InfoSection); - if (!CompileUnitHeaderOrErr) - return CompileUnitHeaderOrErr.takeError(); - CompileUnitHeader &CompileUnitHeader = *CompileUnitHeaderOrErr; + Expected UnitHeaderOrErr = + parseInfoSectionUnitHeader(CurInfoSection.front()); + if (!UnitHeaderOrErr) + return UnitHeaderOrErr.takeError(); + InfoSectionUnitHeader &Header = *UnitHeaderOrErr; + + if (Version == 0) { + Version = Header.Version; + IndexVersion = Version < 5 ? 2 : 5; + } else if (Version != Header.Version) { + return make_error( + "incompatible DWARF compile unit versions: " + utostr(Version) + + " and " + utostr(Header.Version)); + } + + // Add the contributions of each section to this unit entry, now that we + // know the IndexVersion to use. + for (auto Pair : SectionLength) { + auto Index = getContributionIndex(Pair.first, IndexVersion); + CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; + ContributionOffsets[Index] += + (CurEntry.Contributions[Index].Length = Pair.second); + } writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection, - CurStrOffsetSection, CompileUnitHeader); + CurStrOffsetSection, Header.Version); + uint32_t &InfoSectionOffset = + ContributionOffsets[getContributionIndex(DW_SECT_INFO, IndexVersion)]; + bool foundTypeUnits = false; if (CurCUIndexSection.empty()) { - Expected EID = getCUIdentifiers( - AbbrevSection, InfoSection, CurStrOffsetSection, CurStrSection); - if (!EID) - return createFileError(Input, EID.takeError()); - const auto &ID = *EID; - auto P = IndexEntries.insert(std::make_pair(ID.Signature, CurEntry)); - if (!P.second) - return buildDuplicateError(*P.first, ID, ""); - P.first->second.Name = ID.Name; - P.first->second.DWOName = ID.DWOName; - addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, - CurEntry, - ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)]); + Out.SwitchSection(InfoSection); + for (StringRef Info : CurInfoSection) { + uint64_t UnitOffset = 0; + while (Info.size() > UnitOffset) { + Expected HeaderOrError = + parseInfoSectionUnitHeader(Info.substr(UnitOffset, Info.size())); + if (!HeaderOrError) + return HeaderOrError.takeError(); + InfoSectionUnitHeader &Header = *HeaderOrError; + UnitIndexEntry Entry = CurEntry; + auto &C = Entry.Contributions[getContributionIndex(DW_SECT_INFO, + IndexVersion)]; + C.Offset = InfoSectionOffset; + C.Length = Header.Length + 4; + + UnitOffset += C.Length; + // In DWARFv5 the debug info section may contain type units. + if (Header.Version >= 5 && + Header.UnitType == dwarf::DW_UT_split_type) { + auto P = TypeIndexEntries.insert( + std::make_pair(Header.Signature.getValue(), Entry)); + if (!P.second) + continue; + foundTypeUnits = true; + } else { + // Otherwise, this is assumed to be a compile unit. + Expected EID = + getCUIdentifiers(Header, AbbrevSection, + Info.substr(UnitOffset - C.Length, C.Length), + CurStrOffsetSection, CurStrSection); + if (!EID) + return createFileError(Input, EID.takeError()); + const auto &ID = *EID; + auto P = IndexEntries.insert(std::make_pair(ID.Signature, Entry)); + if (!P.second) + return buildDuplicateError(*P.first, ID, ""); + P.first->second.Name = ID.Name; + P.first->second.DWOName = ID.DWOName; + } + Out.emitBytes(Info.substr(UnitOffset - C.Length, C.Length)); + InfoSectionOffset += C.Length; + } + } + + // Add types from the .debug_types section from DWARF < 5. + if (IndexVersion == 2) { + addAllTypesFromTypesSection(Out, TypeIndexEntries, TypesSection, + CurTypesSection, CurEntry, + ContributionOffsets[getContributionIndex( + DW_SECT_EXT_TYPES, IndexVersion)]); + } continue; } + if (CurInfoSection.size() != 1) + return make_error("expected exactly one occurrence of a debug " + "info section in a .dwp file"); + StringRef DwpSingleInfoSection = CurInfoSection.front(); + + Out.SwitchSection(InfoSection); DWARFUnitIndex CUIndex(DW_SECT_INFO); DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0); if (!CUIndex.parse(CUIndexData)) return make_error("failed to parse cu_index"); - if (CUIndex.getVersion() != 2) - return make_error( - "unsupported cu_index version: " + utostr(CUIndex.getVersion()) + - " (only version 2 is supported)"); + if (CUIndex.getVersion() != IndexVersion) + return make_error("incompatible cu_index versions, found " + + utostr(CUIndex.getVersion()) + + " and expecting " + utostr(IndexVersion)); for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { auto *I = E.getContributions(); if (!I) continue; auto P = IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry)); + Expected HeaderOrError = + parseInfoSectionUnitHeader(DwpSingleInfoSection); + if (!HeaderOrError) + return HeaderOrError.takeError(); + InfoSectionUnitHeader &Header = *HeaderOrError; + Expected EID = getCUIdentifiers( - getSubsection(AbbrevSection, E, DW_SECT_ABBREV), - getSubsection(InfoSection, E, DW_SECT_INFO), + Header, getSubsection(AbbrevSection, E, DW_SECT_ABBREV), + getSubsection(DwpSingleInfoSection, E, DW_SECT_INFO), getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS), CurStrSection); if (!EID) @@ -766,45 +841,78 @@ for (auto Kind : CUIndex.getColumnKinds()) { if (!isSupportedSectionKind(Kind)) continue; - auto &C = NewEntry.Contributions[getContributionIndex(Kind)]; + auto &C = + NewEntry.Contributions[getContributionIndex(Kind, IndexVersion)]; C.Offset += I->Offset; C.Length = I->Length; ++I; } + unsigned Index = getContributionIndex(DW_SECT_INFO, IndexVersion); + auto &C = NewEntry.Contributions[Index]; + Out.emitBytes(DwpSingleInfoSection.substr( + C.Offset - CurEntry.Contributions[Index].Offset, C.Length)); + C.Offset = InfoSectionOffset; + InfoSectionOffset += C.Length; } - if (!CurTypesSection.empty()) { - if (CurTypesSection.size() != 1) - return make_error("multiple type unit sections in .dwp file"); - DWARFUnitIndex TUIndex(DW_SECT_EXT_TYPES); + foundTypeUnits |= !CurTypesSection.empty(); + if (foundTypeUnits) { + llvm::DWARFSectionKind TUSectionKind; + MCSection *OutSection; + StringRef TypeInputSection; + // Write type units into debug info section for DWARFv5. + if (Version >= 5) { + TUSectionKind = DW_SECT_INFO; + OutSection = InfoSection; + TypeInputSection = DwpSingleInfoSection; + } else { + // Write type units into debug types section for DWARF < 5. + if (CurTypesSection.size() != 1) + return make_error( + "multiple type unit sections in .dwp file"); + + TUSectionKind = DW_SECT_EXT_TYPES; + OutSection = TypesSection; + TypeInputSection = CurTypesSection.front(); + } + + DWARFUnitIndex TUIndex(TUSectionKind); DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0); if (!TUIndex.parse(TUIndexData)) return make_error("failed to parse tu_index"); - if (TUIndex.getVersion() != 2) - return make_error( - "unsupported tu_index version: " + utostr(TUIndex.getVersion()) + - " (only version 2 is supported)"); - - addAllTypesFromDWP( - Out, TypeIndexEntries, TUIndex, TypesSection, CurTypesSection.front(), - CurEntry, - ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)]); + if (TUIndex.getVersion() != IndexVersion) + return make_error("incompatible tu_index versions, found " + + utostr(TUIndex.getVersion()) + + " and expecting " + utostr(IndexVersion)); + + unsigned TypesContributionIndex = + getContributionIndex(TUSectionKind, IndexVersion); + addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, OutSection, + TypeInputSection, CurEntry, + ContributionOffsets[TypesContributionIndex], + TypesContributionIndex); } } - // Lie about there being no info contributions so the TU index only includes - // the type unit contribution - ContributionOffsets[0] = 0; - writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets, - TypeIndexEntries); - - // Lie about the type contribution - ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)] = 0; - // Unlie about the info contribution - ContributionOffsets[0] = 1; + if (Version < 5) { + // Lie about there being no info contributions so the TU index only includes + // the type unit contribution for DWARF < 5. In DWARFv5 the TU index has a + // contribution to the info section, so we do not want to lie about it. + ContributionOffsets[0] = 0; + } + writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets, + TypeIndexEntries, IndexVersion); + + if (Version < 5) { + // Lie about the type contribution for DWARF < 5. In DWARFv5 the type + // section does not exist, so no need to do anything a bout this. + ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)] = 0; + // Unlie about the info contribution + ContributionOffsets[0] = 1; + } writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets, - IndexEntries); + IndexEntries, IndexVersion); return Error::success(); }