[Lldb-commits] [lldb] [llvm] [lldb] Support DW_OP_deref_type (PR #233381)

via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 19 22:03:08 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: firmiana (firmiana402)

<details>
<summary>Changes</summary>

Implement the DWARF 5 typed dereference opcode so LLDB can read values wider than the address-sized generic type. This is the consumer-side follow-up to the wide bit-field extraction work discussed in #<!-- -->227952.

Decode the one-byte read size and CU-relative base-type reference, validate their sizes, and preserve the loaded value's width and signedness. Support integer types and the same 32-, 64-, and 80-bit floating-point formats as `DW_OP_convert`, interpreting floating-point data as raw bits rather than numerically converting an integer. Reuse the existing base-type resolver and target memory reader, with separate handling for LLDB host-address buffers and their byte order.

Leave the existing `DW_OP_deref` and `DW_OP_deref_size` evaluator unchanged. A follow-up could factor out common memory-reading logic while keeping the opcodes' different result-type semantics separate.

Add unit tests for signed and unsigned values, wide reads, both byte orders, floating-point formats, file addresses, host buffers with and without a target, operand scanning, and error paths. Other unimplemented typed opcodes are unchanged.

---

Patch is 28.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/233381.diff


4 Files Affected:

- (modified) lldb/source/Expression/DWARFExpression.cpp (+130-2) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp (+3-5) 
- (modified) lldb/unittests/Expression/DWARFExpressionTest.cpp (+366-13) 
- (modified) llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp (+1) 


``````````diff
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index f884724766714..2d27e54d69910 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -46,6 +46,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"
 #include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
 #include "llvm/Support/ErrorExtras.h"
+#include "llvm/Support/MathExtras.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -333,7 +334,6 @@ GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset,
   case DW_OP_pick:        // 0x15 1 1-byte stack index
   case DW_OP_deref_size:  // 0x94 1 1-byte size of data retrieved
   case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
-  case DW_OP_deref_type:  // 0xa6 1 1-byte constant
     return 1;
 
   // Opcodes with a single 2 byte arguments
@@ -412,6 +412,11 @@ GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset,
     data.Skip_LEB128(&offset);
     return offset - data_offset;
 
+  case DW_OP_deref_type: // 0xa6 1-byte size followed by ULEB128 type DIE offset
+    offset += 1;
+    data.Skip_LEB128(&offset);
+    return offset - data_offset;
+
   case DW_OP_implicit_value: // 0x9e ULEB128 size followed by block of that size
                              // (DWARF4)
   {
@@ -1106,6 +1111,123 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx,
   return llvm::Error::success();
 }
 
+static llvm::Error Evaluate_DW_OP_deref_type(EvalContext &eval_ctx,
+                                             unsigned size,
+                                             uint64_t relative_die_offset,
+                                             ByteOrder expression_byte_order) {
+  if (!eval_ctx.dwarf_cu)
+    return llvm::createStringError("DW_OP_deref_type requires a DWARF unit");
+  auto type = eval_ctx.dwarf_cu->GetDIEBitSizeAndEncoding(relative_die_offset);
+  if (!type)
+    return type.takeError();
+  const auto [bit_size, encoding] = *type;
+  if (size == 0 || bit_size == 0 || llvm::divideCeil(bit_size, 8) != size)
+    return llvm::createStringError(
+        "DW_OP_deref_type size (%u) does not match type size (%" PRIu64
+        " bits)",
+        size, bit_size);
+
+  const llvm::fltSemantics *semantics = nullptr;
+  if (encoding == DW_ATE_float) {
+    switch (bit_size) {
+    case 32:
+      semantics = &llvm::APFloat::IEEEsingle();
+      break;
+    case 64:
+      semantics = &llvm::APFloat::IEEEdouble();
+      break;
+    case 80:
+      semantics = &llvm::APFloat::x87DoubleExtended();
+      break;
+    default:
+      return llvm::createStringError("unsupported floating-point type size");
+    }
+  }
+
+  Value &value = eval_ctx.stack.back();
+  if (value.GetScalar().GetType() != Scalar::e_int)
+    return llvm::createStringError(
+        "DW_OP_deref_type requires an integral address");
+
+  Scalar scalar;
+  if (value.GetValueType() == Value::ValueType::HostAddress) {
+    // Implicit blocks use the expression's byte order. Other host buffers
+    // follow Value::GetValueAsData, including host-order scalar register
+    // buffers.
+    ByteOrder byte_order = expression_byte_order;
+    if (eval_ctx.loc_desc_kind != Implicit)
+      byte_order = eval_ctx.target
+                       ? eval_ctx.target->GetArchitecture().GetByteOrder()
+                       : endian::InlHostByteOrder();
+    if (const RegisterInfo *reg_info = value.GetRegisterInfo();
+        reg_info &&
+        !llvm::isa_and_present<RegisterTypeVector>(reg_info->register_type))
+      byte_order = endian::InlHostByteOrder();
+    const auto *bytes =
+        reinterpret_cast<const uint8_t *>(value.GetScalar().ULongLong());
+    const auto &buffer = value.GetBuffer();
+    const size_t available_size =
+        bytes == buffer.GetBytes() ? buffer.GetByteSize() : size;
+    DataExtractor data(
+        bytes, available_size, byte_order,
+        eval_ctx.target
+            ? eval_ctx.target->GetArchitecture().GetAddressByteSize()
+            : sizeof(void *));
+    if (Status error = scalar.SetValueFromData(data, lldb::eEncodingUint, size);
+        error.Fail())
+      return error.ToError();
+  } else if (eval_ctx.loc_desc_kind == Register ||
+             eval_ctx.loc_desc_kind == Implicit) {
+    // Match DW_OP_deref_size's handling of scalar register and implicit
+    // locations.
+    scalar = value.GetScalar();
+    scalar.TruncOrExtendTo(size * 8, /*sign=*/false);
+  } else {
+    if (!eval_ctx.target)
+      return llvm::createStringError("no target for DW_OP_deref_type");
+
+    Address address(value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS));
+    switch (value.GetValueType()) {
+    case Value::ValueType::FileAddress:
+      if (!eval_ctx.module_sp)
+        return llvm::createStringError(
+            "need module to resolve file address for DW_OP_deref_type");
+      if (!eval_ctx.module_sp->ResolveFileAddress(address.GetOffset(), address))
+        return llvm::createStringError(
+            "failed to resolve file address in module");
+      break;
+    case Value::ValueType::Scalar:
+    case Value::ValueType::LoadAddress:
+      break;
+    default:
+      return llvm::createStringError("invalid address for DW_OP_deref_type");
+    }
+
+    std::vector<uint8_t> bytes(size);
+    Status error;
+    if (eval_ctx.target->ReadMemory(address, bytes.data(), size, error) != size)
+      return llvm::createStringError(
+          "failed to dereference pointer for DW_OP_deref_type: %s",
+          error.Fail() ? error.AsCString() : "short memory read");
+
+    DataExtractor data(bytes.data(), bytes.size(),
+                       eval_ctx.target->GetArchitecture().GetByteOrder(),
+                       eval_ctx.target->GetArchitecture().GetAddressByteSize());
+    error = scalar.SetValueFromData(data, lldb::eEncodingUint, size);
+    if (error.Fail())
+      return error.ToError();
+  }
+
+  // Keep the referenced type's width rather than extending to the generic type.
+  const bool sign = encoding == DW_ATE_signed || encoding == DW_ATE_signed_char;
+  scalar.TruncOrExtendTo(bit_size, sign);
+  if (semantics)
+    scalar = Scalar(llvm::APFloat(*semantics, scalar.GetAPSInt()));
+  value = Value(scalar);
+  eval_ctx.loc_desc_kind = Memory;
+  return llvm::Error::success();
+}
+
 static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx,
                                         uint64_t piece_byte_size) {
   LocationDescriptionKind piece_locdesc = eval_ctx.loc_desc_kind;
@@ -1531,6 +1653,13 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
     } break;
 
+    case DW_OP_deref_type:
+      if (llvm::Error err = Evaluate_DW_OP_deref_type(
+              eval_ctx, op->getRawOperand(0), op->getRawOperand(1),
+              opcodes.GetByteOrder()))
+        return err;
+      break;
+
     case DW_OP_const1u:
       stack.push_back(to_generic(op->getRawOperand(0)));
       break;
@@ -2221,7 +2350,6 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
     case DW_OP_constx:
     case DW_OP_const_type:
     case DW_OP_regval_type:
-    case DW_OP_deref_type:
     case DW_OP_xderef_type:
     case DW_OP_reinterpret:
     case DW_OP_GNU_implicit_pointer:
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index bb89ebd52f766..f815e2ddc2b8a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -717,16 +717,14 @@ llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {
 
 llvm::Expected<std::pair<uint64_t, llvm::dwarf::TypeKind>>
 DWARFUnit::GetDIEBitSizeAndEncoding(uint64_t relative_die_offset) const {
-  // Retrieve the type DIE that the value is being converted to. This
-  // offset is compile unit relative so we need to fix it up.
+  // The referenced base type's offset is compile unit relative.
   const uint64_t abs_die_offset = relative_die_offset + GetOffset();
   // FIXME: the constness has annoying ripple effects.
   DWARFDIE die = const_cast<DWARFUnit *>(this)->GetDIE(abs_die_offset);
   if (!die)
-    return llvm::createStringError("cannot resolve DW_OP_convert type DIE");
+    return llvm::createStringError("cannot resolve type DIE");
   if (die.Tag() != DW_TAG_base_type)
-    return llvm::createStringError(
-        "DW_OP_convert type DIE is not a DW_TAG_base_type");
+    return llvm::createStringError("type DIE is not a DW_TAG_base_type");
   uint64_t encoding =
       die.GetAttributeValueAsUnsigned(DW_AT_encoding, DW_ATE_hi_user);
   uint64_t bit_size = die.GetAttributeValueAsUnsigned(DW_AT_bit_size, 0);
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 31e629967c6a2..92186d10e3678 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 #include "lldb/Expression/DWARFExpression.h"
 #include "ValueMatcher.h"
+#include <algorithm>
 #include <unordered_map>
 #ifdef ARCH_AARCH64
 #include "Plugins/ABI/AArch64/ABISysV_arm64.h"
@@ -28,9 +29,11 @@
 #include "lldb/Target/ABI.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/Endian.h"
 #include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/StreamString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
@@ -91,6 +94,23 @@ class MockDwarfDelegate : public DWARFExpression::Delegate {
   DebugAddrMap m_debug_addr;
 };
 
+class DerefTypeDelegate : public MockDwarfDelegate {
+public:
+  DerefTypeDelegate(uint64_t bit_size, TypeKind encoding)
+      : m_bit_size(bit_size), m_encoding(encoding) {}
+
+  llvm::Expected<std::pair<uint64_t, TypeKind>>
+  GetDIEBitSizeAndEncoding(uint64_t relative_die_offset) const override {
+    if (relative_die_offset != 0x123)
+      return llvm::createStringError("unknown base type offset");
+    return std::pair{m_bit_size, m_encoding};
+  }
+
+private:
+  uint64_t m_bit_size;
+  TypeKind m_encoding;
+};
+
 /// Mock memory implementation for testing.
 /// Stores predefined memory contents indexed by {address, size} pairs.
 class MockMemory {
@@ -118,9 +138,9 @@ class MockMemory {
   typedef std::unordered_map<Request, std::vector<uint8_t>, Request::Hash> Map;
   MockMemory() = default;
   MockMemory(Map memory) : m_memory(std::move(memory)) {
-    // Make sure the requested memory size matches the returned value.
+    // Allow short reads, but never return more bytes than requested.
     for ([[maybe_unused]] auto &[req, bytes] : m_memory) {
-      assert(bytes.size() == req.size);
+      assert(bytes.size() <= req.size);
     }
   }
 
@@ -156,9 +176,9 @@ struct MockProcess : Process {
       error = Status::FromError(expected_memory.takeError());
       return 0;
     }
-    assert(expected_memory->size() == size);
-    std::memcpy(buf, expected_memory->data(), expected_memory->size());
-    return size;
+    const size_t bytes_read = expected_memory->size();
+    std::memcpy(buf, expected_memory->data(), bytes_read);
+    return bytes_read;
   }
   size_t ReadMemory(const ProcessAddress &process_addr, void *buf, size_t size,
                     Status &status) override {
@@ -751,8 +771,7 @@ TEST(DWARFExpression, DW_OP_convert) {
   // Not a DW_TAG_base_type.
   EXPECT_THAT_ERROR(
       t.Eval({DW_OP_const1s, 'X', DW_OP_convert, offs_enum}).takeError(),
-      llvm::FailedWithMessage(
-          "DW_OP_convert type DIE is not a DW_TAG_base_type"));
+      llvm::FailedWithMessage("type DIE is not a DW_TAG_base_type"));
 
   // A non-zero DIE offset with no DWARF unit.
   EXPECT_THAT_ERROR(
@@ -1535,12 +1554,6 @@ TEST(DWARFExpression, DW_OP_regval_type_unimplemented) {
       llvm::FailedWithMessage("unimplemented opcode DW_OP_regval_type"));
 }
 
-TEST(DWARFExpression, DW_OP_deref_type_unimplemented) {
-  EXPECT_THAT_EXPECTED(
-      Evaluate({DW_OP_lit0, DW_OP_deref_type, 0x04, 0x00}),
-      llvm::FailedWithMessage("unimplemented opcode DW_OP_deref_type"));
-}
-
 TEST(DWARFExpression, DW_OP_xderef_type_unimplemented) {
   EXPECT_THAT_EXPECTED(
       Evaluate({DW_OP_lit0, DW_OP_lit0, DW_OP_xderef_type, 0x04, 0x00}),
@@ -1790,6 +1803,346 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref_address_size) {
   EXPECT_EQ(deref_size_result->GetScalar().GetAPSInt().getBitWidth(), 32u);
 }
 
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref_type_integer) {
+  for (const char *triple : {"i386-pc-linux", "powerpc-pc-linux"}) {
+    for (unsigned bit_size : {8, 31, 32, 64, 128, 1024, 2040}) {
+      for (TypeKind encoding : {DW_ATE_signed, DW_ATE_unsigned,
+                                DW_ATE_signed_char, DW_ATE_unsigned_char}) {
+        if (bit_size != 8 && (encoding == DW_ATE_signed_char ||
+                              encoding == DW_ATE_unsigned_char))
+          continue;
+        SCOPED_TRACE(llvm::formatv("{0}, {1} bits, encoding {2}", triple,
+                                   bit_size, static_cast<unsigned>(encoding))
+                         .str());
+        const unsigned byte_size = (bit_size + 7) / 8;
+        std::vector<uint8_t> bytes(byte_size, 0);
+        bytes.front() = 42;
+        bytes.back() |= 1 << ((bit_size - 1) % 8);
+        if (ArchSpec(triple).GetByteOrder() == lldb::eByteOrderBig)
+          std::reverse(bytes.begin(), bytes.end());
+
+        TestContext test_ctx;
+        MockMemory::Map memory = {{{4, byte_size}, bytes}};
+        ASSERT_TRUE(CreateTestContext(&test_ctx, triple, {}, {}, memory));
+        ExecutionContext exe_ctx(test_ctx.process_sp);
+        DerefTypeDelegate unit(bit_size, encoding);
+        const uint8_t expr[] = {
+            DW_OP_lit4, DW_OP_deref_type, static_cast<uint8_t>(byte_size), 0xa3,
+            0x02,       DW_OP_stack_value};
+        auto result = Evaluate(expr, {}, &unit, &exe_ctx);
+        const bool is_signed =
+            encoding == DW_ATE_signed || encoding == DW_ATE_signed_char;
+        llvm::APSInt expected(
+            llvm::APInt::getOneBitSet(bit_size, bit_size - 1) | 42, !is_signed);
+        ASSERT_THAT_EXPECTED(result, ExpectScalar(Scalar(expected)));
+        EXPECT_EQ(result->GetScalar().GetAPSInt().getBitWidth(), bit_size);
+        EXPECT_EQ(result->GetScalar().IsSigned(), is_signed);
+      }
+    }
+  }
+}
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref_type_float) {
+  struct TestCase {
+    const llvm::fltSemantics &semantics;
+    std::vector<uint8_t> bytes;
+  };
+  const TestCase tests[] = {
+      {llvm::APFloat::IEEEsingle(), {0x00, 0x00, 0x20, 0xc0}},
+      {llvm::APFloat::IEEEdouble(),
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xc0}},
+      {llvm::APFloat::x87DoubleExtended(),
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0xc0}},
+  };
+  for (const char *triple : {"i386-pc-linux", "powerpc-pc-linux"}) {
+    for (const TestCase &test : tests) {
+      SCOPED_TRACE(
+          llvm::formatv("{0}, {1} bytes", triple, test.bytes.size()).str());
+      std::vector<uint8_t> bytes = test.bytes;
+      if (ArchSpec(triple).GetByteOrder() == lldb::eByteOrderBig)
+        std::reverse(bytes.begin(), bytes.end());
+      TestContext test_ctx;
+      MockMemory::Map memory = {{{4, bytes.size()}, bytes}};
+      ASSERT_TRUE(CreateTestContext(&test_ctx, triple, {}, {}, memory));
+      ExecutionContext exe_ctx(test_ctx.process_sp);
+      DerefTypeDelegate unit(bytes.size() * 8, DW_ATE_float);
+      const uint8_t expr[] = {DW_OP_lit4,
+                              DW_OP_deref_type,
+                              static_cast<uint8_t>(bytes.size()),
+                              0xa3,
+                              0x02,
+                              DW_OP_stack_value};
+      auto result = Evaluate(expr, {}, &unit, &exe_ctx);
+      ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
+      EXPECT_EQ(result->GetScalar().GetType(), Scalar::e_float);
+      EXPECT_TRUE(result->GetScalar().GetAPFloat().bitwiseIsEqual(
+          llvm::APFloat(test.semantics, "-2.5")));
+    }
+  }
+}
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref_type_file_address) {
+  const char *yaml = R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_386
+Sections:
+  - Name:    .data
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_WRITE ]
+    Address: 0x1000
+    Content: '78563412'
+)";
+  SubsystemRAII<ObjectFileELF> subsystems;
+  auto file = TestFile::fromYaml(yaml);
+  ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
+  auto module_sp = std::make_shared<Module>(file->moduleSpec());
+  TestContext test_ctx;
+  ASSERT_TRUE(CreateTestContext(&test_ctx, "i386-pc-linux"));
+  ExecutionContext exe_ctx(test_ctx.target_sp, false);
+  DerefTypeDelegate unit(32, DW_ATE_unsigned);
+  const uint8_t expr[] = {
+      DW_OP_addr,       0x00, 0x10, 0x00, 0x00,
+      DW_OP_deref_type, 4,    0xa3, 0x02, DW_OP_stack_value};
+  EXPECT_THAT_EXPECTED(Evaluate(expr, module_sp, &unit, &exe_ctx),
+                       ExpectScalar(32, 0x12345678, false));
+  EXPECT_THAT_EXPECTED(
+      Evaluate(expr, {}, &unit, &exe_ctx),
+      llvm::FailedWithMessage(
+          "need module to resolve file address for DW_OP_deref_type"));
+}
+
+TEST(DWARFExpression, DW_OP_deref_type_host_address) {
+  for (unsigned bit_size : {8, 31, 128, 1024}) {
+    for (TypeKind encoding : {DW_ATE_signed, DW_ATE_unsigned}) {
+      const unsigned byte_size = (bit_size + 7) / 8;
+      std::vector<uint8_t> bytes(byte_size, 0);
+      bytes.front() = 42;
+      bytes.back() |= 1 << ((bit_size - 1) % 8);
+      if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
+        std::reverse(bytes.begin(), bytes.end());
+      DerefTypeDelegate unit(bit_size, encoding);
+      const uint8_t expr[] = {DW_OP_deref_type, static_cast<uint8_t>(byte_size),
+                              0xa3, 0x02, DW_OP_stack_value};
+      DataExtractor extractor(expr, sizeof(expr), endian::InlHostByteOrder(),
+                              sizeof(void *));
+
+      for (bool owns_buffer : {false, true}) {
+        SCOPED_TRACE(llvm::formatv("{0} bits, encoding {1}, owns buffer {2}",
+                                   bit_size, static_cast<unsigned>(encoding),
+                                   owns_buffer)
+                         .str());
+        Value address =
+            owns_buffer
+                ? Value(bytes.data(), bytes.size())
+                : Value(Scalar(reinterpret_cast<uintptr_t>(bytes.data())));
+        address.SetValueType(Value::ValueType::HostAddress);
+        auto result = DWARFExpression::Evaluate(
+            /*exe_ctx=*/nullptr, /*reg_ctx=*/nullptr, /*module_sp=*/{},
+            extractor, &unit, lldb::eRegisterKindLLDB, &address,
+            /*object_address_ptr=*/nullptr);
+        const bool is_signed = encoding == DW_ATE_signed;
+        llvm::APSInt expected(
+            llvm::APInt::getOneBitSet(bit_size, bit_size - 1) | 42, !is_signed);
+        ASSERT_THAT_EXPECTED(result, ExpectScalar(Scalar(expected)));
+        EXPECT_EQ(result->GetScalar().GetAPSInt().getBitWidth(), bit_size);
+        EXPECT_EQ(result->GetScalar().IsSigned(), is_signed);
+      }
+    }
+  }
+}
+
+TEST_F(DWARFExpressionMockProcessTest,
+       DW_OP_deref_type_host_address_byte_order) {
+  for (const char *triple : {"i386-pc-linux", "powerpc-pc-linux"}) {
+    for (unsigned bit_size : {16, 128}) {
+      SCOPED_TRACE(llvm::formatv("{0}, {1} bits", triple, bit_size).str());
+      TestContext test_ctx;
+      ASSERT_TRUE(CreateTestContext(&test_ctx, triple));
+      ExecutionContext exe_ctx(test_ctx.target_sp, false);
+      const lldb::ByteOrder byte_order = ArchSpec(triple).GetByteOrder();
+      const unsigned byte_size = bit_size / 8;
+      DerefTypeDelegate unit(bit_size, DW_ATE_unsigned);
+      const uint8_t expr[] = {DW_OP_push_object_address,
+                              DW_OP_deref_type,
+                              static_cast<uint8_t>(byte_size),
+                              0xa3,
+                              0x02,
+                              DW_OP_stack_value};
+      DataExtractor ex...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/233381


More information about the lldb-commits mailing list