[llvm-dwp] Add support for DWARFv5 type units ...
authorKim-Anh Tran <kimanh@chromium.org>
Wed, 2 Jun 2021 19:24:08 +0000 (12:24 -0700)
committerDavid Blaikie <dblaikie@gmail.com>
Wed, 2 Jun 2021 19:24:08 +0000 (12:24 -0700)
This patch adds support for DWARFv5 type units: parsing from
the .debug_info section, and writing index to the type unit index.
Previously, the type units were part of the .debug_types section
which is no longer used in DWARFv5.

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D101818

llvm/test/tools/llvm-dwp/Inputs/type_dedup_v5/a.s [new file with mode: 0644]
llvm/test/tools/llvm-dwp/Inputs/type_dedup_v5/b.s [new file with mode: 0644]
llvm/test/tools/llvm-dwp/X86/cu_and_tu_info_section_v5.s
llvm/test/tools/llvm-dwp/X86/incompatible_tu_index_version.s [moved from llvm/test/tools/llvm-dwp/X86/unsupported_tu_index_version.s with 97% similarity]
llvm/test/tools/llvm-dwp/X86/missing_tu_index.test
llvm/test/tools/llvm-dwp/X86/tu_units_v5.s [new file with mode: 0644]
llvm/test/tools/llvm-dwp/X86/type_dedup_v5.test [new file with mode: 0644]
llvm/tools/llvm-dwp/llvm-dwp.cpp

diff --git a/llvm/test/tools/llvm-dwp/Inputs/type_dedup_v5/a.s b/llvm/test/tools/llvm-dwp/Inputs/type_dedup_v5/a.s
new file mode 100644 (file)
index 0000000..e1806f3
--- /dev/null
@@ -0,0 +1,39 @@
+## Note: For the purpose of checking the de-duplication of type units
+## it is not necessary to have the DIEs for the structure type, that
+## are referenced by the type unit.
+
+  .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 (DW_UT_split_type)
+  .byte        8                               # Address Size (in bytes)
+  .long        0                               # Offset Into Abbrev. Section
+  .quad        5657452045627120676             # Type Signature
+  .long        25                              # Type DIE Offset
+  .byte        2                               # Abbrev [2] DW_TAG_type_unit
+  .byte        3                               # Abbrev [3] DW_TAG_structure_type
+  .byte        0                               # End Of Children Mark
+.Ldebug_info_dwo_end0:
+  .section     .debug_info.dwo,"e",@progbits
+  .long        .Ldebug_info_dwo_end2-.Ldebug_info_dwo_start2 # Length of Unit
+.Ldebug_info_dwo_start2:
+  .short       5                               # DWARF version number
+  .byte        5                               # DWARF Unit Type (DW_UT_split_compile)
+  .byte        8                               # Address Size (in bytes)
+  .long        0                               # Offset Into Abbrev. Section
+  .quad        0
+  .byte        1                               # Abbrev [1] DW_TAG_compile_unit
+.Ldebug_info_dwo_end2:
+  .section     .debug_abbrev.dwo,"e",@progbits
+  .byte        1                               # Abbreviation Code
+  .byte        17                              # DW_TAG_compile_unit
+  .byte        0                               # DW_CHILDREN_no
+  .byte        0                               # EOM(1)
+  .byte        0                               # EOM(2)
+  .byte        2                               # Abbreviation Code
+  .byte        65                              # DW_TAG_type_unit
+  .byte        1                               # DW_CHILDREN_yes
+  .byte        0                               # EOM
+  .byte        0                               # EOM
+  .byte        0                               # EOM
diff --git a/llvm/test/tools/llvm-dwp/Inputs/type_dedup_v5/b.s b/llvm/test/tools/llvm-dwp/Inputs/type_dedup_v5/b.s
new file mode 100644 (file)
index 0000000..3751256
--- /dev/null
@@ -0,0 +1,39 @@
+## Note: For the purpose of checking the de-duplication of type units
+## it is not necessary to have the DIEs for the structure type, that
+## are referenced by the type unit.
+
+    .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 (DW_UT_split_type)
+    .byte      8                               # Address Size (in bytes)
+    .long      0                               # Offset Into Abbrev. Section
+    .quad      5657452045627120676             # Type Signature
+    .long      25                              # Type DIE Offset
+    .byte      2                               # Abbrev [2] DW_TAG_type_unit
+    .byte      3                               # Abbrev [3] DW_TAG_structure_type
+    .byte      0                               # End Of Children Mark
+.Ldebug_info_dwo_end0:
+    .section   .debug_info.dwo,"e",@progbits
+    .long      .Ldebug_info_dwo_end2-.Ldebug_info_dwo_start2 # Length of Unit
+.Ldebug_info_dwo_start2:
+    .short     5                               # DWARF version number
+    .byte      5                               # DWARF Unit Type (DW_UT_split_compile)
+    .byte      8                               # Address Size (in bytes)
+    .long      0                               # Offset Into Abbrev. Section
+    .quad      -1709724327721109161
+    .byte      1                               # Abbrev [1] DW_TAG_compile_unit
+.Ldebug_info_dwo_end2:
+    .section   .debug_abbrev.dwo,"e",@progbits
+    .byte      1                               # Abbreviation Code
+    .byte      17                              # DW_TAG_compile_unit
+    .byte      0                               # DW_CHILDREN_no
+    .byte      0                               # EOM(1)
+    .byte      0                               # EOM(2)
+    .byte      2                               # Abbreviation Code
+    .byte      65                              # DW_TAG_type_unit
+    .byte      1                               # DW_CHILDREN_yes
+    .byte      0                               # EOM
+    .byte      0                               # EOM
+    .byte      0                               # EOM
index 8a1051b..09c79bf 100644 (file)
@@ -9,8 +9,8 @@
 ## have the info on the type and compile units.
 
 # CHECK-DAG: .debug_info.dwo contents
-# CHECK-NOT: Type Unit:
-# CHECK: 0x00000000: Compile Unit: length = 0x00000011, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_compile, abbr_offset = 0x0000, addr_size = 0x08, DWO_id = {{.*}} (next unit at 0x00000015)
+# CHECK: 0x00000000: Type Unit: length = 0x00000017, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_type, abbr_offset = 0x0000, addr_size = 0x08, name = '', type_signature = {{.*}}, type_offset = 0x0019 (next unit at 0x0000001b)
+# CHECK: 0x0000001b: Compile Unit: length = 0x00000011, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_compile, abbr_offset = 0x0000, addr_size = 0x08, DWO_id = {{.*}} (next unit at 0x00000030)
     .section   .debug_info.dwo,"e",@progbits
     .long      .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit
 .Ldebug_info_dwo_start0:
@@ -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: expected index version 2, but got: 5
+# CHECK: error: incompatible tu_index versions, found 5 and expecting 2 
 
 .section .debug_abbrev.dwo, "e", @progbits
 .LAbbrevBegin:
index b84ed7c..b927aa3 100644 (file)
@@ -1,3 +1,61 @@
-RUN: not llvm-dwp %p/../Inputs/missing_tu_index/x.dwp -o %t 2>&1 | FileCheck %s
+# 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: failed to parse tu_index
+## Note: To reach the test point, we need a DWP file with a CU, a CU index
+## and a broken TU index.
+
+# CHECK: error: failed to parse tu_index
+
+.section .debug_abbrev.dwo, "e", @progbits
+.LAbbrevBegin:
+    .uleb128 1                      # Abbreviation Code
+    .uleb128 17                     # DW_TAG_compile_unit
+    .byte 1                         # DW_CHILDREN_no
+    .uleb128 0x2131                 # DW_AT_GNU_dwo_id
+    .uleb128 7                      # DW_FORM_data8
+    .byte 0                         # EOM(1)
+    .byte 0                         # EOM(2)
+    .byte 0                         # EOM(3)
+.LAbbrevEnd:
+
+    .section .debug_info.dwo, "e", @progbits
+.LCUBegin:
+    .long .LCUEnd-.LCUVersion       # Length of Unit
+.LCUVersion:
+    .short 4                        # Version
+    .long 0                         # Abbrev offset
+    .byte 8                         # Address size
+    .uleb128 1                      # Abbrev [1] DW_TAG_compile_unit
+    .quad 0x1100001122222222        # DW_AT_GNU_dwo_id
+.LCUEnd:
+
+    .section .debug_types.dwo, "e", @progbits
+    .space 1
+
+    .section .debug_cu_index, "", @progbits
+
+## Header:
+    .long 2                         # Version
+    .long 2                         # Section count
+    .long 1                         # Unit count
+    .long 2                         # Slot count
+## Hash Table of Signatures:
+    .quad 0x1100001122222222
+    .quad 0
+## Parallel Table of Indexes:
+    .long 1
+    .long 0
+## Table of Section Offsets:
+## Row 0:
+    .long 1                         # DW_SECT_INFO
+    .long 3                         # DW_SECT_ABBREV
+## Row 1:
+    .long 0                         # Offset in .debug_info.dwo
+    .long 0                         # Offset in .debug_abbrev.dwo
+## Table of Section Sizes:
+    .long .LCUEnd-.LCUBegin         # Size in .debug_info.dwo
+    .long .LAbbrevEnd-.LAbbrevBegin # Size in .debug_abbrev.dwo
+
+    .section .debug_tu_index, "", @progbits
+## Header:
+    .short 2                        # Version
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 (file)
index 0000000..161e20f
--- /dev/null
@@ -0,0 +1,72 @@
+# 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
+
+## Note: In order to check whether the type unit index is generated
+## there is no need to add the missing DIEs for the structure type of the type unit.
+
+# CHECK-DAG: .debug_info.dwo contents:
+# CHECK: 0x00000000: Type Unit: length = 0x00000017, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_type, abbr_offset = 0x0000, addr_size = 0x08, name = '', type_signature = [[TUID1:.*]], type_offset = 0x0019 (next unit at 0x0000001b)
+# CHECK: 0x0000001b: Type Unit: length = 0x00000017, format = DWARF32, version = 0x0005, unit_type = DW_UT_split_type, abbr_offset = 0x0000, addr_size = 0x08, name = '', type_signature = [[TUID2:.*]], type_offset = 0x0019 (next unit at 0x00000036)
+# CHECK_DAG: .debug_tu_index contents:
+# CHECK: version = 5, units = 2, slots = 4
+# CHECK: Index Signature          INFO                     ABBREV
+# CHECK:     1 [[TUID1]]          [0x00000000, 0x0000001b) [0x00000000, 0x00000010)
+# CHECK:     4 [[TUID2]]          [0x0000001b, 0x00000036) [0x00000000, 0x00000010)
+
+    .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 (DW_UT_split_type)
+    .byte      8                               # Address Size (in bytes)
+    .long      0                               # Offset Into Abbrev. Section
+    .quad      5657452045627120676             # Type Signature
+    .long      25                              # Type DIE Offset
+    .byte      2                               # Abbrev [2] DW_TAG_type_unit
+    .byte      3                               # Abbrev [3] DW_TAG_structure_type
+    .byte      0                               # End Of Children Mark
+.Ldebug_info_dwo_end0:
+    .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      6                               # DWARF Unit Type (DW_UT_split_type)
+    .byte      8                               # Address Size (in bytes)
+    .long      0                               # Offset Into Abbrev. Section
+    .quad      -8528522068957683993            # Type Signature
+    .long      25                              # Type DIE Offset
+    .byte      4                               # Abbrev [4] DW_TAG_type_unit
+    .byte      5                               # Abbrev [5] DW_TAG_structure_type
+    .byte      0                               # End Of Children Mark
+.Ldebug_info_dwo_end1:
+    .section   .debug_info.dwo,"e",@progbits
+    .long      .Ldebug_info_dwo_end2-.Ldebug_info_dwo_start2 # Length of Unit
+.Ldebug_info_dwo_start2:
+    .short     5                               # DWARF version number
+    .byte      5                               # DWARF Unit Type (DW_UT_split_compile)
+    .byte      8                               # Address Size (in bytes)
+    .long      0                               # Offset Into Abbrev. Section
+    .quad      0
+    .byte      1                               # Abbrev [1] DW_TAG_compile_unit
+.Ldebug_info_dwo_end2:
+    .section   .debug_abbrev.dwo,"e",@progbits
+    .byte      1                               # Abbreviation Code
+    .byte      17                              # DW_TAG_compile_unit
+    .byte      0                               # DW_CHILDREN_no
+    .byte      0                               # EOM(1)
+    .byte      0                               # EOM(2)
+    .byte      2                               # Abbreviation Code
+    .byte      65                              # DW_TAG_type_unit
+    .byte      1                               # DW_CHILDREN_yes
+    .byte      0                               # EOM
+    .byte      0                               # EOM
+    .byte      4                               # Abbreviation Code
+    .byte      65                              # DW_TAG_type_unit
+    .byte      1                               # DW_CHILDREN_yes
+    .byte      0                               # EOM
+    .byte      0                               # EOM
+    .byte      0                               # EOM
diff --git a/llvm/test/tools/llvm-dwp/X86/type_dedup_v5.test b/llvm/test/tools/llvm-dwp/X86/type_dedup_v5.test
new file mode 100644 (file)
index 0000000..9fa007a
--- /dev/null
@@ -0,0 +1,11 @@
+# This test checks if llvm-dwp can deduplicate tu units (v5).
+
+# RUN: llvm-mc -triple x86_64-unknown-linux %p/../Inputs/type_dedup_v5/a.s -filetype=obj -o a.o \
+# RUN:         -split-dwarf-file=a.dwo -dwarf-version=5
+# RUN: llvm-mc -triple x86_64-unknown-linux %p/../Inputs/type_dedup_v5/b.s -filetype=obj -o b.o \
+# RUN:         -split-dwarf-file=b.dwo -dwarf-version=5
+# RUN: llvm-dwp a.dwo b.dwo -o %t.dwp
+# RUN: llvm-dwarfdump -debug-tu-index %t.dwp | FileCheck %s
+
+# CHECK_DAG: .debug_tu_index contents:
+# CHECK: version = 5, units = 1, slots = 2
index 21a5437..bdddc85 100644 (file)
@@ -361,10 +361,12 @@ static StringRef getSubsection(StringRef Section,
   return Section.substr(Off->Offset, Off->Length);
 }
 
-static void addAllTypesFromDWP(
-    MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
-    const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types,
-    const UnitIndexEntry &TUEntry, uint32_t &TypesOffset) {
+static void
+addAllTypesFromDWP(MCStreamer &Out,
+                   MapVector<uint64_t, UnitIndexEntry> &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();
@@ -385,21 +387,19 @@ static void addAllTypesFromDWP(
       C.Length = I->Length;
       ++I;
     }
-    unsigned TypesIndex =
-        getContributionIndex(DW_SECT_EXT_TYPES, TUIndex.getVersion());
-    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<uint64_t, UnitIndexEntry> &TypeIndexEntries,
-                        MCSection *OutputTypes,
-                        const std::vector<StringRef> &TypesSections,
-                        const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) {
+static void addAllTypesFromTypesSection(
+    MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
+    MCSection *OutputTypes, const std::vector<StringRef> &TypesSections,
+    const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) {
   for (StringRef Types : TypesSections) {
     Out.SwitchSection(OutputTypes);
     uint64_t Offset = 0;
@@ -748,8 +748,6 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
       bool FoundCUUnit = false;
       Out.SwitchSection(InfoSection);
       for (StringRef Info : CurInfoSection) {
-        if (FoundCUUnit)
-          break;
         uint64_t UnitOffset = 0;
         while (Info.size() > UnitOffset) {
           Expected<InfoSectionUnitHeader> HeaderOrError =
@@ -763,12 +761,13 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
                                                              IndexVersion)];
           C.Offset = InfoSectionOffset;
           C.Length = Header.Length + 4;
-
+          UnitOffset += C.Length;
           if (Header.Version < 5 ||
               Header.UnitType == dwarf::DW_UT_split_compile) {
-            Expected<CompileUnitIdentifiers> EID = getCUIdentifiers(
-                Header, AbbrevSection, Info.substr(UnitOffset, C.Length),
-                CurStrOffsetSection, CurStrSection);
+            Expected<CompileUnitIdentifiers> EID =
+                getCUIdentifiers(Header, AbbrevSection,
+                                 Info.substr(UnitOffset - C.Length, C.Length),
+                                 CurStrOffsetSection, CurStrSection);
 
             if (!EID)
               return createFileError(Input, EID.takeError());
@@ -779,12 +778,15 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
             P.first->second.Name = ID.Name;
             P.first->second.DWOName = ID.DWOName;
 
-            Out.emitBytes(Info.substr(UnitOffset, C.Length));
-            InfoSectionOffset += C.Length;
             FoundCUUnit = true;
-            break;
+          } else if (Header.UnitType == dwarf::DW_UT_split_type) {
+            auto P = TypeIndexEntries.insert(
+                std::make_pair(Header.Signature.getValue(), Entry));
+            if (!P.second)
+              continue;
           }
-          UnitOffset += Header.Length + 4;
+          Out.emitBytes(Info.substr(UnitOffset - C.Length, C.Length));
+          InfoSectionOffset += C.Length;
         }
       }
 
@@ -793,7 +795,7 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
 
       if (IndexVersion == 2) {
         // Add types from the .debug_types section from DWARF < 5.
-        addAllTypes(
+        addAllTypesFromTypesSection(
             Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry,
             ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)]);
       }
@@ -858,21 +860,41 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
       InfoSectionOffset += C.Length;
     }
 
-    if (!CurTypesSection.empty()) {
-      if (CurTypesSection.size() != 1)
-        return make_error<DWPError>("multiple type unit sections in .dwp file");
-      DWARFUnitIndex TUIndex(DW_SECT_EXT_TYPES);
+    if (!CurTUIndexSection.empty()) {
+      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<DWPError>(
+              "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<DWPError>("failed to parse tu_index");
-      if (TUIndex.getVersion() != 2)
-        return make_error<DWPError>("expected index version 2, but got: " +
-                                    utostr(TUIndex.getVersion()));
-
-      addAllTypesFromDWP(
-          Out, TypeIndexEntries, TUIndex, TypesSection, CurTypesSection.front(),
-          CurEntry,
-          ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)]);
+      if (TUIndex.getVersion() != IndexVersion)
+        return make_error<DWPError>("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);
     }
   }