https://github.com/firmiana402 created 
https://github.com/llvm/llvm-project/pull/214519

`GetOpcodeDataSize` incorrectly scanned reference operands in two DWARF 
operations. It treated the `DW_OP_call_ref` reference as target-address-sized, 
although its width is determined by the containing unit's DWARF32/DWARF64 
format. It also treated the `DW_OP_implicit_pointer` reference as address-sized 
and attempted to decode its following SLEB128 offset from the beginning of the 
reference.

Expose the unit's DWARF offset byte size through `DWARFExpression::Delegate` 
and use it for both reference operands. `DW_OP_implicit_pointer` now skips the 
complete reference before decoding its SLEB128 offset. A scan without a DWARF 
unit fails conservatively instead of guessing the width.

## Testing

Unit tests cover `DW_OP_call_ref` with mismatched DWARF/address widths and a 
DWARF64 `DW_OP_implicit_pointer` with a multi-byte SLEB128 offset.

Fixes #43966
Fixes #214459

>From 75dd97829bb608a8aa4d94167b3d0e09f7d0d34c Mon Sep 17 00:00:00 2001
From: firmiana402 <[email protected]>
Date: Thu, 6 Aug 2026 17:51:45 +0800
Subject: [PATCH 1/2] [lldb] Use the DWARF format for DW_OP_call_ref operand
 size

---
 .../include/lldb/Expression/DWARFExpression.h |  1 +
 lldb/source/Expression/DWARFExpression.cpp    |  3 +-
 .../Plugins/SymbolFile/DWARF/DWARFUnit.h      |  3 ++
 .../Expression/DWARFExpressionTest.cpp        | 42 ++++++++++++++++++-
 4 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpression.h 
b/lldb/include/lldb/Expression/DWARFExpression.h
index feecd50fc9c22..d5e12eda4ac0c 100644
--- a/lldb/include/lldb/Expression/DWARFExpression.h
+++ b/lldb/include/lldb/Expression/DWARFExpression.h
@@ -45,6 +45,7 @@ class DWARFExpression {
     virtual uint16_t GetVersion() const = 0;
     virtual dw_addr_t GetBaseAddress() const = 0;
     virtual uint8_t GetAddressByteSize() const = 0;
+    virtual uint8_t GetDwarfOffsetByteSize() const = 0;
     virtual llvm::Expected<std::pair<uint64_t, bool>>
     GetDIEBitSizeAndSign(uint64_t relative_die_offset) const = 0;
     virtual dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const = 
0;
diff --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index 2dbf61a14eac4..81eae980286c6 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -223,8 +223,9 @@ GetOpcodeDataSize(const DataExtractor &data, const 
lldb::offset_t data_offset,
     break;
 
   case DW_OP_addr:
-  case DW_OP_call_ref: // 0x9a 1 address sized offset of DIE (DWARF3)
     return data.GetAddressByteSize();
+  case DW_OP_call_ref:
+    return dwarf_cu ? dwarf_cu->GetDwarfOffsetByteSize() : LLDB_INVALID_OFFSET;
 
   // Opcodes with no arguments
   case DW_OP_deref:                // 0x06
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index 6fde9af57fa8b..acea9f49b1c6a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -127,6 +127,9 @@ class DWARFUnit : public DWARFExpression::Delegate, public 
UserID {
   uint8_t GetAddressByteSize() const override {
     return m_header.getAddressByteSize();
   }
+  uint8_t GetDwarfOffsetByteSize() const override {
+    return GetFormParams().getDwarfOffsetByteSize();
+  }
   dw_addr_t GetAddrBase() const { return m_addr_base.value_or(0); }
   dw_addr_t GetBaseAddress() const override { return m_base_addr; }
   dw_offset_t GetLineTableOffset();
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index e8bca7208c8d5..cd4b90c414e6c 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -42,15 +42,20 @@ using namespace llvm::dwarf;
 namespace {
 /// A mock implementation of DWARFExpression::Delegate for testing.
 /// This class provides default implementations of all delegate methods,
-/// with the DWARF version being configurable via the constructor.
+/// with the DWARF version and offset byte size configurable via the
+/// constructor.
 class MockDwarfDelegate : public DWARFExpression::Delegate {
 public:
   static constexpr uint16_t DEFAULT_DWARF_VERSION = 5;
   static MockDwarfDelegate Dwarf5() { return MockDwarfDelegate(5); }
   static MockDwarfDelegate Dwarf2() { return MockDwarfDelegate(2); }
+  static MockDwarfDelegate Dwarf64() {
+    return MockDwarfDelegate(DEFAULT_DWARF_VERSION, /*offset_byte_size=*/8);
+  }
 
   MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {}
-  explicit MockDwarfDelegate(uint16_t version) : m_dwarf_version(version) {}
+  explicit MockDwarfDelegate(uint16_t version, uint8_t offset_byte_size = 4)
+      : m_dwarf_version(version), m_offset_byte_size(offset_byte_size) {}
 
   uint16_t GetVersion() const override { return m_dwarf_version; }
 
@@ -58,6 +63,8 @@ class MockDwarfDelegate : public DWARFExpression::Delegate {
 
   uint8_t GetAddressByteSize() const override { return 4; }
 
+  uint8_t GetDwarfOffsetByteSize() const override { return m_offset_byte_size; 
}
+
   llvm::Expected<std::pair<uint64_t, bool>>
   GetDIEBitSizeAndSign(uint64_t relative_die_offset) const override {
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -83,6 +90,7 @@ class MockDwarfDelegate : public DWARFExpression::Delegate {
 
 private:
   uint16_t m_dwarf_version;
+  uint8_t m_offset_byte_size;
 };
 
 /// Mock memory implementation for testing.
@@ -820,6 +828,36 @@ TEST(DWARFExpression, DW_OP_implicit_value) {
                        llvm::HasValue(0x40302010u));
 }
 
+TEST(DWARFExpression, GetLocationSkipsDW_OP_call_refOperand) {
+  {
+    // In DWARF64 the reference is eight bytes even when addresses are four
+    // bytes. Embed a false DW_OP_addr after the first four operand bytes to
+    // detect an address-sized skip.
+    uint8_t expr[] = {DW_OP_call_ref, 0x00, 0x00, 0x00, 0x00,
+                      DW_OP_addr,     0x11, 0x22, 0x33, DW_OP_addr,
+                      0x10,           0x20, 0x30, 0x40};
+    DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
+                            /*addr_size=*/4);
+    DWARFExpression dwarf_expr(extractor);
+    MockDwarfDelegate dwarf64 = MockDwarfDelegate::Dwarf64();
+    EXPECT_THAT_EXPECTED(dwarf_expr.GetLocation_DW_OP_addr(&dwarf64),
+                         llvm::HasValue(0x40302010u));
+  }
+
+  {
+    // In DWARF32 the reference is four bytes even when addresses are eight
+    // bytes. An address-sized skip would consume the following DW_OP_addr.
+    uint8_t expr[] = {DW_OP_call_ref, 0x00, 0x00, 0x00, 0x00, DW_OP_addr, 0x30,
+                      0x31,           0x32, 0x30, 0x31, 0x32, 0x33,       
0x34};
+    DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
+                            /*addr_size=*/8);
+    DWARFExpression dwarf_expr(extractor);
+    MockDwarfDelegate dwarf32;
+    EXPECT_THAT_EXPECTED(dwarf_expr.GetLocation_DW_OP_addr(&dwarf32),
+                         llvm::HasValue(lldb::addr_t{0x3433323130323130}));
+  }
+}
+
 TEST(DWARFExpression, DW_OP_unknown) {
   EXPECT_THAT_EXPECTED(
       Evaluate({0xff}),

>From c60846a1982b3d66fac504b27863b860755ed963 Mon Sep 17 00:00:00 2001
From: firmiana402 <[email protected]>
Date: Thu, 6 Aug 2026 17:59:16 +0800
Subject: [PATCH 2/2] [lldb] Correct DW_OP_implicit_pointer operand scanning

---
 lldb/source/Expression/DWARFExpression.cpp    | 10 +++++----
 .../Expression/DWARFExpressionTest.cpp        | 21 +++++++++++++++++++
 2 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index 81eae980286c6..da4094cd8c6cc 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -420,12 +420,14 @@ GetOpcodeDataSize(const DataExtractor &data, const 
lldb::offset_t data_offset,
     return offset - data_offset;
   }
 
-  case DW_OP_implicit_pointer: // 0xa0 4-byte (or 8-byte for DWARF 64) constant
-                               // + LEB128
+  case DW_OP_implicit_pointer: // 0xa0 4-byte (or 8-byte for DWARF 64)
+                               // reference + SLEB128 offset
   {
+    if (!dwarf_cu)
+      return LLDB_INVALID_OFFSET;
+    offset += dwarf_cu->GetDwarfOffsetByteSize();
     data.Skip_LEB128(&offset);
-    return (dwarf_cu ? dwarf_cu->GetAddressByteSize() : 4) + offset -
-           data_offset;
+    return offset - data_offset;
   }
 
   case DW_OP_GNU_entry_value:
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index cd4b90c414e6c..624ae081d2dca 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -858,6 +858,27 @@ TEST(DWARFExpression, 
GetLocationSkipsDW_OP_call_refOperand) {
   }
 }
 
+TEST(DWARFExpression, GetLocationSkipsDW_OP_implicit_pointerOperands) {
+  // DW_OP_implicit_pointer contains an eight-byte reference in DWARF64,
+  // followed by an SLEB128 offset. The operand bytes contain false DW_OP_addr
+  // operations that detect either an address-sized reference or decoding the
+  // SLEB128 before skipping the reference.
+  uint8_t expr[] = {
+      DW_OP_implicit_pointer,
+      // Eight-byte reference with a false DW_OP_addr at byte six.
+      0x00, 0x11, 0x22, 0x33, 0x44, DW_OP_addr, 0x55, 0x66,
+      // Two-byte SLEB128 whose final byte is another false DW_OP_addr.
+      0x80, DW_OP_addr,
+      // The real address operation.
+      DW_OP_addr, 0x10, 0x20, 0x30, 0x40};
+  DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
+                          /*addr_size=*/4);
+  DWARFExpression dwarf_expr(extractor);
+  MockDwarfDelegate dwarf64 = MockDwarfDelegate::Dwarf64();
+  EXPECT_THAT_EXPECTED(dwarf_expr.GetLocation_DW_OP_addr(&dwarf64),
+                       llvm::HasValue(0x40302010u));
+}
+
 TEST(DWARFExpression, DW_OP_unknown) {
   EXPECT_THAT_EXPECTED(
       Evaluate({0xff}),

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to