From 384ff183f7db3d18ac122e943874b487c099fda4 Mon Sep 17 00:00:00 2001 From: David Peixotto Date: Wed, 12 Nov 2025 16:54:42 -0800 Subject: [PATCH] [lldb] Add helper to create mock objects for dwarf expression tests This commit adds a new helper function that creates various mock objects that can be used in dwarf expression testing. The optional register value and memory contents are used to create MockProcessWithMemRead and MockRegisterContext that can return expected memory contents and register values. This simplifies some tests by removing redundant code that creates these objects in individual tests and consolidates the logic into one place. --- .../Expression/DWARFExpressionTest.cpp | 221 +++++++----------- 1 file changed, 89 insertions(+), 132 deletions(-) diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 8c5568d9e4e65..13110ef7cbb0a 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -67,6 +67,33 @@ struct MockProcess : Process { } }; +/// A Process whose `ReadMemory` override queries a DenseMap. +struct MockProcessWithMemRead : Process { + using addr_t = lldb::addr_t; + + llvm::DenseMap memory_map; + + MockProcessWithMemRead(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + llvm::DenseMap &&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(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; } +}; + class MockThread : public Thread { public: MockThread(Process &process) : Thread(process, /*tid=*/1), m_reg_ctx_sp() {} @@ -175,24 +202,55 @@ class DWARFExpressionMockProcessTest : public ::testing::Test { } }; -struct PlatformTargetDebugger { +struct TestContext { lldb::PlatformSP platform_sp; lldb::TargetSP target_sp; lldb::DebuggerSP debugger_sp; + lldb::ProcessSP process_sp; + lldb::ThreadSP thread_sp; + lldb::RegisterContextSP reg_ctx_sp; }; -/// A helper function to create objects with the -/// "aarch64-pc-linux" ArchSpec. -static PlatformTargetDebugger CreateTarget() { - ArchSpec arch("aarch64-pc-linux"); +/// A helper function to create TestContext objects with the +/// given triple, memory, and register contents. +static bool CreateTestContext( + TestContext *ctx, llvm::StringRef triple, + std::optional reg_value = {}, + std::optional> memory = {}) { + ArchSpec arch(triple); 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( + Status status = debugger_sp->GetTargetList().CreateTarget( *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); - return PlatformTargetDebugger{platform_sp, target_sp, debugger_sp}; + + EXPECT_TRUE(status.Success()); + if (!status.Success()) + return false; + + lldb::ProcessSP process_sp; + if (memory) + process_sp = std::make_shared( + target_sp, Listener::MakeListener("dummy"), std::move(*memory)); + else + process_sp = std::make_shared(target_sp, + Listener::MakeListener("dummy")); + + auto thread_sp = std::make_shared(*process_sp); + + process_sp->GetThreadList().AddThread(thread_sp); + + lldb::RegisterContextSP reg_ctx_sp; + if (reg_value) { + reg_ctx_sp = std::make_shared(*thread_sp, *reg_value); + thread_sp->SetRegisterContext(reg_ctx_sp); + } + + *ctx = TestContext{platform_sp, target_sp, debugger_sp, + process_sp, thread_sp, reg_ctx_sp}; + return true; } // NB: This class doesn't use the override keyword to avoid @@ -486,24 +544,10 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed()); // Set up a mock process. - ArchSpec arch("i386-pc-linux"); - Platform::SetHostPlatform( - platform_linux::PlatformLinux::CreateInstance(true, &arch)); - lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); - ASSERT_TRUE(debugger_sp); - lldb::TargetSP target_sp; - lldb::PlatformSP platform_sp; - debugger_sp->GetTargetList().CreateTarget( - *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); - ASSERT_TRUE(target_sp); - ASSERT_TRUE(target_sp->GetArchitecture().IsValid()); - ASSERT_TRUE(platform_sp); - lldb::ListenerSP listener_sp(Listener::MakeListener("dummy")); - lldb::ProcessSP process_sp = - std::make_shared(target_sp, listener_sp); - ASSERT_TRUE(process_sp); + TestContext test_ctx; + ASSERT_TRUE(CreateTestContext(&test_ctx, "i386-pc-linux")); - ExecutionContext exe_ctx(process_sp); + ExecutionContext exe_ctx(test_ctx.process_sp); // Implicit location: *0x4. EXPECT_THAT_EXPECTED( Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx), @@ -518,20 +562,10 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) { TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr) { // Set up a wasm target - ArchSpec arch("wasm32-unknown-unknown-wasm"); - lldb::PlatformSP host_platform_sp = - platform_linux::PlatformLinux::CreateInstance(true, &arch); - ASSERT_TRUE(host_platform_sp); - Platform::SetHostPlatform(host_platform_sp); - lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); - ASSERT_TRUE(debugger_sp); - lldb::TargetSP target_sp; - lldb::PlatformSP platform_sp; - debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch, - lldb_private::eLoadDependentsNo, - platform_sp, target_sp); + TestContext test_ctx; + ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm")); - ExecutionContext exe_ctx(target_sp, false); + ExecutionContext exe_ctx(test_ctx.target_sp, false); // DW_OP_addr takes a single operand of address size width: EXPECT_THAT_EXPECTED( Evaluate({DW_OP_addr, 0x40, 0x0, 0x0, 0x0}, {}, {}, &exe_ctx), @@ -587,20 +621,9 @@ TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) { dwarf_cu->ExtractDIEsIfNeeded(); // Set up a wasm target - ArchSpec arch("wasm32-unknown-unknown-wasm"); - lldb::PlatformSP host_platform_sp = - platform_linux::PlatformLinux::CreateInstance(true, &arch); - ASSERT_TRUE(host_platform_sp); - Platform::SetHostPlatform(host_platform_sp); - lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); - ASSERT_TRUE(debugger_sp); - lldb::TargetSP target_sp; - lldb::PlatformSP platform_sp; - debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch, - lldb_private::eLoadDependentsNo, - platform_sp, target_sp); - - ExecutionContext exe_ctx(target_sp, false); + TestContext test_ctx; + ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm")); + ExecutionContext exe_ctx(test_ctx.target_sp, false); auto evaluate = [&](DWARFExpression &expr) -> llvm::Expected { DataExtractor extractor; @@ -823,28 +846,10 @@ TEST(DWARFExpression, Extensions) { subsystems; // Set up a wasm target. - ArchSpec arch("wasm32-unknown-unknown-wasm"); - lldb::PlatformSP host_platform_sp = - platform_linux::PlatformLinux::CreateInstance(true, &arch); - ASSERT_TRUE(host_platform_sp); - Platform::SetHostPlatform(host_platform_sp); - lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); - ASSERT_TRUE(debugger_sp); - lldb::TargetSP target_sp; - lldb::PlatformSP platform_sp; - debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch, - lldb_private::eLoadDependentsNo, - platform_sp, target_sp); - // Set up a mock process and thread. - lldb::ListenerSP listener_sp(Listener::MakeListener("dummy")); - lldb::ProcessSP process_sp = - std::make_shared(target_sp, listener_sp); - ASSERT_TRUE(process_sp); - MockThread thread(*process_sp); + TestContext test_ctx; const uint32_t kExpectedValue = 42; - lldb::RegisterContextSP reg_ctx_sp = std::make_shared( - thread, RegisterValue(kExpectedValue)); - thread.SetRegisterContext(reg_ctx_sp); + ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm", + RegisterValue(kExpectedValue))); llvm::Expected file = TestFile::fromYaml(yamldata); EXPECT_THAT_EXPECTED(file, llvm::Succeeded()); @@ -853,7 +858,8 @@ TEST(DWARFExpression, Extensions) { SymbolFileWasm sym_file_wasm(obj_file_sp, nullptr); auto *dwarf_unit = sym_file_wasm.DebugInfo().GetUnitAtIndex(0); - testExpressionVendorExtensions(module_sp, *dwarf_unit, reg_ctx_sp.get()); + testExpressionVendorExtensions(module_sp, *dwarf_unit, + test_ctx.reg_ctx_sp.get()); } TEST(DWARFExpression, ExtensionsSplitSymbols) { @@ -1022,28 +1028,10 @@ TEST(DWARFExpression, ExtensionsSplitSymbols) { subsystems; // Set up a wasm target. - ArchSpec arch("wasm32-unknown-unknown-wasm"); - lldb::PlatformSP host_platform_sp = - platform_linux::PlatformLinux::CreateInstance(true, &arch); - ASSERT_TRUE(host_platform_sp); - Platform::SetHostPlatform(host_platform_sp); - lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); - ASSERT_TRUE(debugger_sp); - lldb::TargetSP target_sp; - lldb::PlatformSP platform_sp; - debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch, - lldb_private::eLoadDependentsNo, - platform_sp, target_sp); - // Set up a mock process and thread. - lldb::ListenerSP listener_sp(Listener::MakeListener("dummy")); - lldb::ProcessSP process_sp = - std::make_shared(target_sp, listener_sp); - ASSERT_TRUE(process_sp); - MockThread thread(*process_sp); + TestContext test_ctx; const uint32_t kExpectedValue = 42; - lldb::RegisterContextSP reg_ctx_sp = std::make_shared( - thread, RegisterValue(kExpectedValue)); - thread.SetRegisterContext(reg_ctx_sp); + ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm", + RegisterValue(kExpectedValue))); llvm::Expected skeleton_file = TestFile::fromYaml(skeleton_yamldata); @@ -1059,7 +1047,8 @@ TEST(DWARFExpression, ExtensionsSplitSymbols) { SymbolFileWasm sym_file_wasm(obj_file_sp, nullptr); auto *dwarf_unit = sym_file_wasm.DebugInfo().GetUnitAtIndex(0); - testExpressionVendorExtensions(sym_module_sp, *dwarf_unit, reg_ctx_sp.get()); + testExpressionVendorExtensions(sym_module_sp, *dwarf_unit, + test_ctx.reg_ctx_sp.get()); } TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) { @@ -1092,33 +1081,6 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) { ExpectHostAddress({0x11, 0x22})); } -/// A Process whose `ReadMemory` override queries a DenseMap. -struct MockProcessWithMemRead : Process { - using addr_t = lldb::addr_t; - - llvm::DenseMap memory_map; - - MockProcessWithMemRead(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - llvm::DenseMap &&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(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; } -}; - class DWARFExpressionMockProcessTestWithAArch : public DWARFExpressionMockProcessTest { public: @@ -1149,18 +1111,13 @@ TEST_F(DWARFExpressionMockProcessTestWithAArch, DW_op_deref_no_ptr_fixing) { constexpr lldb::addr_t addr = 42; memory[addr] = expected_value; - PlatformTargetDebugger test_setup = CreateTarget(); - lldb::ProcessSP process_sp = std::make_shared( - test_setup.target_sp, Listener::MakeListener("dummy"), std::move(memory)); - auto thread = std::make_shared(*process_sp); - lldb::RegisterContextSP reg_ctx_sp = - std::make_shared(*thread, RegisterValue(addr)); - thread->SetRegisterContext(reg_ctx_sp); - process_sp->GetThreadList().AddThread(thread); + TestContext test_ctx; + ASSERT_TRUE(CreateTestContext(&test_ctx, "aarch64-pc-linux", + RegisterValue(addr), std::move(memory))); auto evaluate_expr = [&](auto &expr_data) { - ExecutionContext exe_ctx(process_sp); - return Evaluate(expr_data, {}, {}, &exe_ctx, reg_ctx_sp.get()); + ExecutionContext exe_ctx(test_ctx.process_sp); + return Evaluate(expr_data, {}, {}, &exe_ctx, test_ctx.reg_ctx_sp.get()); }; uint8_t expr_reg[] = {DW_OP_breg22, 0};