[llvm] bd0dd27 - [DWARFLinker][DWARFv5] Add handling of DW_OP_addrx and DW_OP_constx expression operands.

Alexey Lapshin via llvm-commits llvm-commits at lists.llvm.org
Tue May 16 10:27:58 PDT 2023


Author: Alexey Lapshin
Date: 2023-05-16T19:27:16+02:00
New Revision: bd0dd27bb5be0fbf60c1b2a4ce15188812388574

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

LOG: [DWARFLinker][DWARFv5] Add handling of DW_OP_addrx and DW_OP_constx expression operands.

This patch adds handling of DW_OP_addrx and DW_OP_constx expression operands.
In --update case these operands are preserved as is. Otherwise they are
converted into the DW_OP_addr and DW_OP_const[*]u correspondingly.

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

Added: 
    llvm/test/tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o
    llvm/test/tools/dsymutil/X86/dwarf5-dw-op-addrx.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test

Modified: 
    llvm/include/llvm/DWARFLinker/DWARFLinker.h
    llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
    llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
    llvm/lib/DWARFLinker/DWARFLinker.cpp
    llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
    llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
    llvm/test/tools/dsymutil/X86/op-convert-offset.test
    llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
    llvm/tools/dsymutil/DwarfLinkerForBinary.h
    llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp

Removed: 
    llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addrx.test


################################################################################
diff  --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index 4d519479fab6e..d94e31d5e6cd4 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -17,6 +17,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
 #include <map>
 
 namespace llvm {
@@ -48,14 +49,16 @@ class AddressesMap {
   /// section.
   virtual bool hasValidRelocs() = 0;
 
-  /// Checks that the specified variable \p DIE references the live code
-  /// section and returns the relocation adjustment value (to get the linked
-  /// address this value might be added to the source variable address).
-  /// Allowed kinds of input DIE: DW_TAG_variable, DW_TAG_constant.
+  /// Checks that the specified DWARF expression operand \p Op references live
+  /// code section and returns the relocation adjustment value (to get the
+  /// linked address this value might be added to the source expression operand
+  /// address).
   /// \returns relocation adjustment value or std::nullopt if there is no
   /// corresponding live address.
   virtual std::optional<int64_t>
-  getVariableRelocAdjustment(const DWARFDie &DIE) = 0;
+  getExprOpAddressRelocAdjustment(DWARFUnit &U,
+                                  const DWARFExpression::Operation &Op,
+                                  uint64_t StartOffset, uint64_t EndOffset) = 0;
 
   /// Checks that the specified subprogram \p DIE references the live code
   /// section and returns the relocation adjustment value (to get the linked
@@ -572,6 +575,12 @@ class DWARFLinker {
                          CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
                          unsigned Flags);
 
+  /// This function checks whether variable has DWARF expression containing
+  /// operation referencing live address(f.e. DW_OP_addr, DW_OP_addrx...).
+  /// \returns relocation adjustment value if live address is referenced.
+  std::optional<int64_t> getVariableRelocAdjustment(AddressesMap &RelocMgr,
+                                                    const DWARFDie &DIE);
+
   /// Check if a variable describing DIE should be kept.
   /// \returns updated TraversalFlags.
   unsigned shouldKeepVariableDIE(AddressesMap &RelocMgr, const DWARFDie &DIE,
@@ -703,14 +712,16 @@ class DWARFLinker {
     /// Clone a DWARF expression that may be referencing another DIE.
     void cloneExpression(DataExtractor &Data, DWARFExpression Expression,
                          const DWARFFile &File, CompileUnit &Unit,
-                         SmallVectorImpl<uint8_t> &OutputBuffer);
+                         SmallVectorImpl<uint8_t> &OutputBuffer,
+                         int64_t AddrRelocAdjustment);
 
     /// Clone an attribute referencing another DIE and add
     /// it to \p Die.
     /// \returns the size of the new attribute.
-    unsigned cloneBlockAttribute(DIE &Die, const DWARFFile &File,
-                                 CompileUnit &Unit, AttributeSpec AttrSpec,
-                                 const DWARFFormValue &Val, unsigned AttrSize,
+    unsigned cloneBlockAttribute(DIE &Die, const DWARFDie &InputDIE,
+                                 const DWARFFile &File, CompileUnit &Unit,
+                                 AttributeSpec AttrSpec,
+                                 const DWARFFormValue &Val,
                                  bool IsLittleEndian);
 
     /// Clone an attribute referencing another DIE and add
@@ -761,8 +772,9 @@ class DWARFLinker {
   /// .debug_rnglists) for \p Unit, patch the attributes referencing it.
   void generateUnitRanges(CompileUnit &Unit, const DWARFFile &File) const;
 
-  using ExpressionHandlerRef = function_ref<void(SmallVectorImpl<uint8_t> &,
-                                                 SmallVectorImpl<uint8_t> &)>;
+  using ExpressionHandlerRef =
+      function_ref<void(SmallVectorImpl<uint8_t> &, SmallVectorImpl<uint8_t> &,
+                        int64_t AddrRelocAdjustment)>;
 
   /// Compute and emit debug locations (.debug_loc, .debug_loclists)
   /// for \p Unit, patch the attributes referencing it.

diff  --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
index cfbd13414f703..3736033f3a046 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
@@ -23,12 +23,22 @@ class DeclContext;
 /// linked address.
 using RangesTy = AddressRangesMap;
 
-// FIXME: Delete this structure.
+// This structure keeps patch for the attribute and, optionally,
+// the value of relocation which should be applied. Currently,
+// only location attribute needs to have relocation: either to the
+// function ranges if location attribute is of type 'loclist',
+// either to the operand of DW_OP_addr/DW_OP_addrx if location attribute
+// is of type 'exprloc'.
+// ASSUMPTION: Location attributes of 'loclist' type containing 'exprloc'
+//             with address expression operands are not supported yet.
 struct PatchLocation {
   DIE::value_iterator I;
+  int64_t RelocAdjustment = 0;
 
   PatchLocation() = default;
   PatchLocation(DIE::value_iterator I) : I(I) {}
+  PatchLocation(DIE::value_iterator I, int64_t Reloc)
+      : I(I), RelocAdjustment(Reloc) {}
 
   void set(uint64_t New) const {
     assert(I);
@@ -44,7 +54,7 @@ struct PatchLocation {
 };
 
 using RngListAttributesTy = SmallVector<PatchLocation>;
-using LocListAttributesTy = SmallVector<std::pair<PatchLocation, int64_t>>;
+using LocListAttributesTy = 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.
@@ -191,7 +201,7 @@ class CompileUnit {
 
   /// Keep track of a location attribute pointing to a location list in the
   /// debug_loc section.
-  void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset);
+  void noteLocationAttribute(PatchLocation Attr);
 
   /// Add a name accelerator entry for \a Die with \a Name.
   void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name);
@@ -286,9 +296,10 @@ class CompileUnit {
   /// @}
 
   /// Location attributes that need to be transferred from the
-  /// original debug_loc section to the liked one. They are stored
+  /// original debug_loc section to the linked one. They are stored
   /// along with the PC offset that is to be applied to their
-  /// function's address.
+  /// function's address or to be applied to address operands of
+  /// location expression.
   LocListAttributesTy LocationAttributes;
 
   /// Accelerator entries for the unit, both for the pub*

diff  --git a/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h b/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
index eadd7120f70c7..5386f9ca68674 100644
--- a/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
+++ b/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
@@ -11,6 +11,7 @@
 
 #include "llvm/ADT/AddressRanges.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
 #include <cstdint>
 
 namespace llvm {
@@ -32,14 +33,16 @@ class AddressesMap {
   /// section.
   virtual bool hasValidRelocs() = 0;
 
-  /// Checks that the specified variable \p DIE references the live code
-  /// section and returns the relocation adjustment value (to get the linked
-  /// address this value might be added to the source variable address).
-  /// Allowed kinds of input DIE: DW_TAG_variable, DW_TAG_constant.
+  /// Checks that the specified DWARF expression operand \p Op references live
+  /// code section and returns the relocation adjustment value (to get the
+  /// linked address this value might be added to the source expression operand
+  /// address).
   /// \returns relocation adjustment value or std::nullopt if there is no
   /// corresponding live address.
   virtual std::optional<int64_t>
-  getVariableRelocAdjustment(const DWARFDie &DIE) = 0;
+  getExprOpAddressRelocAdjustment(DWARFUnit &U,
+                                  const DWARFExpression::Operation &Op,
+                                  uint64_t StartOffset, uint64_t EndOffset) = 0;
 
   /// Checks that the specified subprogram \p DIE references the live code
   /// section and returns the relocation adjustment value (to get the linked

diff  --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 3307f5384158f..93c03a10cf91b 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -419,6 +419,94 @@ void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) {
   DIEAlloc.Reset();
 }
 
+std::optional<int64_t>
+DWARFLinker::getVariableRelocAdjustment(AddressesMap &RelocMgr,
+                                        const DWARFDie &DIE) {
+  assert((DIE.getTag() == dwarf::DW_TAG_variable ||
+          DIE.getTag() == dwarf::DW_TAG_constant) &&
+         "Wrong type of input die");
+
+  const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
+
+  // Check if DIE has DW_AT_location attribute.
+  DWARFUnit *U = DIE.getDwarfUnit();
+  std::optional<uint32_t> LocationIdx =
+      Abbrev->findAttributeIndex(dwarf::DW_AT_location);
+  if (!LocationIdx)
+    return std::nullopt;
+
+  // Get offset to the DW_AT_location attribute.
+  uint64_t AttrOffset =
+      Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U);
+
+  // Get value of the DW_AT_location attribute.
+  std::optional<DWARFFormValue> LocationValue =
+      Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U);
+  if (!LocationValue)
+    return std::nullopt;
+
+  // Check that DW_AT_location attribute is of 'exprloc' class.
+  // Handling value of location expressions for attributes of 'loclist'
+  // class is not implemented yet.
+  std::optional<ArrayRef<uint8_t>> Expr = LocationValue->getAsBlock();
+  if (!Expr)
+    return std::nullopt;
+
+  // Parse 'exprloc' expression.
+  DataExtractor Data(toStringRef(*Expr), U->getContext().isLittleEndian(),
+                     U->getAddressByteSize());
+  DWARFExpression Expression(Data, U->getAddressByteSize(),
+                             U->getFormParams().Format);
+
+  uint64_t CurExprOffset = 0;
+  for (DWARFExpression::iterator It = Expression.begin();
+       It != Expression.end(); ++It) {
+    DWARFExpression::iterator NextIt = It;
+    ++NextIt;
+
+    const DWARFExpression::Operation &Op = *It;
+    switch (Op.getCode()) {
+    case dwarf::DW_OP_const4u:
+    case dwarf::DW_OP_const8u:
+    case dwarf::DW_OP_const4s:
+    case dwarf::DW_OP_const8s:
+      if (NextIt == Expression.end() ||
+          NextIt->getCode() != dwarf::DW_OP_form_tls_address)
+        break;
+      [[fallthrough]];
+    case dwarf::DW_OP_addr: {
+      // Check relocation for the address.
+      if (std::optional<int64_t> RelocAdjustment =
+              RelocMgr.getExprOpAddressRelocAdjustment(
+                  *U, Op, AttrOffset + CurExprOffset,
+                  AttrOffset + Op.getEndOffset()))
+        return *RelocAdjustment;
+    } break;
+    case dwarf::DW_OP_constx:
+    case dwarf::DW_OP_addrx: {
+      if (std::optional<uint64_t> AddrOffsetSectionBase =
+              DIE.getDwarfUnit()->getAddrOffsetSectionBase()) {
+        uint64_t StartOffset = *AddrOffsetSectionBase + Op.getRawOperand(0);
+        uint64_t EndOffset =
+            StartOffset + DIE.getDwarfUnit()->getAddressByteSize();
+
+        // Check relocation for the address.
+        if (std::optional<int64_t> RelocAdjustment =
+                RelocMgr.getExprOpAddressRelocAdjustment(*U, Op, StartOffset,
+                                                         EndOffset))
+          return *RelocAdjustment;
+      }
+    } break;
+    default: {
+      // Nothing to do.
+    } break;
+    }
+    CurExprOffset = Op.getEndOffset();
+  }
+
+  return std::nullopt;
+}
+
 /// Check if a variable describing DIE should be kept.
 /// \returns updated TraversalFlags.
 unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,
@@ -440,7 +528,7 @@ unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,
   // However, we don't want a static variable in a function to force us to keep
   // the enclosing function, unless requested explicitly.
   std::optional<int64_t> RelocAdjustment =
-      RelocMgr.getVariableRelocAdjustment(DIE);
+      getVariableRelocAdjustment(RelocMgr, DIE);
 
   if (RelocAdjustment) {
     MyInfo.AddrAdjust = *RelocAdjustment;
@@ -1053,9 +1141,12 @@ unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute(
 
 void DWARFLinker::DIECloner::cloneExpression(
     DataExtractor &Data, DWARFExpression Expression, const DWARFFile &File,
-    CompileUnit &Unit, SmallVectorImpl<uint8_t> &OutputBuffer) {
+    CompileUnit &Unit, SmallVectorImpl<uint8_t> &OutputBuffer,
+    int64_t AddrRelocAdjustment) {
   using Encoding = DWARFExpression::Operation::Encoding;
 
+  uint8_t OrigAddressByteSize = Unit.getOrigUnit().getAddressByteSize();
+
   uint64_t OpOffset = 0;
   for (auto &Op : Expression) {
     auto Description = Op.getDescription();
@@ -1107,6 +1198,55 @@ void DWARFLinker::DIECloner::cloneExpression(
       assert(RealSize == ULEBsize && "padding failed");
       ArrayRef<uint8_t> ULEBbytes(ULEB, ULEBsize);
       OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end());
+    } else if (!Linker.Options.Update && Op.getCode() == dwarf::DW_OP_addrx) {
+      if (std::optional<object::SectionedAddress> SA =
+              Unit.getOrigUnit().getAddrOffsetSectionItem(
+                  Op.getRawOperand(0))) {
+        // DWARFLinker does not use addrx forms since it generates relocated
+        // addresses. Replace DW_OP_addrx with DW_OP_addr here.
+        // Argument of DW_OP_addrx should be relocated here as it is not
+        // processed by applyValidRelocs.
+        OutputBuffer.push_back(dwarf::DW_OP_addr);
+        uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;
+        ArrayRef<uint8_t> AddressBytes(
+            reinterpret_cast<const uint8_t *>(&LinkedAddress),
+            OrigAddressByteSize);
+        OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());
+      } else
+        Linker.reportWarning("cannot read DW_OP_addrx operand.", File);
+    } else if (!Linker.Options.Update && Op.getCode() == dwarf::DW_OP_constx) {
+      if (std::optional<object::SectionedAddress> SA =
+              Unit.getOrigUnit().getAddrOffsetSectionItem(
+                  Op.getRawOperand(0))) {
+        // DWARFLinker does not use constx forms since it generates relocated
+        // addresses. Replace DW_OP_constx with DW_OP_const[*]u here.
+        // Argument of DW_OP_constx should be relocated here as it is not
+        // processed by applyValidRelocs.
+        std::optional<uint8_t> OutOperandKind;
+        switch (OrigAddressByteSize) {
+        case 4:
+          OutOperandKind = dwarf::DW_OP_const4u;
+          break;
+        case 8:
+          OutOperandKind = dwarf::DW_OP_const8u;
+          break;
+        default:
+          Linker.reportWarning(
+              formatv(("unsupported address size: {0}."), OrigAddressByteSize),
+              File);
+          break;
+        }
+
+        if (OutOperandKind) {
+          OutputBuffer.push_back(*OutOperandKind);
+          uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;
+          ArrayRef<uint8_t> AddressBytes(
+              reinterpret_cast<const uint8_t *>(&LinkedAddress),
+              OrigAddressByteSize);
+          OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());
+        }
+      } else
+        Linker.reportWarning("cannot read DW_OP_constx operand.", File);
     } else {
       // Copy over everything else unmodified.
       StringRef Bytes = Data.getData().slice(OpOffset, Op.getEndOffset());
@@ -1117,8 +1257,9 @@ void DWARFLinker::DIECloner::cloneExpression(
 }
 
 unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
-    DIE &Die, const DWARFFile &File, CompileUnit &Unit, AttributeSpec AttrSpec,
-    const DWARFFormValue &Val, unsigned AttrSize, bool IsLittleEndian) {
+    DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File,
+    CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val,
+    bool IsLittleEndian) {
   DIEValueList *Attr;
   DIEValue Value;
   DIELoc *Loc = nullptr;
@@ -1152,7 +1293,8 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
                        IsLittleEndian, OrigUnit.getAddressByteSize());
     DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(),
                          OrigUnit.getFormParams().Format);
-    cloneExpression(Data, Expr, File, Unit, Buffer);
+    cloneExpression(Data, Expr, File, Unit, Buffer,
+                    Unit.getInfo(InputDIE).AddrAdjust);
     Bytes = Buffer;
   }
   for (auto Byte : Bytes)
@@ -1168,7 +1310,7 @@ unsigned DWARFLinker::DIECloner::cloneBlockAttribute(
     Block->setSize(Bytes.size());
 
   Die.addValue(DIEAlloc, Value);
-  return AttrSize;
+  return getULEB128Size(Bytes.size()) + Bytes.size();
 }
 
 unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
@@ -1355,7 +1497,7 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
     return 0;
   }
 
-  PatchLocation Patch =
+  DIE::value_iterator Patch =
       Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
                    dwarf::Form(AttrSpec.Form), DIEInteger(Value));
   if (AttrSpec.Attr == dwarf::DW_AT_ranges ||
@@ -1366,7 +1508,11 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
              dwarf::doesFormBelongToClass(AttrSpec.Form,
                                           DWARFFormValue::FC_SectionOffset,
                                           Unit.getOrigUnit().getVersion())) {
-    Unit.noteLocationAttribute(Patch, Info.PCOffset);
+
+    CompileUnit::DIEInfo &LocationDieInfo = Unit.getInfo(InputDIE);
+    Unit.noteLocationAttribute({Patch, LocationDieInfo.InDebugMap
+                                           ? LocationDieInfo.AddrAdjust
+                                           : Info.PCOffset});
   } else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
     Info.IsDeclaration = true;
 
@@ -1408,7 +1554,7 @@ unsigned DWARFLinker::DIECloner::cloneAttribute(
   case dwarf::DW_FORM_block2:
   case dwarf::DW_FORM_block4:
   case dwarf::DW_FORM_exprloc:
-    return cloneBlockAttribute(Die, File, Unit, AttrSpec, Val, AttrSize,
+    return cloneBlockAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,
                                IsLittleEndian);
   case dwarf::DW_FORM_addr:
   case dwarf::DW_FORM_addrx:
@@ -1803,7 +1949,7 @@ void DWARFLinker::generateUnitLocations(
     // Get location expressions vector corresponding to the current attribute
     // from the source DWARF.
     Expected<DWARFLocationExpressionsVector> OriginalLocations =
-        Unit.getOrigUnit().findLoclistFromOffset((CurLocAttr.first).get());
+        Unit.getOrigUnit().findLoclistFromOffset(CurLocAttr.get());
 
     if (!OriginalLocations) {
       llvm::consumeError(OriginalLocations.takeError());
@@ -1813,26 +1959,26 @@ void DWARFLinker::generateUnitLocations(
 
     DWARFLocationExpressionsVector LinkedLocationExpressions;
     for (DWARFLocationExpression &CurExpression : *OriginalLocations) {
-
       DWARFLocationExpression LinkedExpression;
 
       if (CurExpression.Range) {
         // Relocate address range.
         LinkedExpression.Range = {
-            CurExpression.Range->LowPC + CurLocAttr.second,
-            CurExpression.Range->HighPC + CurLocAttr.second};
+            CurExpression.Range->LowPC + CurLocAttr.RelocAdjustment,
+            CurExpression.Range->HighPC + CurLocAttr.RelocAdjustment};
       }
 
       // Clone expression.
       LinkedExpression.Expr.reserve(CurExpression.Expr.size());
-      ExprHandler(CurExpression.Expr, LinkedExpression.Expr);
+      ExprHandler(CurExpression.Expr, LinkedExpression.Expr,
+                  CurLocAttr.RelocAdjustment);
 
       LinkedLocationExpressions.push_back(LinkedExpression);
     }
 
     // Emit locations list table fragment corresponding to the CurLocAttr.
     TheDwarfEmitter->emitDwarfDebugLocListFragment(
-        Unit, LinkedLocationExpressions, CurLocAttr.first);
+        Unit, LinkedLocationExpressions, CurLocAttr);
   }
 
   // Emit locations list table footer.
@@ -2399,14 +2545,15 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
       Linker.generateUnitRanges(*CurrentUnit, File);
 
       auto ProcessExpr = [&](SmallVectorImpl<uint8_t> &SrcBytes,
-                             SmallVectorImpl<uint8_t> &OutBytes) {
+                             SmallVectorImpl<uint8_t> &OutBytes,
+                             int64_t RelocAdjustment) {
         DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit();
         DataExtractor Data(SrcBytes, IsLittleEndian,
                            OrigUnit.getAddressByteSize());
         cloneExpression(Data,
                         DWARFExpression(Data, OrigUnit.getAddressByteSize(),
                                         OrigUnit.getFormParams().Format),
-                        File, *CurrentUnit, OutBytes);
+                        File, *CurrentUnit, OutBytes, RelocAdjustment);
       };
       Linker.generateUnitLocations(*CurrentUnit, File, ProcessExpr);
     }

diff  --git a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
index 870a841951e0f..4aa6f33c2908b 100644
--- a/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinkerCompileUnit.cpp
@@ -8,6 +8,8 @@
 
 #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
 #include "llvm/Support/FormatVariadic.h"
 
 namespace llvm {
@@ -63,6 +65,7 @@ void CompileUnit::markEverythingAsKept() {
     // Mark everything that wasn't explicit marked for pruning.
     I.Keep = !I.Prune;
     auto DIE = OrigUnit.getDIEAtIndex(Idx++);
+    DWARFUnit *U = DIE.getDwarfUnit();
 
     // Try to guess which DIEs must go to the accelerator tables. We do that
     // just for variables, because functions will be handled depending on
@@ -78,10 +81,39 @@ void CompileUnit::markEverythingAsKept() {
         I.InDebugMap = true;
       continue;
     }
-    if (auto Block = Value->getAsBlock()) {
-      if (Block->size() > OrigUnit.getAddressByteSize() &&
-          (*Block)[0] == dwarf::DW_OP_addr)
-        I.InDebugMap = true;
+
+    if (auto ExprLockBlock = Value->getAsBlock()) {
+      // Parse 'exprloc' expression.
+      DataExtractor Data(toStringRef(*ExprLockBlock),
+                         U->getContext().isLittleEndian(),
+                         U->getAddressByteSize());
+      DWARFExpression Expression(Data, U->getAddressByteSize(),
+                                 U->getFormParams().Format);
+
+      for (DWARFExpression::iterator It = Expression.begin();
+           (It != Expression.end()) && !I.InDebugMap; ++It) {
+        DWARFExpression::iterator NextIt = It;
+        ++NextIt;
+
+        switch (It->getCode()) {
+        case dwarf::DW_OP_const4u:
+        case dwarf::DW_OP_const8u:
+        case dwarf::DW_OP_const4s:
+        case dwarf::DW_OP_const8s:
+          if (NextIt == Expression.end() ||
+              NextIt->getCode() != dwarf::DW_OP_form_tls_address)
+            break;
+          [[fallthrough]];
+        case dwarf::DW_OP_constx:
+        case dwarf::DW_OP_addr:
+        case dwarf::DW_OP_addrx:
+          I.InDebugMap = true;
+          break;
+        default:
+          // Nothing to do.
+          break;
+        }
+      }
     }
   }
 }
@@ -143,8 +175,8 @@ void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
   RangeAttributes.emplace_back(Attr);
 }
 
-void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) {
-  LocationAttributes.emplace_back(Attr, PcOffset);
+void CompileUnit::noteLocationAttribute(PatchLocation Attr) {
+  LocationAttributes.emplace_back(Attr);
 }
 
 void CompileUnit::addNamespaceAccelerator(const DIE *Die,

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index 3adc6c7bcbe56..109731e73c71d 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -94,11 +94,12 @@ static DescVector getDescriptions() {
   Descriptions[DW_OP_WASM_location] =
       Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg);
   Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
-  Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
 
+  Descriptions[DW_OP_addrx] = Desc(Op::Dwarf5, Op::SizeLEB);
+  Descriptions[DW_OP_constx] = Desc(Op::Dwarf5, Op::SizeLEB);
   Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
   Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
   Descriptions[DW_OP_regval_type] =

diff  --git a/llvm/test/tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o b/llvm/test/tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o
new file mode 100644
index 0000000000000..fb2a6d3242ec5
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/dwarf5-dw-op-addrx.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/dwarf5-dw-op-addrx.test b/llvm/test/tools/dsymutil/X86/dwarf5-dw-op-addrx.test
new file mode 100644
index 0000000000000..8951470f4c5b6
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/dwarf5-dw-op-addrx.test
@@ -0,0 +1,47 @@
+## This test checks that DW_OP_addrx expression operand
+## is correctly recognized and converted into the DW_OP_addr
+## operand or just preserved in case --update.
+
+## cat dwarf5-dw-op-addrx.c
+
+## $ clang -gdwarf-5 dwarf5-dw-op-addrx.c -c -O2 -o dwarf5-dw-op-addrx.o
+
+#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_AT_name {{.*}}"dwarf5-dw-op-addrx.c"
+#DWARF-CHECK: DW_AT_low_pc {{.*}}0x0000000100000fb0
+#DWARF-CHECK: DW_TAG_variable
+#DWARF-CHECK:   DW_AT_name {{.*}}"arr"
+#DWARF-CHECK:   DW_AT_location {{.*}}(DW_OP_addr 0x100002000)
+#DWARF-CHECK-NOT: .debug_addr
+
+#UPD-DWARF-CHECK: DW_TAG_compile_unit
+#UPD-DWARF-CHECK: DW_AT_name {{.*}}"dwarf5-dw-op-addrx.c"
+#UPD-DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx]      (indexed (00000001) address = 0x0000000000000000)
+#UPD-DWARF-CHECK: DW_AT_high_pc [DW_FORM_data4]     (0x00000008)
+#UPD-DWARF-CHECK: DW_AT_addr_base [DW_FORM_sec_offset]      (0x00000008)
+#UPD-DWARF-CHECK: DW_TAG_variable
+#UPD-DWARF-CHECK:   DW_AT_name {{.*}}"arr"
+#UPD-DWARF-CHECK:   DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)
+#UPD-DWARF-CHECK: .debug_addr contents:
+#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x00000014, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
+#UPD-DWARF-CHECK: 0x0000000000000000
+#UPD-DWARF-CHECK: 0x0000000000000000
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename:        'dwarf5-dw-op-addrx.o'
+    timestamp:       1676048242
+    symbols:
+      - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000FB0, size: 0x00000008 }
+      - { sym: _arr, binAddr: 0x0000000100002000, size: 0x00000000 }

diff  --git a/llvm/test/tools/dsymutil/X86/op-convert-offset.test b/llvm/test/tools/dsymutil/X86/op-convert-offset.test
index 5694535322810..8cf378c114a39 100644
--- a/llvm/test/tools/dsymutil/X86/op-convert-offset.test
+++ b/llvm/test/tools/dsymutil/X86/op-convert-offset.test
@@ -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: 0x0000008d:   DW_TAG_base_type
+DSYM: 0x000000ae:   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: 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: 0x000000d5:     DW_TAG_formal_parameter
+DSYM:                   DW_AT_location        (DW_OP_breg2 RCX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert (0x000000ae) "DW_ATE_unsigned_1", DW_OP_convert (0x000000b5) "DW_ATE_unsigned_8", DW_OP_stack_value)
 DSYM:                   DW_AT_name    ("b")
-DSYM:                   DW_AT_type    (0x000000d2 "_Bool")
+DSYM:                   DW_AT_type    (0x000000f3 "_Bool")

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addrx.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
similarity index 71%
rename from llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addrx.test
rename to llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
index bf52bac1237c1..3a3bf54c61d7d 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addrx.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
@@ -1,6 +1,11 @@
-## 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.
+## Test that DWARFv5 address attributes and address expression operands
+## are handled correctly, specifically:
+## 1. 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.
+## 2. DW_OP_addrx is correctly recognized and converted into the DW_OP_addr
+##    in --garbage-collection case or correctly preserved in --no-garbage-collection case.
+## 3. DW_OP_constx is correctly recognized and converted into the DW_OP_const[*]u
+##    in --garbage-collection case or correctly preserved in --no-garbage-collection case.
 
 # RUN: yaml2obj %s -o %t.o
 
@@ -46,6 +51,18 @@
 #DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "foo6"
 #DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000000001180)
 #DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#DWARF-CHECK:   DW_TAG_variable
+#DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "var1"
+#DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x2000)
+#DWARF-CHECK:   DW_TAG_variable
+#DWARF-CHECK:     DW_AT_name  [DW_FORM_strp] {{.*}}   "var2"
+#DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x2000)
+#DWARF-CHECK:   DW_TAG_variable
+#DWARF-CHECK:     DW_AT_name [DW_FORM_strp]  {{.*}}   "var3"
+#DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc] (DW_OP_const8u 0x2000, DW_OP_form_tls_address)
+#DWARF-CHECK:   DW_TAG_variable
+#DWARF-CHECK:     DW_AT_name [DW_FORM_strp]  {{.*}}   "var4"
+#DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc] (DW_OP_const8u 0x2000, DW_OP_form_tls_address)
 #DWARF-CHECK=NOT: .debug_addr contents:
 
 #UPD-DWARF-CHECK: DW_TAG_compile_unit
@@ -76,8 +93,20 @@
 #UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"foo6"
 #UPD-DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx4]   (indexed (00000005) address = 0x0000000000001180)
 #UPD-DWARF-CHECK:     DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000010)
+#UPD-DWARF-CHECK:   DW_TAG_variable
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"var1"
+#UPD-DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x6)
+#UPD-DWARF-CHECK:   DW_TAG_variable
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"var2"
+#UPD-DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc]        (DW_OP_addr 0x2000)
+#UPD-DWARF-CHECK:   DW_TAG_variable
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"var3"
+#UPD-DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc] (DW_OP_constx 0x6, DW_OP_form_tls_address)
+#UPD-DWARF-CHECK:   DW_TAG_variable
+#UPD-DWARF-CHECK:     DW_AT_name  {{.*}}"var4"
+#UPD-DWARF-CHECK:     DW_AT_location [DW_FORM_exprloc] (DW_OP_const8u 0x2000, DW_OP_form_tls_address)
 #UPD-DWARF-CHECK: .debug_addr contents:
-#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x00000034, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
+#UPD-DWARF-CHECK: 0x00000000: Address table header: length = 0x0000003c, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
 #UPD-DWARF-CHECK: Addrs: [
 #UPD-DWARF-CHECK: 0x0000000000001130
 #UPD-DWARF-CHECK: 0x0000000000001140
@@ -85,6 +114,7 @@
 #UPD-DWARF-CHECK: 0x0000000000001160
 #UPD-DWARF-CHECK: 0x0000000000001170
 #UPD-DWARF-CHECK: 0x0000000000001180
+#UPD-DWARF-CHECK: 0x0000000000002000
 #UPD-DWARF-CHECK: ]
 
 --- !ELF
@@ -98,7 +128,7 @@ Sections:
     Type:            SHT_PROGBITS
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
     Address:         0x1130
-    Size:            0x60
+    Size:            0x1000
 DWARF:
   debug_abbrev:
     - Table:
@@ -166,6 +196,15 @@ DWARF:
         Attributes:
           - Attribute: DW_AT_name
             Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+          - Attribute: DW_AT_location
+            Form:      DW_FORM_exprloc
   debug_info:
     - Version: 5
       UnitType:   DW_UT_compile
@@ -223,6 +262,50 @@ DWARF:
         - AbbrCode: 6
           Values:
             - CStr: int
+        - AbbrCode: 7
+          Values:
+            - CStr: var1
+            - Value: 0xa4
+            - BlockData:
+                - 0xa1
+                - 0x6
+        - AbbrCode: 7
+          Values:
+            - CStr: var2
+            - Value: 0xa4
+            - BlockData:
+                - 0x03
+                - 0x00
+                - 0x20
+                - 0x00
+                - 0x00
+                - 0x00
+                - 0x00
+                - 0x00
+                - 0x00
+        - AbbrCode: 7
+          Values:
+            - CStr: var3
+            - Value: 0xa4
+            - BlockData:
+                - 0xa2
+                - 0x6
+                - 0x9b
+        - AbbrCode: 7
+          Values:
+            - CStr: var4
+            - Value: 0xa4
+            - BlockData:
+                - 0x0e
+                - 0x00
+                - 0x20
+                - 0x00
+                - 0x00
+                - 0x00
+                - 0x00
+                - 0x00
+                - 0x00
+                - 0x9b
         - AbbrCode: 0
   debug_addr:
     - Version: 5
@@ -234,4 +317,5 @@ DWARF:
         - Address: 0x1160
         - Address: 0x1170
         - Address: 0x1180
+        - Address: 0x2000
 ...

diff  --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index 62251162e7b33..efa490ebbb40f 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -40,6 +40,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
@@ -985,23 +986,27 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
 }
 
 std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager::getVariableRelocAdjustment(
-    const DWARFDie &DIE) {
-  const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
-
-  std::optional<uint32_t> LocationIdx =
-      Abbrev->findAttributeIndex(dwarf::DW_AT_location);
-  if (!LocationIdx)
-    return std::nullopt;
-
-  uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
-  uint64_t LocationOffset, LocationEndOffset;
-  std::tie(LocationOffset, LocationEndOffset) =
-      getAttributeOffsets(Abbrev, *LocationIdx, Offset, *DIE.getDwarfUnit());
+DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
+    DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
+    uint64_t EndOffset) {
+  switch (Op.getCode()) {
+  default: {
+    assert(false && "Specified operation does not have address operand");
+  } break;
+  case dwarf::DW_OP_const4u:
+  case dwarf::DW_OP_const8u:
+  case dwarf::DW_OP_const4s:
+  case dwarf::DW_OP_const8s:
+  case dwarf::DW_OP_addr: {
+    return hasValidRelocationAt(ValidDebugInfoRelocs, StartOffset, EndOffset);
+  } break;
+  case dwarf::DW_OP_constx:
+  case dwarf::DW_OP_addrx: {
+    return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset);
+  } break;
+  }
 
-  // FIXME: Support relocations debug_addr.
-  return hasValidRelocationAt(ValidDebugInfoRelocs, LocationOffset,
-                              LocationEndOffset);
+  return std::nullopt;
 }
 
 std::optional<int64_t>

diff  --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h
index ec54265bdd77b..8b967f9f418e2 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.h
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h
@@ -177,8 +177,9 @@ class DwarfLinkerForBinary {
     hasValidRelocationAt(const std::vector<ValidReloc> &Relocs,
                          uint64_t StartOffset, uint64_t EndOffset);
 
-    std::optional<int64_t>
-    getVariableRelocAdjustment(const DWARFDie &DIE) override;
+    std::optional<int64_t> getExprOpAddressRelocAdjustment(
+        DWARFUnit &U, const DWARFExpression::Operation &Op,
+        uint64_t StartOffset, uint64_t EndOffset) override;
     std::optional<int64_t>
     getSubprogramRelocAdjustment(const DWARFDie &DIE) override;
 

diff  --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
index 534a56a4f7d04..b36c57a737098 100644
--- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -88,38 +88,33 @@ class ObjFileAddressMap : public AddressesMap {
     return std::nullopt;
   }
 
-  std::optional<int64_t>
-  getVariableRelocAdjustment(const DWARFDie &DIE) override {
-    assert((DIE.getTag() == dwarf::DW_TAG_variable ||
-            DIE.getTag() == dwarf::DW_TAG_constant) &&
-           "Wrong type of input die");
-
-    if (Expected<DWARFLocationExpressionsVector> Loc =
-            DIE.getLocations(dwarf::DW_AT_location)) {
-      DWARFUnit *U = DIE.getDwarfUnit();
-      for (const auto &Entry : *Loc) {
-        DataExtractor Data(toStringRef(Entry.Expr),
-                           U->getContext().isLittleEndian(), 0);
-        DWARFExpression Expression(Data, U->getAddressByteSize(),
-                                   U->getFormParams().Format);
-        bool HasLiveAddresses =
-            any_of(Expression, [&](const DWARFExpression::Operation &Op) {
-              // TODO: add handling of dwarf::DW_OP_addrx
-              return !Op.isError() &&
-                     (Op.getCode() == dwarf::DW_OP_addr &&
-                      !isDeadAddress(Op.getRawOperand(0), U->getVersion(),
-                                     Opts.Tombstone,
-                                     DIE.getDwarfUnit()->getAddressByteSize()));
-            });
-
-        if (HasLiveAddresses)
+  std::optional<int64_t> getExprOpAddressRelocAdjustment(
+      DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
+      uint64_t EndOffset) override {
+    switch (Op.getCode()) {
+    default: {
+      assert(false && "Specified operation does not have address operand");
+    } break;
+    case dwarf::DW_OP_const4u:
+    case dwarf::DW_OP_const8u:
+    case dwarf::DW_OP_const4s:
+    case dwarf::DW_OP_const8s:
+    case dwarf::DW_OP_addr: {
+      if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone,
+                         U.getAddressByteSize()))
+        // Relocation value for the linked binary is 0.
+        return 0;
+    } break;
+    case dwarf::DW_OP_constx:
+    case dwarf::DW_OP_addrx: {
+      if (std::optional<object::SectionedAddress> Address =
+              U.getAddrOffsetSectionItem(Op.getRawOperand(0))) {
+        if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone,
+                           U.getAddressByteSize()))
           // Relocation value for the linked binary is 0.
           return 0;
       }
-    } else {
-      // FIXME: missing DW_AT_location is OK here, but other errors should be
-      // reported to the user.
-      consumeError(Loc.takeError());
+    } break;
     }
 
     return std::nullopt;


        


More information about the llvm-commits mailing list