xref: /openbsd-src/gnu/llvm/lldb/tools/lldb-server/lldb-gdbserver.cpp (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
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 
9*a0747c9fSpatrick #include <cerrno>
10*a0747c9fSpatrick #include <cstdint>
11*a0747c9fSpatrick #include <cstdio>
12*a0747c9fSpatrick #include <cstdlib>
13*a0747c9fSpatrick #include <cstring>
14061da546Spatrick 
15061da546Spatrick #ifndef _WIN32
16*a0747c9fSpatrick #include <csignal>
17061da546Spatrick #include <unistd.h>
18061da546Spatrick #endif
19061da546Spatrick 
20061da546Spatrick #include "Acceptor.h"
21061da546Spatrick #include "LLDBServerUtilities.h"
22061da546Spatrick #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
23061da546Spatrick #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
24061da546Spatrick #include "lldb/Host/Config.h"
25061da546Spatrick #include "lldb/Host/ConnectionFileDescriptor.h"
26061da546Spatrick #include "lldb/Host/FileSystem.h"
27061da546Spatrick #include "lldb/Host/Pipe.h"
28061da546Spatrick #include "lldb/Host/Socket.h"
29061da546Spatrick #include "lldb/Host/StringConvert.h"
30061da546Spatrick #include "lldb/Host/common/NativeProcessProtocol.h"
31061da546Spatrick #include "lldb/Target/Process.h"
32061da546Spatrick #include "lldb/Utility/Status.h"
33061da546Spatrick #include "llvm/ADT/StringRef.h"
34*a0747c9fSpatrick #include "llvm/Option/ArgList.h"
35*a0747c9fSpatrick #include "llvm/Option/OptTable.h"
36*a0747c9fSpatrick #include "llvm/Option/Option.h"
37061da546Spatrick #include "llvm/Support/Errno.h"
38*a0747c9fSpatrick #include "llvm/Support/WithColor.h"
39061da546Spatrick 
40061da546Spatrick #if defined(__linux__)
41061da546Spatrick #include "Plugins/Process/Linux/NativeProcessLinux.h"
42*a0747c9fSpatrick #elif defined(__FreeBSD__)
43*a0747c9fSpatrick #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
44061da546Spatrick #elif defined(__NetBSD__)
45061da546Spatrick #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
46adae0cfdSpatrick #elif defined(__OpenBSD__)
47adae0cfdSpatrick #include "Plugins/Process/OpenBSD/NativeProcessOpenBSD.h"
48061da546Spatrick #elif defined(_WIN32)
49061da546Spatrick #include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
50061da546Spatrick #endif
51061da546Spatrick 
52061da546Spatrick #ifndef LLGS_PROGRAM_NAME
53061da546Spatrick #define LLGS_PROGRAM_NAME "lldb-server"
54061da546Spatrick #endif
55061da546Spatrick 
56061da546Spatrick #ifndef LLGS_VERSION_STR
57061da546Spatrick #define LLGS_VERSION_STR "local_build"
58061da546Spatrick #endif
59061da546Spatrick 
60061da546Spatrick using namespace llvm;
61061da546Spatrick using namespace lldb;
62061da546Spatrick using namespace lldb_private;
63061da546Spatrick using namespace lldb_private::lldb_server;
64061da546Spatrick using namespace lldb_private::process_gdb_remote;
65061da546Spatrick 
66061da546Spatrick namespace {
67061da546Spatrick #if defined(__linux__)
68061da546Spatrick typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory;
69*a0747c9fSpatrick #elif defined(__FreeBSD__)
70*a0747c9fSpatrick typedef process_freebsd::NativeProcessFreeBSD::Factory NativeProcessFactory;
71061da546Spatrick #elif defined(__NetBSD__)
72061da546Spatrick typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory;
73adae0cfdSpatrick #elif defined(__OpenBSD__)
74adae0cfdSpatrick typedef process_openbsd::NativeProcessOpenBSD::Factory NativeProcessFactory;
75061da546Spatrick #elif defined(_WIN32)
76061da546Spatrick typedef NativeProcessWindows::Factory NativeProcessFactory;
77061da546Spatrick #else
78061da546Spatrick // Dummy implementation to make sure the code compiles
79061da546Spatrick class NativeProcessFactory : public NativeProcessProtocol::Factory {
80061da546Spatrick public:
81061da546Spatrick   llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
82061da546Spatrick   Launch(ProcessLaunchInfo &launch_info,
83061da546Spatrick          NativeProcessProtocol::NativeDelegate &delegate,
84061da546Spatrick          MainLoop &mainloop) const override {
85061da546Spatrick     llvm_unreachable("Not implemented");
86061da546Spatrick   }
87061da546Spatrick   llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
88061da546Spatrick   Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate,
89061da546Spatrick          MainLoop &mainloop) const override {
90061da546Spatrick     llvm_unreachable("Not implemented");
91061da546Spatrick   }
92061da546Spatrick };
93061da546Spatrick #endif
94061da546Spatrick }
95061da546Spatrick 
96061da546Spatrick #ifndef _WIN32
97061da546Spatrick // Watch for signals
98061da546Spatrick static int g_sighup_received_count = 0;
99061da546Spatrick 
100061da546Spatrick static void sighup_handler(MainLoopBase &mainloop) {
101061da546Spatrick   ++g_sighup_received_count;
102061da546Spatrick 
103061da546Spatrick   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
104061da546Spatrick   LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)",
105061da546Spatrick             __FUNCTION__, g_sighup_received_count);
106061da546Spatrick 
107061da546Spatrick   if (g_sighup_received_count >= 2)
108061da546Spatrick     mainloop.RequestTermination();
109061da546Spatrick }
110061da546Spatrick #endif // #ifndef _WIN32
111061da546Spatrick 
112061da546Spatrick void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server,
113061da546Spatrick                           lldb::pid_t pid) {
114061da546Spatrick   Status error = gdb_server.AttachToProcess(pid);
115061da546Spatrick   if (error.Fail()) {
116061da546Spatrick     fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid,
117061da546Spatrick             error.AsCString());
118061da546Spatrick     exit(1);
119061da546Spatrick   }
120061da546Spatrick }
121061da546Spatrick 
122061da546Spatrick void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server,
123061da546Spatrick                                    const std::string &process_name) {
124061da546Spatrick   // FIXME implement.
125061da546Spatrick }
126061da546Spatrick 
127061da546Spatrick void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server,
128061da546Spatrick                    const std::string &attach_target) {
129061da546Spatrick   assert(!attach_target.empty() && "attach_target cannot be empty");
130061da546Spatrick 
131061da546Spatrick   // First check if the attach_target is convertible to a long. If so, we'll use
132061da546Spatrick   // it as a pid.
133061da546Spatrick   char *end_p = nullptr;
134061da546Spatrick   const long int pid = strtol(attach_target.c_str(), &end_p, 10);
135061da546Spatrick 
136061da546Spatrick   // We'll call it a match if the entire argument is consumed.
137061da546Spatrick   if (end_p &&
138061da546Spatrick       static_cast<size_t>(end_p - attach_target.c_str()) ==
139061da546Spatrick           attach_target.size())
140061da546Spatrick     handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid));
141061da546Spatrick   else
142061da546Spatrick     handle_attach_to_process_name(gdb_server, attach_target);
143061da546Spatrick }
144061da546Spatrick 
145*a0747c9fSpatrick void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server,
146*a0747c9fSpatrick                    llvm::ArrayRef<llvm::StringRef> Arguments) {
147061da546Spatrick   ProcessLaunchInfo info;
148061da546Spatrick   info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug |
149061da546Spatrick                       eLaunchFlagDisableASLR);
150*a0747c9fSpatrick   info.SetArguments(Args(Arguments), true);
151061da546Spatrick 
152061da546Spatrick   llvm::SmallString<64> cwd;
153061da546Spatrick   if (std::error_code ec = llvm::sys::fs::current_path(cwd)) {
154061da546Spatrick     llvm::errs() << "Error getting current directory: " << ec.message() << "\n";
155061da546Spatrick     exit(1);
156061da546Spatrick   }
157061da546Spatrick   FileSpec cwd_spec(cwd);
158061da546Spatrick   FileSystem::Instance().Resolve(cwd_spec);
159061da546Spatrick   info.SetWorkingDirectory(cwd_spec);
160061da546Spatrick   info.GetEnvironment() = Host::GetEnvironment();
161061da546Spatrick 
162061da546Spatrick   gdb_server.SetLaunchInfo(info);
163061da546Spatrick 
164061da546Spatrick   Status error = gdb_server.LaunchProcess();
165061da546Spatrick   if (error.Fail()) {
166061da546Spatrick     llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n",
167*a0747c9fSpatrick                                   Arguments[0], error);
168061da546Spatrick     exit(1);
169061da546Spatrick   }
170061da546Spatrick }
171061da546Spatrick 
172061da546Spatrick Status writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) {
173061da546Spatrick   size_t bytes_written = 0;
174061da546Spatrick   // Write the port number as a C string with the NULL terminator.
175061da546Spatrick   return port_pipe.Write(socket_id.c_str(), socket_id.size() + 1,
176061da546Spatrick                          bytes_written);
177061da546Spatrick }
178061da546Spatrick 
179061da546Spatrick Status writeSocketIdToPipe(const char *const named_pipe_path,
180061da546Spatrick                            const std::string &socket_id) {
181061da546Spatrick   Pipe port_name_pipe;
182061da546Spatrick   // Wait for 10 seconds for pipe to be opened.
183061da546Spatrick   auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
184061da546Spatrick                                                       std::chrono::seconds{10});
185061da546Spatrick   if (error.Fail())
186061da546Spatrick     return error;
187061da546Spatrick   return writeSocketIdToPipe(port_name_pipe, socket_id);
188061da546Spatrick }
189061da546Spatrick 
190061da546Spatrick Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
191061da546Spatrick                            const std::string &socket_id) {
192061da546Spatrick   Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
193061da546Spatrick   return writeSocketIdToPipe(port_pipe, socket_id);
194061da546Spatrick }
195061da546Spatrick 
196061da546Spatrick void ConnectToRemote(MainLoop &mainloop,
197061da546Spatrick                      GDBRemoteCommunicationServerLLGS &gdb_server,
198*a0747c9fSpatrick                      bool reverse_connect, llvm::StringRef host_and_port,
199061da546Spatrick                      const char *const progname, const char *const subcommand,
200061da546Spatrick                      const char *const named_pipe_path, pipe_t unnamed_pipe,
201061da546Spatrick                      int connection_fd) {
202061da546Spatrick   Status error;
203061da546Spatrick 
204061da546Spatrick   std::unique_ptr<Connection> connection_up;
205061da546Spatrick   if (connection_fd != -1) {
206061da546Spatrick     // Build the connection string.
207061da546Spatrick     char connection_url[512];
208061da546Spatrick     snprintf(connection_url, sizeof(connection_url), "fd://%d", connection_fd);
209061da546Spatrick 
210061da546Spatrick     // Create the connection.
211061da546Spatrick #if LLDB_ENABLE_POSIX && !defined _WIN32
212061da546Spatrick     ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC);
213061da546Spatrick #endif
214061da546Spatrick     connection_up.reset(new ConnectionFileDescriptor);
215061da546Spatrick     auto connection_result = connection_up->Connect(connection_url, &error);
216061da546Spatrick     if (connection_result != eConnectionStatusSuccess) {
217061da546Spatrick       fprintf(stderr, "error: failed to connect to client at '%s' "
218061da546Spatrick                       "(connection status: %d)\n",
219061da546Spatrick               connection_url, static_cast<int>(connection_result));
220061da546Spatrick       exit(-1);
221061da546Spatrick     }
222061da546Spatrick     if (error.Fail()) {
223061da546Spatrick       fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
224061da546Spatrick               connection_url, error.AsCString());
225061da546Spatrick       exit(-1);
226061da546Spatrick     }
227*a0747c9fSpatrick   } else if (!host_and_port.empty()) {
228061da546Spatrick     // Parse out host and port.
229061da546Spatrick     std::string final_host_and_port;
230061da546Spatrick     std::string connection_host;
231061da546Spatrick     std::string connection_port;
232061da546Spatrick     uint32_t connection_portno = 0;
233061da546Spatrick 
234061da546Spatrick     // If host_and_port starts with ':', default the host to be "localhost" and
235061da546Spatrick     // expect the remainder to be the port.
236061da546Spatrick     if (host_and_port[0] == ':')
237061da546Spatrick       final_host_and_port.append("localhost");
238*a0747c9fSpatrick     final_host_and_port.append(host_and_port.str());
239061da546Spatrick 
240*a0747c9fSpatrick     // Note: use rfind, because the host/port may look like "[::1]:12345".
241*a0747c9fSpatrick     const std::string::size_type colon_pos = final_host_and_port.rfind(':');
242061da546Spatrick     if (colon_pos != std::string::npos) {
243061da546Spatrick       connection_host = final_host_and_port.substr(0, colon_pos);
244061da546Spatrick       connection_port = final_host_and_port.substr(colon_pos + 1);
245061da546Spatrick       connection_portno = StringConvert::ToUInt32(connection_port.c_str(), 0);
246061da546Spatrick     }
247061da546Spatrick 
248061da546Spatrick 
249061da546Spatrick     if (reverse_connect) {
250061da546Spatrick       // llgs will connect to the gdb-remote client.
251061da546Spatrick 
252061da546Spatrick       // Ensure we have a port number for the connection.
253061da546Spatrick       if (connection_portno == 0) {
254061da546Spatrick         fprintf(stderr, "error: port number must be specified on when using "
255061da546Spatrick                         "reverse connect\n");
256061da546Spatrick         exit(1);
257061da546Spatrick       }
258061da546Spatrick 
259061da546Spatrick       // Build the connection string.
260061da546Spatrick       char connection_url[512];
261061da546Spatrick       snprintf(connection_url, sizeof(connection_url), "connect://%s",
262061da546Spatrick                final_host_and_port.c_str());
263061da546Spatrick 
264061da546Spatrick       // Create the connection.
265061da546Spatrick       connection_up.reset(new ConnectionFileDescriptor);
266061da546Spatrick       auto connection_result = connection_up->Connect(connection_url, &error);
267061da546Spatrick       if (connection_result != eConnectionStatusSuccess) {
268061da546Spatrick         fprintf(stderr, "error: failed to connect to client at '%s' "
269061da546Spatrick                         "(connection status: %d)\n",
270061da546Spatrick                 connection_url, static_cast<int>(connection_result));
271061da546Spatrick         exit(-1);
272061da546Spatrick       }
273061da546Spatrick       if (error.Fail()) {
274061da546Spatrick         fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
275061da546Spatrick                 connection_url, error.AsCString());
276061da546Spatrick         exit(-1);
277061da546Spatrick       }
278061da546Spatrick     } else {
279061da546Spatrick       std::unique_ptr<Acceptor> acceptor_up(
280061da546Spatrick           Acceptor::Create(final_host_and_port, false, error));
281061da546Spatrick       if (error.Fail()) {
282061da546Spatrick         fprintf(stderr, "failed to create acceptor: %s\n", error.AsCString());
283061da546Spatrick         exit(1);
284061da546Spatrick       }
285061da546Spatrick       error = acceptor_up->Listen(1);
286061da546Spatrick       if (error.Fail()) {
287061da546Spatrick         fprintf(stderr, "failed to listen: %s\n", error.AsCString());
288061da546Spatrick         exit(1);
289061da546Spatrick       }
290061da546Spatrick       const std::string socket_id = acceptor_up->GetLocalSocketId();
291061da546Spatrick       if (!socket_id.empty()) {
292061da546Spatrick         // If we have a named pipe to write the socket id back to, do that now.
293061da546Spatrick         if (named_pipe_path && named_pipe_path[0]) {
294061da546Spatrick           error = writeSocketIdToPipe(named_pipe_path, socket_id);
295061da546Spatrick           if (error.Fail())
296061da546Spatrick             fprintf(stderr, "failed to write to the named pipe \'%s\': %s\n",
297061da546Spatrick                     named_pipe_path, error.AsCString());
298061da546Spatrick         }
299061da546Spatrick         // If we have an unnamed pipe to write the socket id back to, do that
300061da546Spatrick         // now.
301061da546Spatrick         else if (unnamed_pipe != LLDB_INVALID_PIPE) {
302061da546Spatrick           error = writeSocketIdToPipe(unnamed_pipe, socket_id);
303061da546Spatrick           if (error.Fail())
304061da546Spatrick             fprintf(stderr, "failed to write to the unnamed pipe: %s\n",
305061da546Spatrick                     error.AsCString());
306061da546Spatrick         }
307061da546Spatrick       } else {
308061da546Spatrick         fprintf(stderr,
309061da546Spatrick                 "unable to get the socket id for the listening connection\n");
310061da546Spatrick       }
311061da546Spatrick 
312061da546Spatrick       Connection *conn = nullptr;
313061da546Spatrick       error = acceptor_up->Accept(false, conn);
314061da546Spatrick       if (error.Fail()) {
315061da546Spatrick         printf("failed to accept new connection: %s\n", error.AsCString());
316061da546Spatrick         exit(1);
317061da546Spatrick       }
318061da546Spatrick       connection_up.reset(conn);
319061da546Spatrick     }
320061da546Spatrick   }
321061da546Spatrick   error = gdb_server.InitializeConnection(std::move(connection_up));
322061da546Spatrick   if (error.Fail()) {
323061da546Spatrick     fprintf(stderr, "Failed to initialize connection: %s\n",
324061da546Spatrick             error.AsCString());
325061da546Spatrick     exit(-1);
326061da546Spatrick   }
327061da546Spatrick   printf("Connection established.\n");
328061da546Spatrick }
329061da546Spatrick 
330*a0747c9fSpatrick namespace {
331*a0747c9fSpatrick enum ID {
332*a0747c9fSpatrick   OPT_INVALID = 0, // This is not an option ID.
333*a0747c9fSpatrick #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
334*a0747c9fSpatrick                HELPTEXT, METAVAR, VALUES)                                      \
335*a0747c9fSpatrick   OPT_##ID,
336*a0747c9fSpatrick #include "LLGSOptions.inc"
337*a0747c9fSpatrick #undef OPTION
338*a0747c9fSpatrick };
339*a0747c9fSpatrick 
340*a0747c9fSpatrick #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
341*a0747c9fSpatrick #include "LLGSOptions.inc"
342*a0747c9fSpatrick #undef PREFIX
343*a0747c9fSpatrick 
344*a0747c9fSpatrick const opt::OptTable::Info InfoTable[] = {
345*a0747c9fSpatrick #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
346*a0747c9fSpatrick                HELPTEXT, METAVAR, VALUES)                                      \
347*a0747c9fSpatrick   {                                                                            \
348*a0747c9fSpatrick       PREFIX,      NAME,      HELPTEXT,                                        \
349*a0747c9fSpatrick       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
350*a0747c9fSpatrick       PARAM,       FLAGS,     OPT_##GROUP,                                     \
351*a0747c9fSpatrick       OPT_##ALIAS, ALIASARGS, VALUES},
352*a0747c9fSpatrick #include "LLGSOptions.inc"
353*a0747c9fSpatrick #undef OPTION
354*a0747c9fSpatrick };
355*a0747c9fSpatrick 
356*a0747c9fSpatrick class LLGSOptTable : public opt::OptTable {
357*a0747c9fSpatrick public:
358*a0747c9fSpatrick   LLGSOptTable() : OptTable(InfoTable) {}
359*a0747c9fSpatrick 
360*a0747c9fSpatrick   void PrintHelp(llvm::StringRef Name) {
361*a0747c9fSpatrick     std::string Usage =
362*a0747c9fSpatrick         (Name + " [options] [[host]:port] [[--] program args...]").str();
363*a0747c9fSpatrick     OptTable::printHelp(llvm::outs(), Usage.c_str(), "lldb-server");
364*a0747c9fSpatrick     llvm::outs() << R"(
365*a0747c9fSpatrick DESCRIPTION
366*a0747c9fSpatrick   lldb-server connects to the LLDB client, which drives the debugging session.
367*a0747c9fSpatrick   If no connection options are given, the [host]:port argument must be present
368*a0747c9fSpatrick   and will denote the address that lldb-server will listen on. [host] defaults
369*a0747c9fSpatrick   to "localhost" if empty. Port can be zero, in which case the port number will
370*a0747c9fSpatrick   be chosen dynamically and written to destinations given by --named-pipe and
371*a0747c9fSpatrick   --pipe arguments.
372*a0747c9fSpatrick 
373*a0747c9fSpatrick   If no target is selected at startup, lldb-server can be directed by the LLDB
374*a0747c9fSpatrick   client to launch or attach to a process.
375*a0747c9fSpatrick 
376*a0747c9fSpatrick )";
377*a0747c9fSpatrick   }
378*a0747c9fSpatrick };
379*a0747c9fSpatrick } // namespace
380*a0747c9fSpatrick 
381061da546Spatrick int main_gdbserver(int argc, char *argv[]) {
382061da546Spatrick   Status error;
383061da546Spatrick   MainLoop mainloop;
384061da546Spatrick #ifndef _WIN32
385061da546Spatrick   // Setup signal handlers first thing.
386061da546Spatrick   signal(SIGPIPE, SIG_IGN);
387061da546Spatrick   MainLoop::SignalHandleUP sighup_handle =
388061da546Spatrick       mainloop.RegisterSignal(SIGHUP, sighup_handler, error);
389061da546Spatrick #endif
390061da546Spatrick 
391061da546Spatrick   const char *progname = argv[0];
392061da546Spatrick   const char *subcommand = argv[1];
393061da546Spatrick   std::string attach_target;
394061da546Spatrick   std::string named_pipe_path;
395061da546Spatrick   std::string log_file;
396061da546Spatrick   StringRef
397061da546Spatrick       log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
398061da546Spatrick   lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE;
399061da546Spatrick   bool reverse_connect = false;
400061da546Spatrick   int connection_fd = -1;
401061da546Spatrick 
402061da546Spatrick   // ProcessLaunchInfo launch_info;
403061da546Spatrick   ProcessAttachInfo attach_info;
404061da546Spatrick 
405*a0747c9fSpatrick   LLGSOptTable Opts;
406*a0747c9fSpatrick   llvm::BumpPtrAllocator Alloc;
407*a0747c9fSpatrick   llvm::StringSaver Saver(Alloc);
408*a0747c9fSpatrick   bool HasError = false;
409*a0747c9fSpatrick   opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN,
410*a0747c9fSpatrick                                           Saver, [&](llvm::StringRef Msg) {
411*a0747c9fSpatrick                                             WithColor::error() << Msg << "\n";
412*a0747c9fSpatrick                                             HasError = true;
413*a0747c9fSpatrick                                           });
414*a0747c9fSpatrick   std::string Name =
415*a0747c9fSpatrick       (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str();
416*a0747c9fSpatrick   std::string HelpText =
417*a0747c9fSpatrick       "Use '" + Name + " --help' for a complete list of options.\n";
418*a0747c9fSpatrick   if (HasError) {
419*a0747c9fSpatrick     llvm::errs() << HelpText;
420*a0747c9fSpatrick     return 1;
421*a0747c9fSpatrick   }
422061da546Spatrick 
423*a0747c9fSpatrick   if (Args.hasArg(OPT_help)) {
424*a0747c9fSpatrick     Opts.PrintHelp(Name);
425*a0747c9fSpatrick     return 0;
426*a0747c9fSpatrick   }
427061da546Spatrick 
428061da546Spatrick #ifndef _WIN32
429*a0747c9fSpatrick   if (Args.hasArg(OPT_setsid)) {
430061da546Spatrick     // Put llgs into a new session. Terminals group processes
431061da546Spatrick     // into sessions and when a special terminal key sequences
432061da546Spatrick     // (like control+c) are typed they can cause signals to go out to
433061da546Spatrick     // all processes in a session. Using this --setsid (-S) option
434061da546Spatrick     // will cause debugserver to run in its own sessions and be free
435061da546Spatrick     // from such issues.
436061da546Spatrick     //
437061da546Spatrick     // This is useful when llgs is spawned from a command
438061da546Spatrick     // line application that uses llgs to do the debugging,
439061da546Spatrick     // yet that application doesn't want llgs receiving the
440061da546Spatrick     // signals sent to the session (i.e. dying when anyone hits ^C).
441061da546Spatrick     {
442061da546Spatrick       const ::pid_t new_sid = setsid();
443061da546Spatrick       if (new_sid == -1) {
444*a0747c9fSpatrick         WithColor::warning()
445*a0747c9fSpatrick             << llvm::formatv("failed to set new session id for {0} ({1})\n",
446*a0747c9fSpatrick                              LLGS_PROGRAM_NAME, llvm::sys::StrError());
447061da546Spatrick       }
448061da546Spatrick     }
449*a0747c9fSpatrick   }
450061da546Spatrick #endif
451061da546Spatrick 
452*a0747c9fSpatrick   log_file = Args.getLastArgValue(OPT_log_file).str();
453*a0747c9fSpatrick   log_channels = Args.getLastArgValue(OPT_log_channels);
454*a0747c9fSpatrick   named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str();
455*a0747c9fSpatrick   reverse_connect = Args.hasArg(OPT_reverse_connect);
456*a0747c9fSpatrick   attach_target = Args.getLastArgValue(OPT_attach).str();
457*a0747c9fSpatrick   if (Args.hasArg(OPT_pipe)) {
458*a0747c9fSpatrick     uint64_t Arg;
459*a0747c9fSpatrick     if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) {
460*a0747c9fSpatrick       WithColor::error() << "invalid '--pipe' argument\n" << HelpText;
461*a0747c9fSpatrick       return 1;
462061da546Spatrick     }
463*a0747c9fSpatrick     unnamed_pipe = (pipe_t)Arg;
464061da546Spatrick   }
465*a0747c9fSpatrick   if (Args.hasArg(OPT_fd)) {
466*a0747c9fSpatrick     if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), connection_fd)) {
467*a0747c9fSpatrick       WithColor::error() << "invalid '--fd' argument\n" << HelpText;
468*a0747c9fSpatrick       return 1;
469*a0747c9fSpatrick     }
470061da546Spatrick   }
471061da546Spatrick 
472061da546Spatrick   if (!LLDBServerUtilities::SetupLogging(
473061da546Spatrick           log_file, log_channels,
474061da546Spatrick           LLDB_LOG_OPTION_PREPEND_TIMESTAMP |
475061da546Spatrick               LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION))
476061da546Spatrick     return -1;
477061da546Spatrick 
478*a0747c9fSpatrick   std::vector<llvm::StringRef> Inputs;
479*a0747c9fSpatrick   for (opt::Arg *Arg : Args.filtered(OPT_INPUT))
480*a0747c9fSpatrick     Inputs.push_back(Arg->getValue());
481*a0747c9fSpatrick   if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) {
482*a0747c9fSpatrick     for (const char *Val : Arg->getValues())
483*a0747c9fSpatrick       Inputs.push_back(Val);
484061da546Spatrick   }
485*a0747c9fSpatrick   if (Inputs.empty() && connection_fd == -1) {
486*a0747c9fSpatrick     WithColor::error() << "no connection arguments\n" << HelpText;
487*a0747c9fSpatrick     return 1;
488061da546Spatrick   }
489061da546Spatrick 
490061da546Spatrick   NativeProcessFactory factory;
491061da546Spatrick   GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory);
492061da546Spatrick 
493*a0747c9fSpatrick   llvm::StringRef host_and_port;
494*a0747c9fSpatrick   if (!Inputs.empty()) {
495*a0747c9fSpatrick     host_and_port = Inputs.front();
496*a0747c9fSpatrick     Inputs.erase(Inputs.begin());
497*a0747c9fSpatrick   }
498061da546Spatrick 
499061da546Spatrick   // Any arguments left over are for the program that we need to launch. If
500061da546Spatrick   // there
501061da546Spatrick   // are no arguments, then the GDB server will start up and wait for an 'A'
502061da546Spatrick   // packet
503061da546Spatrick   // to launch a program, or a vAttach packet to attach to an existing process,
504061da546Spatrick   // unless
505061da546Spatrick   // explicitly asked to attach with the --attach={pid|program_name} form.
506061da546Spatrick   if (!attach_target.empty())
507061da546Spatrick     handle_attach(gdb_server, attach_target);
508*a0747c9fSpatrick   else if (!Inputs.empty())
509*a0747c9fSpatrick     handle_launch(gdb_server, Inputs);
510061da546Spatrick 
511061da546Spatrick   // Print version info.
512061da546Spatrick   printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
513061da546Spatrick 
514061da546Spatrick   ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
515061da546Spatrick                   progname, subcommand, named_pipe_path.c_str(),
516061da546Spatrick                   unnamed_pipe, connection_fd);
517061da546Spatrick 
518061da546Spatrick   if (!gdb_server.IsConnected()) {
519061da546Spatrick     fprintf(stderr, "no connection information provided, unable to run\n");
520061da546Spatrick     return 1;
521061da546Spatrick   }
522061da546Spatrick 
523061da546Spatrick   Status ret = mainloop.Run();
524061da546Spatrick   if (ret.Fail()) {
525061da546Spatrick     fprintf(stderr, "lldb-server terminating due to error: %s\n",
526061da546Spatrick             ret.AsCString());
527061da546Spatrick     return 1;
528061da546Spatrick   }
529061da546Spatrick   fprintf(stderr, "lldb-server exiting...\n");
530061da546Spatrick 
531061da546Spatrick   return 0;
532061da546Spatrick }
533