[llvm-branch-commits] [llvm] f1d5cbb - [dsymutil] Add preliminary support for DWARF 5.

Jonas Devlieghere via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jan 12 22:00:18 PST 2021


Author: Jonas Devlieghere
Date: 2021-01-12T21:55:41-08:00
New Revision: f1d5cbbdee5526bc86eac0a5652b115d9bc158e5

URL: https://github.com/llvm/llvm-project/commit/f1d5cbbdee5526bc86eac0a5652b115d9bc158e5
DIFF: https://github.com/llvm/llvm-project/commit/f1d5cbbdee5526bc86eac0a5652b115d9bc158e5.diff

LOG: [dsymutil] Add preliminary support for DWARF 5.

Currently dsymutil will silently fail when processing binaries with
Dwarf 5 debug info. This patch adds rudimentary support for Dwarf 5 in
dsymutil.

 - Recognize relocations in the debug_addr section.
 - Recognize (a subset of) Dwarf 5 form values.
 - Emits valid Dwarf 5 compile unit header chains.

To simplify things (and avoid having to emit indexed sections) I decided
to emit the relocated addresses directly in the debug info section.

 - DW_FORM_strx gets relocated and rewritten to DW_FORM_strp
 - DW_FORM_addrx gets relocated and rewritten to DW_FORM_addr

Obviously there's a lot of work left, but this should be a step in the
right direction.

rdar://62345491

Differential revision: https://reviews.llvm.org/D94323

Added: 
    llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o
    llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out
    llvm/test/tools/dsymutil/X86/dwarf5.test

Modified: 
    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/tools/dsymutil/DwarfLinkerForBinary.cpp
    llvm/tools/dsymutil/DwarfLinkerForBinary.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index 97faad6b6180..7281966fc608 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -85,6 +85,9 @@ class AddressesMap {
   virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
                                 bool IsLittleEndian) = 0;
 
+  /// Relocate the given address offset if a valid relocation exists.
+  virtual llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t Offset) = 0;
+
   /// Returns all valid functions address ranges(i.e., those ranges
   /// which points to sections with code).
   virtual RangesTy &getValidAddressRanges() = 0;
@@ -183,7 +186,8 @@ class DwarfEmitter {
   ///
   /// As a side effect, this also switches the current Dwarf version
   /// of the MC layer to the one of U.getOrigUnit().
-  virtual void emitCompileUnitHeader(CompileUnit &Unit) = 0;
+  virtual void emitCompileUnitHeader(CompileUnit &Unit,
+                                     unsigned DwarfVersion) = 0;
 
   /// Recursively emit the DIE tree rooted at \p Die.
   virtual void emitDIE(DIE &Die) = 0;

diff  --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
index 549a0ce4e4b7..a6310bcb5df1 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
@@ -159,7 +159,7 @@ class CompileUnit {
   /// Compute the end offset for this unit. Must be called after the CU's DIEs
   /// have been cloned.  \returns the next unit offset (which is also the
   /// current debug_info section size).
-  uint64_t computeNextUnitOffset();
+  uint64_t computeNextUnitOffset(uint16_t DwarfVersion);
 
   /// Keep track of a forward reference to DIE \p Die in \p RefUnit by \p
   /// Attr. The attribute should be fixed up later to point to the absolute

diff  --git a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
index de58f5dedf24..7b0851159252 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
@@ -64,7 +64,7 @@ class DwarfStreamer : public DwarfEmitter {
   ///
   /// As a side effect, this also switches the current Dwarf version
   /// of the MC layer to the one of U.getOrigUnit().
-  void emitCompileUnitHeader(CompileUnit &Unit) override;
+  void emitCompileUnitHeader(CompileUnit &Unit, unsigned DwarfVersion) override;
 
   /// Recursively emit the DIE tree rooted at \p Die.
   void emitDIE(DIE &Die) override;

diff  --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 1595b31cb4f9..a09cbf9c95ea 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -419,7 +419,6 @@ void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) {
   DIEAlloc.Reset();
 }
 
-
 /// Check if a variable describing DIE should be kept.
 /// \returns updated TraversalFlags.
 unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,
@@ -845,9 +844,12 @@ void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) {
 unsigned DWARFLinker::DIECloner::cloneStringAttribute(
     DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
     const DWARFUnit &U, OffsetsStringPool &StringPool, AttributesInfo &Info) {
+  Optional<const char *> String = Val.getAsCString();
+  if (!String)
+    return 0;
+
   // Switch everything to out of line strings.
-  const char *String = *Val.getAsCString();
-  auto StringEntry = StringPool.getEntry(String);
+  auto StringEntry = StringPool.getEntry(*String);
 
   // Update attributes info.
   if (AttrSpec.Attr == dwarf::DW_AT_name)
@@ -1056,6 +1058,7 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
 unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
     DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
     const CompileUnit &Unit, AttributesInfo &Info) {
+  dwarf::Form Form = AttrSpec.Form;
   uint64_t Addr = *Val.getAsAddress();
 
   if (LLVM_UNLIKELY(Linker.Options.Update)) {
@@ -1105,8 +1108,19 @@ unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
       Addr = (Info.OrigCallPc ? Info.OrigCallPc : Addr) + Info.PCOffset;
   }
 
+  // If this is an indexed address emit the relocated address.
+  if (Form == dwarf::DW_FORM_addrx) {
+    if (llvm::Expected<uint64_t> RelocAddr =
+            ObjFile.Addresses->relocateIndexedAddr(Addr)) {
+      Addr = *RelocAddr;
+      Form = dwarf::DW_FORM_addr;
+    } else {
+      Linker.reportWarning(toString(RelocAddr.takeError()), ObjFile);
+    }
+  }
+
   Die.addValue(DIEAlloc, static_cast<dwarf::Attribute>(AttrSpec.Attr),
-               static_cast<dwarf::Form>(AttrSpec.Form), DIEInteger(Addr));
+               static_cast<dwarf::Form>(Form), DIEInteger(Addr));
   return Unit.getOrigUnit().getAddressByteSize();
 }
 
@@ -1188,6 +1202,11 @@ unsigned DWARFLinker::DIECloner::cloneAttribute(
   switch (AttrSpec.Form) {
   case dwarf::DW_FORM_strp:
   case dwarf::DW_FORM_string:
+  case dwarf::DW_FORM_strx:
+  case dwarf::DW_FORM_strx1:
+  case dwarf::DW_FORM_strx2:
+  case dwarf::DW_FORM_strx3:
+  case dwarf::DW_FORM_strx4:
     return cloneStringAttribute(Die, AttrSpec, Val, U, StringPool, Info);
   case dwarf::DW_FORM_ref_addr:
   case dwarf::DW_FORM_ref1:
@@ -1204,6 +1223,7 @@ unsigned DWARFLinker::DIECloner::cloneAttribute(
     return cloneBlockAttribute(Die, File, Unit, AttrSpec, Val, AttrSize,
                                IsLittleEndian);
   case dwarf::DW_FORM_addr:
+  case dwarf::DW_FORM_addrx:
     return cloneAddressAttribute(Die, AttrSpec, Val, Unit, Info);
   case dwarf::DW_FORM_data1:
   case dwarf::DW_FORM_data2:
@@ -1284,6 +1304,9 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
   case dwarf::DW_AT_high_pc:
   case dwarf::DW_AT_ranges:
     return SkipPC;
+  case dwarf::DW_AT_str_offsets_base:
+    // FIXME: Use the string offset table with Dwarf 5.
+    return true;
   case dwarf::DW_AT_location:
   case dwarf::DW_AT_frame_base:
     // FIXME: for some reason dsymutil-classic keeps the location attributes
@@ -2127,10 +2150,12 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
   const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
 
   for (auto &CurrentUnit : CompileUnits) {
+    const uint16_t DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
+    const uint32_t UnitHeaderSize = DwarfVersion >= 5 ? 12 : 11;
     auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
     CurrentUnit->setStartOffset(OutputDebugInfoSize);
     if (!InputDIE) {
-      OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
+      OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
       continue;
     }
     if (CurrentUnit->getInfo(0).Keep) {
@@ -2138,11 +2163,11 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
       // already has a DIE inside of it.
       CurrentUnit->createOutputDIE();
       cloneDIE(InputDIE, File, *CurrentUnit, StringPool, 0 /* PC offset */,
-               11 /* Unit Header size */, 0, IsLittleEndian,
+               UnitHeaderSize, 0, IsLittleEndian,
                CurrentUnit->getOutputUnitDIE());
     }
 
-    OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
+    OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
 
     if (!Linker.Options.NoOutput) {
       assert(Emitter);
@@ -2183,12 +2208,14 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
       if (!CurrentUnit->getOutputUnitDIE())
         continue;
 
+      unsigned DwarfVersion = CurrentUnit->getOrigUnit().getVersion();
+
       assert(Emitter->getDebugInfoSectionSize() ==
              CurrentUnit->getStartOffset());
-      Emitter->emitCompileUnitHeader(*CurrentUnit);
+      Emitter->emitCompileUnitHeader(*CurrentUnit, DwarfVersion);
       Emitter->emitDIE(*CurrentUnit->getOutputUnitDIE());
       assert(Emitter->getDebugInfoSectionSize() ==
-             CurrentUnit->computeNextUnitOffset());
+             CurrentUnit->computeNextUnitOffset(DwarfVersion));
     }
   }
 

diff  --git a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
index f59a9023c690..925ab3d295c2 100644
--- a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
@@ -36,7 +36,7 @@ StringRef CompileUnit::getSysRoot() {
   }
   return SysRoot;
 }
- 
+
 void CompileUnit::markEverythingAsKept() {
   unsigned Idx = 0;
 
@@ -69,10 +69,10 @@ void CompileUnit::markEverythingAsKept() {
   }
 }
 
-uint64_t CompileUnit::computeNextUnitOffset() {
+uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) {
   NextUnitOffset = StartOffset;
   if (NewUnit) {
-    NextUnitOffset += 11 /* Header size */;
+    NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size
     NextUnitOffset += NewUnit->getUnitDie().getSize();
   }
   return NextUnitOffset;

diff  --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
index e900335f24b3..c0043ae39efe 100644
--- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp
+++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
@@ -121,16 +121,23 @@ void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) {
 
 /// Emit the compilation unit header for \p Unit in the debug_info section.
 ///
-/// A Dwarf section header is encoded as:
+/// A Dwarf 4 section header is encoded as:
 ///  uint32_t   Unit length (omitting this field)
 ///  uint16_t   Version
 ///  uint32_t   Abbreviation table offset
 ///  uint8_t    Address size
-///
 /// Leading to a total of 11 bytes.
-void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
-  unsigned Version = Unit.getOrigUnit().getVersion();
-  switchToDebugInfoSection(Version);
+///
+/// A Dwarf 5 section header is encoded as:
+///  uint32_t   Unit length (omitting this field)
+///  uint16_t   Version
+///  uint8_t    Unit type
+///  uint8_t    Address size
+///  uint32_t   Abbreviation table offset
+/// Leading to a total of 12 bytes.
+void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit,
+                                          unsigned DwarfVersion) {
+  switchToDebugInfoSection(DwarfVersion);
 
   /// The start of the unit within its section.
   Unit.setLabelBegin(Asm->createTempSymbol("cu_begin"));
@@ -140,13 +147,22 @@ void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
   // been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to
   // account for the length field.
   Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4);
-  Asm->emitInt16(Version);
-
-  // We share one abbreviations table across all units so it's always at the
-  // start of the section.
-  Asm->emitInt32(0);
-  Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
-  DebugInfoSectionSize += 11;
+  Asm->emitInt16(DwarfVersion);
+
+  if (DwarfVersion >= 5) {
+    Asm->emitInt8(dwarf::DW_UT_compile);
+    Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
+    // We share one abbreviations table across all units so it's always at the
+    // start of the section.
+    Asm->emitInt32(0);
+    DebugInfoSectionSize += 12;
+  } else {
+    // We share one abbreviations table across all units so it's always at the
+    // start of the section.
+    Asm->emitInt32(0);
+    Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize());
+    DebugInfoSectionSize += 11;
+  }
 
   // Remember this CU.
   EmittedUnits.push_back({Unit.getUniqueID(), Unit.getLabelBegin()});
@@ -211,6 +227,16 @@ void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
     // Emit a null terminator.
     Asm->emitInt8(0);
   }
+
+#if 0
+  if (DwarfVersion >= 5) {
+    // Emit an empty string offset section.
+    Asm->OutStreamer->SwitchSection(MOFI->getDwarfStrOffSection());
+    Asm->emitDwarfUnitLength(4, "Length of String Offsets Set");
+    Asm->emitInt16(DwarfVersion);
+    Asm->emitInt16(0);
+  }
+#endif
 }
 
 void DwarfStreamer::emitDebugNames(

diff  --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o
new file mode 100644
index 000000000000..1f47f6a225de
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out
new file mode 100755
index 000000000000..420395f0d15b
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5.out 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/dwarf5.test b/llvm/test/tools/dsymutil/X86/dwarf5.test
new file mode 100644
index 000000000000..9d1ad3c4fdf4
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/dwarf5.test
@@ -0,0 +1,59 @@
+Test DWARF5 support in dsymutil. Currently this still generates an empty dSYM.
+
+$ cat dwarf5.c
+__attribute__ ((optnone))
+int foo() {
+  volatile i;
+  return i;
+}
+
+int main(int argc, char** argv) {
+  return foo();
+}
+
+$ clang -gdwarf-5 dwarf5.c -c -o dwarf5.o
+$ clang dwarf5.o -o dwarf5.out
+
+RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/dwarf5/dwarf5.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 %t.dSYM | FileCheck %s --check-prefix DWARF
+DWARF: DW_TAG_compile_unit
+DWARF:   DW_AT_producer    ("clang version 12.0.0
+DWARF:   DW_AT_language    (DW_LANG_C99)
+DWARF:   DW_AT_name        ("dwarf5.c")
+DWARF:   DW_AT_LLVM_sysroot        ("/")
+DWARF:   DW_AT_stmt_list   (0x00000000)
+DWARF:   DW_AT_comp_dir    ("/private/tmp/dwarf5")
+DWARF:   DW_AT_low_pc      (0x0000000100003f80)
+DWARF:   DW_AT_high_pc     (0x0000000100003fb1)
+DWARF:   DW_AT_addr_base   (0x00000008)
+DWARF:   DW_TAG_subprogram
+DWARF:     DW_AT_name      ("foo")
+DWARF:     DW_AT_decl_file (0x00)
+DWARF:     DW_AT_decl_line (2)
+DWARF:     DW_AT_type      (0x0000006c "int")
+DWARF:     DW_AT_external  (true)
+DWARF:     DW_TAG_variable
+DWARF:       DW_AT_name    ("i")
+DWARF:       DW_AT_decl_file       (0x00)
+DWARF:       DW_AT_decl_line       (3)
+DWARF:       DW_AT_type    (0x00000073 "volatile int")
+DWARF:   DW_TAG_subprogram
+DWARF:     DW_AT_name      ("main")
+DWARF:     DW_AT_decl_file (0x00)
+DWARF:     DW_AT_decl_line (7)
+DWARF:     DW_AT_prototyped        (true)
+DWARF:     DW_AT_type      (0x0000006c "int")
+DWARF:     DW_AT_external  (true)
+DWARF:     DW_TAG_formal_parameter
+DWARF:       DW_AT_name    ("argc")
+DWARF:       DW_AT_decl_file       (0x00)
+DWARF:       DW_AT_decl_line       (7)
+DWARF:       DW_AT_type    (0x0000006c "int")
+DWARF:     DW_TAG_formal_parameter
+DWARF:       DW_AT_name    ("argv")
+DWARF:       DW_AT_decl_file       (0x00)
+DWARF:       DW_AT_decl_line       (7)
+DWARF:       DW_AT_type    (0x00000078 "char**")

diff  --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index bd9529c4cd0f..29408e7c4946 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -489,7 +489,7 @@ static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {
 /// ValidRelocs array.
 void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
     const object::SectionRef &Section, const object::MachOObjectFile &Obj,
-    const DebugMapObject &DMO) {
+    const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
   Expected<StringRef> ContentsOrErr = Section.getContents();
   if (!ContentsOrErr) {
     consumeError(ContentsOrErr.takeError());
@@ -511,7 +511,8 @@ void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
     if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
                            Obj.getArch())) {
       SkipNext = true;
-      Linker.reportWarning("unsupported relocation in debug_info section.",
+      Linker.reportWarning("unsupported relocation in " + *Section.getName() +
+                               " section.",
                            DMO.getObjectFilename());
       continue;
     }
@@ -519,7 +520,8 @@ void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
     unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
     uint64_t Offset64 = Reloc.getOffset();
     if ((RelocSize != 4 && RelocSize != 8)) {
-      Linker.reportWarning("unsupported relocation in debug_info section.",
+      Linker.reportWarning("unsupported relocation in " + *Section.getName() +
+                               " section.",
                            DMO.getObjectFilename());
       continue;
     }
@@ -564,33 +566,33 @@ void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
 /// appropriate handler depending on the object file format.
 bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
     const object::SectionRef &Section, const object::ObjectFile &Obj,
-    const DebugMapObject &DMO) {
+    const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
   // Dispatch to the right handler depending on the file type.
   if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
-    findValidRelocsMachO(Section, *MachOObj, DMO);
+    findValidRelocsMachO(Section, *MachOObj, DMO, Relocs);
   else
     Linker.reportWarning(Twine("unsupported object file type: ") +
                              Obj.getFileName(),
                          DMO.getObjectFilename());
-  if (ValidRelocs.empty())
+  if (Relocs.empty())
     return false;
 
   // Sort the relocations by offset. We will walk the DIEs linearly in
   // the file, this allows us to just keep an index in the relocation
   // array that we advance during our walk, rather than resorting to
   // some associative container. See DwarfLinkerForBinary::NextValidReloc.
-  llvm::sort(ValidRelocs);
+  llvm::sort(Relocs);
   return true;
 }
 
-/// Look for relocations in the debug_info section that match
-/// entries in the debug map. These relocations will drive the Dwarf
-/// link by indicating which DIEs refer to symbols present in the
-/// linked binary.
+/// Look for relocations in the debug_info and debug_addr section that match
+/// entries in the debug map. These relocations will drive the Dwarf link by
+/// indicating which DIEs refer to symbols present in the linked binary.
 /// \returns whether there are any valid relocations in the debug info.
-bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugInfo(
+bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
     const object::ObjectFile &Obj, const DebugMapObject &DMO) {
   // Find the debug_info section.
+  bool FoundValidRelocs = false;
   for (const object::SectionRef &Section : Obj.sections()) {
     StringRef SectionName;
     if (Expected<StringRef> NameOrErr = Section.getName())
@@ -599,39 +601,44 @@ bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugInfo(
       consumeError(NameOrErr.takeError());
 
     SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
-    if (SectionName != "debug_info")
-      continue;
-    return findValidRelocs(Section, Obj, DMO);
+    if (SectionName == "debug_info")
+      FoundValidRelocs |=
+          findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs);
+    if (SectionName == "debug_addr")
+      FoundValidRelocs |=
+          findValidRelocs(Section, Obj, DMO, ValidDebugAddrRelocs);
   }
-  return false;
+  return FoundValidRelocs;
 }
 
-/// Checks that there is a relocation against an actual debug
-/// map entry between \p StartOffset and \p NextOffset.
-///
-/// This function must be called with offsets in strictly ascending
-/// order because it never looks back at relocations it already 'went past'.
-/// \returns true and sets Info.InDebugMap if it is the case.
-bool DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
+bool DwarfLinkerForBinary::AddressManager::hasValidDebugAddrRelocationAt(
+    uint64_t Offset) {
+  auto It = std::lower_bound(ValidDebugAddrRelocs.begin(),
+                             ValidDebugAddrRelocs.end(), Offset);
+  return It != ValidDebugAddrRelocs.end();
+}
+
+bool DwarfLinkerForBinary::AddressManager::hasValidDebugInfoRelocationAt(
     uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
   assert(NextValidReloc == 0 ||
-         StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
-  if (NextValidReloc >= ValidRelocs.size())
+         StartOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset);
+  if (NextValidReloc >= ValidDebugInfoRelocs.size())
     return false;
 
-  uint64_t RelocOffset = ValidRelocs[NextValidReloc].Offset;
+  uint64_t RelocOffset = ValidDebugInfoRelocs[NextValidReloc].Offset;
 
   // We might need to skip some relocs that we didn't consider. For
   // example the high_pc of a discarded DIE might contain a reloc that
   // is in the list because it actually corresponds to the start of a
   // function that is in the debug map.
-  while (RelocOffset < StartOffset && NextValidReloc < ValidRelocs.size() - 1)
-    RelocOffset = ValidRelocs[++NextValidReloc].Offset;
+  while (RelocOffset < StartOffset &&
+         NextValidReloc < ValidDebugInfoRelocs.size() - 1)
+    RelocOffset = ValidDebugInfoRelocs[++NextValidReloc].Offset;
 
   if (RelocOffset < StartOffset || RelocOffset >= EndOffset)
     return false;
 
-  const auto &ValidReloc = ValidRelocs[NextValidReloc++];
+  const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++];
   const auto &Mapping = ValidReloc.Mapping->getValue();
   const uint64_t BinaryAddress = Mapping.BinaryAddress;
   const uint64_t ObjectAddress = Mapping.ObjectAddress
@@ -673,7 +680,6 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
 
 bool DwarfLinkerForBinary::AddressManager::hasLiveMemoryLocation(
     const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
-
   const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
 
   Optional<uint32_t> LocationIdx =
@@ -686,7 +692,9 @@ bool DwarfLinkerForBinary::AddressManager::hasLiveMemoryLocation(
   std::tie(LocationOffset, LocationEndOffset) =
       getAttributeOffsets(Abbrev, *LocationIdx, Offset, *DIE.getDwarfUnit());
 
-  return hasValidRelocationAt(LocationOffset, LocationEndOffset, MyInfo);
+  // FIXME: Support relocations debug_addr.
+  return hasValidDebugInfoRelocationAt(LocationOffset, LocationEndOffset,
+                                       MyInfo);
 }
 
 bool DwarfLinkerForBinary::AddressManager::hasLiveAddressRange(
@@ -697,12 +705,22 @@ bool DwarfLinkerForBinary::AddressManager::hasLiveAddressRange(
   if (!LowPcIdx)
     return false;
 
-  uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
-  uint64_t LowPcOffset, LowPcEndOffset;
-  std::tie(LowPcOffset, LowPcEndOffset) =
-      getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());
+  dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);
 
-  return hasValidRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo);
+  if (Form == dwarf::DW_FORM_addr) {
+    uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
+    uint64_t LowPcOffset, LowPcEndOffset;
+    std::tie(LowPcOffset, LowPcEndOffset) =
+        getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());
+    return hasValidDebugInfoRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo);
+  }
+
+  if (Form == dwarf::DW_FORM_addrx) {
+    Optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);
+    return hasValidDebugAddrRelocationAt(*AddrValue->getAsAddress());
+  }
+
+  return false;
 }
 /// Apply the valid relocations found by findValidRelocs() to
 /// the buffer \p Data, taking into account that Data is at \p BaseOffset
@@ -716,22 +734,22 @@ bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
     MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
   assert(areRelocationsResolved());
   assert((NextValidReloc == 0 ||
-          BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
+          BaseOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset) &&
          "BaseOffset should only be increasing.");
-  if (NextValidReloc >= ValidRelocs.size())
+  if (NextValidReloc >= ValidDebugInfoRelocs.size())
     return false;
 
   // Skip relocs that haven't been applied.
-  while (NextValidReloc < ValidRelocs.size() &&
-         ValidRelocs[NextValidReloc].Offset < BaseOffset)
+  while (NextValidReloc < ValidDebugInfoRelocs.size() &&
+         ValidDebugInfoRelocs[NextValidReloc].Offset < BaseOffset)
     ++NextValidReloc;
 
   bool Applied = false;
   uint64_t EndOffset = BaseOffset + Data.size();
-  while (NextValidReloc < ValidRelocs.size() &&
-         ValidRelocs[NextValidReloc].Offset >= BaseOffset &&
-         ValidRelocs[NextValidReloc].Offset < EndOffset) {
-    const auto &ValidReloc = ValidRelocs[NextValidReloc++];
+  while (NextValidReloc < ValidDebugInfoRelocs.size() &&
+         ValidDebugInfoRelocs[NextValidReloc].Offset >= BaseOffset &&
+         ValidDebugInfoRelocs[NextValidReloc].Offset < EndOffset) {
+    const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++];
     assert(ValidReloc.Offset - BaseOffset < Data.size());
     assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size());
     char Buf[8];
@@ -749,6 +767,17 @@ bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
   return Applied;
 }
 
+llvm::Expected<uint64_t>
+DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) {
+  auto It = std::lower_bound(ValidDebugAddrRelocs.begin(),
+                             ValidDebugAddrRelocs.end(), Offset);
+  if (It == ValidDebugAddrRelocs.end())
+    return createStringError(
+        std::make_error_code(std::errc::invalid_argument),
+        "no relocation for offset %llu in debug_addr section", Offset);
+  return It->Mapping->getValue().BinaryAddress + It->Addend;
+}
+
 bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
                const DebugMap &DM, LinkOptions Options) {
   DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options));

diff  --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h
index ec157e38ccf9..c6c07d689f6f 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.h
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h
@@ -70,13 +70,17 @@ class DwarfLinkerForBinary {
       bool operator<(const ValidReloc &RHS) const {
         return Offset < RHS.Offset;
       }
+      bool operator<(uint64_t RHS) const { return Offset < RHS; }
     };
 
     const DwarfLinkerForBinary &Linker;
 
     /// The valid relocations for the current DebugMapObject.
     /// This vector is sorted by relocation offset.
-    std::vector<ValidReloc> ValidRelocs;
+    /// {
+    std::vector<ValidReloc> ValidDebugInfoRelocs;
+    std::vector<ValidReloc> ValidDebugAddrRelocs;
+    /// }
 
     /// Index into ValidRelocs of the next relocation to consider. As we walk
     /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
@@ -90,7 +94,7 @@ class DwarfLinkerForBinary {
     AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
                    const DebugMapObject &DMO)
         : Linker(Linker) {
-      findValidRelocsInDebugInfo(Obj, DMO);
+      findValidRelocsInDebugSections(Obj, DMO);
 
       // Iterate over the debug map entries and put all the ones that are
       // functions (because they have a size) into the Ranges map. This map is
@@ -124,27 +128,39 @@ class DwarfLinkerForBinary {
     bool hasValidRelocs(bool ResetRelocsPtr = true) override {
       if (ResetRelocsPtr)
         NextValidReloc = 0;
-      return !ValidRelocs.empty();
+      return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty();
     }
 
     /// \defgroup FindValidRelocations Translate debug map into a list
     /// of relevant relocations
     ///
     /// @{
-    bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
-                                    const DebugMapObject &DMO);
+    bool findValidRelocsInDebugSections(const object::ObjectFile &Obj,
+                                        const DebugMapObject &DMO);
 
     bool findValidRelocs(const object::SectionRef &Section,
                          const object::ObjectFile &Obj,
-                         const DebugMapObject &DMO);
+                         const DebugMapObject &DMO,
+                         std::vector<ValidReloc> &ValidRelocs);
 
     void findValidRelocsMachO(const object::SectionRef &Section,
                               const object::MachOObjectFile &Obj,
-                              const DebugMapObject &DMO);
+                              const DebugMapObject &DMO,
+                              std::vector<ValidReloc> &ValidRelocs);
     /// @}
 
-    bool hasValidRelocationAt(uint64_t StartOffset, uint64_t EndOffset,
-                              CompileUnit::DIEInfo &Info);
+    /// Checks that there is a relocation in the debug_addr section  against a
+    /// debug map entry between \p StartOffset and \p NextOffset.
+    ///
+    /// This function must be called with offsets in strictly ascending order
+    /// because it never looks back at relocations it already 'went past'.
+    /// \returns true and sets Info.InDebugMap if it is the case.
+    bool hasValidDebugInfoRelocationAt(uint64_t StartOffset, uint64_t EndOffset,
+                                       CompileUnit::DIEInfo &Info);
+
+    /// Checks that there is a relocation in the debug_addr section against a
+    /// debug map entry at the given offset.
+    bool hasValidDebugAddrRelocationAt(uint64_t Offset);
 
     bool hasLiveMemoryLocation(const DWARFDie &DIE,
                                CompileUnit::DIEInfo &Info) override;
@@ -154,11 +170,14 @@ class DwarfLinkerForBinary {
     bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
                           bool IsLittleEndian) override;
 
+    llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t Offset) override;
+
     RangesTy &getValidAddressRanges() override { return AddressRanges; }
 
     void clear() override {
       AddressRanges.clear();
-      ValidRelocs.clear();
+      ValidDebugInfoRelocs.clear();
+      ValidDebugAddrRelocs.clear();
       NextValidReloc = 0;
     }
   };


        


More information about the llvm-branch-commits mailing list