[llvm-dwp] Adding support for v5 index writing
authorKim-Anh Tran <kimanh@chromium.org>
Wed, 2 Jun 2021 19:07:53 +0000 (12:07 -0700)
committerDavid Blaikie <dblaikie@gmail.com>
Wed, 2 Jun 2021 19:21:31 +0000 (12:21 -0700)
This patch adds general support for DWARFv5 index writing.
In particular, this means only allowing inputs with one version,
either DWARFv5 or DWARFv4.

This patch adds the .debug_macro section as an example,
but the DWARFv5 type support and loc and rangelists are still
missing (and upcoming).

Reviewed By: dblaikie

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

llvm/test/tools/llvm-dwp/X86/debug_macro_v5.s [new file with mode: 0644]
llvm/test/tools/llvm-dwp/X86/incompatible_cu_index_versions.s [moved from llvm/test/tools/llvm-dwp/X86/unsupported_cu_index_version.s with 80% similarity]
llvm/test/tools/llvm-dwp/X86/info-v5.s
llvm/test/tools/llvm-dwp/X86/unsupported_tu_index_version.s
llvm/tools/llvm-dwp/llvm-dwp.cpp

diff --git a/llvm/test/tools/llvm-dwp/X86/debug_macro_v5.s b/llvm/test/tools/llvm-dwp/X86/debug_macro_v5.s
new file mode 100644 (file)
index 0000000..d5e8be4
--- /dev/null
@@ -0,0 +1,55 @@
+# This test checks the support for writing macro sections and their index (v5).
+
+# RUN: llvm-mc -triple x86_64-unknown-linux --filetype=obj --split-dwarf-file=%t.dwo -dwarf-version=5 %s -o %t.o
+# RUN: llvm-dwp %t.dwo -o %t.dwp 2>&1
+# RUN: llvm-dwarfdump -debug-macro -debug-cu-index %t.dwp | FileCheck %s
+
+# CHECK-DAG: .debug_macro.dwo contents:
+# CHECK: macro header: version = 0x0005, flags = 0x00, format = DWARF32
+# CHECK-NEXT: DW_MACRO_start_file - lineno: 0 filenum: 0
+# CHECK-NEXT: DW_MACRO_define_strx - lineno: 1 macro: x 5
+# CHECK-NEXT: DW_MACRO_end_file
+
+# CHECK-DAG: .debug_cu_index contents:
+# CHECK-NEXT: version = 5, units = 1, slots = 2
+# CHECK: Index Signature          INFO                     ABBREV                   STR_OFFSETS              MACRO
+# CHECK:     1 0x0000000000000000 [0x00000000, 0x00000019) [0x00000000, 0x00000008) [0x00000000, 0x0000000c) [0x00000000, 0x0000000b)
+
+    .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      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] 0x14:0x5 DW_TAG_compile_unit
+    .long      0                               # DW_AT_macros
+.Ldebug_info_dwo_end0:
+    .section   .debug_macro.dwo,"e",@progbits
+    .short     5                               # Macro information version
+    .byte      0                               # Flags: 32 bit
+    .byte      3                               # DW_MACRO_start_file
+    .byte      0                               # Line Number
+    .byte      0                               # File Number
+    .byte      11                              # DW_MACRO_define_strx
+    .byte      1                               # Line Number
+    .byte      0                               # Macro String
+    .byte      4                               # DW_MACRO_end_file
+    .byte      0                               # End Of Macro List Mark
+    .section   .debug_abbrev.dwo,"e",@progbits
+    .byte      1                               # Abbreviation Code
+    .byte      17                              # DW_TAG_compile_unit
+    .byte      0                               # DW_CHILDREN_no
+    .byte      121                             # DW_AT_macros
+    .byte      23                              # DW_FORM_sec_offset
+    .byte      0                               # EOM(1)
+    .byte      0                               # EOM(2)
+    .byte      0                               # EOM(3)
+    .section   .debug_str.dwo,"eMS",@progbits,1
+    .asciz     "x 5"                           # string offset=0
+    .section   .debug_str_offsets.dwo,"e",@progbits
+    .long      8                            # Length of String Offsets Set
+    .short     5
+    .short     0
+  .long        0
@@ -1,19 +1,20 @@
 # 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:
     .short 5                       # DWARF version number
-    .byte 5                        # DWARF Unit type
+    .byte 5                        # DWARF Unit type (DW_UT_split_compile)
     .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
index c4ffdfc..c628df3 100644 (file)
@@ -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)
 
index cbbb77b..9e12c8e 100644 (file)
@@ -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: expected index version 2, but got: 5
 
 .section .debug_abbrev.dwo, "e", @progbits
 .LAbbrevBegin:
index 926df64..21a5437 100644 (file)
@@ -174,7 +174,7 @@ static void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings,
                                    MCSection *StrOffsetSection,
                                    StringRef CurStrSection,
                                    StringRef CurStrOffsetSection,
-                                   const InfoSectionUnitHeader &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())
@@ -195,7 +195,7 @@ static void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings,
 
   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.
@@ -340,10 +340,10 @@ static bool isSupportedSectionKind(DWARFSectionKind Kind) {
 
 // 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
@@ -379,12 +379,14 @@ static void addAllTypesFromDWP(
     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);
+    unsigned TypesIndex =
+        getContributionIndex(DW_SECT_EXT_TYPES, TUIndex.getVersion());
     auto &C = Entry.Contributions[TypesIndex];
     Out.emitBytes(Types.substr(
         C.Offset - TUEntry.Contributions[TypesIndex].Offset, C.Length));
@@ -406,7 +408,7 @@ static void addAllTypes(MCStreamer &Out,
       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.
@@ -438,10 +440,10 @@ writeIndexTable(MCStreamer &Out, ArrayRef<unsigned> ContributionOffsets,
         Out.emitIntValue(E.second.Contributions[i].*Field, 4);
 }
 
-static void
-writeIndex(MCStreamer &Out, MCSection *Section,
-           ArrayRef<unsigned> ContributionOffsets,
-           const MapVector<uint64_t, UnitIndexEntry> &IndexEntries) {
+static void writeIndex(MCStreamer &Out, MCSection *Section,
+                       ArrayRef<unsigned> ContributionOffsets,
+                       const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
+                       uint32_t IndexVersion) {
   if (IndexEntries.empty())
     return;
 
@@ -467,7 +469,7 @@ writeIndex(MCStreamer &Out, MCSection *Section,
   }
 
   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
@@ -551,7 +553,8 @@ static Error handleSection(
     StringRef &CurStrSection, StringRef &CurStrOffsetSection,
     std::vector<StringRef> &CurTypesSection,
     std::vector<StringRef> &CurInfoSection, StringRef &AbbrevSection,
-    StringRef &CurCUIndexSection, StringRef &CurTUIndexSection) {
+    StringRef &CurCUIndexSection, StringRef &CurTUIndexSection,
+    std::vector<std::pair<DWARFSectionKind, uint32_t>> &SectionLength) {
   if (Section.isBSS())
     return Error::success();
 
@@ -578,11 +581,8 @@ static Error handleSection(
     return Error::success();
 
   if (DWARFSectionKind Kind = SectionPair->second.second) {
-    auto Index = getContributionIndex(Kind);
     if (Kind != DW_SECT_EXT_TYPES && Kind != DW_SECT_INFO) {
-      CurEntry.Contributions[Index].Offset = ContributionOffsets[Index];
-      ContributionOffsets[Index] +=
-          (CurEntry.Contributions[Index].Length = Contents.size());
+      SectionLength.push_back(std::make_pair(Kind, Contents.size()));
     }
 
     if (Kind == DW_SECT_ABBREV) {
@@ -664,6 +664,7 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
       {"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}},
       {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}},
       {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}},
+      {"debug_macro.dwo", {MCOFI.getDwarfMacroDWOSection(), DW_SECT_MACRO}},
       {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}},
       {"debug_cu_index", {CUIndexSection, static_cast<DWARFSectionKind>(0)}},
       {"debug_tu_index", {TUIndexSection, static_cast<DWARFSectionKind>(0)}}};
@@ -672,6 +673,8 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
   MapVector<uint64_t, UnitIndexEntry> TypeIndexEntries;
 
   uint32_t ContributionOffsets[8] = {};
+  uint16_t Version = 0;
+  uint32_t IndexVersion = 0;
 
   DWPStringPool Strings(Out, StrSection);
 
@@ -698,6 +701,11 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
     StringRef CurCUIndexSection;
     StringRef CurTUIndexSection;
 
+    // This maps each section contained in this file to its length.
+    // This information is later on used to calculate the contributions,
+    // i.e. offset and length, of each compile/type unit to a section.
+    std::vector<std::pair<DWARFSectionKind, uint32_t>> SectionLength;
+
     for (const auto &Section : Obj.sections())
       if (auto Err = handleSection(
               KnownSections, StrSection, StrOffsetSection, TypesSection,
@@ -705,7 +713,7 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
               UncompressedSections, ContributionOffsets, CurEntry,
               CurStrSection, CurStrOffsetSection, CurTypesSection,
               CurInfoSection, AbbrevSection, CurCUIndexSection,
-              CurTUIndexSection))
+              CurTUIndexSection, SectionLength))
         return Err;
 
     if (CurInfoSection.empty())
@@ -717,11 +725,25 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
       return HeaderOrErr.takeError();
     InfoSectionUnitHeader &Header = *HeaderOrErr;
 
+    if (Version == 0) {
+      Version = Header.Version;
+      IndexVersion = Version < 5 ? 2 : 5;
+    } else if (Version != Header.Version) {
+      return make_error<DWPError>("incompatible DWARF compile unit versions.");
+    }
+
     writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection,
-                           CurStrOffsetSection, Header);
+                           CurStrOffsetSection, Header.Version);
+
+    for (auto Pair : SectionLength) {
+      auto Index = getContributionIndex(Pair.first, IndexVersion);
+      CurEntry.Contributions[Index].Offset = ContributionOffsets[Index];
+      ContributionOffsets[Index] +=
+          (CurEntry.Contributions[Index].Length = Pair.second);
+    }
 
     uint32_t &InfoSectionOffset =
-        ContributionOffsets[getContributionIndex(DW_SECT_INFO)];
+        ContributionOffsets[getContributionIndex(DW_SECT_INFO, IndexVersion)];
     if (CurCUIndexSection.empty()) {
       bool FoundCUUnit = false;
       Out.SwitchSection(InfoSection);
@@ -737,7 +759,8 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
           InfoSectionUnitHeader &Header = *HeaderOrError;
 
           UnitIndexEntry Entry = CurEntry;
-          auto &C = Entry.Contributions[getContributionIndex(DW_SECT_INFO)];
+          auto &C = Entry.Contributions[getContributionIndex(DW_SECT_INFO,
+                                                             IndexVersion)];
           C.Offset = InfoSectionOffset;
           C.Length = Header.Length + 4;
 
@@ -768,11 +791,12 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
       if (!FoundCUUnit)
         return make_error<DWPError>("no compile unit found in file: " + Input);
 
-      // Add types from the .debug_types section from DWARF < 5.
-      addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection,
-                  CurEntry,
-                  ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)]);
-
+      if (IndexVersion == 2) {
+        // Add types from the .debug_types section from DWARF < 5.
+        addAllTypes(
+            Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry,
+            ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)]);
+      }
       continue;
     }
 
@@ -785,10 +809,10 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
     DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0);
     if (!CUIndex.parse(CUIndexData))
       return make_error<DWPError>("failed to parse cu_index");
-    if (CUIndex.getVersion() != 2)
-      return make_error<DWPError>(
-          "unsupported cu_index version: " + utostr(CUIndex.getVersion()) +
-          " (only version 2 is supported)");
+    if (CUIndex.getVersion() != IndexVersion)
+      return make_error<DWPError>("incompatible cu_index versions, found " +
+                                  utostr(CUIndex.getVersion()) +
+                                  " and expecting " + utostr(IndexVersion));
 
     Out.SwitchSection(InfoSection);
     for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) {
@@ -821,12 +845,13 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
       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);
+      unsigned Index = getContributionIndex(DW_SECT_INFO, IndexVersion);
       auto &C = NewEntry.Contributions[Index];
       Out.emitBytes(CUInfoSection);
       C.Offset = InfoSectionOffset;
@@ -841,30 +866,35 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
       if (!TUIndex.parse(TUIndexData))
         return make_error<DWPError>("failed to parse tu_index");
       if (TUIndex.getVersion() != 2)
-        return make_error<DWPError>(
-            "unsupported tu_index version: " + utostr(TUIndex.getVersion()) +
-            " (only version 2 is supported)");
+        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)]);
+          ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)]);
     }
   }
 
-  // Lie about there being no info contributions so the TU index only includes
-  // the type unit contribution
-  ContributionOffsets[0] = 0;
+  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);
-
-  // Lie about the type contribution
-  ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)] = 0;
-  // Unlie about the info contribution
-  ContributionOffsets[0] = 1;
+             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 about 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();
 }