[lldb] Add Model Context Protocol (MCP) support to LLDB by JDevlieghere · Pull Request #143628 · llvm/llvm-project (original) (raw)

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

This PR adds an MCP (Model Context Protocol ) server to LLDB. For motivation and background, please refer to the corresponding RFC: https://discourse.llvm.org/t/rfc-adding-mcp-support-to-lldb/86798

I implemented this as a new kind of plugin. The idea is that we could support multiple protocol servers (e.g. if we want to support DAP from within LLDB). This also introduces a corresponding top-level command (protocol-server) with two subcommands to start and stop the server.

(lldb) protocol-server start MCP tcp://localhost:1234
MCP server started with connection listeners: connection://[::1]:1234, connection://[127.0.0.1]:1234

The MCP sever supports one tool (lldb_command) which executes a command, but can easily be extended with more commands.


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

32 Files Affected:

diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index d73aba1e3ce58..0f6659d1a0bf7 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -598,6 +598,10 @@ class Debugger : public std::enable_shared_from_this, void FlushProcessOutput(Process &process, bool flush_stdout, bool flush_stderr);

diff --git a/lldb/include/lldb/Core/ProtocolServer.h b/lldb/include/lldb/Core/ProtocolServer.h new file mode 100644 index 0000000000000..fafe460904323 --- /dev/null +++ b/lldb/include/lldb/Core/ProtocolServer.h @@ -0,0 +1,39 @@ +//===-- ProtocolServer.h --------------------------------------------------===// +// +// 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_CORE_PROTOCOLSERVER_H +#define LLDB_CORE_PROTOCOLSERVER_H + +#include "lldb/Core/PluginInterface.h" +#include "lldb/Host/Socket.h" +#include "lldb/lldb-private-interfaces.h" + +namespace lldb_private { + +class ProtocolServer : public PluginInterface { +public:

diff --git a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h index 8535dfcf46da5..4face717531b1 100644 --- a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h +++ b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h @@ -315,6 +315,7 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = { { lldb::eArgTypeCPUName, "cpu-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a CPU." }, { lldb::eArgTypeCPUFeatures, "cpu-features", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The CPU feature string." }, { lldb::eArgTypeManagedPlugin, "managed-plugin", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Plugins managed by the PluginManager" },

diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index eeb7299a354e1..69e8671b6e21b 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -664,6 +664,7 @@ enum CommandArgumentType { eArgTypeCPUName, eArgTypeCPUFeatures, eArgTypeManagedPlugin,

}; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index c664d1398f74d..558818e8e2309 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -164,13 +164,13 @@ class PersistentExpressionState; class Platform; class Process; class ProcessAttachInfo; -class ProcessLaunchInfo; class ProcessInfo; class ProcessInstanceInfo; class ProcessInstanceInfoMatch; class ProcessLaunchInfo; class ProcessModID; class Property; +class ProtocolServer; class Queue; class QueueImpl; class QueueItem; @@ -391,6 +391,7 @@ typedef std::shared_ptr<lldb_private::Platform> PlatformSP; typedef std::shared_ptr<lldb_private::Process> ProcessSP; typedef std::shared_ptr<lldb_private::ProcessAttachInfo> ProcessAttachInfoSP; typedef std::shared_ptr<lldb_private::ProcessLaunchInfo> ProcessLaunchInfoSP; +typedef std::shared_ptr<lldb_private::ProtocolServer> ProtocolServerSP; typedef std::weak_ptr<lldb_private::Process> ProcessWP; typedef std::shared_ptr<lldb_private::RegisterCheckpoint> RegisterCheckpointSP; typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP; diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h index d366dbd1d7832..34eaaa8e581e9 100644 --- a/lldb/include/lldb/lldb-private-interfaces.h +++ b/lldb/include/lldb/lldb-private-interfaces.h @@ -81,6 +81,8 @@ typedef lldb::PlatformSP (*PlatformCreateInstance)(bool force, typedef lldb::ProcessSP (*ProcessCreateInstance)( lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec *crash_file_path, bool can_connect); +typedef lldb::ProtocolServerSP (*ProtocolServerCreateInstance)(

typedef lldb::RegisterTypeBuilderSP (*RegisterTypeBuilderCreateInstance)( Target &target); typedef lldb::ScriptInterpreterSP (*ScriptInterpreterCreateInstance)( diff --git a/lldb/source/Commands/CMakeLists.txt b/lldb/source/Commands/CMakeLists.txt index 1ea51acec5f15..69e4c45f0b8e5 100644 --- a/lldb/source/Commands/CMakeLists.txt +++ b/lldb/source/Commands/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_library(lldbCommands NO_PLUGIN_DEPENDENCIES CommandObjectPlatform.cpp CommandObjectPlugin.cpp CommandObjectProcess.cpp

+#include "lldb/Core/PluginManager.h" +#include "lldb/Core/ProtocolServer.h" +#include "lldb/Host/Socket.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Utility/UriParser.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/FormatAdapters.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +#define LLDB_OPTIONS_mcp +#include "CommandOptions.inc" + +static std::vectorllvm::StringRef GetSupportedProtocols() {

+} + +class CommandObjectProtocolServerStart : public CommandObjectParsed { +public:

+} + +CommandObjectProtocolServer::~CommandObjectProtocolServer() = default; diff --git a/lldb/source/Commands/CommandObjectProtocolServer.h b/lldb/source/Commands/CommandObjectProtocolServer.h new file mode 100644 index 0000000000000..3591216b014cb --- /dev/null +++ b/lldb/source/Commands/CommandObjectProtocolServer.h @@ -0,0 +1,25 @@ +//===-- CommandObjectProtocolServer.h +//------------------------------------------------===// +// +// 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_SOURCE_COMMANDS_COMMANDOBJECTPROTOCOLSERVER_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTPROTOCOLSERVER_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectProtocolServer : public CommandObjectMultiword { +public:

diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt index d6b75bca7f2d6..df35bd5c025f3 100644 --- a/lldb/source/Core/CMakeLists.txt +++ b/lldb/source/Core/CMakeLists.txt @@ -46,6 +46,7 @@ add_lldb_library(lldbCore NO_PLUGIN_DEPENDENCIES Opcode.cpp PluginManager.cpp Progress.cpp

#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Progress.h" +#include "lldb/Core/ProtocolServer.h" #include "lldb/Core/StreamAsynchronousIO.h" #include "lldb/Core/Telemetry.h" #include "lldb/DataFormatters/DataVisualization.h" @@ -2363,3 +2364,26 @@ llvm::ThreadPoolInterface &Debugger::GetThreadPool() { "Debugger::GetThreadPool called before Debugger::Initialize"); return *g_thread_pool; } + +void Debugger::AddProtocolServer(lldb::ProtocolServerSP protocol_server_sp) {

+} + +lldb::ProtocolServerSP +Debugger::GetProtocolServer(llvm::StringRef protocol) const {

+#pragma mark ProtocolServer + +typedef PluginInstance ProtocolServerInstance; +typedef PluginInstances ProtocolServerInstances; + +static ProtocolServerInstances &GetProtocolServerInstances() {

+} + +bool PluginManager::UnregisterPlugin(

diff --git a/lldb/source/Core/ProtocolServer.cpp b/lldb/source/Core/ProtocolServer.cpp new file mode 100644 index 0000000000000..d57a047afa7b2 --- /dev/null +++ b/lldb/source/Core/ProtocolServer.cpp @@ -0,0 +1,21 @@ +//===-- ProtocolServer.cpp ------------------------------------------------===// +// +// 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 "lldb/Core/ProtocolServer.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb_private; +using namespace lldb; + +ProtocolServerSP ProtocolServer::Create(llvm::StringRef name,

#include "Commands/CommandObjectPlatform.h" #include "Commands/CommandObjectPlugin.h" #include "Commands/CommandObjectProcess.h" +#include "Commands/CommandObjectProtocolServer.h" #include "Commands/CommandObjectQuit.h" #include "Commands/CommandObjectRegexCommand.h" #include "Commands/CommandObjectRegister.h" @@ -574,6 +575,7 @@ void CommandInterpreter::LoadCommandDictionary() { REGISTER_COMMAND_OBJECT("... [truncated]