88
99#include " lldb/Host/Config.h"
1010#include " lldb/Host/File.h"
11+ #include " lldb/Host/FileSystem.h"
12+ #include " lldb/Host/Host.h"
1113#include " lldb/Host/MainLoop.h"
1214#include " lldb/Host/MainLoopBase.h"
15+ #include " lldb/Host/ProcessLaunchInfo.h"
1316#include " lldb/Host/Socket.h"
1417#include " lldb/Initialization/SystemInitializerCommon.h"
1518#include " lldb/Initialization/SystemLifetimeManager.h"
1619#include " lldb/Protocol/MCP/Server.h"
20+ #include " lldb/Utility/FileSpec.h"
1721#include " lldb/Utility/Status.h"
1822#include " lldb/Utility/UriParser.h"
1923#include " lldb/lldb-forward.h"
2428#include " llvm/Support/ManagedStatic.h"
2529#include " llvm/Support/Signals.h"
2630#include " llvm/Support/WithColor.h"
31+ #include < chrono>
2732#include < cstdlib>
2833#include < memory>
34+ #include < thread>
2935
3036#if defined(_WIN32)
3137#include < fcntl.h>
@@ -35,24 +41,93 @@ using namespace llvm;
3541using namespace lldb ;
3642using namespace lldb_protocol ::mcp;
3743
44+ using lldb_private::Environment;
3845using lldb_private::File;
46+ using lldb_private::FileSpec;
47+ using lldb_private::FileSystem;
48+ using lldb_private::Host;
3949using lldb_private::MainLoop;
4050using lldb_private::MainLoopBase;
4151using lldb_private::NativeFile;
4252
4353namespace {
4454
55+ #if defined(_WIN32)
56+ constexpr StringLiteral kDriverName = " lldb.exe" ;
57+ #else
58+ constexpr StringLiteral kDriverName = " lldb" ;
59+ #endif
60+
61+ constexpr size_t kForwardIOBufferSize = 1024 ;
62+
4563inline void exitWithError (llvm::Error Err, StringRef Prefix = " " ) {
4664 handleAllErrors (std::move (Err), [&](ErrorInfoBase &Info) {
4765 WithColor::error (errs (), Prefix) << Info.message () << ' \n ' ;
4866 });
4967 std::exit (EXIT_FAILURE);
5068}
5169
52- constexpr size_t kForwardIOBufferSize = 1024 ;
70+ FileSpec driverPath () {
71+ Environment host_env = Host::GetEnvironment ();
72+
73+ // Check if an override for which lldb we're using exists, otherwise look next
74+ // to the current binary.
75+ std::string lldb_exe_path = host_env.lookup (" LLDB_EXE_PATH" );
76+ auto &fs = FileSystem::Instance ();
77+ if (fs.Exists (lldb_exe_path))
78+ return FileSpec (lldb_exe_path);
79+
80+ FileSpec lldb_exec_spec = lldb_private::HostInfo::GetProgramFileSpec ();
81+ lldb_exec_spec.SetFilename (kDriverName );
82+ return lldb_exec_spec;
83+ }
84+
85+ llvm::Error launch () {
86+ FileSpec lldb_exec = driverPath ();
87+ lldb_private::ProcessLaunchInfo info;
88+ info.SetExecutableFile (lldb_exec,
89+ /* add_exe_file_as_first_arg=*/ true );
90+ info.GetArguments ().AppendArgument (" -O" );
91+ info.GetArguments ().AppendArgument (" protocol start MCP" );
92+ return Host::LaunchProcess (info).takeError ();
93+ }
94+
95+ Expected<ServerInfo> loadOrStart (
96+ // FIXME: This should become a CLI arg.
97+ lldb_private::Timeout<std::micro> timeout = std::chrono::seconds(30 )) {
98+ using namespace std ::chrono;
99+ bool started = false ;
100+
101+ const auto deadline = steady_clock::now () + *timeout;
102+ while (steady_clock::now () < deadline) {
103+ Expected<std::vector<ServerInfo>> servers = ServerInfo::Load ();
104+ if (!servers)
105+ return servers.takeError ();
106+
107+ if (servers->empty ()) {
108+ if (!started) {
109+ started = true ;
110+ if (llvm::Error err = launch ())
111+ return std::move (err);
112+ }
113+
114+ // FIXME: Can we use MainLoop to watch the directory?
115+ std::this_thread::sleep_for (microseconds (250 ));
116+ continue ;
117+ }
118+
119+ // FIXME: Support selecting / multiplexing a specific lldb instance.
120+ if (servers->size () > 1 )
121+ return createStringError (" too many MCP servers running, picking a "
122+ " specific one is not yet implemented" );
123+
124+ return servers->front ();
125+ }
126+
127+ return createStringError (" timed out waiting for MCP server to start" );
128+ }
53129
54- void forwardIO (lldb_private::MainLoopBase &loop, lldb::IOObjectSP &from,
55- lldb::IOObjectSP &to) {
130+ void forwardIO (MainLoopBase &loop, IOObjectSP &from, IOObjectSP &to) {
56131 char buf[kForwardIOBufferSize ];
57132 size_t num_bytes = sizeof (buf);
58133
@@ -67,46 +142,47 @@ void forwardIO(lldb_private::MainLoopBase &loop, lldb::IOObjectSP &from,
67142 exitWithError (std::move (err));
68143}
69144
70- void connectAndForwardIO (lldb_private::MainLoop &loop, ServerInfo &info,
71- IOObjectSP &input_sp, IOObjectSP &output_sp) {
145+ llvm::Error connectAndForwardIO (lldb_private::MainLoop &loop, ServerInfo &info,
146+ IOObjectSP &input_sp, IOObjectSP &output_sp) {
72147 auto uri = lldb_private::URI::Parse (info.connection_uri );
73148 if (!uri)
74- exitWithError ( createStringError (" invalid connection_uri" ) );
149+ return createStringError (" invalid connection_uri" );
75150
76151 std::optional<lldb_private::Socket::ProtocolModePair> protocol_and_mode =
77152 lldb_private::Socket::GetProtocolAndMode (uri->scheme );
78153
154+ if (!protocol_and_mode)
155+ return createStringError (" unknown protocol scheme" );
156+
79157 lldb_private::Status status;
80158 std::unique_ptr<lldb_private::Socket> sock =
81159 lldb_private::Socket::Create (protocol_and_mode->first , status);
82160
83161 if (status.Fail ())
84- exitWithError ( status.takeError () );
162+ return status.takeError ();
85163
86164 if (uri->port && !uri->hostname .empty ())
87165 status = sock->Connect (
88166 llvm::formatv (" [{0}]:{1}" , uri->hostname , *uri->port ).str ());
89167 else
90168 status = sock->Connect (uri->path );
91169 if (status.Fail ())
92- exitWithError ( status.takeError () );
170+ return status.takeError ();
93171
94172 IOObjectSP sock_sp = std::move (sock);
95173 auto input_handle = loop.RegisterReadObject (
96174 input_sp, std::bind (forwardIO, std::placeholders::_1, input_sp, sock_sp),
97175 status);
98176 if (status.Fail ())
99- exitWithError ( status.takeError () );
177+ return status.takeError ();
100178
101179 auto socket_handle = loop.RegisterReadObject (
102180 sock_sp, std::bind (forwardIO, std::placeholders::_1, sock_sp, output_sp),
103181 status);
104182 if (status.Fail ())
105- exitWithError ( status.takeError () );
183+ return status.takeError ();
106184
107- status = loop.Run ();
108- if (status.Fail ())
109- exitWithError (status.takeError ());
185+ return loop.Run ().takeError ();
110186}
111187
112188llvm::ManagedStatic<lldb_private::SystemLifetimeManager> g_debugger_lifetime;
@@ -147,30 +223,19 @@ int main(int argc, char *argv[]) {
147223 IOObjectSP output_sp = std::make_shared<NativeFile>(
148224 fileno (stdout), File::eOpenOptionWriteOnly, NativeFile::Unowned);
149225
150- static MainLoop loop;
226+ Expected<ServerInfo> server_info = loadOrStart ();
227+ if (!server_info)
228+ exitWithError (server_info.takeError ());
151229
230+ static MainLoop loop;
152231 sys::SetInterruptFunction ([]() {
153232 loop.AddPendingCallback (
154233 [](MainLoopBase &loop) { loop.RequestTermination (); });
155234 });
156235
157- auto existing_servers = ServerInfo::Load ();
158-
159- if (!existing_servers)
160- exitWithError (existing_servers.takeError ());
161-
162- // FIXME: Launch `lldb -o 'protocol start MCP'`.
163- if (existing_servers->empty ())
164- exitWithError (createStringError (" No MCP servers running" ));
165-
166- // FIXME: Support selecting a specific server.
167- if (existing_servers->size () != 1 )
168- exitWithError (
169- createStringError (" To many MCP servers running, picking a specific "
170- " one is not yet implemented." ));
171-
172- ServerInfo &info = existing_servers->front ();
173- connectAndForwardIO (loop, info, input_sp, output_sp);
236+ if (llvm::Error error =
237+ connectAndForwardIO (loop, *server_info, input_sp, output_sp))
238+ exitWithError (std::move (error));
174239
175240 return EXIT_SUCCESS;
176241}
0 commit comments