Skip to content

Commit 4d6de90

Browse files
committed
1 parent 2704b27 commit 4d6de90

33 files changed

+1665
-21
lines changed

lldb/cmake/modules/LLDBConfig.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ add_optional_dependency(LLDB_ENABLE_FBSDVMCORE "Enable libfbsdvmcore support in
6767

6868
option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON)
6969
option(LLDB_BUILD_FRAMEWORK "Build LLDB.framework (Darwin only)" OFF)
70+
option(LLDB_ENABLE_PROTOCOL_SERVERS "Enable protocol servers (e.g. MCP) in LLDB" ON)
7071
option(LLDB_NO_INSTALL_DEFAULT_RPATH "Disable default RPATH settings in binaries" OFF)
7172
option(LLDB_USE_SYSTEM_DEBUGSERVER "Use the system's debugserver for testing (Darwin only)." OFF)
7273
option(LLDB_SKIP_STRIP "Whether to skip stripping of binaries when installing lldb." OFF)

lldb/include/lldb/Core/Debugger.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
598598
void FlushProcessOutput(Process &process, bool flush_stdout,
599599
bool flush_stderr);
600600

601+
void AddProtocolServer(lldb::ProtocolServerSP protocol_server_sp);
602+
void RemoveProtocolServer(lldb::ProtocolServerSP protocol_server_sp);
603+
lldb::ProtocolServerSP GetProtocolServer(llvm::StringRef protocol) const;
604+
601605
SourceManager::SourceFileCache &GetSourceFileCache() {
602606
return m_source_file_cache;
603607
}
@@ -768,6 +772,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
768772
mutable std::mutex m_progress_reports_mutex;
769773
/// @}
770774

775+
llvm::SmallVector<lldb::ProtocolServerSP> m_protocol_servers;
776+
771777
std::mutex m_destroy_callback_mutex;
772778
lldb::callback_token_t m_destroy_callback_next_token = 0;
773779
struct DestroyCallbackInfo {

lldb/include/lldb/Core/PluginManager.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,17 @@ class PluginManager {
327327
static void AutoCompleteProcessName(llvm::StringRef partial_name,
328328
CompletionRequest &request);
329329

330+
// Protocol
331+
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
332+
ProtocolServerCreateInstance create_callback);
333+
334+
static bool UnregisterPlugin(ProtocolServerCreateInstance create_callback);
335+
336+
static llvm::StringRef GetProtocolServerPluginNameAtIndex(uint32_t idx);
337+
338+
static ProtocolServerCreateInstance
339+
GetProtocolCreateCallbackForPluginName(llvm::StringRef name);
340+
330341
// Register Type Provider
331342
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
332343
RegisterTypeBuilderCreateInstance create_callback);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===-- ProtocolServer.h --------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_CORE_PROTOCOLSERVER_H
10+
#define LLDB_CORE_PROTOCOLSERVER_H
11+
12+
#include "lldb/Core/PluginInterface.h"
13+
#include "lldb/Host/Socket.h"
14+
#include "lldb/lldb-private-interfaces.h"
15+
16+
namespace lldb_private {
17+
18+
class ProtocolServer : public PluginInterface {
19+
public:
20+
ProtocolServer() = default;
21+
virtual ~ProtocolServer() = default;
22+
23+
static lldb::ProtocolServerSP Create(llvm::StringRef name,
24+
Debugger &debugger);
25+
26+
struct Connection {
27+
Socket::SocketProtocol protocol;
28+
std::string name;
29+
};
30+
31+
virtual llvm::Error Start(Connection connection) = 0;
32+
virtual llvm::Error Stop() = 0;
33+
34+
virtual Socket *GetSocket() const = 0;
35+
};
36+
37+
} // namespace lldb_private
38+
39+
#endif

lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = {
315315
{ lldb::eArgTypeCPUName, "cpu-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a CPU." },
316316
{ lldb::eArgTypeCPUFeatures, "cpu-features", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The CPU feature string." },
317317
{ lldb::eArgTypeManagedPlugin, "managed-plugin", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Plugins managed by the PluginManager" },
318+
{ lldb::eArgTypeProtocol, "protocol", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of the protocol." },
318319
// clang-format on
319320
};
320321

lldb/include/lldb/lldb-enumerations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ enum CommandArgumentType {
664664
eArgTypeCPUName,
665665
eArgTypeCPUFeatures,
666666
eArgTypeManagedPlugin,
667+
eArgTypeProtocol,
667668
eArgTypeLastArg // Always keep this entry as the last entry in this
668669
// enumeration!!
669670
};

lldb/include/lldb/lldb-forward.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@ class PersistentExpressionState;
164164
class Platform;
165165
class Process;
166166
class ProcessAttachInfo;
167-
class ProcessLaunchInfo;
168167
class ProcessInfo;
169168
class ProcessInstanceInfo;
170169
class ProcessInstanceInfoMatch;
171170
class ProcessLaunchInfo;
172171
class ProcessModID;
173172
class Property;
173+
class ProtocolServer;
174174
class Queue;
175175
class QueueImpl;
176176
class QueueItem;
@@ -391,6 +391,7 @@ typedef std::shared_ptr<lldb_private::Platform> PlatformSP;
391391
typedef std::shared_ptr<lldb_private::Process> ProcessSP;
392392
typedef std::shared_ptr<lldb_private::ProcessAttachInfo> ProcessAttachInfoSP;
393393
typedef std::shared_ptr<lldb_private::ProcessLaunchInfo> ProcessLaunchInfoSP;
394+
typedef std::shared_ptr<lldb_private::ProtocolServer> ProtocolServerSP;
394395
typedef std::weak_ptr<lldb_private::Process> ProcessWP;
395396
typedef std::shared_ptr<lldb_private::RegisterCheckpoint> RegisterCheckpointSP;
396397
typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP;

lldb/include/lldb/lldb-private-interfaces.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ typedef lldb::PlatformSP (*PlatformCreateInstance)(bool force,
8181
typedef lldb::ProcessSP (*ProcessCreateInstance)(
8282
lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
8383
const FileSpec *crash_file_path, bool can_connect);
84+
typedef lldb::ProtocolServerSP (*ProtocolServerCreateInstance)(
85+
Debugger &debugger);
8486
typedef lldb::RegisterTypeBuilderSP (*RegisterTypeBuilderCreateInstance)(
8587
Target &target);
8688
typedef lldb::ScriptInterpreterSP (*ScriptInterpreterCreateInstance)(

lldb/source/Commands/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_lldb_library(lldbCommands NO_PLUGIN_DEPENDENCIES
2323
CommandObjectPlatform.cpp
2424
CommandObjectPlugin.cpp
2525
CommandObjectProcess.cpp
26+
CommandObjectProtocolServer.cpp
2627
CommandObjectQuit.cpp
2728
CommandObjectRegexCommand.cpp
2829
CommandObjectRegister.cpp
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
//===-- CommandObjectProtocolServer.cpp
2+
//----------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "CommandObjectProtocolServer.h"
11+
#include "lldb/Core/PluginManager.h"
12+
#include "lldb/Core/ProtocolServer.h"
13+
#include "lldb/Host/Socket.h"
14+
#include "lldb/Interpreter/CommandInterpreter.h"
15+
#include "lldb/Interpreter/CommandReturnObject.h"
16+
#include "lldb/Utility/UriParser.h"
17+
#include "llvm/ADT/STLExtras.h"
18+
#include "llvm/Support/FormatAdapters.h"
19+
20+
using namespace llvm;
21+
using namespace lldb;
22+
using namespace lldb_private;
23+
24+
#define LLDB_OPTIONS_mcp
25+
#include "CommandOptions.inc"
26+
27+
static std::vector<llvm::StringRef> GetSupportedProtocols() {
28+
std::vector<llvm::StringRef> supported_protocols;
29+
size_t i = 0;
30+
31+
for (llvm::StringRef protocol_name =
32+
PluginManager::GetProtocolServerPluginNameAtIndex(i++);
33+
!protocol_name.empty();
34+
protocol_name = PluginManager::GetProtocolServerPluginNameAtIndex(i++)) {
35+
supported_protocols.push_back(protocol_name);
36+
}
37+
38+
return supported_protocols;
39+
}
40+
41+
static llvm::Expected<std::pair<Socket::SocketProtocol, std::string>>
42+
validateConnection(llvm::StringRef conn) {
43+
auto uri = lldb_private::URI::Parse(conn);
44+
45+
if (uri && (uri->scheme == "tcp" || uri->scheme == "connect" ||
46+
!uri->hostname.empty() || uri->port)) {
47+
return std::make_pair(
48+
Socket::ProtocolTcp,
49+
formatv("[{0}]:{1}", uri->hostname.empty() ? "0.0.0.0" : uri->hostname,
50+
uri->port.value_or(0)));
51+
}
52+
53+
if (uri && (uri->scheme == "unix" || uri->scheme == "unix-connect" ||
54+
uri->path != "/")) {
55+
return std::make_pair(Socket::ProtocolUnixDomain, uri->path.str());
56+
}
57+
58+
return llvm::createStringError(
59+
"Unsupported connection specifier, expected 'unix-connect:///path' or "
60+
"'connect://[host]:port', got '%s'.",
61+
conn.str().c_str());
62+
}
63+
64+
class CommandObjectProtocolServerStart : public CommandObjectParsed {
65+
public:
66+
CommandObjectProtocolServerStart(CommandInterpreter &interpreter)
67+
: CommandObjectParsed(interpreter, "protocol-server start",
68+
"start protocol server",
69+
"protocol-server start <protocol> <connection>") {
70+
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
71+
AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);
72+
}
73+
74+
~CommandObjectProtocolServerStart() override = default;
75+
76+
protected:
77+
void DoExecute(Args &args, CommandReturnObject &result) override {
78+
if (args.GetArgumentCount() < 1) {
79+
result.AppendError("no protocol specified");
80+
return;
81+
}
82+
83+
llvm::StringRef protocol = args.GetArgumentAtIndex(0);
84+
std::vector<llvm::StringRef> supported_protocols = GetSupportedProtocols();
85+
if (llvm::find(supported_protocols, protocol) ==
86+
supported_protocols.end()) {
87+
result.AppendErrorWithFormatv(
88+
"unsupported protocol: {0}. Supported protocols are: {1}", protocol,
89+
llvm::join(GetSupportedProtocols(), ", "));
90+
return;
91+
}
92+
93+
if (args.GetArgumentCount() < 2) {
94+
result.AppendError("no connection specified");
95+
return;
96+
}
97+
llvm::StringRef connection_uri = args.GetArgumentAtIndex(1);
98+
99+
ProtocolServerSP server_sp = GetDebugger().GetProtocolServer(protocol);
100+
if (!server_sp)
101+
server_sp = ProtocolServer::Create(protocol, GetDebugger());
102+
103+
auto maybeProtoclAndName = validateConnection(connection_uri);
104+
if (auto error = maybeProtoclAndName.takeError()) {
105+
result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
106+
return;
107+
}
108+
109+
ProtocolServer::Connection connection;
110+
std::tie(connection.protocol, connection.name) = *maybeProtoclAndName;
111+
112+
if (llvm::Error error = server_sp->Start(connection)) {
113+
result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
114+
return;
115+
}
116+
117+
GetDebugger().AddProtocolServer(server_sp);
118+
119+
if (Socket *socket = server_sp->GetSocket()) {
120+
std::string address =
121+
llvm::join(socket->GetListeningConnectionURI(), ", ");
122+
result.AppendMessageWithFormatv(
123+
"{0} server started with connection listeners: {1}", protocol,
124+
address);
125+
}
126+
}
127+
};
128+
129+
class CommandObjectProtocolServerStop : public CommandObjectParsed {
130+
public:
131+
CommandObjectProtocolServerStop(CommandInterpreter &interpreter)
132+
: CommandObjectParsed(interpreter, "protocol-server stop",
133+
"stop protocol server",
134+
"protocol-server stop <protocol>") {
135+
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
136+
}
137+
138+
~CommandObjectProtocolServerStop() override = default;
139+
140+
protected:
141+
void DoExecute(Args &args, CommandReturnObject &result) override {
142+
if (args.GetArgumentCount() < 1) {
143+
result.AppendError("no protocol specified");
144+
return;
145+
}
146+
147+
llvm::StringRef protocol = args.GetArgumentAtIndex(0);
148+
std::vector<llvm::StringRef> supported_protocols = GetSupportedProtocols();
149+
if (llvm::find(supported_protocols, protocol) ==
150+
supported_protocols.end()) {
151+
result.AppendErrorWithFormatv(
152+
"unsupported protocol: {0}. Supported protocols are: {1}", protocol,
153+
llvm::join(GetSupportedProtocols(), ", "));
154+
return;
155+
}
156+
157+
Debugger &debugger = GetDebugger();
158+
159+
ProtocolServerSP server_sp = debugger.GetProtocolServer(protocol);
160+
if (!server_sp) {
161+
result.AppendError(
162+
llvm::formatv("no {0} protocol server running", protocol).str());
163+
return;
164+
}
165+
166+
if (llvm::Error error = server_sp->Stop()) {
167+
result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
168+
return;
169+
}
170+
171+
debugger.RemoveProtocolServer(server_sp);
172+
}
173+
};
174+
175+
CommandObjectProtocolServer::CommandObjectProtocolServer(
176+
CommandInterpreter &interpreter)
177+
: CommandObjectMultiword(interpreter, "protocol-server",
178+
"Start and stop a protocol server.",
179+
"protocol-server") {
180+
LoadSubCommand("start", CommandObjectSP(new CommandObjectProtocolServerStart(
181+
interpreter)));
182+
LoadSubCommand("stop", CommandObjectSP(
183+
new CommandObjectProtocolServerStop(interpreter)));
184+
}
185+
186+
CommandObjectProtocolServer::~CommandObjectProtocolServer() = default;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//===-- CommandObjectProtocolServer.h
2+
//------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTPROTOCOLSERVER_H
11+
#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTPROTOCOLSERVER_H
12+
13+
#include "lldb/Interpreter/CommandObjectMultiword.h"
14+
15+
namespace lldb_private {
16+
17+
class CommandObjectProtocolServer : public CommandObjectMultiword {
18+
public:
19+
CommandObjectProtocolServer(CommandInterpreter &interpreter);
20+
~CommandObjectProtocolServer() override;
21+
};
22+
23+
} // namespace lldb_private
24+
25+
#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTMCP_H

lldb/source/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_lldb_library(lldbCore NO_PLUGIN_DEPENDENCIES
4646
Opcode.cpp
4747
PluginManager.cpp
4848
Progress.cpp
49+
ProtocolServer.cpp
4950
Statusline.cpp
5051
RichManglingContext.cpp
5152
SearchFilter.cpp

lldb/source/Core/Debugger.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "lldb/Core/ModuleSpec.h"
1717
#include "lldb/Core/PluginManager.h"
1818
#include "lldb/Core/Progress.h"
19+
#include "lldb/Core/ProtocolServer.h"
1920
#include "lldb/Core/StreamAsynchronousIO.h"
2021
#include "lldb/Core/Telemetry.h"
2122
#include "lldb/DataFormatters/DataVisualization.h"
@@ -2363,3 +2364,26 @@ llvm::ThreadPoolInterface &Debugger::GetThreadPool() {
23632364
"Debugger::GetThreadPool called before Debugger::Initialize");
23642365
return *g_thread_pool;
23652366
}
2367+
2368+
void Debugger::AddProtocolServer(lldb::ProtocolServerSP protocol_server_sp) {
2369+
assert(protocol_server_sp &&
2370+
GetProtocolServer(protocol_server_sp->GetPluginName()) == nullptr);
2371+
m_protocol_servers.push_back(protocol_server_sp);
2372+
}
2373+
2374+
void Debugger::RemoveProtocolServer(lldb::ProtocolServerSP protocol_server_sp) {
2375+
auto it = llvm::find(m_protocol_servers, protocol_server_sp);
2376+
if (it != m_protocol_servers.end())
2377+
m_protocol_servers.erase(it);
2378+
}
2379+
2380+
lldb::ProtocolServerSP
2381+
Debugger::GetProtocolServer(llvm::StringRef protocol) const {
2382+
for (ProtocolServerSP protocol_server_sp : m_protocol_servers) {
2383+
if (!protocol_server_sp)
2384+
continue;
2385+
if (protocol_server_sp->GetPluginName() == protocol)
2386+
return protocol_server_sp;
2387+
}
2388+
return nullptr;
2389+
}

0 commit comments

Comments
 (0)