Skip to content

Commit a9ea7cf

Browse files
ashgtiJDevlieghere
andauthored
[lldb] Adjust ProtocolServer connection defaults. (#155714)
This adjusts the ProtocolServer command to default to create a new connection listening on `localhost:0` and adds a new `ServerMetadata` details to `~/.lldb/mcp/lldb-<pid>.json` to record information about the current MCP server. This can be consumed by the lldb-mcp binary to establish a connection from an LLM client. --------- Co-authored-by: Jonas Devlieghere <[email protected]>
1 parent 781d2d0 commit a9ea7cf

File tree

13 files changed

+151
-56
lines changed

13 files changed

+151
-56
lines changed

lldb/include/lldb/Host/HostInfoBase.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,19 @@ class HostInfoBase {
102102
/// member of the FileSpec is filled in.
103103
static FileSpec GetSystemPluginDir();
104104

105+
/// Returns the directory containing the users home (e.g. `~/`). Only the
106+
/// directory member of the FileSpec is filled in.
107+
static FileSpec GetUserHomeDir();
108+
109+
/// Returns the directory containing the users lldb home (e.g. `~/.lldb/`).
110+
/// Only the directory member of the FileSpec is filled in.
111+
static FileSpec GetUserLLDBDir();
112+
105113
/// Returns the directory containing the user plugins. Only the directory
106114
/// member of the FileSpec is filled in.
107115
static FileSpec GetUserPluginDir();
108116

109-
/// Returns the proces temporary directory. This directory will be cleaned up
117+
/// Returns the process temporary directory. This directory will be cleaned up
110118
/// when this process exits. Only the directory member of the FileSpec is
111119
/// filled in.
112120
static FileSpec GetProcessTempDir();
@@ -167,11 +175,13 @@ class HostInfoBase {
167175
static bool ComputeTempFileBaseDirectory(FileSpec &file_spec);
168176
static bool ComputeHeaderDirectory(FileSpec &file_spec);
169177
static bool ComputeSystemPluginsDirectory(FileSpec &file_spec);
178+
static bool ComputeUserHomeDirectory(FileSpec &file_spec);
179+
static bool ComputeUserLLDBHomeDirectory(FileSpec &file_spec);
170180
static bool ComputeUserPluginsDirectory(FileSpec &file_spec);
171181

172182
static void ComputeHostArchitectureSupport(ArchSpec &arch_32,
173183
ArchSpec &arch_64);
174184
};
175-
}
185+
} // namespace lldb_private
176186

177187
#endif

lldb/include/lldb/Host/macosx/HostInfoMacOSX.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class HostInfoMacOSX : public HostInfoPosix {
5656
static std::string FindComponentInPath(llvm::StringRef path,
5757
llvm::StringRef component);
5858
};
59-
}
59+
60+
} // namespace lldb_private
6061

6162
#endif

lldb/include/lldb/Protocol/MCP/Server.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ class MCPTransport
4141
LogCallback m_log_callback;
4242
};
4343

44+
/// Information about this instance of lldb's MCP server for lldb-mcp to use to
45+
/// coordinate connecting an lldb-mcp client.
46+
struct ServerInfo {
47+
std::string connection_uri;
48+
lldb::pid_t pid;
49+
};
50+
llvm::json::Value toJSON(const ServerInfo &);
51+
bool fromJSON(const llvm::json::Value &, ServerInfo &, llvm::json::Path);
52+
4453
class Server : public MCPTransport::MessageHandler {
4554
public:
4655
Server(std::string name, std::string version,

lldb/source/API/SBHostOS.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,7 @@ SBFileSpec SBHostOS::GetLLDBPath(lldb::PathType path_type) {
8686

8787
SBFileSpec SBHostOS::GetUserHomeDirectory() {
8888
LLDB_INSTRUMENT();
89-
90-
FileSpec homedir;
91-
FileSystem::Instance().GetHomeDirectory(homedir);
92-
FileSystem::Instance().Resolve(homedir);
93-
94-
SBFileSpec sb_fspec;
95-
sb_fspec.SetFileSpec(homedir);
96-
97-
return sb_fspec;
89+
return HostInfo::GetUserHomeDir();
9890
}
9991

10092
lldb::thread_t SBHostOS::ThreadCreate(const char *name,

lldb/source/Commands/CommandObjectProtocolServer.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "lldb/Utility/UriParser.h"
1616
#include "llvm/ADT/STLExtras.h"
1717
#include "llvm/Support/FormatAdapters.h"
18+
#include <string>
1819

1920
using namespace llvm;
2021
using namespace lldb;
@@ -28,7 +29,7 @@ class CommandObjectProtocolServerStart : public CommandObjectParsed {
2829
CommandObjectProtocolServerStart(CommandInterpreter &interpreter)
2930
: CommandObjectParsed(interpreter, "protocol-server start",
3031
"start protocol server",
31-
"protocol-server start <protocol> <connection>") {
32+
"protocol-server start <protocol> [<connection>]") {
3233
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
3334
AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);
3435
}
@@ -51,15 +52,13 @@ class CommandObjectProtocolServerStart : public CommandObjectParsed {
5152
return;
5253
}
5354

54-
if (args.GetArgumentCount() < 2) {
55-
result.AppendError("no connection specified");
56-
return;
57-
}
58-
llvm::StringRef connection_uri = args.GetArgumentAtIndex(1);
55+
std::string connection_uri = "listen://[localhost]:0";
56+
if (args.GetArgumentCount() >= 2)
57+
connection_uri = args.GetArgumentAtIndex(1);
5958

6059
const char *connection_error =
61-
"unsupported connection specifier, expected 'accept:///path' or "
62-
"'listen://[host]:port', got '{0}'.";
60+
"unsupported connection specifier, expected 'accept:///path' "
61+
"or 'listen://[host]:port', got '{0}'.";
6362
auto uri = lldb_private::URI::Parse(connection_uri);
6463
if (!uri) {
6564
result.AppendErrorWithFormatv(connection_error, connection_uri);

lldb/source/Host/common/Editline.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
#include <iomanip>
1111
#include <optional>
1212

13-
#include "lldb/Host/ConnectionFileDescriptor.h"
1413
#include "lldb/Host/Editline.h"
15-
#include "lldb/Host/FileSystem.h"
16-
#include "lldb/Host/Host.h"
14+
#include "lldb/Host/HostInfo.h"
1715
#include "lldb/Host/StreamFile.h"
1816
#include "lldb/Utility/AnsiTerminal.h"
1917
#include "lldb/Utility/CompletionRequest.h"
@@ -219,20 +217,19 @@ class EditlineHistory {
219217
const char *GetHistoryFilePath() {
220218
// Compute the history path lazily.
221219
if (m_path.empty() && m_history && !m_prefix.empty()) {
222-
llvm::SmallString<128> lldb_history_file;
223-
FileSystem::Instance().GetHomeDirectory(lldb_history_file);
224-
llvm::sys::path::append(lldb_history_file, ".lldb");
220+
FileSpec lldb_dir = HostInfo::GetUserLLDBDir();
225221

226222
// LLDB stores its history in ~/.lldb/. If for some reason this directory
227223
// isn't writable or cannot be created, history won't be available.
228-
if (!llvm::sys::fs::create_directory(lldb_history_file)) {
224+
if (!llvm::sys::fs::create_directory(lldb_dir.GetPath())) {
229225
#if LLDB_EDITLINE_USE_WCHAR
230226
std::string filename = m_prefix + "-widehistory";
231227
#else
232228
std::string filename = m_prefix + "-history";
233229
#endif
234-
llvm::sys::path::append(lldb_history_file, filename);
235-
m_path = std::string(lldb_history_file.str());
230+
FileSpec lldb_history_file =
231+
lldb_dir.CopyByAppendingPathComponent(filename);
232+
m_path = lldb_history_file.GetPath();
236233
}
237234
}
238235

lldb/source/Host/common/HostInfoBase.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ struct HostInfoBaseFields {
6161
FileSpec m_lldb_clang_resource_dir;
6262
llvm::once_flag m_lldb_system_plugin_dir_once;
6363
FileSpec m_lldb_system_plugin_dir;
64+
llvm::once_flag m_lldb_user_home_dir_once;
65+
FileSpec m_lldb_user_home_dir;
66+
llvm::once_flag m_lldb_user_lldb_dir_once;
67+
FileSpec m_lldb_user_lldb_dir;
6468
llvm::once_flag m_lldb_user_plugin_dir_once;
6569
FileSpec m_lldb_user_plugin_dir;
6670
llvm::once_flag m_lldb_process_tmp_dir_once;
@@ -161,6 +165,26 @@ FileSpec HostInfoBase::GetSystemPluginDir() {
161165
return g_fields->m_lldb_system_plugin_dir;
162166
}
163167

168+
FileSpec HostInfoBase::GetUserHomeDir() {
169+
llvm::call_once(g_fields->m_lldb_user_home_dir_once, []() {
170+
if (!HostInfo::ComputeUserHomeDirectory(g_fields->m_lldb_user_home_dir))
171+
g_fields->m_lldb_user_home_dir = FileSpec();
172+
LLDB_LOG(GetLog(LLDBLog::Host), "user home dir -> `{0}`",
173+
g_fields->m_lldb_user_home_dir);
174+
});
175+
return g_fields->m_lldb_user_home_dir;
176+
}
177+
178+
FileSpec HostInfoBase::GetUserLLDBDir() {
179+
llvm::call_once(g_fields->m_lldb_user_lldb_dir_once, []() {
180+
if (!HostInfo::ComputeUserLLDBHomeDirectory(g_fields->m_lldb_user_lldb_dir))
181+
g_fields->m_lldb_user_lldb_dir = FileSpec();
182+
LLDB_LOG(GetLog(LLDBLog::Host), "user lldb home dir -> `{0}`",
183+
g_fields->m_lldb_user_lldb_dir);
184+
});
185+
return g_fields->m_lldb_user_lldb_dir;
186+
}
187+
164188
FileSpec HostInfoBase::GetUserPluginDir() {
165189
llvm::call_once(g_fields->m_lldb_user_plugin_dir_once, []() {
166190
if (!HostInfo::ComputeUserPluginsDirectory(
@@ -316,6 +340,20 @@ bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
316340
return false;
317341
}
318342

343+
bool HostInfoBase::ComputeUserHomeDirectory(FileSpec &file_spec) {
344+
FileSpec temp_file("~");
345+
FileSystem::Instance().Resolve(temp_file);
346+
file_spec.SetDirectory(temp_file.GetPathAsConstString());
347+
return true;
348+
}
349+
350+
bool HostInfoBase::ComputeUserLLDBHomeDirectory(FileSpec &file_spec) {
351+
FileSpec home_dir_spec = GetUserHomeDir();
352+
home_dir_spec.AppendPathComponent(".lldb");
353+
file_spec.SetDirectory(home_dir_spec.GetPathAsConstString());
354+
return true;
355+
}
356+
319357
bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
320358
// TODO(zturner): Figure out how to compute the user plugins directory for
321359
// all platforms.

lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
#include <Foundation/Foundation.h>
4040
#include <mach-o/dyld.h>
4141
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
42-
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
42+
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
4343
#if __has_include(<mach-o/dyld_introspection.h>)
4444
#include <mach-o/dyld_introspection.h>
4545
#define SDK_HAS_NEW_DYLD_INTROSPECTION_SPIS
@@ -78,8 +78,8 @@
7878
static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) {
7979
@autoreleasepool {
8080
NSDictionary *version_info =
81-
[NSDictionary dictionaryWithContentsOfFile:
82-
@"/System/Library/CoreServices/SystemVersion.plist"];
81+
[NSDictionary dictionaryWithContentsOfFile:
82+
@"/System/Library/CoreServices/SystemVersion.plist"];
8383
NSString *version_value = [version_info objectForKey: Key];
8484
const char *version_str = [version_value UTF8String];
8585
version.tryParse(version_str);
@@ -225,9 +225,9 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
225225
}
226226

227227
bool HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec) {
228-
FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns");
229-
FileSystem::Instance().Resolve(temp_file);
230-
file_spec.SetDirectory(temp_file.GetPathAsConstString());
228+
FileSpec home_dir_spec = GetUserHomeDir();
229+
home_dir_spec.AppendPathComponent("Library/Application Support/LLDB/PlugIns");
230+
file_spec.SetDirectory(home_dir_spec.GetPathAsConstString());
231231
return true;
232232
}
233233

lldb/source/Interpreter/CommandInterpreter.cpp

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "lldb/Core/Telemetry.h"
5353
#include "lldb/Host/StreamFile.h"
5454
#include "lldb/Utility/ErrorMessages.h"
55+
#include "lldb/Utility/FileSpec.h"
5556
#include "lldb/Utility/LLDBLog.h"
5657
#include "lldb/Utility/Log.h"
5758
#include "lldb/Utility/State.h"
@@ -2502,22 +2503,18 @@ int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
25022503
return position;
25032504
}
25042505

2505-
static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
2506-
llvm::StringRef suffix = {}) {
2506+
static void GetHomeInitFile(FileSpec &init_file, llvm::StringRef suffix = {}) {
25072507
std::string init_file_name = ".lldbinit";
25082508
if (!suffix.empty()) {
25092509
init_file_name.append("-");
25102510
init_file_name.append(suffix.str());
25112511
}
25122512

2513-
FileSystem::Instance().GetHomeDirectory(init_file);
2514-
llvm::sys::path::append(init_file, init_file_name);
2515-
2516-
FileSystem::Instance().Resolve(init_file);
2513+
init_file =
2514+
HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
25172515
}
25182516

2519-
static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
2520-
LanguageType language) {
2517+
static void GetHomeREPLInitFile(FileSpec &init_file, LanguageType language) {
25212518
if (language == eLanguageTypeUnknown) {
25222519
LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
25232520
if (auto main_repl_language = repl_languages.GetSingularLanguage())
@@ -2531,9 +2528,9 @@ static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
25312528
llvm::Twine(Language::GetNameForLanguageType(language)) +
25322529
llvm::Twine("-repl"))
25332530
.str();
2534-
FileSystem::Instance().GetHomeDirectory(init_file);
2535-
llvm::sys::path::append(init_file, init_file_name);
2536-
FileSystem::Instance().Resolve(init_file);
2531+
2532+
init_file =
2533+
HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
25372534
}
25382535

25392536
static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
@@ -2588,10 +2585,10 @@ void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
25882585
SourceInitFile(FileSpec(init_file.str()), result);
25892586
break;
25902587
case eLoadCWDlldbinitWarn: {
2591-
llvm::SmallString<128> home_init_file;
2588+
FileSpec home_init_file;
25922589
GetHomeInitFile(home_init_file);
25932590
if (llvm::sys::path::parent_path(init_file) ==
2594-
llvm::sys::path::parent_path(home_init_file)) {
2591+
llvm::sys::path::parent_path(home_init_file.GetPath())) {
25952592
result.SetStatus(eReturnStatusSuccessFinishNoResult);
25962593
} else {
25972594
result.AppendError(InitFileWarning);
@@ -2611,24 +2608,24 @@ void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
26112608
return;
26122609
}
26132610

2614-
llvm::SmallString<128> init_file;
2611+
FileSpec init_file;
26152612

26162613
if (is_repl)
26172614
GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
26182615

2619-
if (init_file.empty())
2616+
if (init_file.GetPath().empty())
26202617
GetHomeInitFile(init_file);
26212618

26222619
if (!m_skip_app_init_files) {
26232620
llvm::StringRef program_name =
26242621
HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2625-
llvm::SmallString<128> program_init_file;
2622+
FileSpec program_init_file;
26262623
GetHomeInitFile(program_init_file, program_name);
26272624
if (FileSystem::Instance().Exists(program_init_file))
26282625
init_file = program_init_file;
26292626
}
26302627

2631-
SourceInitFile(FileSpec(init_file.str()), result);
2628+
SourceInitFile(init_file, result);
26322629
}
26332630

26342631
void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {

0 commit comments

Comments
 (0)