1061da546Spatrick //===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9a0747c9fSpatrick #include <cerrno>
10a0747c9fSpatrick #include <cstdint>
11a0747c9fSpatrick #include <cstdio>
12a0747c9fSpatrick #include <cstdlib>
13a0747c9fSpatrick #include <cstring>
14061da546Spatrick
15061da546Spatrick #ifndef _WIN32
16a0747c9fSpatrick #include <csignal>
17061da546Spatrick #include <unistd.h>
18061da546Spatrick #endif
19061da546Spatrick
20061da546Spatrick #include "LLDBServerUtilities.h"
21061da546Spatrick #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
22061da546Spatrick #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
23061da546Spatrick #include "lldb/Host/Config.h"
24061da546Spatrick #include "lldb/Host/ConnectionFileDescriptor.h"
25061da546Spatrick #include "lldb/Host/FileSystem.h"
26061da546Spatrick #include "lldb/Host/Pipe.h"
27061da546Spatrick #include "lldb/Host/Socket.h"
28061da546Spatrick #include "lldb/Host/common/NativeProcessProtocol.h"
29061da546Spatrick #include "lldb/Target/Process.h"
30*101d251dSrobert #include "lldb/Utility/LLDBLog.h"
31061da546Spatrick #include "lldb/Utility/Status.h"
32061da546Spatrick #include "llvm/ADT/StringRef.h"
33a0747c9fSpatrick #include "llvm/Option/ArgList.h"
34a0747c9fSpatrick #include "llvm/Option/OptTable.h"
35a0747c9fSpatrick #include "llvm/Option/Option.h"
36061da546Spatrick #include "llvm/Support/Errno.h"
37a0747c9fSpatrick #include "llvm/Support/WithColor.h"
38061da546Spatrick
39061da546Spatrick #if defined(__linux__)
40061da546Spatrick #include "Plugins/Process/Linux/NativeProcessLinux.h"
41a0747c9fSpatrick #elif defined(__FreeBSD__)
42a0747c9fSpatrick #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
43061da546Spatrick #elif defined(__NetBSD__)
44061da546Spatrick #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
45adae0cfdSpatrick #elif defined(__OpenBSD__)
46adae0cfdSpatrick #include "Plugins/Process/OpenBSD/NativeProcessOpenBSD.h"
47061da546Spatrick #elif defined(_WIN32)
48061da546Spatrick #include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
49061da546Spatrick #endif
50061da546Spatrick
51061da546Spatrick #ifndef LLGS_PROGRAM_NAME
52061da546Spatrick #define LLGS_PROGRAM_NAME "lldb-server"
53061da546Spatrick #endif
54061da546Spatrick
55061da546Spatrick #ifndef LLGS_VERSION_STR
56061da546Spatrick #define LLGS_VERSION_STR "local_build"
57061da546Spatrick #endif
58061da546Spatrick
59061da546Spatrick using namespace llvm;
60061da546Spatrick using namespace lldb;
61061da546Spatrick using namespace lldb_private;
62061da546Spatrick using namespace lldb_private::lldb_server;
63061da546Spatrick using namespace lldb_private::process_gdb_remote;
64061da546Spatrick
65061da546Spatrick namespace {
66061da546Spatrick #if defined(__linux__)
67061da546Spatrick typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory;
68a0747c9fSpatrick #elif defined(__FreeBSD__)
69a0747c9fSpatrick typedef process_freebsd::NativeProcessFreeBSD::Factory NativeProcessFactory;
70061da546Spatrick #elif defined(__NetBSD__)
71061da546Spatrick typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory;
72adae0cfdSpatrick #elif defined(__OpenBSD__)
73adae0cfdSpatrick typedef process_openbsd::NativeProcessOpenBSD::Factory NativeProcessFactory;
74061da546Spatrick #elif defined(_WIN32)
75061da546Spatrick typedef NativeProcessWindows::Factory NativeProcessFactory;
76061da546Spatrick #else
77061da546Spatrick // Dummy implementation to make sure the code compiles
78061da546Spatrick class NativeProcessFactory : public NativeProcessProtocol::Factory {
79061da546Spatrick public:
80061da546Spatrick llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
81061da546Spatrick Launch(ProcessLaunchInfo &launch_info,
82061da546Spatrick NativeProcessProtocol::NativeDelegate &delegate,
83061da546Spatrick MainLoop &mainloop) const override {
84061da546Spatrick llvm_unreachable("Not implemented");
85061da546Spatrick }
86061da546Spatrick llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
87061da546Spatrick Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate,
88061da546Spatrick MainLoop &mainloop) const override {
89061da546Spatrick llvm_unreachable("Not implemented");
90061da546Spatrick }
91061da546Spatrick };
92061da546Spatrick #endif
93061da546Spatrick }
94061da546Spatrick
95061da546Spatrick #ifndef _WIN32
96061da546Spatrick // Watch for signals
97061da546Spatrick static int g_sighup_received_count = 0;
98061da546Spatrick
sighup_handler(MainLoopBase & mainloop)99061da546Spatrick static void sighup_handler(MainLoopBase &mainloop) {
100061da546Spatrick ++g_sighup_received_count;
101061da546Spatrick
102*101d251dSrobert Log *log = GetLog(LLDBLog::Process);
103061da546Spatrick LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)",
104061da546Spatrick __FUNCTION__, g_sighup_received_count);
105061da546Spatrick
106061da546Spatrick if (g_sighup_received_count >= 2)
107061da546Spatrick mainloop.RequestTermination();
108061da546Spatrick }
109061da546Spatrick #endif // #ifndef _WIN32
110061da546Spatrick
handle_attach_to_pid(GDBRemoteCommunicationServerLLGS & gdb_server,lldb::pid_t pid)111061da546Spatrick void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server,
112061da546Spatrick lldb::pid_t pid) {
113061da546Spatrick Status error = gdb_server.AttachToProcess(pid);
114061da546Spatrick if (error.Fail()) {
115061da546Spatrick fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid,
116061da546Spatrick error.AsCString());
117061da546Spatrick exit(1);
118061da546Spatrick }
119061da546Spatrick }
120061da546Spatrick
handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS & gdb_server,const std::string & process_name)121061da546Spatrick void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server,
122061da546Spatrick const std::string &process_name) {
123061da546Spatrick // FIXME implement.
124061da546Spatrick }
125061da546Spatrick
handle_attach(GDBRemoteCommunicationServerLLGS & gdb_server,const std::string & attach_target)126061da546Spatrick void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server,
127061da546Spatrick const std::string &attach_target) {
128061da546Spatrick assert(!attach_target.empty() && "attach_target cannot be empty");
129061da546Spatrick
130061da546Spatrick // First check if the attach_target is convertible to a long. If so, we'll use
131061da546Spatrick // it as a pid.
132061da546Spatrick char *end_p = nullptr;
133061da546Spatrick const long int pid = strtol(attach_target.c_str(), &end_p, 10);
134061da546Spatrick
135061da546Spatrick // We'll call it a match if the entire argument is consumed.
136061da546Spatrick if (end_p &&
137061da546Spatrick static_cast<size_t>(end_p - attach_target.c_str()) ==
138061da546Spatrick attach_target.size())
139061da546Spatrick handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid));
140061da546Spatrick else
141061da546Spatrick handle_attach_to_process_name(gdb_server, attach_target);
142061da546Spatrick }
143061da546Spatrick
handle_launch(GDBRemoteCommunicationServerLLGS & gdb_server,llvm::ArrayRef<llvm::StringRef> Arguments)144a0747c9fSpatrick void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server,
145a0747c9fSpatrick llvm::ArrayRef<llvm::StringRef> Arguments) {
146061da546Spatrick ProcessLaunchInfo info;
147061da546Spatrick info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug |
148061da546Spatrick eLaunchFlagDisableASLR);
149a0747c9fSpatrick info.SetArguments(Args(Arguments), true);
150061da546Spatrick
151061da546Spatrick llvm::SmallString<64> cwd;
152061da546Spatrick if (std::error_code ec = llvm::sys::fs::current_path(cwd)) {
153061da546Spatrick llvm::errs() << "Error getting current directory: " << ec.message() << "\n";
154061da546Spatrick exit(1);
155061da546Spatrick }
156061da546Spatrick FileSpec cwd_spec(cwd);
157061da546Spatrick FileSystem::Instance().Resolve(cwd_spec);
158061da546Spatrick info.SetWorkingDirectory(cwd_spec);
159061da546Spatrick info.GetEnvironment() = Host::GetEnvironment();
160061da546Spatrick
161061da546Spatrick gdb_server.SetLaunchInfo(info);
162061da546Spatrick
163061da546Spatrick Status error = gdb_server.LaunchProcess();
164061da546Spatrick if (error.Fail()) {
165061da546Spatrick llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n",
166a0747c9fSpatrick Arguments[0], error);
167061da546Spatrick exit(1);
168061da546Spatrick }
169061da546Spatrick }
170061da546Spatrick
writeSocketIdToPipe(Pipe & port_pipe,llvm::StringRef socket_id)171*101d251dSrobert Status writeSocketIdToPipe(Pipe &port_pipe, llvm::StringRef socket_id) {
172061da546Spatrick size_t bytes_written = 0;
173061da546Spatrick // Write the port number as a C string with the NULL terminator.
174*101d251dSrobert return port_pipe.Write(socket_id.data(), socket_id.size() + 1, bytes_written);
175061da546Spatrick }
176061da546Spatrick
writeSocketIdToPipe(const char * const named_pipe_path,llvm::StringRef socket_id)177061da546Spatrick Status writeSocketIdToPipe(const char *const named_pipe_path,
178*101d251dSrobert llvm::StringRef socket_id) {
179061da546Spatrick Pipe port_name_pipe;
180061da546Spatrick // Wait for 10 seconds for pipe to be opened.
181061da546Spatrick auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
182061da546Spatrick std::chrono::seconds{10});
183061da546Spatrick if (error.Fail())
184061da546Spatrick return error;
185061da546Spatrick return writeSocketIdToPipe(port_name_pipe, socket_id);
186061da546Spatrick }
187061da546Spatrick
writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,llvm::StringRef socket_id)188061da546Spatrick Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
189*101d251dSrobert llvm::StringRef socket_id) {
190061da546Spatrick Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
191061da546Spatrick return writeSocketIdToPipe(port_pipe, socket_id);
192061da546Spatrick }
193061da546Spatrick
ConnectToRemote(MainLoop & mainloop,GDBRemoteCommunicationServerLLGS & gdb_server,bool reverse_connect,llvm::StringRef host_and_port,const char * const progname,const char * const subcommand,const char * const named_pipe_path,pipe_t unnamed_pipe,int connection_fd)194061da546Spatrick void ConnectToRemote(MainLoop &mainloop,
195061da546Spatrick GDBRemoteCommunicationServerLLGS &gdb_server,
196a0747c9fSpatrick bool reverse_connect, llvm::StringRef host_and_port,
197061da546Spatrick const char *const progname, const char *const subcommand,
198061da546Spatrick const char *const named_pipe_path, pipe_t unnamed_pipe,
199061da546Spatrick int connection_fd) {
200061da546Spatrick Status error;
201061da546Spatrick
202061da546Spatrick std::unique_ptr<Connection> connection_up;
203*101d251dSrobert std::string url;
204*101d251dSrobert
205061da546Spatrick if (connection_fd != -1) {
206*101d251dSrobert url = llvm::formatv("fd://{0}", connection_fd).str();
207061da546Spatrick
208061da546Spatrick // Create the connection.
209061da546Spatrick #if LLDB_ENABLE_POSIX && !defined _WIN32
210061da546Spatrick ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC);
211061da546Spatrick #endif
212a0747c9fSpatrick } else if (!host_and_port.empty()) {
213*101d251dSrobert llvm::Expected<std::string> url_exp =
214*101d251dSrobert LLGSArgToURL(host_and_port, reverse_connect);
215*101d251dSrobert if (!url_exp) {
216*101d251dSrobert llvm::errs() << llvm::formatv("error: invalid host:port or URL '{0}': "
217*101d251dSrobert "{1}\n",
218*101d251dSrobert host_and_port,
219*101d251dSrobert llvm::toString(url_exp.takeError()));
220061da546Spatrick exit(-1);
221061da546Spatrick }
222*101d251dSrobert
223*101d251dSrobert url = std::move(url_exp.get());
224061da546Spatrick }
225*101d251dSrobert
226*101d251dSrobert if (!url.empty()) {
227*101d251dSrobert // Create the connection or server.
228*101d251dSrobert std::unique_ptr<ConnectionFileDescriptor> conn_fd_up{
229*101d251dSrobert new ConnectionFileDescriptor};
230*101d251dSrobert auto connection_result = conn_fd_up->Connect(
231*101d251dSrobert url,
232*101d251dSrobert [named_pipe_path, unnamed_pipe](llvm::StringRef socket_id) {
233*101d251dSrobert // If we have a named pipe to write the socket id back to, do that
234*101d251dSrobert // now.
235061da546Spatrick if (named_pipe_path && named_pipe_path[0]) {
236*101d251dSrobert Status error = writeSocketIdToPipe(named_pipe_path, socket_id);
237061da546Spatrick if (error.Fail())
238*101d251dSrobert llvm::errs() << llvm::formatv(
239*101d251dSrobert "failed to write to the named peipe '{0}': {1}\n",
240061da546Spatrick named_pipe_path, error.AsCString());
241061da546Spatrick }
242*101d251dSrobert // If we have an unnamed pipe to write the socket id back to, do
243*101d251dSrobert // that now.
244061da546Spatrick else if (unnamed_pipe != LLDB_INVALID_PIPE) {
245*101d251dSrobert Status error = writeSocketIdToPipe(unnamed_pipe, socket_id);
246061da546Spatrick if (error.Fail())
247*101d251dSrobert llvm::errs() << llvm::formatv(
248*101d251dSrobert "failed to write to the unnamed pipe: {0}\n", error);
249061da546Spatrick }
250*101d251dSrobert },
251*101d251dSrobert &error);
252061da546Spatrick
253061da546Spatrick if (error.Fail()) {
254*101d251dSrobert llvm::errs() << llvm::formatv(
255*101d251dSrobert "error: failed to connect to client at '{0}': {1}\n", url, error);
256*101d251dSrobert exit(-1);
257061da546Spatrick }
258*101d251dSrobert if (connection_result != eConnectionStatusSuccess) {
259*101d251dSrobert llvm::errs() << llvm::formatv(
260*101d251dSrobert "error: failed to connect to client at '{0}' "
261*101d251dSrobert "(connection status: {1})\n",
262*101d251dSrobert url, static_cast<int>(connection_result));
263*101d251dSrobert exit(-1);
264061da546Spatrick }
265*101d251dSrobert connection_up = std::move(conn_fd_up);
266061da546Spatrick }
267061da546Spatrick error = gdb_server.InitializeConnection(std::move(connection_up));
268061da546Spatrick if (error.Fail()) {
269*101d251dSrobert llvm::errs() << llvm::formatv("failed to initialize connection\n", error);
270061da546Spatrick exit(-1);
271061da546Spatrick }
272*101d251dSrobert llvm::outs() << "Connection established.\n";
273061da546Spatrick }
274061da546Spatrick
275a0747c9fSpatrick namespace {
276a0747c9fSpatrick enum ID {
277a0747c9fSpatrick OPT_INVALID = 0, // This is not an option ID.
278a0747c9fSpatrick #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
279a0747c9fSpatrick HELPTEXT, METAVAR, VALUES) \
280a0747c9fSpatrick OPT_##ID,
281a0747c9fSpatrick #include "LLGSOptions.inc"
282a0747c9fSpatrick #undef OPTION
283a0747c9fSpatrick };
284a0747c9fSpatrick
285*101d251dSrobert #define PREFIX(NAME, VALUE) \
286*101d251dSrobert constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
287*101d251dSrobert constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
288*101d251dSrobert NAME##_init, std::size(NAME##_init) - 1);
289a0747c9fSpatrick #include "LLGSOptions.inc"
290a0747c9fSpatrick #undef PREFIX
291a0747c9fSpatrick
292*101d251dSrobert static constexpr opt::OptTable::Info InfoTable[] = {
293a0747c9fSpatrick #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
294a0747c9fSpatrick HELPTEXT, METAVAR, VALUES) \
295a0747c9fSpatrick { \
296a0747c9fSpatrick PREFIX, NAME, HELPTEXT, \
297a0747c9fSpatrick METAVAR, OPT_##ID, opt::Option::KIND##Class, \
298a0747c9fSpatrick PARAM, FLAGS, OPT_##GROUP, \
299a0747c9fSpatrick OPT_##ALIAS, ALIASARGS, VALUES},
300a0747c9fSpatrick #include "LLGSOptions.inc"
301a0747c9fSpatrick #undef OPTION
302a0747c9fSpatrick };
303a0747c9fSpatrick
304*101d251dSrobert class LLGSOptTable : public opt::GenericOptTable {
305a0747c9fSpatrick public:
LLGSOptTable()306*101d251dSrobert LLGSOptTable() : opt::GenericOptTable(InfoTable) {}
307a0747c9fSpatrick
PrintHelp(llvm::StringRef Name)308a0747c9fSpatrick void PrintHelp(llvm::StringRef Name) {
309a0747c9fSpatrick std::string Usage =
310a0747c9fSpatrick (Name + " [options] [[host]:port] [[--] program args...]").str();
311a0747c9fSpatrick OptTable::printHelp(llvm::outs(), Usage.c_str(), "lldb-server");
312a0747c9fSpatrick llvm::outs() << R"(
313a0747c9fSpatrick DESCRIPTION
314a0747c9fSpatrick lldb-server connects to the LLDB client, which drives the debugging session.
315a0747c9fSpatrick If no connection options are given, the [host]:port argument must be present
316a0747c9fSpatrick and will denote the address that lldb-server will listen on. [host] defaults
317a0747c9fSpatrick to "localhost" if empty. Port can be zero, in which case the port number will
318a0747c9fSpatrick be chosen dynamically and written to destinations given by --named-pipe and
319a0747c9fSpatrick --pipe arguments.
320a0747c9fSpatrick
321a0747c9fSpatrick If no target is selected at startup, lldb-server can be directed by the LLDB
322a0747c9fSpatrick client to launch or attach to a process.
323a0747c9fSpatrick
324a0747c9fSpatrick )";
325a0747c9fSpatrick }
326a0747c9fSpatrick };
327a0747c9fSpatrick } // namespace
328a0747c9fSpatrick
main_gdbserver(int argc,char * argv[])329061da546Spatrick int main_gdbserver(int argc, char *argv[]) {
330061da546Spatrick Status error;
331061da546Spatrick MainLoop mainloop;
332061da546Spatrick #ifndef _WIN32
333061da546Spatrick // Setup signal handlers first thing.
334061da546Spatrick signal(SIGPIPE, SIG_IGN);
335061da546Spatrick MainLoop::SignalHandleUP sighup_handle =
336061da546Spatrick mainloop.RegisterSignal(SIGHUP, sighup_handler, error);
337061da546Spatrick #endif
338061da546Spatrick
339061da546Spatrick const char *progname = argv[0];
340061da546Spatrick const char *subcommand = argv[1];
341061da546Spatrick std::string attach_target;
342061da546Spatrick std::string named_pipe_path;
343061da546Spatrick std::string log_file;
344061da546Spatrick StringRef
345061da546Spatrick log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
346061da546Spatrick lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE;
347061da546Spatrick bool reverse_connect = false;
348061da546Spatrick int connection_fd = -1;
349061da546Spatrick
350061da546Spatrick // ProcessLaunchInfo launch_info;
351061da546Spatrick ProcessAttachInfo attach_info;
352061da546Spatrick
353a0747c9fSpatrick LLGSOptTable Opts;
354a0747c9fSpatrick llvm::BumpPtrAllocator Alloc;
355a0747c9fSpatrick llvm::StringSaver Saver(Alloc);
356a0747c9fSpatrick bool HasError = false;
357a0747c9fSpatrick opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN,
358a0747c9fSpatrick Saver, [&](llvm::StringRef Msg) {
359a0747c9fSpatrick WithColor::error() << Msg << "\n";
360a0747c9fSpatrick HasError = true;
361a0747c9fSpatrick });
362a0747c9fSpatrick std::string Name =
363a0747c9fSpatrick (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str();
364a0747c9fSpatrick std::string HelpText =
365a0747c9fSpatrick "Use '" + Name + " --help' for a complete list of options.\n";
366a0747c9fSpatrick if (HasError) {
367a0747c9fSpatrick llvm::errs() << HelpText;
368a0747c9fSpatrick return 1;
369a0747c9fSpatrick }
370061da546Spatrick
371a0747c9fSpatrick if (Args.hasArg(OPT_help)) {
372a0747c9fSpatrick Opts.PrintHelp(Name);
373a0747c9fSpatrick return 0;
374a0747c9fSpatrick }
375061da546Spatrick
376061da546Spatrick #ifndef _WIN32
377a0747c9fSpatrick if (Args.hasArg(OPT_setsid)) {
378061da546Spatrick // Put llgs into a new session. Terminals group processes
379061da546Spatrick // into sessions and when a special terminal key sequences
380061da546Spatrick // (like control+c) are typed they can cause signals to go out to
381061da546Spatrick // all processes in a session. Using this --setsid (-S) option
382061da546Spatrick // will cause debugserver to run in its own sessions and be free
383061da546Spatrick // from such issues.
384061da546Spatrick //
385061da546Spatrick // This is useful when llgs is spawned from a command
386061da546Spatrick // line application that uses llgs to do the debugging,
387061da546Spatrick // yet that application doesn't want llgs receiving the
388061da546Spatrick // signals sent to the session (i.e. dying when anyone hits ^C).
389061da546Spatrick {
390061da546Spatrick const ::pid_t new_sid = setsid();
391061da546Spatrick if (new_sid == -1) {
392a0747c9fSpatrick WithColor::warning()
393a0747c9fSpatrick << llvm::formatv("failed to set new session id for {0} ({1})\n",
394a0747c9fSpatrick LLGS_PROGRAM_NAME, llvm::sys::StrError());
395061da546Spatrick }
396061da546Spatrick }
397a0747c9fSpatrick }
398061da546Spatrick #endif
399061da546Spatrick
400a0747c9fSpatrick log_file = Args.getLastArgValue(OPT_log_file).str();
401a0747c9fSpatrick log_channels = Args.getLastArgValue(OPT_log_channels);
402a0747c9fSpatrick named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str();
403a0747c9fSpatrick reverse_connect = Args.hasArg(OPT_reverse_connect);
404a0747c9fSpatrick attach_target = Args.getLastArgValue(OPT_attach).str();
405a0747c9fSpatrick if (Args.hasArg(OPT_pipe)) {
406a0747c9fSpatrick uint64_t Arg;
407a0747c9fSpatrick if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) {
408a0747c9fSpatrick WithColor::error() << "invalid '--pipe' argument\n" << HelpText;
409a0747c9fSpatrick return 1;
410061da546Spatrick }
411a0747c9fSpatrick unnamed_pipe = (pipe_t)Arg;
412061da546Spatrick }
413a0747c9fSpatrick if (Args.hasArg(OPT_fd)) {
414a0747c9fSpatrick if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), connection_fd)) {
415a0747c9fSpatrick WithColor::error() << "invalid '--fd' argument\n" << HelpText;
416a0747c9fSpatrick return 1;
417a0747c9fSpatrick }
418061da546Spatrick }
419061da546Spatrick
420061da546Spatrick if (!LLDBServerUtilities::SetupLogging(
421061da546Spatrick log_file, log_channels,
422061da546Spatrick LLDB_LOG_OPTION_PREPEND_TIMESTAMP |
423061da546Spatrick LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION))
424061da546Spatrick return -1;
425061da546Spatrick
426a0747c9fSpatrick std::vector<llvm::StringRef> Inputs;
427a0747c9fSpatrick for (opt::Arg *Arg : Args.filtered(OPT_INPUT))
428a0747c9fSpatrick Inputs.push_back(Arg->getValue());
429a0747c9fSpatrick if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) {
430a0747c9fSpatrick for (const char *Val : Arg->getValues())
431a0747c9fSpatrick Inputs.push_back(Val);
432061da546Spatrick }
433a0747c9fSpatrick if (Inputs.empty() && connection_fd == -1) {
434a0747c9fSpatrick WithColor::error() << "no connection arguments\n" << HelpText;
435a0747c9fSpatrick return 1;
436061da546Spatrick }
437061da546Spatrick
438061da546Spatrick NativeProcessFactory factory;
439061da546Spatrick GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory);
440061da546Spatrick
441a0747c9fSpatrick llvm::StringRef host_and_port;
442a0747c9fSpatrick if (!Inputs.empty()) {
443a0747c9fSpatrick host_and_port = Inputs.front();
444a0747c9fSpatrick Inputs.erase(Inputs.begin());
445a0747c9fSpatrick }
446061da546Spatrick
447061da546Spatrick // Any arguments left over are for the program that we need to launch. If
448061da546Spatrick // there
449061da546Spatrick // are no arguments, then the GDB server will start up and wait for an 'A'
450061da546Spatrick // packet
451061da546Spatrick // to launch a program, or a vAttach packet to attach to an existing process,
452061da546Spatrick // unless
453061da546Spatrick // explicitly asked to attach with the --attach={pid|program_name} form.
454061da546Spatrick if (!attach_target.empty())
455061da546Spatrick handle_attach(gdb_server, attach_target);
456a0747c9fSpatrick else if (!Inputs.empty())
457a0747c9fSpatrick handle_launch(gdb_server, Inputs);
458061da546Spatrick
459061da546Spatrick // Print version info.
460061da546Spatrick printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
461061da546Spatrick
462061da546Spatrick ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
463061da546Spatrick progname, subcommand, named_pipe_path.c_str(),
464061da546Spatrick unnamed_pipe, connection_fd);
465061da546Spatrick
466061da546Spatrick if (!gdb_server.IsConnected()) {
467061da546Spatrick fprintf(stderr, "no connection information provided, unable to run\n");
468061da546Spatrick return 1;
469061da546Spatrick }
470061da546Spatrick
471061da546Spatrick Status ret = mainloop.Run();
472061da546Spatrick if (ret.Fail()) {
473061da546Spatrick fprintf(stderr, "lldb-server terminating due to error: %s\n",
474061da546Spatrick ret.AsCString());
475061da546Spatrick return 1;
476061da546Spatrick }
477061da546Spatrick fprintf(stderr, "lldb-server exiting...\n");
478061da546Spatrick
479061da546Spatrick return 0;
480061da546Spatrick }
481