Skip to content

Commit 4156ce2

Browse files
committed
1 parent 2704b27 commit 4156ce2

32 files changed

+1645
-21
lines changed

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: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
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, "mcp start", "start MCP server",
68+
"mcp start <connection>") {
69+
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
70+
AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);
71+
}
72+
73+
~CommandObjectProtocolServerStart() override = default;
74+
75+
protected:
76+
void DoExecute(Args &args, CommandReturnObject &result) override {
77+
if (args.GetArgumentCount() < 1) {
78+
result.AppendError("no protocol specified");
79+
return;
80+
}
81+
82+
llvm::StringRef protocol = args.GetArgumentAtIndex(0);
83+
std::vector<llvm::StringRef> supported_protocols = GetSupportedProtocols();
84+
if (llvm::find(supported_protocols, protocol) ==
85+
supported_protocols.end()) {
86+
result.AppendErrorWithFormatv(
87+
"unsupported protocol: {0}. Supported protocols are: {1}", protocol,
88+
llvm::join(GetSupportedProtocols(), ", "));
89+
return;
90+
}
91+
92+
if (args.GetArgumentCount() < 2) {
93+
result.AppendError("no connection specified");
94+
return;
95+
}
96+
llvm::StringRef connection_uri = args.GetArgumentAtIndex(1);
97+
98+
ProtocolServerSP server_sp = GetDebugger().GetProtocolServer(protocol);
99+
if (!server_sp)
100+
server_sp = ProtocolServer::Create(protocol, GetDebugger());
101+
102+
auto maybeProtoclAndName = validateConnection(connection_uri);
103+
if (auto error = maybeProtoclAndName.takeError()) {
104+
result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
105+
return;
106+
}
107+
108+
ProtocolServer::Connection connection;
109+
std::tie(connection.protocol, connection.name) = *maybeProtoclAndName;
110+
111+
if (llvm::Error error = server_sp->Start(connection)) {
112+
result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
113+
return;
114+
}
115+
116+
GetDebugger().AddProtocolServer(server_sp);
117+
118+
if (Socket *socket = server_sp->GetSocket()) {
119+
std::string address =
120+
llvm::join(socket->GetListeningConnectionURI(), ", ");
121+
result.AppendMessageWithFormatv(
122+
"{0} server started with connection listeners: {1}", protocol,
123+
address);
124+
}
125+
}
126+
};
127+
128+
class CommandObjectProtocolServerStop : public CommandObjectParsed {
129+
public:
130+
CommandObjectProtocolServerStop(CommandInterpreter &interpreter)
131+
: CommandObjectParsed(interpreter, "protocol-server stop",
132+
"stop protocol server", "protocol-server stop") {
133+
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
134+
}
135+
136+
~CommandObjectProtocolServerStop() override = default;
137+
138+
protected:
139+
void DoExecute(Args &args, CommandReturnObject &result) override {
140+
if (args.GetArgumentCount() < 1) {
141+
result.AppendError("no protocol specified");
142+
return;
143+
}
144+
145+
llvm::StringRef protocol = args.GetArgumentAtIndex(0);
146+
std::vector<llvm::StringRef> supported_protocols = GetSupportedProtocols();
147+
if (llvm::find(supported_protocols, protocol) ==
148+
supported_protocols.end()) {
149+
result.AppendErrorWithFormatv(
150+
"unsupported protocol: {0}. Supported protocols are: {1}", protocol,
151+
llvm::join(GetSupportedProtocols(), ", "));
152+
return;
153+
}
154+
155+
Debugger &debugger = GetDebugger();
156+
157+
ProtocolServerSP server_sp = debugger.GetProtocolServer(protocol);
158+
if (!server_sp) {
159+
result.AppendError(
160+
llvm::formatv("no {0} protocol server running", protocol).str());
161+
return;
162+
}
163+
164+
if (llvm::Error error = server_sp->Stop()) {
165+
result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
166+
return;
167+
}
168+
169+
debugger.RemoveProtocolServer(server_sp);
170+
}
171+
};
172+
173+
CommandObjectProtocolServer::CommandObjectProtocolServer(
174+
CommandInterpreter &interpreter)
175+
: CommandObjectMultiword(interpreter, "protocol-server",
176+
"Start and stop a protocol server.",
177+
"protocol-server") {
178+
LoadSubCommand("start", CommandObjectSP(new CommandObjectProtocolServerStart(
179+
interpreter)));
180+
LoadSubCommand("stop", CommandObjectSP(
181+
new CommandObjectProtocolServerStop(interpreter)));
182+
}
183+
184+
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)