[DWARFLinker][DWARFv5] Add support for .debug_rnglists.
authorAlexey Lapshin <a.v.lapshin@mail.ru>
Sun, 26 Feb 2023 17:57:50 +0000 (18:57 +0100)
committerAlexey Lapshin <a.v.lapshin@mail.ru>
Sun, 26 Feb 2023 18:18:51 +0000 (19:18 +0100)
This patch adds support of DWARFv5 .debug_rnglists table.
As DWARFLinker resolves relocations, it is able to always
use DW_FORM_addr instead of DW_FORM_addrx. DW_FORM_addrx
helps to minimize number of relocations, it is also used for
split DWARF. Both of these cases are not relevant for the
DWARFLinker. Thus, this patch converts all DW_FORM_addrx
forms into the DW_FORM_addr. And, as the result, it converts
range lists of DW_FORM_rnglistx form into the DW_FORM_sec_offset.
For the --update case all DW_FORM_addrx, DW_FORM_rnglistx
are preserved as is.

Reviewed By: aprantl

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

13 files changed:
llvm/include/llvm/DWARFLinker/DWARFLinker.h
llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
llvm/include/llvm/DWARFLinker/DWARFStreamer.h
llvm/lib/DWARFLinker/DWARFLinker.cpp
llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
llvm/lib/DWARFLinker/DWARFStreamer.cpp
llvm/test/tools/dsymutil/Inputs/dwarf5-rnglists.o [new file with mode: 0644]
llvm/test/tools/dsymutil/X86/dwarf5-addrx.test
llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test [new file with mode: 0644]
llvm/test/tools/dsymutil/X86/op-convert-offset.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addrx.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test [new file with mode: 0644]
llvm/test/tools/llvm-dwarfutil/ELF/X86/warning-skipped-rnglists.test [deleted file]

index 30f0c1c..ebfac89 100644 (file)
@@ -117,16 +117,23 @@ public:
   virtual void
   emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &Table) = 0;
 
-  /// Emit piece of .debug_ranges for \p Ranges.
+  /// Emit debug ranges(.debug_ranges, .debug_rnglists) header.
+  virtual MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) = 0;
+
+  /// Emit debug ranges(.debug_ranges, .debug_rnglists) fragment.
   virtual void
-  emitDwarfDebugRangesTableFragment(const CompileUnit &Unit,
-                                    const AddressRanges &LinkedRanges) = 0;
+  emitDwarfDebugRangeListFragment(const CompileUnit &Unit,
+                                  const AddressRanges &LinkedRanges,
+                                  PatchLocation Patch) = 0;
+
+  /// Emit debug ranges(.debug_ranges, .debug_rnglists) footer.
+  virtual void emitDwarfDebugRangeListFooter(const CompileUnit &Unit,
+                                             MCSymbol *EndLabel) = 0;
 
-  /// Emit .debug_aranges entries for \p Unit and if \p DoRangesSection is true,
-  /// also emit the .debug_ranges entries for the DW_TAG_compile_unit's
-  /// DW_AT_ranges attribute.
-  virtual void emitUnitRangesEntries(CompileUnit &Unit,
-                                     bool DoRangesSection) = 0;
+  /// Emit .debug_aranges entries for \p Unit
+  virtual void
+  emitDwarfDebugArangesTable(const CompileUnit &Unit,
+                             const AddressRanges &LinkedRanges) = 0;
 
   /// Copy the .debug_line over to the updated binary while unobfuscating the
   /// file names and directories.
@@ -189,6 +196,9 @@ public:
   /// Returns size of generated .debug_ranges section.
   virtual uint64_t getRangesSectionSize() const = 0;
 
+  /// Returns size of generated .debug_rnglists section.
+  virtual uint64_t getRngListsSectionSize() const = 0;
+
   /// Returns size of generated .debug_info section.
   virtual uint64_t getDebugInfoSectionSize() const = 0;
 
@@ -724,14 +734,9 @@ private:
   /// Assign an abbreviation number to \p Abbrev
   void assignAbbrev(DIEAbbrev &Abbrev);
 
-  /// Compute and emit .debug_ranges section for \p Unit, and
-  /// patch the attributes referencing it.
-  void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf,
-                          const DWARFFile &File) const;
-
-  /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had
-  /// one.
-  void generateUnitRanges(CompileUnit &Unit) const;
+  /// Compute and emit debug ranges(.debug_aranges, .debug_ranges,
+  /// .debug_rnglists) for \p Unit, patch the attributes referencing it.
+  void generateUnitRanges(CompileUnit &Unit, const DWARFFile &File) const;
 
   /// Extract the line tables from the original dwarf, extract the relevant
   /// parts according to the linked function ranges and emit the result in the
index 9c7f24e..39305a3 100644 (file)
@@ -43,6 +43,8 @@ struct PatchLocation {
   }
 };
 
+using RngListAttributesTy = SmallVector<PatchLocation>;
+
 /// Stores all information relating to a compile unit, be it in its original
 /// instance in the object file to its brand new cloned and generated DIE tree.
 class CompileUnit {
@@ -143,14 +145,12 @@ public:
   uint64_t getHighPc() const { return HighPc; }
   bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); }
 
-  std::optional<PatchLocation> getUnitRangesAttribute() const {
-    return UnitRangeAttribute;
-  }
-
   const RangesTy &getFunctionRanges() const { return Ranges; }
 
-  const std::vector<PatchLocation> &getRangesAttributes() const {
-    return RangeAttributes;
+  const RngListAttributesTy &getRangesAttributes() { return RangeAttributes; }
+
+  std::optional<PatchLocation> getUnitRangesAttribute() const {
+    return UnitRangeAttribute;
   }
 
   const std::vector<std::pair<PatchLocation, int64_t>> &
@@ -278,10 +278,10 @@ private:
   /// The DW_AT_low_pc of each DW_TAG_label.
   SmallDenseMap<uint64_t, uint64_t, 1> Labels;
 
-  /// DW_AT_ranges attributes to patch after we have gathered
-  /// all the unit's function addresses.
+  /// 'rnglist'(DW_AT_ranges, DW_AT_start_scope) attributes to patch after
+  /// we have gathered all the unit's function addresses.
   /// @{
-  std::vector<PatchLocation> RangeAttributes;
+  RngListAttributesTy RangeAttributes;
   std::optional<PatchLocation> UnitRangeAttribute;
   /// @}
 
index 24248c8..69d1f93 100644 (file)
@@ -93,18 +93,28 @@ public:
       llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
       StringRef Buffer, uint32_t Alignment, uint32_t Size);
 
-  /// Emit piece of .debug_ranges for \p Ranges.
-  virtual void
-  emitDwarfDebugRangesTableFragment(const CompileUnit &Unit,
-                                    const AddressRanges &LinkedRanges) override;
+  /// Emit debug ranges(.debug_ranges, .debug_rnglists) header.
+  MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) override;
 
-  /// Emit debug_aranges entries for \p Unit and if \p DoRangesSection is true,
-  /// also emit the debug_ranges entries for the DW_TAG_compile_unit's
-  /// DW_AT_ranges attribute.
-  void emitUnitRangesEntries(CompileUnit &Unit, bool DoRangesSection) override;
+  /// Emit debug ranges(.debug_ranges, .debug_rnglists) fragment.
+  void emitDwarfDebugRangeListFragment(const CompileUnit &Unit,
+                                       const AddressRanges &LinkedRanges,
+                                       PatchLocation Patch) override;
+
+  /// Emit debug ranges(.debug_ranges, .debug_rnglists) footer.
+  void emitDwarfDebugRangeListFooter(const CompileUnit &Unit,
+                                     MCSymbol *EndLabel) override;
+
+  /// Emit .debug_aranges entries for \p Unit
+  void emitDwarfDebugArangesTable(const CompileUnit &Unit,
+                                  const AddressRanges &LinkedRanges) override;
 
   uint64_t getRangesSectionSize() const override { return RangesSectionSize; }
 
+  uint64_t getRngListsSectionSize() const override {
+    return RngListsSectionSize;
+  }
+
   /// Emit the debug_loc contribution for \p Unit by copying the entries from
   /// \p Dwarf and offsetting them. Update the location attributes to point to
   /// the new entries.
@@ -189,8 +199,16 @@ private:
   void emitMacroTableImpl(const DWARFDebugMacro *MacroTable,
                           const Offset2UnitMap &UnitMacroMap,
                           OffsetsStringPool &StringPool, uint64_t &OutOffset);
-  void emitDwarfDebugArangesTable(const CompileUnit &Unit,
-                                  const AddressRanges &LinkedRanges);
+
+  /// Emit piece of .debug_ranges for \p LinkedRanges.
+  void emitDwarfDebugRangesTableFragment(const CompileUnit &Unit,
+                                         const AddressRanges &LinkedRanges,
+                                         PatchLocation Patch);
+
+  /// Emit piece of .debug_rnglists for \p LinkedRanges.
+  void emitDwarfDebugRngListsTableFragment(const CompileUnit &Unit,
+                                           const AddressRanges &LinkedRanges,
+                                           PatchLocation Patch);
 
   /// \defgroup MCObjects MC layer objects constructed by the streamer
   /// @{
@@ -214,6 +232,7 @@ private:
   std::function<StringRef(StringRef Input)> Translator;
 
   uint64_t RangesSectionSize = 0;
+  uint64_t RngListsSectionSize = 0;
   uint64_t LocSectionSize = 0;
   uint64_t LineSectionSize = 0;
   uint64_t FrameSectionSize = 0;
index abe77ea..7640dfa 100644 (file)
@@ -1203,8 +1203,8 @@ unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
 
   dwarf::Form Form = AttrSpec.Form;
 
-  // FIXME: Generation of DWARFv5 .debug_addr table is not supported yet.
-  // Convert attribute into the dwarf::DW_FORM_addr.
+  // DWARFLinker does not use addrx forms since it generates relocated
+  // addresses. Replace DW_FORM_addrx with DW_FORM_addr here.
   if (Form == dwarf::DW_FORM_addrx)
     Form = dwarf::DW_FORM_addr;
 
@@ -1257,8 +1257,30 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
     return AttrSize;
   }
 
-  if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
-      Die.getTag() == dwarf::DW_TAG_compile_unit) {
+  [[maybe_unused]] dwarf::Form OriginalForm = AttrSpec.Form;
+  if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) {
+    // DWARFLinker does not generate .debug_addr table. Thus we need to change
+    // all "addrx" related forms to "addr" version. Change DW_FORM_rnglistx
+    // to DW_FORM_sec_offset here.
+    std::optional<uint64_t> Index = Val.getAsSectionOffset();
+    if (!Index) {
+      Linker.reportWarning("Cannot read the attribute. Dropping.", File,
+                           &InputDIE);
+      return 0;
+    }
+    std::optional<uint64_t> Offset =
+        Unit.getOrigUnit().getRnglistOffset(*Index);
+    if (!Offset) {
+      Linker.reportWarning("Cannot read the attribute. Dropping.", File,
+                           &InputDIE);
+      return 0;
+    }
+
+    Value = *Offset;
+    AttrSpec.Form = dwarf::DW_FORM_sec_offset;
+    AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();
+  } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
+             Die.getTag() == dwarf::DW_TAG_compile_unit) {
     std::optional<uint64_t> LowPC = Unit.getLowPc();
     if (!LowPC)
       return 0;
@@ -1279,11 +1301,11 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
   PatchLocation Patch =
       Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
                    dwarf::Form(AttrSpec.Form), DIEInteger(Value));
-  if (AttrSpec.Attr == dwarf::DW_AT_ranges) {
+  if (AttrSpec.Attr == dwarf::DW_AT_ranges ||
+      AttrSpec.Attr == dwarf::DW_AT_start_scope) {
     Unit.noteRangeAttribute(Die, Patch);
     Info.HasRanges = true;
   }
-
   // A more generic way to check for location attributes would be
   // nice, but it's very unlikely that any other attribute needs a
   // location list.
@@ -1294,6 +1316,10 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
   } else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
     Info.IsDeclaration = true;
 
+  // check that all dwarf::DW_FORM_rnglistx are handled previously.
+  assert((Info.HasRanges || (OriginalForm != dwarf::DW_FORM_rnglistx)) &&
+         "Unhandled DW_FORM_rnglistx attribute");
+
   return AttrSize;
 }
 
@@ -1343,6 +1369,7 @@ unsigned DWARFLinker::DIECloner::cloneAttribute(
   case dwarf::DW_FORM_sec_offset:
   case dwarf::DW_FORM_flag:
   case dwarf::DW_FORM_flag_present:
+  case dwarf::DW_FORM_rnglistx:
     return cloneScalarAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
                                 AttrSize, Info);
   default:
@@ -1412,6 +1439,15 @@ static bool shouldSkipAttribute(
   case dwarf::DW_AT_high_pc:
   case dwarf::DW_AT_ranges:
     return !Update && SkipPC;
+  case dwarf::DW_AT_addr_base:
+    // In case !Update the .debug_addr table is not generated/preserved.
+    return !Update;
+  case dwarf::DW_AT_rnglists_base:
+    // In case !Update the .debug_addr table is not generated/preserved.
+    // Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used.
+    // Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the
+    // DW_AT_rnglists_base is removed.
+    return !Update;
   case dwarf::DW_AT_str_offsets_base:
     // FIXME: Use the string offset table with Dwarf 5.
     return true;
@@ -1612,77 +1648,75 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
   return Die;
 }
 
-/// Patch the input object file relevant debug_ranges entries
-/// and emit them in the output file. Update the relevant attributes
+/// Patch the input object file relevant debug_ranges or debug_rnglists
+/// entries and emit them in the output file. Update the relevant attributes
 /// to point at the new entries.
-void DWARFLinker::patchRangesForUnit(const CompileUnit &Unit,
-                                     DWARFContext &OrigDwarf,
+void DWARFLinker::generateUnitRanges(CompileUnit &Unit,
                                      const DWARFFile &File) const {
-  DWARFDebugRangeList RangeList;
-  const auto &FunctionRanges = Unit.getFunctionRanges();
-  unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
-  DWARFDataExtractor RangeExtractor(OrigDwarf.getDWARFObj(),
-                                    OrigDwarf.getDWARFObj().getRangesSection(),
-                                    OrigDwarf.isLittleEndian(), AddressSize);
-  std::optional<AddressRangeValuePair> CachedRange;
-  DWARFUnit &OrigUnit = Unit.getOrigUnit();
-  auto OrigUnitDie = OrigUnit.getUnitDIE(false);
-  uint64_t UnitBaseAddress =
-      dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc), 0);
-
-  for (const auto &RangeAttribute : Unit.getRangesAttributes()) {
-    uint64_t Offset = RangeAttribute.get();
-    RangeAttribute.set(TheDwarfEmitter->getRangesSectionSize());
-    if (Error E = RangeList.extract(RangeExtractor, &Offset)) {
-      llvm::consumeError(std::move(E));
-      reportWarning("invalid range list ignored.", File);
-      RangeList.clear();
-    }
-    const auto &Entries = RangeList.getEntries();
-
-    uint64_t BaseAddress = UnitBaseAddress;
-    AddressRanges LinkedRanges;
-
-    if (!Entries.empty()) {
-      for (const auto &Range : Entries) {
-        if (Range.isBaseAddressSelectionEntry(
-                Unit.getOrigUnit().getAddressByteSize())) {
-          BaseAddress = Range.EndAddress;
-          continue;
-        }
+  if (LLVM_UNLIKELY(Options.Update))
+    return;
 
-        if (!CachedRange ||
-            !CachedRange->Range.contains(Range.StartAddress + BaseAddress))
-          CachedRange = FunctionRanges.getRangeThatContains(Range.StartAddress +
-                                                            BaseAddress);
+  const auto &FunctionRanges = Unit.getFunctionRanges();
 
-        // All range entries should lie in the function range.
-        if (!CachedRange) {
-          reportWarning("inconsistent range data.", File);
-          continue;
+  // Build set of linked address ranges for unit function ranges.
+  AddressRanges LinkedFunctionRanges;
+  for (const AddressRangeValuePair &Range : FunctionRanges)
+    LinkedFunctionRanges.insert(
+        {Range.Range.start() + Range.Value, Range.Range.end() + Range.Value});
+
+  // Emit LinkedFunctionRanges into .debug_aranges
+  if (!LinkedFunctionRanges.empty())
+    TheDwarfEmitter->emitDwarfDebugArangesTable(Unit, LinkedFunctionRanges);
+
+  RngListAttributesTy AllRngListAttributes = Unit.getRangesAttributes();
+  std::optional<PatchLocation> UnitRngListAttribute =
+      Unit.getUnitRangesAttribute();
+
+  if (!AllRngListAttributes.empty() || UnitRngListAttribute) {
+    std::optional<AddressRangeValuePair> CachedRange;
+    MCSymbol *EndLabel = TheDwarfEmitter->emitDwarfDebugRangeListHeader(Unit);
+
+    // Read original address ranges, apply relocation value, emit linked address
+    // ranges.
+    for (PatchLocation &AttributePatch : AllRngListAttributes) {
+      // Get ranges from the source DWARF corresponding to the current
+      // attribute.
+      AddressRanges LinkedRanges;
+      if (Expected<DWARFAddressRangesVector> OriginalRanges =
+              Unit.getOrigUnit().findRnglistFromOffset(AttributePatch.get())) {
+        // Apply relocation adjustment.
+        for (const auto &Range : *OriginalRanges) {
+          if (!CachedRange || !CachedRange->Range.contains(Range.LowPC))
+            CachedRange = FunctionRanges.getRangeThatContains(Range.LowPC);
+
+          // All range entries should lie in the function range.
+          if (!CachedRange) {
+            reportWarning("inconsistent range data.", File);
+            continue;
+          }
+
+          // Store range for emiting.
+          LinkedRanges.insert({Range.LowPC + CachedRange->Value,
+                               Range.HighPC + CachedRange->Value});
         }
-
-        LinkedRanges.insert(
-            {Range.StartAddress + BaseAddress + CachedRange->Value,
-             Range.EndAddress + BaseAddress + CachedRange->Value});
+      } else {
+        llvm::consumeError(OriginalRanges.takeError());
+        reportWarning("invalid range list ignored.", File);
       }
+
+      // Emit linked ranges.
+      TheDwarfEmitter->emitDwarfDebugRangeListFragment(Unit, LinkedRanges,
+                                                       AttributePatch);
     }
 
-    TheDwarfEmitter->emitDwarfDebugRangesTableFragment(Unit, LinkedRanges);
-  }
-}
+    // Emit ranges for Unit AT_ranges attribute.
+    if (UnitRngListAttribute.has_value())
+      TheDwarfEmitter->emitDwarfDebugRangeListFragment(
+          Unit, LinkedFunctionRanges, *UnitRngListAttribute);
 
-/// Generate the debug_aranges entries for \p Unit and if the
-/// unit has a DW_AT_ranges attribute, also emit the debug_ranges
-/// contribution for this attribute.
-/// FIXME: this could actually be done right in patchRangesForUnit,
-/// but for the sake of initial bit-for-bit compatibility with legacy
-/// dsymutil, we have to do it in a delayed pass.
-void DWARFLinker::generateUnitRanges(CompileUnit &Unit) const {
-  auto Attr = Unit.getUnitRangesAttribute();
-  if (Attr)
-    Attr->set(TheDwarfEmitter->getRangesSectionSize());
-  TheDwarfEmitter->emitUnitRangesEntries(Unit, static_cast<bool>(Attr));
+    // Emit ranges footer.
+    TheDwarfEmitter->emitDwarfDebugRangeListFooter(Unit, EndLabel);
+  }
 }
 
 /// Insert the new line info sequence \p Seq into the current
@@ -2265,7 +2299,8 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
       if (LLVM_UNLIKELY(Linker.Options.Update))
         continue;
 
-      Linker.patchRangesForUnit(*CurrentUnit, DwarfContext, File);
+      Linker.generateUnitRanges(*CurrentUnit, File);
+
       auto ProcessExpr = [&](StringRef Bytes,
                              SmallVectorImpl<uint8_t> &Buffer) {
         DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit();
@@ -2287,9 +2322,6 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
 
     // Emit all the compile unit's debug information.
     for (auto &CurrentUnit : CompileUnits) {
-      if (LLVM_LIKELY(!Linker.Options.Update))
-        Linker.generateUnitRanges(*CurrentUnit);
-
       CurrentUnit->fixupForwardReferences();
 
       if (!CurrentUnit->getOutputUnitDIE())
@@ -2384,6 +2416,10 @@ void DWARFLinker::copyInvariantDebugSection(DWARFContext &Dwarf) {
       Dwarf.getDWARFObj().getFrameSection().Data, "debug_frame");
   TheDwarfEmitter->emitSectionContents(Dwarf.getDWARFObj().getArangesSection(),
                                        "debug_aranges");
+  TheDwarfEmitter->emitSectionContents(
+      Dwarf.getDWARFObj().getAddrSection().Data, "debug_addr");
+  TheDwarfEmitter->emitSectionContents(
+      Dwarf.getDWARFObj().getRnglistsSection().Data, "debug_rnglists");
 }
 
 void DWARFLinker::addObjectFile(DWARFFile &File, objFileLoader Loader,
@@ -2474,16 +2510,6 @@ Error DWARFLinker::link() {
     // support or update references to these tables. Thus we report warning
     // and skip corresponding object file.
     if (!OptContext.File.Dwarf->getDWARFObj()
-             .getRnglistsSection()
-             .Data.empty()) {
-      reportWarning("'.debug_rnglists' is not currently supported: file "
-                    "will be skipped",
-                    OptContext.File);
-      OptContext.Skip = true;
-      continue;
-    }
-
-    if (!OptContext.File.Dwarf->getDWARFObj()
              .getLoclistsSection()
              .Data.empty()) {
       reportWarning("'.debug_loclists' is not currently supported: file "
index 6c9e052..870a841 100644 (file)
@@ -135,10 +135,12 @@ void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
 }
 
 void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
-  if (Die.getTag() != dwarf::DW_TAG_compile_unit)
-    RangeAttributes.push_back(Attr);
-  else
+  if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
     UnitRangeAttribute = Attr;
+    return;
+  }
+
+  RangeAttributes.emplace_back(Attr);
 }
 
 void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) {
index a34c407..3af7cde 100644 (file)
@@ -108,6 +108,7 @@ bool DwarfStreamer::init(Triple TheTriple,
   Asm->setDwarfUsesRelocationsAcrossSections(false);
 
   RangesSectionSize = 0;
+  RngListsSectionSize = 0;
   LocSectionSize = 0;
   LineSectionSize = 0;
   FrameSectionSize = 0;
@@ -202,6 +203,9 @@ void DwarfStreamer::emitSectionContents(StringRef SecData, StringRef SecName) {
           .Case("debug_frame", MC->getObjectFileInfo()->getDwarfFrameSection())
           .Case("debug_aranges",
                 MC->getObjectFileInfo()->getDwarfARangesSection())
+          .Case("debug_addr", MC->getObjectFileInfo()->getDwarfAddrSection())
+          .Case("debug_rnglists",
+                MC->getObjectFileInfo()->getDwarfRnglistsSection())
           .Default(nullptr);
 
   if (Section) {
@@ -363,11 +367,13 @@ void DwarfStreamer::emitDwarfDebugArangesTable(
 }
 
 void DwarfStreamer::emitDwarfDebugRangesTableFragment(
-    const CompileUnit &Unit, const AddressRanges &LinkedRanges) {
-  unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+    const CompileUnit &Unit, const AddressRanges &LinkedRanges,
+    PatchLocation Patch) {
+  Patch.set(RangesSectionSize);
 
   // Make .debug_ranges to be current section.
   MS->switchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
+  unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
 
   // Emit ranges.
   uint64_t BaseAddress = 0;
@@ -390,27 +396,91 @@ void DwarfStreamer::emitDwarfDebugRangesTableFragment(
   RangesSectionSize += AddressSize;
 }
 
-/// Emit the debug_aranges contribution of a unit and
-/// if \p DoDebugRanges is true the debug_range contents for a
-/// compile_unit level DW_AT_ranges attribute (Which are basically the
-/// same thing with a different base address).
-/// Just aggregate all the ranges gathered inside that unit.
-void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
-                                          bool DoDebugRanges) {
-  const RangesTy &FunctionRanges = Unit.getFunctionRanges();
-
-  // Linked addresses might end up in a different order.
-  // Build linked address ranges.
-  AddressRanges LinkedRanges;
-  for (const AddressRangeValuePair &Range : FunctionRanges)
-    LinkedRanges.insert(
-        {Range.Range.start() + Range.Value, Range.Range.end() + Range.Value});
-
-  if (!FunctionRanges.empty())
-    emitDwarfDebugArangesTable(Unit, LinkedRanges);
-
-  if (DoDebugRanges)
-    emitDwarfDebugRangesTableFragment(Unit, LinkedRanges);
+MCSymbol *
+DwarfStreamer::emitDwarfDebugRangeListHeader(const CompileUnit &Unit) {
+  if (Unit.getOrigUnit().getVersion() < 5)
+    return nullptr;
+
+  // Make .debug_rnglists to be current section.
+  MS->switchSection(MC->getObjectFileInfo()->getDwarfRnglistsSection());
+
+  MCSymbol *BeginLabel = Asm->createTempSymbol("Brnglists");
+  MCSymbol *EndLabel = Asm->createTempSymbol("Ernglists");
+  unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+
+  // Length
+  Asm->emitLabelDifference(EndLabel, BeginLabel, sizeof(uint32_t));
+  Asm->OutStreamer->emitLabel(BeginLabel);
+  RngListsSectionSize += sizeof(uint32_t);
+
+  // Version.
+  MS->emitInt16(5);
+  RngListsSectionSize += sizeof(uint16_t);
+
+  // Address size.
+  MS->emitInt8(AddressSize);
+  RngListsSectionSize++;
+
+  // Seg_size
+  MS->emitInt8(0);
+  RngListsSectionSize++;
+
+  // Offset entry count
+  MS->emitInt32(0);
+  RngListsSectionSize += sizeof(uint32_t);
+
+  return EndLabel;
+}
+
+void DwarfStreamer::emitDwarfDebugRangeListFragment(
+    const CompileUnit &Unit, const AddressRanges &LinkedRanges,
+    PatchLocation Patch) {
+  if (Unit.getOrigUnit().getVersion() < 5) {
+    emitDwarfDebugRangesTableFragment(Unit, LinkedRanges, Patch);
+    return;
+  }
+
+  emitDwarfDebugRngListsTableFragment(Unit, LinkedRanges, Patch);
+}
+
+void DwarfStreamer::emitDwarfDebugRangeListFooter(const CompileUnit &Unit,
+                                                  MCSymbol *EndLabel) {
+  if (Unit.getOrigUnit().getVersion() < 5)
+    return;
+
+  // Make .debug_rnglists to be current section.
+  MS->switchSection(MC->getObjectFileInfo()->getDwarfRnglistsSection());
+
+  if (EndLabel != nullptr)
+    Asm->OutStreamer->emitLabel(EndLabel);
+}
+
+void DwarfStreamer::emitDwarfDebugRngListsTableFragment(
+    const CompileUnit &Unit, const AddressRanges &LinkedRanges,
+    PatchLocation Patch) {
+  Patch.set(RngListsSectionSize);
+
+  // Make .debug_rnglists to be current section.
+  MS->switchSection(MC->getObjectFileInfo()->getDwarfRnglistsSection());
+
+  unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+
+  for (const AddressRange &Range : LinkedRanges) {
+    // Emit type of entry.
+    MS->emitInt8(dwarf::DW_RLE_start_length);
+    RngListsSectionSize += 1;
+
+    // Emit start address.
+    MS->emitIntValue(Range.start(), AddressSize);
+    RngListsSectionSize += AddressSize;
+
+    // Emit length of the range.
+    RngListsSectionSize += MS->emitSLEB128IntValue(Range.end() - Range.start());
+  }
+
+  // Emit the terminator entry.
+  MS->emitInt8(dwarf::DW_RLE_end_of_list);
+  RngListsSectionSize += 1;
 }
 
 /// Emit location lists for \p Unit and update attributes to point to the new
diff --git a/llvm/test/tools/dsymutil/Inputs/dwarf5-rnglists.o b/llvm/test/tools/dsymutil/Inputs/dwarf5-rnglists.o
new file mode 100644 (file)
index 0000000..8dfd4e7
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/dwarf5-rnglists.o differ
index 292f760..db7802c 100644 (file)
@@ -1,5 +1,6 @@
 ## Test that DWARF5 DW_FORM_addrx is correctly recognized
-## and converted into the DW_FORM_addr
+## and converted into the DW_FORM_addr or just preserved
+## in case --update.
 
 ## $ cat dwarf5-addrx.c
 ## __attribute__ ((optnone)) int foo1 ( ) {
 
 RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/dwarf5/dwarf5-addrx.out -o %t.dSYM 2>&1 | FileCheck %s --allow-empty
 RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
-CHECK-NOT: error:
 
 RUN: llvm-dwarfdump --verbose %t.dSYM | FileCheck %s --check-prefix DWARF
+
+RUN: dsymutil --update -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/dwarf5/dwarf5-addrx.out -o %t.dSYM 2>&1 | FileCheck %s --allow-empty
+RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
+
+RUN: llvm-dwarfdump --verbose %t.dSYM | FileCheck %s --check-prefix UPDATE-DWARF
+
+CHECK-NOT: error:
+
 DWARF: DW_TAG_compile_unit
 DWARF:   DW_AT_name [DW_FORM_strp]  {{.*}}     "dwarf5-addrx.c"
 DWARF:   DW_AT_low_pc [DW_FORM_addr]     (0x0000000100000eb0)
 DWARF:   DW_AT_high_pc [DW_FORM_data4]   (0x00000103)
-DWARF:   DW_AT_addr_base [DW_FORM_sec_offset]   (0x00000008)
 DWARF:   DW_TAG_subprogram
 DWARF:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000100000eb0)
 DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
@@ -87,3 +94,58 @@ DWARF:   DW_TAG_subprogram
 DWARF:     DW_AT_low_pc  [DW_FORM_addr]    (0x0000000100000f30)
 DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000083)
 DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "main"
+DWARF-NOT:  .debug_addr contents
+
+UPDATE-DWARF: DW_TAG_compile_unit
+UPDATE-DWARF:   DW_AT_name [DW_FORM_strp]  {{.*}}     "dwarf5-addrx.c"
+UPDATE-DWARF:   DW_AT_low_pc [DW_FORM_addrx]  (indexed (00000000) address = 0x0000000000000000)
+UPDATE-DWARF:   DW_AT_high_pc [DW_FORM_data4]   (0x00000103)
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000000000)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo1"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc [DW_FORM_addrx] (indexed (00000001) address = 0x0000000000000010)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo2"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc [DW_FORM_addrx]  (indexed (00000002) address = 0x0000000000000020)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo3"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc  [DW_FORM_addrx] (indexed (00000003) address = 0x0000000000000030)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo4"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc [DW_FORM_addrx]  (indexed (00000004) address = 0x0000000000000040)
+UPDATE-DWARF:     DW_AT_high_pc  [DW_FORM_data4]  (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo5"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc  [DW_FORM_addrx] (indexed (00000005) address = 0x0000000000000050)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo6"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc  [DW_FORM_addrx] (indexed (00000006) address = 0x0000000000000060)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo7"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc  [DW_FORM_addrx] (indexed (00000007) address = 0x0000000000000070)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000010)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo8"
+UPDATE-DWARF:   DW_TAG_subprogram
+UPDATE-DWARF:     DW_AT_low_pc  [DW_FORM_addrx] (indexed (00000008) address = 0x0000000000000080)
+UPDATE-DWARF:     DW_AT_high_pc [DW_FORM_data4]   (0x00000083)
+UPDATE-DWARF:     DW_AT_name  [DW_FORM_strp] {{.*}}   "main"
+UPDATE-DWARF:  .debug_addr contents:
+UPDATE-DWARF:  0x00000000: Address table header: length = 0x0000004c, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
+UPDATE-DWARF: Addrs: [
+UPDATE-DWARF: 0x0000000000000000
+UPDATE-DWARF: 0x0000000000000010
+UPDATE-DWARF: 0x0000000000000020
+UPDATE-DWARF: 0x0000000000000030
+UPDATE-DWARF: 0x0000000000000040
+UPDATE-DWARF: 0x0000000000000050
+UPDATE-DWARF: 0x0000000000000060
+UPDATE-DWARF: 0x0000000000000070
+UPDATE-DWARF: 0x0000000000000080
+UPDATE-DWARF: ]
diff --git a/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test b/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
new file mode 100644 (file)
index 0000000..e38f6c9
--- /dev/null
@@ -0,0 +1,87 @@
+## This test checks that .debug_rnglists table correclty handled
+## and transformed into the DW_FORM_sec_offset form in case
+## --no-update. Or correctly preservedi in --update case.
+
+## cat dwarf5-rnglists.c
+##
+## #include <stdio.h>
+##
+## int g1;
+##
+## int main ( int argv, char** argc ) {
+##
+##   if ( argv > 10 ) {
+##     volatile int a = 0x4;
+##
+##     if ( g1 ) {
+##       volatile int b = 0;
+##       return b;
+##     }
+##
+##     volatile int c = 7;
+##   } else if ( g1 ) {
+##     volatile int a = 0x5;
+##   }
+##
+##   return 0;
+## }
+
+## $ clang -gdwarf-5 dwarf5-rnglists.c -c -O2 -o dwarf5-rnglists.o
+## $ clang -gdwarf-5 dwarf5-rnglists.o -o dwarf5-rnglists
+
+#RUN: dsymutil -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
+#RUN: llvm-dwarfdump --verify  %t.dSYM | FileCheck %s
+#RUN: llvm-dwarfdump -a --verbose  %t.dSYM | FileCheck %s --check-prefix DWARF-CHECK
+#
+#RUN: dsymutil --update -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
+#RUN: llvm-dwarfdump --verify  %t.dSYM | FileCheck %s
+#RUN: llvm-dwarfdump -a --verbose  %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
+
+#CHECK: No errors.
+
+#DWARF-CHECK: DW_TAG_compile_unit
+#DWARF-CHECK: DW_TAG_lexical_block
+#DWARF-CHECK:   DW_AT_ranges [DW_FORM_sec_offset]     (0x0000000c
+#DWARF-CHECK:      [0x0000000100000f79, 0x0000000100000f96)
+#DWARF-CHECK:      [0x0000000100000fad, 0x0000000100000fb4))
+#DWARF-CHECK-NOT: debug_addr
+#DWARF-CHECK: .debug_rnglists contents:
+#DWARF-CHECK: 0x00000000: range list header: length = 0x0000001d, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
+#DWARF-CHECK: ranges:
+#DWARF-CHECK: 0x0000000c: [DW_RLE_start_length]:  0x0000000100000f79, 0x000000000000001d => [0x0000000100000f79, 0x0000000100000f96)
+#DWARF-CHECK: 0x00000016: [DW_RLE_start_length]:  0x0000000100000fad, 0x0000000000000007 => [0x0000000100000fad, 0x0000000100000fb4)
+#DWARF-CHECK: 0x00000020: [DW_RLE_end_of_list ]
+#DWARF-CHECK-NOT: debug_addr
+#
+#UPD-DWARF-CHECK: DW_TAG_compile_unit
+#UPD-DWARF-CHECK: DW_TAG_lexical_block
+#UPD-DWARF-CHECK:   DW_AT_ranges [DW_FORM_rnglistx]       (indexed (0x0) rangelist = 0x00000010
+#UPD-DWARF-CHECK:     [0x0000000000000009, 0x0000000000000026)
+#UPD-DWARF-CHECK:     [0x000000000000003d, 0x0000000000000044))
+#UPD-DWARF-CHECK: .debug_addr contents:
+#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x00000024, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
+#UPD-DWARF-CHECK: Addrs: [
+#UPD-DWARF-CHECK: 0x0000000000000000
+#UPD-DWARF-CHECK: 0x0000000000000000
+#UPD-DWARF-CHECK: 0x000000000000001c
+#UPD-DWARF-CHECK: 0x0000000000000034
+#UPD-DWARF-CHECK: ]
+
+#UPD-DWARF-CHECK: .debug_rnglists contents:
+#UPD-DWARF-CHECK: 0x00000000: range list header: length = 0x00000013, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000001
+#UPD-DWARF-CHECK: offsets: [
+#UPD-DWARF-CHECK: 0x00000004 => 0x00000010
+#UPD-DWARF-CHECK: ]
+#UPD-DWARF-CHECK: ranges:
+#UPD-DWARF-CHECK: 0x00000010: [DW_RLE_offset_pair]:  0x0000000000000009, 0x0000000000000026 => [0x0000000000000009, 0x0000000000000026)
+#UPD-DWARF-CHECK: 0x00000013: [DW_RLE_offset_pair]:  0x000000000000003d, 0x0000000000000044 => [0x000000000000003d, 0x0000000000000044)
+#UPD-DWARF-CHECK: 0x00000016: [DW_RLE_end_of_list]
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename:        'dwarf5-rnglists.o'
+    timestamp:       1676048242
+    symbols:
+      - { sym: _main, objAddr: 0x0, binAddr: 0x100000F70, size: 0x48 }
+      - { sym: _g1, binAddr: 0x100001000, size: 0x0 }
index e881afa..5694535 100644 (file)
@@ -34,12 +34,12 @@ OBJ:                   DW_AT_location        (DW_OP_breg2 RCX+0, DW_OP_constu 0x
 OBJ:                   DW_AT_name    ("b")
 OBJ:                   DW_AT_type    (0x000000af "_Bool")
 
-DSYM: 0x00000095:   DW_TAG_base_type
+DSYM: 0x0000008d:   DW_TAG_base_type
 DSYM:                 DW_AT_name      ("DW_ATE_unsigned_1")
 DSYM:                 DW_AT_encoding  (DW_ATE_unsigned)
 DSYM:                 DW_AT_byte_size (0x01)
 
-DSYM: 0x000000bc:     DW_TAG_formal_parameter
-DSYM:                   DW_AT_location        (DW_OP_breg2 RCX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert (0x00000095) "DW_ATE_unsigned_1", DW_OP_convert (0x0000009c) "DW_ATE_unsigned_8", DW_OP_stack_value)
+DSYM: 0x000000b4:     DW_TAG_formal_parameter
+DSYM:                   DW_AT_location        (DW_OP_breg2 RCX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert (0x0000008d) "DW_ATE_unsigned_1", DW_OP_convert (0x00000094) "DW_ATE_unsigned_8", DW_OP_stack_value)
 DSYM:                   DW_AT_name    ("b")
-DSYM:                   DW_AT_type    (0x000000da "_Bool")
+DSYM:                   DW_AT_type    (0x000000d2 "_Bool")
index 20964f9..65e5e81 100644 (file)
@@ -1,11 +1,20 @@
-## Test that DWARF5 DW_FORM_addrx is correctly recognized
-## and converted into the DW_FORM_addr
+## Test that DWARFv5 DW_FORM_addrx is correctly recognized
+## and converted into the DW_FORM_addr in --garbage-collection
+## case or correctly preserved in --no-garbage-collection case.
 
 # RUN: yaml2obj %s -o %t.o
 
 # RUN: llvm-dwarfutil %t.o %t1
 # RUN: llvm-dwarfdump -verify %t1 | FileCheck %s
 # RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s --check-prefix DWARF-CHECK
+#
+# RUN: llvm-dwarfutil --no-garbage-collection %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s --check-prefix UPD-DWARF-CHECK
+#
+# RUN: llvm-dwarfutil --no-garbage-collection --build-accelerator=DWARF %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s --check-prefix UPD-DWARF-CHECK
 
 #CHECK: No errors.
 
@@ -13,7 +22,6 @@
 #DWARF-CHECK:   DW_AT_name [DW_FORM_strp]  {{.*}}     "CU1"
 #DWARF-CHECK:   DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001130)
 #DWARF-CHECK:   DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000030)
-#DWARF-CHECK:   DW_AT_addr_base [DW_FORM_sec_offset]   (0x00000008)
 #DWARF-CHECK:   DW_TAG_subprogram
 #DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo1"
 #DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001130)
 #DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo3"
 #DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001150)
 #DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#DWARF-CHECK=NOT: .debug_addr contents:
+
+#UPD-DWARF-CHECK: DW_TAG_compile_unit
+#UPD-DWARF-CHECK:   DW_AT_name {{.*}}"CU1"
+#UPD-DWARF-CHECK:   DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000000) address = 0x0000000000001130)
+#UPD-DWARF-CHECK:   DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000030)
+#UPD-DWARF-CHECK:   DW_TAG_subprogram
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo1"
+#UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000000) address = 0x0000000000001130)
+#UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK:   DW_TAG_subprogram
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo2"
+#UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000001) address = 0x0000000000001140)
+#UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK:   DW_TAG_subprogram
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo3"
+#UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000002) address = 0x0000000000001150)
+#UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK: .debug_addr contents:
+#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x0000001c, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
+#UPD-DWARF-CHECK: Addrs: [
+#UPD-DWARF-CHECK: 0x0000000000001130
+#UPD-DWARF-CHECK: 0x0000000000001140
+#UPD-DWARF-CHECK: 0x0000000000001150
+#UPD-DWARF-CHECK: ]
 
 --- !ELF
 FileHeader:
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
new file mode 100644 (file)
index 0000000..3a869ef
--- /dev/null
@@ -0,0 +1,264 @@
+## Test that DWARFv5 .debug_rnglists is correctly recognized
+## and converted into the DW_FORM_sec_offset form in --garbage-collection
+## case or correctly preserved in --no-garbage-collection case.
+
+# RUN: yaml2obj %s -o %t.o
+
+# RUN: llvm-dwarfutil %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s --check-prefix DWARF-CHECK
+
+# RUN: llvm-dwarfutil --no-garbage-collection %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s --check-prefix UPD-DWARF-CHECK
+
+# RUN: llvm-dwarfutil --no-garbage-collection --build-accelerator=DWARF %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s --check-prefix UPD-DWARF-CHECK
+
+#CHECK: No errors.
+
+#DWARF-CHECK: DW_TAG_compile_unit
+#DWARF-CHECK:   DW_AT_name [DW_FORM_strp]  {{.*}}     "CU1"
+#DWARF-CHECK:   DW_AT_low_pc [DW_FORM_addr]  (0x0000000000001130) 
+#DWARF-CHECK:   DW_AT_ranges [DW_FORM_sec_offset] (0x[[CURANGE_OFF:[0-9a-f]*]]
+#DWARF-CHECK:   [0x0000000000001130, 0x0000000000001170))
+#DWARF-CHECK:   DW_TAG_subprogram
+#DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo1"
+#DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001130)
+#DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#DWARF-CHECK:     DW_TAG_lexical_block
+#DWARF-CHECK:       DW_AT_ranges [DW_FORM_sec_offset]     (0x[[F1RANGE_OFF:[0-9a-f]*]]
+#DWARF-CHECK:       [0x0000000000001130, 0x0000000000001140))
+#DWARF-CHECK:   DW_TAG_subprogram
+#DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo2"
+#DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001140)
+#DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#DWARF-CHECK:     DW_TAG_lexical_block
+#DWARF-CHECK:       DW_AT_ranges [DW_FORM_sec_offset]     (0x[[F2RANGE_OFF:[0-9a-f]*]]
+#DWARF-CHECK:            [0x0000000000001140, 0x0000000000001150))
+#DWARF-CHECK:   DW_TAG_subprogram
+#DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo3"
+#DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001150)
+#DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#DWARF-CHECK:     DW_TAG_lexical_block
+#DWARF-CHECK:       DW_AT_ranges [DW_FORM_sec_offset]     (0x[[F3RANGE_OFF:[0-9a-f]*]]
+#DWARF-CHECK:          [0x0000000000001150, 0x0000000000001160))
+#DWARF-CHECK:   DW_TAG_subprogram
+#DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo4"
+#DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001160)
+#DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#DWARF-CHECK:     DW_TAG_lexical_block
+#DWARF-CHECK:       DW_AT_ranges [DW_FORM_sec_offset]     (0x[[F4RANGE_OFF:[0-9a-f]*]]
+#DWARF-CHECK:          [0x0000000000001160, 0x0000000000001170))
+#DWARF-CHECK-NOT: .debug_addr contents:
+#DWARF-CHECK: .debug_aranges contents:
+#DWARF-CHECK: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
+#DWARF-CHECK: [0x0000000000001130, 0x0000000000001170)
+#DWARF-CHECK-NOT: .debug_addr contents:
+#DWARF-CHECK: .debug_rnglists contents:
+#DWARF-CHECK: 0x00000000: range list header: length = 0x00000040, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
+#DWARF-CHECK: ranges:
+#DWARF-CHECK: 0x[[F1RANGE_OFF]]: [DW_RLE_start_length]:  0x0000000000001130, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140)
+#DWARF-CHECK: {{.*}} [DW_RLE_end_of_list ]
+#DWARF-CHECK: 0x[[F2RANGE_OFF]]: [DW_RLE_start_length]:  0x0000000000001140, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150)
+#DWARF-CHECK: {{.*}} [DW_RLE_end_of_list ]
+#DWARF-CHECK: 0x[[F3RANGE_OFF]]: [DW_RLE_start_length]:  0x0000000000001150, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160)
+#DWARF-CHECK: {{.*}} [DW_RLE_end_of_list ]
+#DWARF-CHECK: 0x[[F4RANGE_OFF]]: [DW_RLE_start_length]:  0x0000000000001160, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170)
+#DWARF-CHECK: {{.*}} [DW_RLE_end_of_list ]
+#DWARF-CHECK: 0x[[CURANGE_OFF]]: [DW_RLE_start_length]:  0x0000000000001130, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170)
+#DWARF-CHECK: {{.*}} [DW_RLE_end_of_list ]
+#DWARF-CHECK-NOT: .debug_addr contents:
+
+#UPD-DWARF-CHECK: DW_TAG_compile_unit
+#UPD-DWARF-CHECK:   DW_AT_name {{.*}}"CU1"
+#UPD-DWARF-CHECK:   DW_AT_low_pc [DW_FORM_addrx]      (indexed (00000000) address = 0x0000000000001130)
+#UPD-DWARF-CHECK:   DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x4) rangelist = 0x0000003e
+#UPD-DWARF-CHECK:      [0x0000000000001130, 0x0000000000001170))
+#UPD-DWARF-CHECK:   DW_TAG_subprogram
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo1"
+#UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000000) address = 0x0000000000001130) 
+#UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK:     DW_TAG_lexical_block
+#UPD-DWARF-CHECK:     DW_AT_ranges [DW_FORM_rnglistx]       (indexed (0x0) rangelist = 0x00000020
+#UPD-DWARF-CHECK:        [0x0000000000001130, 0x0000000000001140))
+#UPD-DWARF-CHECK:   DW_TAG_subprogram
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo2"
+#UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000001) address = 0x0000000000001140) 
+#UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK:     DW_TAG_lexical_block
+#UPD-DWARF-CHECK:     DW_AT_ranges [DW_FORM_rnglistx]       (indexed (0x1) rangelist = 0x00000024
+#UPD-DWARF-CHECK:     [0x0000000000001140, 0x0000000000001150))
+#UPD-DWARF-CHECK:   DW_TAG_subprogram
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo3"
+#UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000002) address = 0x0000000000001150) 
+#UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK:     DW_TAG_lexical_block
+#UPD-DWARF-CHECK:     DW_AT_ranges [DW_FORM_sec_offset]     (0x00000028
+#UPD-DWARF-CHECK:        [0x0000000000001150, 0x0000000000001160))
+#UPD-DWARF-CHECK:   DW_TAG_subprogram
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo4"
+#UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]   (indexed (00000003) address = 0x0000000000001160)
+#UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK:     DW_TAG_lexical_block
+#UPD-DWARF-CHECK:     DW_AT_ranges [DW_FORM_sec_offset]     (0x00000033
+#UPD-DWARF-CHECK:        [0x0000000000001160, 0x0000000000001170))
+#UPD-DWARF-CHECK: .debug_addr contents:
+#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x00000024, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
+#UPD-DWARF-CHECK: Addrs: [
+#UPD-DWARF-CHECK: 0x0000000000001130
+#UPD-DWARF-CHECK: 0x0000000000001140
+#UPD-DWARF-CHECK: 0x0000000000001150
+#UPD-DWARF-CHECK: 0x0000000000001160
+#UPD-DWARF-CHECK: ]
+#UPD-DWARF-CHECK: .debug_rnglists contents:
+#UPD-DWARF-CHECK: 0x00000000: range list header: length = 0x0000003e, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000005
+#UPD-DWARF-CHECK: offsets: [
+#UPD-DWARF-CHECK: 0x00000014 => 0x00000020
+#UPD-DWARF-CHECK: 0x00000018 => 0x00000024
+#UPD-DWARF-CHECK: 0x0000001c => 0x00000028
+#UPD-DWARF-CHECK: 0x00000027 => 0x00000033
+#UPD-DWARF-CHECK: 0x00000032 => 0x0000003e
+#UPD-DWARF-CHECK: ]
+#UPD-DWARF-CHECK: ranges:
+#UPD-DWARF-CHECK: 0x00000020: [DW_RLE_startx_length]:  0x0000000000000000, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140)
+#UPD-DWARF-CHECK: 0x00000023: [DW_RLE_end_of_list  ]
+#UPD-DWARF-CHECK: 0x00000024: [DW_RLE_startx_length]:  0x0000000000000001, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150)
+#UPD-DWARF-CHECK: 0x00000027: [DW_RLE_end_of_list  ]
+#UPD-DWARF-CHECK: 0x00000028: [DW_RLE_start_length ]:  0x0000000000001150, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160)
+#UPD-DWARF-CHECK: 0x00000032: [DW_RLE_end_of_list  ]
+#UPD-DWARF-CHECK: 0x00000033: [DW_RLE_start_length ]:  0x0000000000001160, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170)
+#UPD-DWARF-CHECK: 0x0000003d: [DW_RLE_end_of_list  ]
+#UPD-DWARF-CHECK: 0x0000003e: [DW_RLE_startx_length]:  0x0000000000000000, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170)
+#UPD-DWARF-CHECK: 0x00000041: [DW_RLE_end_of_list  ]
+
+## Following yaml description has Content of the .debug_rnglists exactly like above data ^^^^^^
+--- !ELF
+FileHeader:
+  Class:    ELFCLASS64
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1130
+    Size:            0x70
+  - Name:            .debug_rnglists
+    Type:            SHT_PROGBITS
+    Flags:           [  ]
+    Content:        "3e000000050008000500000014000000180000001c000000270000003200000003001000030110000750110000000000001000076011000000000000100003004000"
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addrx
+          - Attribute: DW_AT_ranges
+            Form:      DW_FORM_rnglistx 
+          - Attribute: DW_AT_rnglists_base
+            Form:      DW_FORM_sec_offset
+          - Attribute: DW_AT_addr_base
+            Form:      DW_FORM_sec_offset
+      - Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addrx 
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+      - Tag:      DW_TAG_lexical_block
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_ranges
+            Form:      DW_FORM_rnglistx
+      - Tag:      DW_TAG_lexical_block
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_ranges    
+            Form:      DW_FORM_sec_offset 
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+  debug_info:
+    - Version: 5
+      UnitType:   DW_UT_compile
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+            - Value:  0x0
+            - Value:  0x4
+            - Value:  0xc
+            - Value:  0x8
+        - AbbrCode: 2
+          Values:
+            - CStr: foo1
+            - Value: 0x00
+            - Value: 0x10
+            - Value: 0x83
+        - AbbrCode: 3
+          Values:
+            - Value: 0x00
+        - AbbrCode: 0
+        - AbbrCode: 2
+          Values:
+            - CStr: foo2
+            - Value: 0x01
+            - Value: 0x10
+            - Value: 0x83
+        - AbbrCode: 3
+          Values:
+            - Value: 0x01
+        - AbbrCode: 0
+        - AbbrCode: 2
+          Values:
+            - CStr: foo3
+            - Value: 0x02
+            - Value: 0x10
+            - Value: 0x83
+        - AbbrCode: 4
+          Values:
+            - Value: 0x28
+        - AbbrCode: 0
+        - AbbrCode: 2
+          Values:
+            - CStr: foo4
+            - Value: 0x03
+            - Value: 0x10
+            - Value: 0x83
+        - AbbrCode: 4
+          Values:
+            - Value: 0x33
+        - AbbrCode: 0
+        - AbbrCode: 5
+          Values:
+            - CStr: int
+        - AbbrCode: 0
+  debug_addr:
+    - Version: 5
+      AddressSize: 0x08
+      Entries:
+        - Address: 0x1130
+        - Address: 0x1140
+        - Address: 0x1150
+        - Address: 0x1160
+...
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/warning-skipped-rnglists.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/warning-skipped-rnglists.test
deleted file mode 100644 (file)
index deea90f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-## This test checks the warning message displayed if input file
-## contains .debug_rnglists section.
-
-# RUN: yaml2obj %s -o %t.o
-
-# RUN: llvm-dwarfutil --garbage-collection %t.o %t1 2>&1 | FileCheck %s -DFILE=%t.o
-
-# CHECK: [[FILE]]: warning: '.debug_rnglists' is not currently supported: file will be skipped
-
---- !ELF
-FileHeader:
-  Class:    ELFCLASS64
-  Data:     ELFDATA2LSB
-  Type:     ET_REL
-  Machine:  EM_X86_64
-Sections:
-  - Name:            .text
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
-    Address:         0x1000
-    AddressAlign:    0x0000000000000010
-    Content:        "FFFFFFFF"
-  - Name:            .debug_rnglists
-    Type:            SHT_PROGBITS
-    Flags:           [  ]
-    Content:        "0000"
-DWARF:
-  debug_abbrev:
-    - Table:
-      - Tag:      DW_TAG_compile_unit
-        Children: DW_CHILDREN_yes
-        Attributes:
-          - Attribute: DW_AT_producer
-            Form:      DW_FORM_string
-          - Attribute: DW_AT_language
-            Form:      DW_FORM_data2
-          - Attribute: DW_AT_name
-            Form:      DW_FORM_string
-          - Attribute: DW_AT_low_pc
-            Form:      DW_FORM_addr
-          - Attribute: DW_AT_high_pc
-            Form:      DW_FORM_data8
-  debug_info:
-    - Version: 4
-      Entries:
-        - AbbrCode: 1
-          Values:
-            - CStr: by_hand
-            - Value:  0x04
-            - CStr: CU1
-            - Value:  0x1000
-            - Value:  0x4
-        - AbbrCode: 0
-...