diff --git a/lldb/source/Plugins/Process/scripted/Python b/lldb/source/Plugins/Process/scripted/Python new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/lldb/test/API/accelerator/mock/Makefile b/lldb/test/API/accelerator/mock/Makefile new file mode 100644 index 0000000000000..692ba17322859 --- /dev/null +++ b/lldb/test/API/accelerator/mock/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c + +include Makefile.rules + diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py b/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py new file mode 100644 index 0000000000000..24ddec119c483 --- /dev/null +++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py @@ -0,0 +1,69 @@ +""" +Tests for the lldb-server Mock Accelerator Plugin. +""" + +import os + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +"""This will go away once the mock plugin starts creating a target.""" +_PLUGIN_OUTPUT_PATH = "/tmp/accelerator_plugin_test.txt" + + +class MockAcceleratorPluginTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def clean_expected_output_file(self): + try: + os.remove(_PLUGIN_OUTPUT_PATH) + except OSError: + pass + + def tearDown(self): + super().tearDown() + self.clean_expected_output_file() + + @add_test_categories(["llgs"]) + def test_mock_accelerator_plugin_writes_pid(self): + """ + When LLDB_SERVER_ENABLE_MOCK_ACCELERATOR_PLUGIN is set, the mock accelerator + plugin must create /tmp/accelerator_plugin_test.txt containing a valid PID. + """ + self.build() + + # Remove any stale file left by a previous run. + self.clean_expected_output_file() + + # Launch the target and let it run to completion. + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + self.assertTrue(target.IsValid()) + + process = target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertEqual( + process.GetState(), + lldb.eStateExited, + "Process should have exited cleanly", + ) + + # After the process exits, verify the plugin output file. + self.assertTrue( + os.path.exists(_PLUGIN_OUTPUT_PATH), + "Mock accelerator plugin did not create %s" % _PLUGIN_OUTPUT_PATH, + ) + with open(_PLUGIN_OUTPUT_PATH) as f: + content = f.read().strip() + self.assertTrue( + content.isdigit(), + "Plugin output file should contain an integer PID, got: %r" % content, + ) + + pid = int(content) + self.assertGreater( + pid, + 0, + "PID in plugin output file should be a valid positive integer", + ) diff --git a/lldb/test/API/accelerator/mock/lit.local.cfg b/lldb/test/API/accelerator/mock/lit.local.cfg new file mode 100644 index 0000000000000..c7668b99327ea --- /dev/null +++ b/lldb/test/API/accelerator/mock/lit.local.cfg @@ -0,0 +1,3 @@ +# Enable the mock accelerator plugin in lldb-server for all tests in this +# directory. The plugin activates when this variable is present and non-empty. +config.environment["LLDB_SERVER_ENABLE_MOCK_ACCELERATOR_PLUGIN"] = "1" diff --git a/lldb/test/API/accelerator/mock/main.c b/lldb/test/API/accelerator/mock/main.c new file mode 100644 index 0000000000000..78f2de106c92b --- /dev/null +++ b/lldb/test/API/accelerator/mock/main.c @@ -0,0 +1 @@ +int main(void) { return 0; } diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt index fb55c64936121..6d22efca75b3c 100644 --- a/lldb/tools/lldb-server/CMakeLists.txt +++ b/lldb/tools/lldb-server/CMakeLists.txt @@ -46,12 +46,17 @@ if(APPLE_EMBEDDED) endif() endif() +add_subdirectory(Plugins) + +set(LLDB_SERVER_PLUGINS lldbServerPluginMockAccelerator) + add_lldb_tool(lldb-server lldb-gdbserver.cpp lldb-platform.cpp lldb-server.cpp LLDBServerUtilities.cpp SystemInitializerLLGS.cpp + LLDBServerPluginRegistry.cpp LINK_COMPONENTS Option @@ -61,6 +66,7 @@ add_lldb_tool(lldb-server lldbInitialization lldbVersion ${LLDB_PLUGINS} + ${LLDB_SERVER_PLUGINS} lldbPluginInstructionARM lldbPluginInstructionLoongArch lldbPluginInstructionMIPS @@ -75,4 +81,5 @@ add_dependencies(lldb-server ${tablegen_deps} ) target_include_directories(lldb-server PRIVATE "${LLDB_SOURCE_DIR}/source") +target_include_directories(lldb-server PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") target_link_libraries(lldb-server PRIVATE ${LLDB_SYSTEM_LIBS}) diff --git a/lldb/tools/lldb-server/LLDBServerPluginRegistry.cpp b/lldb/tools/lldb-server/LLDBServerPluginRegistry.cpp new file mode 100644 index 0000000000000..abcabe0a35517 --- /dev/null +++ b/lldb/tools/lldb-server/LLDBServerPluginRegistry.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LLDBServerPluginRegistry.h" +#include "Plugins/Accelerator/Mock/LLDBServerPluginMockAccelerator.h" +#include "llvm/Support/Threading.h" + +using namespace lldb_private::lldb_server; + +LLDBServerPluginRegistry &LLDBServerPluginRegistry::Instance() { + static LLDBServerPluginRegistry registry; + static llvm::once_flag once; + + llvm::call_once(once, []() { registry.Initialize(); }); + + return registry; +} + +void LLDBServerPluginRegistry::Initialize() { + // Register all known accelerator plugins + Register(PluginKind::Accelerator, + [](LLDBServerPluginAccelerator::GDBServer &gdb_server, + lldb_private::MainLoop &main_loop) + -> std::unique_ptr { + return std::make_unique(gdb_server, + main_loop); + }); +} + +void LLDBServerPluginRegistry::Register(PluginKind kind, + AcceleratorFactory factory) { + m_accelerator_factories.push_back(std::move(factory)); +} + +std::vector> +LLDBServerPluginRegistry::TryInstantiateAllAcceleratorPlugins( + LLDBServerPluginAccelerator::GDBServer &gdb_server, MainLoop &main_loop) { + std::vector> activated; + for (const AcceleratorFactory &factory : m_accelerator_factories) { + std::unique_ptr plugin = factory(gdb_server, main_loop); + if (plugin && plugin->TryActivate()) + activated.push_back(std::move(plugin)); + } + return activated; +} diff --git a/lldb/tools/lldb-server/LLDBServerPluginRegistry.h b/lldb/tools/lldb-server/LLDBServerPluginRegistry.h new file mode 100644 index 0000000000000..7541322347d53 --- /dev/null +++ b/lldb/tools/lldb-server/LLDBServerPluginRegistry.h @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_SERVER_LLDBSERVERPLUGINREGISTRY_H +#define LLDB_TOOLS_LLDB_SERVER_LLDBSERVERPLUGINREGISTRY_H + +#include "Plugins/Accelerator/LLDBServerPluginAccelerator.h" + +namespace lldb_private { + +namespace lldb_server { + +class LLDBServerPluginRegistry { +public: + /// Identifies the category of a plugin. + enum class PluginKind { + Accelerator, + }; + + using AcceleratorFactory = + std::function( + LLDBServerPluginAccelerator::GDBServer &, MainLoop &)>; + + /// Return a singleton instance of the registry that is initialized on first + /// use and that knows of all available plugins. + static LLDBServerPluginRegistry &Instance(); + + /// Instantiate all registered accelerator plugins and return those that + /// successfully activated (TryActivate() returned true). + std::vector> + TryInstantiateAllAcceleratorPlugins( + LLDBServerPluginAccelerator::GDBServer &gdb_server, MainLoop &main_loop); + +private: + /// Initialize and register all known plugins. + void Initialize(); + + /// Register an accelerator plugin factory. + void Register(PluginKind kind, AcceleratorFactory factory); + + LLDBServerPluginRegistry() = default; + std::vector m_accelerator_factories; +}; + +} // namespace lldb_server +} // namespace lldb_private + +#endif // LLDB_TOOLS_LLDB_SERVER_LLDBSERVERPLUGINREGISTRY_H diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/CMakeLists.txt b/lldb/tools/lldb-server/Plugins/Accelerator/CMakeLists.txt new file mode 100644 index 0000000000000..853788384e141 --- /dev/null +++ b/lldb/tools/lldb-server/Plugins/Accelerator/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Mock) diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/LLDBServerPluginAccelerator.cpp b/lldb/tools/lldb-server/Plugins/Accelerator/LLDBServerPluginAccelerator.cpp new file mode 100644 index 0000000000000..6c6e7a17d7f5b --- /dev/null +++ b/lldb/tools/lldb-server/Plugins/Accelerator/LLDBServerPluginAccelerator.cpp @@ -0,0 +1,15 @@ +//===-- LLDBServerPluginAccelerator.cpp -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LLDBServerPluginAccelerator.h" + +using namespace lldb_private::lldb_server; + +LLDBServerPluginAccelerator::LLDBServerPluginAccelerator(GDBServer &gdb_server, + MainLoop &main_loop) + : m_gdb_server(gdb_server), m_main_loop(main_loop) {} diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/LLDBServerPluginAccelerator.h b/lldb/tools/lldb-server/Plugins/Accelerator/LLDBServerPluginAccelerator.h new file mode 100644 index 0000000000000..8087a040dcdda --- /dev/null +++ b/lldb/tools/lldb-server/Plugins/Accelerator/LLDBServerPluginAccelerator.h @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_LLDBSERVERPLUGINACCELERATOR_H +#define LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_LLDBSERVERPLUGINACCELERATOR_H + +#include "llvm/ADT/StringRef.h" +#include "lldb/Host/MainLoop.h" + +namespace lldb_private { + +namespace process_gdb_remote { +class GDBRemoteCommunicationServerLLGS; +} // namespace process_gdb_remote + +namespace lldb_server { + +/// Abstract base class for lldb-server accelerator plugins. +/// +/// An accelerator plugin allows lldb-server to support debugging of hardware +/// accelerators (e.g. GPUs, FPGAs) alongside the native host process. +class LLDBServerPluginAccelerator { +public: + using GDBServer = process_gdb_remote::GDBRemoteCommunicationServerLLGS; + + LLDBServerPluginAccelerator(GDBServer &gdb_server, MainLoop &main_loop); + virtual ~LLDBServerPluginAccelerator() = default; + + /// Returns a short, unique name identifying this plugin (e.g. "mock-accel"). + virtual llvm::StringRef GetPluginName() = 0; + + /// Attempts to activate the plugin if it should be enabled in the current + /// environment (e.g. required hardware is present, an enabling environment + /// variable is set, etc.). Returns true if the plugin was activated. + virtual bool TryActivate() = 0; + + /// Called before lldb-server exits to allow the plugin to perform cleanup. + /// This is called for all plugins that successfully activated. + virtual void Teardown() = 0; + +protected: + GDBServer &m_gdb_server; + MainLoop &m_main_loop; +}; + +} // namespace lldb_server +} // namespace lldb_private + +#endif // LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_LLDBSERVERPLUGINACCELERATOR_H diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/CMakeLists.txt b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/CMakeLists.txt new file mode 100644 index 0000000000000..1b360d8a6d5c3 --- /dev/null +++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbServerPluginMockAccelerator + LLDBServerPluginMockAccelerator.cpp + ../LLDBServerPluginAccelerator.cpp +) + +target_include_directories(lldbServerPluginMockAccelerator + PRIVATE + "${LLDB_SOURCE_DIR}/source" + "${CMAKE_CURRENT_SOURCE_DIR}/../../.." + "${CMAKE_CURRENT_SOURCE_DIR}/.." +) diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerPluginMockAccelerator.cpp b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerPluginMockAccelerator.cpp new file mode 100644 index 0000000000000..824820e265907 --- /dev/null +++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerPluginMockAccelerator.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LLDBServerPluginMockAccelerator.h" + +#include "llvm/Support/Process.h" + +using namespace lldb_private::lldb_server; + +LLDBServerPluginMockAccelerator::LLDBServerPluginMockAccelerator( + GDBServer &gdb_server, MainLoop &main_loop) + : LLDBServerPluginAccelerator(gdb_server, main_loop) {} + +llvm::StringRef LLDBServerPluginMockAccelerator::GetPluginName() { + return "mock-accelerator"; +} + +bool LLDBServerPluginMockAccelerator::TryActivate() { + // Check if the plugin should be enabled + std::optional val = llvm::sys::Process::GetEnv(kEnableEnvVar); + if (!val || val->empty()) + return false; + + // Activate the plugin by writing the parent PID to the test file + std::error_code ec; + llvm::raw_fd_ostream out("/tmp/accelerator_plugin_test.txt", ec, + llvm::sys::fs::OF_Text); + out << llvm::sys::Process::getProcessId() << '\n'; + + return true; +} diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerPluginMockAccelerator.h b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerPluginMockAccelerator.h new file mode 100644 index 0000000000000..e7643550f2c17 --- /dev/null +++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerPluginMockAccelerator.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_LLDBSERVERPLUGINMOCKACCELERATOR_H +#define LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_LLDBSERVERPLUGINMOCKACCELERATOR_H + +#include "../LLDBServerPluginAccelerator.h" + +namespace lldb_private { +namespace lldb_server { + +/// A mock accelerator plugin used for testing the accelerator plugin +/// infrastructure. +/// +/// This plugin is enabled when the environment variable +/// LLDB_SERVER_ENABLE_MOCK_ACCELERATOR_PLUGIN is set to any non-empty value. +class LLDBServerPluginMockAccelerator : public LLDBServerPluginAccelerator { +public: + /// Environment variable that enables this plugin. + static constexpr const char *kEnableEnvVar = + "LLDB_SERVER_ENABLE_MOCK_ACCELERATOR_PLUGIN"; + + LLDBServerPluginMockAccelerator(GDBServer &gdb_server, MainLoop &main_loop); + + llvm::StringRef GetPluginName() override; + bool TryActivate() override; + void Teardown() override {} +}; + +} // namespace lldb_server +} // namespace lldb_private + +#endif // LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_LLDBSERVERPLUGINMOCKACCELERATOR_H diff --git a/lldb/tools/lldb-server/Plugins/CMakeLists.txt b/lldb/tools/lldb-server/Plugins/CMakeLists.txt new file mode 100644 index 0000000000000..c9f43933b3b55 --- /dev/null +++ b/lldb/tools/lldb-server/Plugins/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Accelerator) diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index e1dc15d83069f..5aeb139e75859 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -17,6 +17,7 @@ #include #endif +#include "LLDBServerPluginRegistry.h" #include "LLDBServerUtilities.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h" #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" @@ -453,6 +454,17 @@ int main_gdbserver(int argc, char *argv[]) { NativeProcessManager manager(mainloop); GDBRemoteCommunicationServerLLGS gdb_server(mainloop, manager); + // Create and activate all accelerator plugins. + auto accelerator_plugins = + LLDBServerPluginRegistry::Instance().TryInstantiateAllAcceleratorPlugins( + gdb_server, mainloop); + + // Ensure plugins are torn down on all exit paths. + llvm::scope_exit teardown_plugins([&]() { + for (auto &plugin : accelerator_plugins) + plugin->Teardown(); + }); + llvm::StringRef host_and_port; if (!Inputs.empty() && connection_fd == SharedSocket::kInvalidFD) { host_and_port = Inputs.front();