[Lldb-commits] [lldb] [lldb] Fix OP_deref evaluation for large integer results (PR #159460)
Felipe de Azevedo Piovezan via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 17 14:48:55 PDT 2025
https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/159460
>From ef8ba401c07514076a3367c256e0c8f63d5c2c06 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Wed, 17 Sep 2025 14:22:31 -0700
Subject: [PATCH] [lldb] Fix OP_deref evaluation for large integer results
When evaluating any DWARF expression that ended in OP_deref and whose
previous value on the dwarf stack -- the pointer address for the deref
-- was a load address, we were treating the result itself as a pointer,
calling Process:FixCodeAddress(result). This is wrong: there's no
guarantee that the result is a pointer itself.
---
lldb/source/Expression/DWARFExpression.cpp | 2 -
lldb/unittests/Expression/CMakeLists.txt | 4 +
.../Expression/DWARFExpressionTest.cpp | 100 ++++++++++++++++++
3 files changed, 104 insertions(+), 2 deletions(-)
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 5040351f4975b..4f9d6ebf27bf0 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -909,8 +909,6 @@ static llvm::Error Evaluate_DW_OP_deref(DWARFExpression::Stack &stack,
" for DW_OP_deref",
pointer_addr),
error.takeError());
- if (ABISP abi_sp = process->GetABI())
- pointer_value = abi_sp->FixCodeAddress(pointer_value);
stack.back().GetScalar() = pointer_value;
stack.back().ClearContext();
} break;
diff --git a/lldb/unittests/Expression/CMakeLists.txt b/lldb/unittests/Expression/CMakeLists.txt
index 4c58b3c5e3922..a22341d9155cb 100644
--- a/lldb/unittests/Expression/CMakeLists.txt
+++ b/lldb/unittests/Expression/CMakeLists.txt
@@ -6,12 +6,16 @@ add_lldb_unittest(ExpressionTests
CppModuleConfigurationTest.cpp
ExpressionTest.cpp
+ LINK_COMPONENTS
+ AArch64
+ Support
LINK_LIBS
lldbCore
lldbPluginObjectFileELF
lldbPluginObjectFileWasm
lldbPluginSymbolVendorWasm
lldbPluginPlatformLinux
+ lldbPluginABIAArch64
lldbPluginExpressionParserClang
lldbPluginTypeSystemClang
lldbUtility
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 5a5d3aba0e207..c284765c65d98 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Expression/DWARFExpression.h"
+#include "Plugins/ABI/AArch64/ABISysV_arm64.h"
#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
#include "Plugins/Platform/Linux/PlatformLinux.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
@@ -21,10 +22,12 @@
#include "lldb/Core/dwarf.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
@@ -190,15 +193,39 @@ class DWARFExpressionMockProcessTest : public ::testing::Test {
void SetUp() override {
FileSystem::Initialize();
HostInfo::Initialize();
+ LLVMInitializeAArch64TargetInfo();
+ LLVMInitializeAArch64TargetMC();
platform_linux::PlatformLinux::Initialize();
+ ABISysV_arm64::Initialize();
}
void TearDown() override {
platform_linux::PlatformLinux::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
+ ABISysV_arm64::Terminate();
}
};
+struct PlatformTargetDebugger {
+ lldb::PlatformSP platform_sp;
+ lldb::TargetSP target_sp;
+ lldb::DebuggerSP debugger_sp;
+};
+
+/// A helper function to create <Platform, Target, Debugger> objects with the
+/// "aarch64-pc-linux" ArchSpec.
+static PlatformTargetDebugger CreateTarget() {
+ ArchSpec arch("aarch64-pc-linux");
+ Platform::SetHostPlatform(
+ platform_linux::PlatformLinux::CreateInstance(true, &arch));
+ lldb::PlatformSP platform_sp;
+ lldb::TargetSP target_sp;
+ lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
+ debugger_sp->GetTargetList().CreateTarget(
+ *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
+ return PlatformTargetDebugger{platform_sp, target_sp, debugger_sp};
+}
+
// NB: This class doesn't use the override keyword to avoid
// -Winconsistent-missing-override warnings from the compiler. The
// inconsistency comes from the overriding definitions in the MOCK_*** macros.
@@ -1135,3 +1162,76 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) {
ASSERT_EQ(result->GetValueType(), Value::ValueType::HostAddress);
ASSERT_THAT(result->GetBuffer().GetData(), ElementsAre(0x11, 0x22));
}
+
+/// A Process whose `ReadMemory` override queries a DenseMap.
+struct MockProcessWithMemRead : Process {
+ using addr_t = lldb::addr_t;
+
+ llvm::DenseMap<addr_t, addr_t> memory_map;
+
+ MockProcessWithMemRead(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
+ llvm::DenseMap<addr_t, addr_t> &&memory_map)
+ : Process(target_sp, listener_sp), memory_map(memory_map) {}
+ size_t DoReadMemory(addr_t vm_addr, void *buf, size_t size,
+ Status &error) override {
+ assert(memory_map.contains(vm_addr));
+ assert(size == sizeof(addr_t));
+ *reinterpret_cast<addr_t *>(buf) = memory_map[vm_addr];
+ return sizeof(addr_t);
+ }
+ size_t ReadMemory(addr_t addr, void *buf, size_t size,
+ Status &status) override {
+ return DoReadMemory(addr, buf, size, status);
+ }
+ bool CanDebug(lldb::TargetSP, bool) override { return true; }
+ Status DoDestroy() override { return Status(); }
+ llvm::StringRef GetPluginName() override { return ""; }
+ void RefreshStateAfterStop() override {}
+ bool DoUpdateThreadList(ThreadList &, ThreadList &) override { return false; }
+};
+
+/// Sets the value of register x22 to "42".
+/// Creates a process whose memory address 42 contains the value
+/// memory[42] = ((0xffULL) << 56) | 0xabcdef;
+/// The expression DW_OP_breg22, 0, DW_OP_deref should produce that same value,
+/// without clearing the top byte 0xff.
+TEST_F(DWARFExpressionMockProcessTest, DW_op_deref_no_ptr_fixing) {
+ llvm::DenseMap<lldb::addr_t, lldb::addr_t> memory;
+ constexpr lldb::addr_t expected_value = ((0xffULL) << 56) | 0xabcdefULL;
+ memory[42] = expected_value;
+
+ PlatformTargetDebugger test_setup = CreateTarget();
+ lldb::ProcessSP process_sp = std::make_shared<MockProcessWithMemRead>(
+ test_setup.target_sp, Listener::MakeListener("dummy"), std::move(memory));
+ auto thread = std::make_shared<MockThread>(*process_sp);
+ lldb::RegisterContextSP reg_ctx_sp =
+ std::make_shared<MockRegisterContext>(*thread, RegisterValue(42ull));
+ thread->SetRegisterContext(reg_ctx_sp);
+ process_sp->GetThreadList().AddThread(thread);
+
+ auto evaluate_expr = [&](auto &expr_data) {
+ DataExtractor extractor(expr_data, sizeof(expr_data),
+ lldb::eByteOrderLittle,
+ /*addr_size*/ 8);
+ DWARFExpression expr(extractor);
+
+ ExecutionContext exe_ctx(process_sp);
+ llvm::Expected<Value> result = DWARFExpression::Evaluate(
+ &exe_ctx, reg_ctx_sp.get(), /*module_sp*/ nullptr, extractor,
+ /*unit*/ nullptr, lldb::eRegisterKindLLDB,
+ /*initial_value_ptr=*/nullptr,
+ /*object_address_ptr=*/nullptr);
+ return result;
+ };
+
+ uint8_t expr_reg[] = {DW_OP_breg22, 0};
+ llvm::Expected<Value> result_reg = evaluate_expr(expr_reg);
+ ASSERT_THAT_EXPECTED(result_reg, llvm::Succeeded());
+ ASSERT_EQ(result_reg->GetValueType(), Value::ValueType::LoadAddress);
+ ASSERT_EQ(result_reg->GetScalar().ULongLong(), 42ull);
+
+ uint8_t expr_deref[] = {DW_OP_breg22, 0, DW_OP_deref};
+ llvm::Expected<Value> result_deref = evaluate_expr(expr_deref);
+ ASSERT_THAT_EXPECTED(result_deref, llvm::Succeeded());
+ ASSERT_EQ(result_deref->GetScalar().ULongLong(), expected_value);
+}
More information about the lldb-commits
mailing list