[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