xref: /freebsd/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
10b57cec5SDimitry Andric //===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include <errno.h>
100b57cec5SDimitry Andric #include <stdint.h>
110b57cec5SDimitry Andric #include <stdio.h>
120b57cec5SDimitry Andric #include <stdlib.h>
130b57cec5SDimitry Andric #include <string.h>
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #ifndef _WIN32
160b57cec5SDimitry Andric #include <signal.h>
170b57cec5SDimitry Andric #include <unistd.h>
180b57cec5SDimitry Andric #endif
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include "Acceptor.h"
210b57cec5SDimitry Andric #include "LLDBServerUtilities.h"
220b57cec5SDimitry Andric #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
230b57cec5SDimitry Andric #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
24480093f4SDimitry Andric #include "lldb/Host/Config.h"
250b57cec5SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h"
260b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
270b57cec5SDimitry Andric #include "lldb/Host/Pipe.h"
280b57cec5SDimitry Andric #include "lldb/Host/Socket.h"
290b57cec5SDimitry Andric #include "lldb/Host/StringConvert.h"
300b57cec5SDimitry Andric #include "lldb/Host/common/NativeProcessProtocol.h"
310b57cec5SDimitry Andric #include "lldb/Target/Process.h"
320b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
330b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
34*e8d8bef9SDimitry Andric #include "llvm/Option/ArgList.h"
35*e8d8bef9SDimitry Andric #include "llvm/Option/OptTable.h"
36*e8d8bef9SDimitry Andric #include "llvm/Option/Option.h"
370b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
38*e8d8bef9SDimitry Andric #include "llvm/Support/WithColor.h"
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric #if defined(__linux__)
410b57cec5SDimitry Andric #include "Plugins/Process/Linux/NativeProcessLinux.h"
42*e8d8bef9SDimitry Andric #elif defined(__FreeBSD__)
43*e8d8bef9SDimitry Andric #include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h"
440b57cec5SDimitry Andric #elif defined(__NetBSD__)
450b57cec5SDimitry Andric #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
469dba64beSDimitry Andric #elif defined(_WIN32)
479dba64beSDimitry Andric #include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
480b57cec5SDimitry Andric #endif
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric #ifndef LLGS_PROGRAM_NAME
510b57cec5SDimitry Andric #define LLGS_PROGRAM_NAME "lldb-server"
520b57cec5SDimitry Andric #endif
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric #ifndef LLGS_VERSION_STR
550b57cec5SDimitry Andric #define LLGS_VERSION_STR "local_build"
560b57cec5SDimitry Andric #endif
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric using namespace llvm;
590b57cec5SDimitry Andric using namespace lldb;
600b57cec5SDimitry Andric using namespace lldb_private;
610b57cec5SDimitry Andric using namespace lldb_private::lldb_server;
620b57cec5SDimitry Andric using namespace lldb_private::process_gdb_remote;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric namespace {
650b57cec5SDimitry Andric #if defined(__linux__)
660b57cec5SDimitry Andric typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory;
67*e8d8bef9SDimitry Andric #elif defined(__FreeBSD__)
68*e8d8bef9SDimitry Andric typedef process_freebsd::NativeProcessFreeBSD::Factory NativeProcessFactory;
690b57cec5SDimitry Andric #elif defined(__NetBSD__)
700b57cec5SDimitry Andric typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory;
719dba64beSDimitry Andric #elif defined(_WIN32)
729dba64beSDimitry Andric typedef NativeProcessWindows::Factory NativeProcessFactory;
730b57cec5SDimitry Andric #else
740b57cec5SDimitry Andric // Dummy implementation to make sure the code compiles
750b57cec5SDimitry Andric class NativeProcessFactory : public NativeProcessProtocol::Factory {
760b57cec5SDimitry Andric public:
770b57cec5SDimitry Andric   llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
780b57cec5SDimitry Andric   Launch(ProcessLaunchInfo &launch_info,
790b57cec5SDimitry Andric          NativeProcessProtocol::NativeDelegate &delegate,
800b57cec5SDimitry Andric          MainLoop &mainloop) const override {
810b57cec5SDimitry Andric     llvm_unreachable("Not implemented");
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
840b57cec5SDimitry Andric   Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate,
850b57cec5SDimitry Andric          MainLoop &mainloop) const override {
860b57cec5SDimitry Andric     llvm_unreachable("Not implemented");
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric };
890b57cec5SDimitry Andric #endif
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
929dba64beSDimitry Andric #ifndef _WIN32
930b57cec5SDimitry Andric // Watch for signals
940b57cec5SDimitry Andric static int g_sighup_received_count = 0;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric static void sighup_handler(MainLoopBase &mainloop) {
970b57cec5SDimitry Andric   ++g_sighup_received_count;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
1009dba64beSDimitry Andric   LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)",
1010b57cec5SDimitry Andric             __FUNCTION__, g_sighup_received_count);
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   if (g_sighup_received_count >= 2)
1040b57cec5SDimitry Andric     mainloop.RequestTermination();
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric #endif // #ifndef _WIN32
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server,
1090b57cec5SDimitry Andric                           lldb::pid_t pid) {
1100b57cec5SDimitry Andric   Status error = gdb_server.AttachToProcess(pid);
1110b57cec5SDimitry Andric   if (error.Fail()) {
1120b57cec5SDimitry Andric     fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid,
1130b57cec5SDimitry Andric             error.AsCString());
1140b57cec5SDimitry Andric     exit(1);
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server,
1190b57cec5SDimitry Andric                                    const std::string &process_name) {
1200b57cec5SDimitry Andric   // FIXME implement.
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server,
1240b57cec5SDimitry Andric                    const std::string &attach_target) {
1250b57cec5SDimitry Andric   assert(!attach_target.empty() && "attach_target cannot be empty");
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   // First check if the attach_target is convertible to a long. If so, we'll use
1280b57cec5SDimitry Andric   // it as a pid.
1290b57cec5SDimitry Andric   char *end_p = nullptr;
1300b57cec5SDimitry Andric   const long int pid = strtol(attach_target.c_str(), &end_p, 10);
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   // We'll call it a match if the entire argument is consumed.
1330b57cec5SDimitry Andric   if (end_p &&
1340b57cec5SDimitry Andric       static_cast<size_t>(end_p - attach_target.c_str()) ==
1350b57cec5SDimitry Andric           attach_target.size())
1360b57cec5SDimitry Andric     handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid));
1370b57cec5SDimitry Andric   else
1380b57cec5SDimitry Andric     handle_attach_to_process_name(gdb_server, attach_target);
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
141*e8d8bef9SDimitry Andric void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server,
142*e8d8bef9SDimitry Andric                    llvm::ArrayRef<llvm::StringRef> Arguments) {
1430b57cec5SDimitry Andric   ProcessLaunchInfo info;
1440b57cec5SDimitry Andric   info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug |
1450b57cec5SDimitry Andric                       eLaunchFlagDisableASLR);
146*e8d8bef9SDimitry Andric   info.SetArguments(Args(Arguments), true);
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   llvm::SmallString<64> cwd;
1490b57cec5SDimitry Andric   if (std::error_code ec = llvm::sys::fs::current_path(cwd)) {
1500b57cec5SDimitry Andric     llvm::errs() << "Error getting current directory: " << ec.message() << "\n";
1510b57cec5SDimitry Andric     exit(1);
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric   FileSpec cwd_spec(cwd);
1540b57cec5SDimitry Andric   FileSystem::Instance().Resolve(cwd_spec);
1550b57cec5SDimitry Andric   info.SetWorkingDirectory(cwd_spec);
1560b57cec5SDimitry Andric   info.GetEnvironment() = Host::GetEnvironment();
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   gdb_server.SetLaunchInfo(info);
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   Status error = gdb_server.LaunchProcess();
1610b57cec5SDimitry Andric   if (error.Fail()) {
1620b57cec5SDimitry Andric     llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n",
163*e8d8bef9SDimitry Andric                                   Arguments[0], error);
1640b57cec5SDimitry Andric     exit(1);
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric Status writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) {
1690b57cec5SDimitry Andric   size_t bytes_written = 0;
1700b57cec5SDimitry Andric   // Write the port number as a C string with the NULL terminator.
1710b57cec5SDimitry Andric   return port_pipe.Write(socket_id.c_str(), socket_id.size() + 1,
1720b57cec5SDimitry Andric                          bytes_written);
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric Status writeSocketIdToPipe(const char *const named_pipe_path,
1760b57cec5SDimitry Andric                            const std::string &socket_id) {
1770b57cec5SDimitry Andric   Pipe port_name_pipe;
1780b57cec5SDimitry Andric   // Wait for 10 seconds for pipe to be opened.
1790b57cec5SDimitry Andric   auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
1800b57cec5SDimitry Andric                                                       std::chrono::seconds{10});
1810b57cec5SDimitry Andric   if (error.Fail())
1820b57cec5SDimitry Andric     return error;
1830b57cec5SDimitry Andric   return writeSocketIdToPipe(port_name_pipe, socket_id);
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
1870b57cec5SDimitry Andric                            const std::string &socket_id) {
1880b57cec5SDimitry Andric   Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
1890b57cec5SDimitry Andric   return writeSocketIdToPipe(port_pipe, socket_id);
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric void ConnectToRemote(MainLoop &mainloop,
1930b57cec5SDimitry Andric                      GDBRemoteCommunicationServerLLGS &gdb_server,
194*e8d8bef9SDimitry Andric                      bool reverse_connect, llvm::StringRef host_and_port,
1950b57cec5SDimitry Andric                      const char *const progname, const char *const subcommand,
1960b57cec5SDimitry Andric                      const char *const named_pipe_path, pipe_t unnamed_pipe,
1970b57cec5SDimitry Andric                      int connection_fd) {
1980b57cec5SDimitry Andric   Status error;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   std::unique_ptr<Connection> connection_up;
2010b57cec5SDimitry Andric   if (connection_fd != -1) {
2020b57cec5SDimitry Andric     // Build the connection string.
2030b57cec5SDimitry Andric     char connection_url[512];
2040b57cec5SDimitry Andric     snprintf(connection_url, sizeof(connection_url), "fd://%d", connection_fd);
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     // Create the connection.
207480093f4SDimitry Andric #if LLDB_ENABLE_POSIX && !defined _WIN32
2080b57cec5SDimitry Andric     ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC);
2090b57cec5SDimitry Andric #endif
2100b57cec5SDimitry Andric     connection_up.reset(new ConnectionFileDescriptor);
2110b57cec5SDimitry Andric     auto connection_result = connection_up->Connect(connection_url, &error);
2120b57cec5SDimitry Andric     if (connection_result != eConnectionStatusSuccess) {
2130b57cec5SDimitry Andric       fprintf(stderr, "error: failed to connect to client at '%s' "
2140b57cec5SDimitry Andric                       "(connection status: %d)\n",
2150b57cec5SDimitry Andric               connection_url, static_cast<int>(connection_result));
2160b57cec5SDimitry Andric       exit(-1);
2170b57cec5SDimitry Andric     }
2180b57cec5SDimitry Andric     if (error.Fail()) {
2190b57cec5SDimitry Andric       fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
2200b57cec5SDimitry Andric               connection_url, error.AsCString());
2210b57cec5SDimitry Andric       exit(-1);
2220b57cec5SDimitry Andric     }
223*e8d8bef9SDimitry Andric   } else if (!host_and_port.empty()) {
2240b57cec5SDimitry Andric     // Parse out host and port.
2250b57cec5SDimitry Andric     std::string final_host_and_port;
2260b57cec5SDimitry Andric     std::string connection_host;
2270b57cec5SDimitry Andric     std::string connection_port;
2280b57cec5SDimitry Andric     uint32_t connection_portno = 0;
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric     // If host_and_port starts with ':', default the host to be "localhost" and
2310b57cec5SDimitry Andric     // expect the remainder to be the port.
2320b57cec5SDimitry Andric     if (host_and_port[0] == ':')
2330b57cec5SDimitry Andric       final_host_and_port.append("localhost");
234*e8d8bef9SDimitry Andric     final_host_and_port.append(host_and_port.str());
2350b57cec5SDimitry Andric 
236*e8d8bef9SDimitry Andric     // Note: use rfind, because the host/port may look like "[::1]:12345".
237*e8d8bef9SDimitry Andric     const std::string::size_type colon_pos = final_host_and_port.rfind(':');
2380b57cec5SDimitry Andric     if (colon_pos != std::string::npos) {
2390b57cec5SDimitry Andric       connection_host = final_host_and_port.substr(0, colon_pos);
2400b57cec5SDimitry Andric       connection_port = final_host_and_port.substr(colon_pos + 1);
2410b57cec5SDimitry Andric       connection_portno = StringConvert::ToUInt32(connection_port.c_str(), 0);
2420b57cec5SDimitry Andric     }
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric     if (reverse_connect) {
2460b57cec5SDimitry Andric       // llgs will connect to the gdb-remote client.
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric       // Ensure we have a port number for the connection.
2490b57cec5SDimitry Andric       if (connection_portno == 0) {
2500b57cec5SDimitry Andric         fprintf(stderr, "error: port number must be specified on when using "
2510b57cec5SDimitry Andric                         "reverse connect\n");
2520b57cec5SDimitry Andric         exit(1);
2530b57cec5SDimitry Andric       }
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric       // Build the connection string.
2560b57cec5SDimitry Andric       char connection_url[512];
2570b57cec5SDimitry Andric       snprintf(connection_url, sizeof(connection_url), "connect://%s",
2580b57cec5SDimitry Andric                final_host_and_port.c_str());
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric       // Create the connection.
2610b57cec5SDimitry Andric       connection_up.reset(new ConnectionFileDescriptor);
2620b57cec5SDimitry Andric       auto connection_result = connection_up->Connect(connection_url, &error);
2630b57cec5SDimitry Andric       if (connection_result != eConnectionStatusSuccess) {
2640b57cec5SDimitry Andric         fprintf(stderr, "error: failed to connect to client at '%s' "
2650b57cec5SDimitry Andric                         "(connection status: %d)\n",
2660b57cec5SDimitry Andric                 connection_url, static_cast<int>(connection_result));
2670b57cec5SDimitry Andric         exit(-1);
2680b57cec5SDimitry Andric       }
2690b57cec5SDimitry Andric       if (error.Fail()) {
2700b57cec5SDimitry Andric         fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
2710b57cec5SDimitry Andric                 connection_url, error.AsCString());
2720b57cec5SDimitry Andric         exit(-1);
2730b57cec5SDimitry Andric       }
2740b57cec5SDimitry Andric     } else {
2750b57cec5SDimitry Andric       std::unique_ptr<Acceptor> acceptor_up(
2760b57cec5SDimitry Andric           Acceptor::Create(final_host_and_port, false, error));
2770b57cec5SDimitry Andric       if (error.Fail()) {
2780b57cec5SDimitry Andric         fprintf(stderr, "failed to create acceptor: %s\n", error.AsCString());
2790b57cec5SDimitry Andric         exit(1);
2800b57cec5SDimitry Andric       }
2810b57cec5SDimitry Andric       error = acceptor_up->Listen(1);
2820b57cec5SDimitry Andric       if (error.Fail()) {
2830b57cec5SDimitry Andric         fprintf(stderr, "failed to listen: %s\n", error.AsCString());
2840b57cec5SDimitry Andric         exit(1);
2850b57cec5SDimitry Andric       }
2860b57cec5SDimitry Andric       const std::string socket_id = acceptor_up->GetLocalSocketId();
2870b57cec5SDimitry Andric       if (!socket_id.empty()) {
2880b57cec5SDimitry Andric         // If we have a named pipe to write the socket id back to, do that now.
2890b57cec5SDimitry Andric         if (named_pipe_path && named_pipe_path[0]) {
2900b57cec5SDimitry Andric           error = writeSocketIdToPipe(named_pipe_path, socket_id);
2910b57cec5SDimitry Andric           if (error.Fail())
2920b57cec5SDimitry Andric             fprintf(stderr, "failed to write to the named pipe \'%s\': %s\n",
2930b57cec5SDimitry Andric                     named_pipe_path, error.AsCString());
2940b57cec5SDimitry Andric         }
2950b57cec5SDimitry Andric         // If we have an unnamed pipe to write the socket id back to, do that
2960b57cec5SDimitry Andric         // now.
2970b57cec5SDimitry Andric         else if (unnamed_pipe != LLDB_INVALID_PIPE) {
2980b57cec5SDimitry Andric           error = writeSocketIdToPipe(unnamed_pipe, socket_id);
2990b57cec5SDimitry Andric           if (error.Fail())
3000b57cec5SDimitry Andric             fprintf(stderr, "failed to write to the unnamed pipe: %s\n",
3010b57cec5SDimitry Andric                     error.AsCString());
3020b57cec5SDimitry Andric         }
3030b57cec5SDimitry Andric       } else {
3040b57cec5SDimitry Andric         fprintf(stderr,
3050b57cec5SDimitry Andric                 "unable to get the socket id for the listening connection\n");
3060b57cec5SDimitry Andric       }
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric       Connection *conn = nullptr;
3090b57cec5SDimitry Andric       error = acceptor_up->Accept(false, conn);
3100b57cec5SDimitry Andric       if (error.Fail()) {
3110b57cec5SDimitry Andric         printf("failed to accept new connection: %s\n", error.AsCString());
3120b57cec5SDimitry Andric         exit(1);
3130b57cec5SDimitry Andric       }
3140b57cec5SDimitry Andric       connection_up.reset(conn);
3150b57cec5SDimitry Andric     }
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric   error = gdb_server.InitializeConnection(std::move(connection_up));
3180b57cec5SDimitry Andric   if (error.Fail()) {
3190b57cec5SDimitry Andric     fprintf(stderr, "Failed to initialize connection: %s\n",
3200b57cec5SDimitry Andric             error.AsCString());
3210b57cec5SDimitry Andric     exit(-1);
3220b57cec5SDimitry Andric   }
3230b57cec5SDimitry Andric   printf("Connection established.\n");
3240b57cec5SDimitry Andric }
3250b57cec5SDimitry Andric 
326*e8d8bef9SDimitry Andric namespace {
327*e8d8bef9SDimitry Andric enum ID {
328*e8d8bef9SDimitry Andric   OPT_INVALID = 0, // This is not an option ID.
329*e8d8bef9SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
330*e8d8bef9SDimitry Andric                HELPTEXT, METAVAR, VALUES)                                      \
331*e8d8bef9SDimitry Andric   OPT_##ID,
332*e8d8bef9SDimitry Andric #include "LLGSOptions.inc"
333*e8d8bef9SDimitry Andric #undef OPTION
334*e8d8bef9SDimitry Andric };
335*e8d8bef9SDimitry Andric 
336*e8d8bef9SDimitry Andric #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
337*e8d8bef9SDimitry Andric #include "LLGSOptions.inc"
338*e8d8bef9SDimitry Andric #undef PREFIX
339*e8d8bef9SDimitry Andric 
340*e8d8bef9SDimitry Andric const opt::OptTable::Info InfoTable[] = {
341*e8d8bef9SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
342*e8d8bef9SDimitry Andric                HELPTEXT, METAVAR, VALUES)                                      \
343*e8d8bef9SDimitry Andric   {                                                                            \
344*e8d8bef9SDimitry Andric       PREFIX,      NAME,      HELPTEXT,                                        \
345*e8d8bef9SDimitry Andric       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
346*e8d8bef9SDimitry Andric       PARAM,       FLAGS,     OPT_##GROUP,                                     \
347*e8d8bef9SDimitry Andric       OPT_##ALIAS, ALIASARGS, VALUES},
348*e8d8bef9SDimitry Andric #include "LLGSOptions.inc"
349*e8d8bef9SDimitry Andric #undef OPTION
350*e8d8bef9SDimitry Andric };
351*e8d8bef9SDimitry Andric 
352*e8d8bef9SDimitry Andric class LLGSOptTable : public opt::OptTable {
353*e8d8bef9SDimitry Andric public:
354*e8d8bef9SDimitry Andric   LLGSOptTable() : OptTable(InfoTable) {}
355*e8d8bef9SDimitry Andric 
356*e8d8bef9SDimitry Andric   void PrintHelp(llvm::StringRef Name) {
357*e8d8bef9SDimitry Andric     std::string Usage =
358*e8d8bef9SDimitry Andric         (Name + " [options] [[host]:port] [[--] program args...]").str();
359*e8d8bef9SDimitry Andric     OptTable::PrintHelp(llvm::outs(), Usage.c_str(), "lldb-server");
360*e8d8bef9SDimitry Andric     llvm::outs() << R"(
361*e8d8bef9SDimitry Andric DESCRIPTION
362*e8d8bef9SDimitry Andric   lldb-server connects to the LLDB client, which drives the debugging session.
363*e8d8bef9SDimitry Andric   If no connection options are given, the [host]:port argument must be present
364*e8d8bef9SDimitry Andric   and will denote the address that lldb-server will listen on. [host] defaults
365*e8d8bef9SDimitry Andric   to "localhost" if empty. Port can be zero, in which case the port number will
366*e8d8bef9SDimitry Andric   be chosen dynamically and written to destinations given by --named-pipe and
367*e8d8bef9SDimitry Andric   --pipe arguments.
368*e8d8bef9SDimitry Andric 
369*e8d8bef9SDimitry Andric   If no target is selected at startup, lldb-server can be directed by the LLDB
370*e8d8bef9SDimitry Andric   client to launch or attach to a process.
371*e8d8bef9SDimitry Andric 
372*e8d8bef9SDimitry Andric )";
373*e8d8bef9SDimitry Andric   }
374*e8d8bef9SDimitry Andric };
375*e8d8bef9SDimitry Andric } // namespace
376*e8d8bef9SDimitry Andric 
3770b57cec5SDimitry Andric int main_gdbserver(int argc, char *argv[]) {
3780b57cec5SDimitry Andric   Status error;
3790b57cec5SDimitry Andric   MainLoop mainloop;
3800b57cec5SDimitry Andric #ifndef _WIN32
3810b57cec5SDimitry Andric   // Setup signal handlers first thing.
3820b57cec5SDimitry Andric   signal(SIGPIPE, SIG_IGN);
3830b57cec5SDimitry Andric   MainLoop::SignalHandleUP sighup_handle =
3840b57cec5SDimitry Andric       mainloop.RegisterSignal(SIGHUP, sighup_handler, error);
3850b57cec5SDimitry Andric #endif
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   const char *progname = argv[0];
3880b57cec5SDimitry Andric   const char *subcommand = argv[1];
3890b57cec5SDimitry Andric   std::string attach_target;
3900b57cec5SDimitry Andric   std::string named_pipe_path;
3910b57cec5SDimitry Andric   std::string log_file;
3920b57cec5SDimitry Andric   StringRef
3930b57cec5SDimitry Andric       log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
3940b57cec5SDimitry Andric   lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE;
3950b57cec5SDimitry Andric   bool reverse_connect = false;
3960b57cec5SDimitry Andric   int connection_fd = -1;
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   // ProcessLaunchInfo launch_info;
3990b57cec5SDimitry Andric   ProcessAttachInfo attach_info;
4000b57cec5SDimitry Andric 
401*e8d8bef9SDimitry Andric   LLGSOptTable Opts;
402*e8d8bef9SDimitry Andric   llvm::BumpPtrAllocator Alloc;
403*e8d8bef9SDimitry Andric   llvm::StringSaver Saver(Alloc);
404*e8d8bef9SDimitry Andric   bool HasError = false;
405*e8d8bef9SDimitry Andric   opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN,
406*e8d8bef9SDimitry Andric                                           Saver, [&](llvm::StringRef Msg) {
407*e8d8bef9SDimitry Andric                                             WithColor::error() << Msg << "\n";
408*e8d8bef9SDimitry Andric                                             HasError = true;
409*e8d8bef9SDimitry Andric                                           });
410*e8d8bef9SDimitry Andric   std::string Name =
411*e8d8bef9SDimitry Andric       (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str();
412*e8d8bef9SDimitry Andric   std::string HelpText =
413*e8d8bef9SDimitry Andric       "Use '" + Name + " --help' for a complete list of options.\n";
414*e8d8bef9SDimitry Andric   if (HasError) {
415*e8d8bef9SDimitry Andric     llvm::errs() << HelpText;
416*e8d8bef9SDimitry Andric     return 1;
417*e8d8bef9SDimitry Andric   }
4180b57cec5SDimitry Andric 
419*e8d8bef9SDimitry Andric   if (Args.hasArg(OPT_help)) {
420*e8d8bef9SDimitry Andric     Opts.PrintHelp(Name);
421*e8d8bef9SDimitry Andric     return 0;
422*e8d8bef9SDimitry Andric   }
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric #ifndef _WIN32
425*e8d8bef9SDimitry Andric   if (Args.hasArg(OPT_setsid)) {
4260b57cec5SDimitry Andric     // Put llgs into a new session. Terminals group processes
4270b57cec5SDimitry Andric     // into sessions and when a special terminal key sequences
4280b57cec5SDimitry Andric     // (like control+c) are typed they can cause signals to go out to
4290b57cec5SDimitry Andric     // all processes in a session. Using this --setsid (-S) option
4300b57cec5SDimitry Andric     // will cause debugserver to run in its own sessions and be free
4310b57cec5SDimitry Andric     // from such issues.
4320b57cec5SDimitry Andric     //
4330b57cec5SDimitry Andric     // This is useful when llgs is spawned from a command
4340b57cec5SDimitry Andric     // line application that uses llgs to do the debugging,
4350b57cec5SDimitry Andric     // yet that application doesn't want llgs receiving the
4360b57cec5SDimitry Andric     // signals sent to the session (i.e. dying when anyone hits ^C).
4370b57cec5SDimitry Andric     {
4380b57cec5SDimitry Andric       const ::pid_t new_sid = setsid();
4390b57cec5SDimitry Andric       if (new_sid == -1) {
440*e8d8bef9SDimitry Andric         WithColor::warning()
441*e8d8bef9SDimitry Andric             << llvm::formatv("failed to set new session id for {0} ({1})\n",
442*e8d8bef9SDimitry Andric                              LLGS_PROGRAM_NAME, llvm::sys::StrError());
4430b57cec5SDimitry Andric       }
4440b57cec5SDimitry Andric     }
445*e8d8bef9SDimitry Andric   }
4460b57cec5SDimitry Andric #endif
4470b57cec5SDimitry Andric 
448*e8d8bef9SDimitry Andric   log_file = Args.getLastArgValue(OPT_log_file).str();
449*e8d8bef9SDimitry Andric   log_channels = Args.getLastArgValue(OPT_log_channels);
450*e8d8bef9SDimitry Andric   named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str();
451*e8d8bef9SDimitry Andric   reverse_connect = Args.hasArg(OPT_reverse_connect);
452*e8d8bef9SDimitry Andric   attach_target = Args.getLastArgValue(OPT_attach).str();
453*e8d8bef9SDimitry Andric   if (Args.hasArg(OPT_pipe)) {
454*e8d8bef9SDimitry Andric     uint64_t Arg;
455*e8d8bef9SDimitry Andric     if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) {
456*e8d8bef9SDimitry Andric       WithColor::error() << "invalid '--pipe' argument\n" << HelpText;
457*e8d8bef9SDimitry Andric       return 1;
4580b57cec5SDimitry Andric     }
459*e8d8bef9SDimitry Andric     unnamed_pipe = (pipe_t)Arg;
4600b57cec5SDimitry Andric   }
461*e8d8bef9SDimitry Andric   if (Args.hasArg(OPT_fd)) {
462*e8d8bef9SDimitry Andric     if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), connection_fd)) {
463*e8d8bef9SDimitry Andric       WithColor::error() << "invalid '--fd' argument\n" << HelpText;
464*e8d8bef9SDimitry Andric       return 1;
465*e8d8bef9SDimitry Andric     }
4660b57cec5SDimitry Andric   }
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   if (!LLDBServerUtilities::SetupLogging(
4690b57cec5SDimitry Andric           log_file, log_channels,
4700b57cec5SDimitry Andric           LLDB_LOG_OPTION_PREPEND_TIMESTAMP |
4710b57cec5SDimitry Andric               LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION))
4720b57cec5SDimitry Andric     return -1;
4730b57cec5SDimitry Andric 
474*e8d8bef9SDimitry Andric   std::vector<llvm::StringRef> Inputs;
475*e8d8bef9SDimitry Andric   for (opt::Arg *Arg : Args.filtered(OPT_INPUT))
476*e8d8bef9SDimitry Andric     Inputs.push_back(Arg->getValue());
477*e8d8bef9SDimitry Andric   if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) {
478*e8d8bef9SDimitry Andric     for (const char *Val : Arg->getValues())
479*e8d8bef9SDimitry Andric       Inputs.push_back(Val);
4800b57cec5SDimitry Andric   }
481*e8d8bef9SDimitry Andric   if (Inputs.empty() && connection_fd == -1) {
482*e8d8bef9SDimitry Andric     WithColor::error() << "no connection arguments\n" << HelpText;
483*e8d8bef9SDimitry Andric     return 1;
4840b57cec5SDimitry Andric   }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric   NativeProcessFactory factory;
4870b57cec5SDimitry Andric   GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory);
4880b57cec5SDimitry Andric 
489*e8d8bef9SDimitry Andric   llvm::StringRef host_and_port;
490*e8d8bef9SDimitry Andric   if (!Inputs.empty()) {
491*e8d8bef9SDimitry Andric     host_and_port = Inputs.front();
492*e8d8bef9SDimitry Andric     Inputs.erase(Inputs.begin());
493*e8d8bef9SDimitry Andric   }
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric   // Any arguments left over are for the program that we need to launch. If
4960b57cec5SDimitry Andric   // there
4970b57cec5SDimitry Andric   // are no arguments, then the GDB server will start up and wait for an 'A'
4980b57cec5SDimitry Andric   // packet
4990b57cec5SDimitry Andric   // to launch a program, or a vAttach packet to attach to an existing process,
5000b57cec5SDimitry Andric   // unless
5010b57cec5SDimitry Andric   // explicitly asked to attach with the --attach={pid|program_name} form.
5020b57cec5SDimitry Andric   if (!attach_target.empty())
5030b57cec5SDimitry Andric     handle_attach(gdb_server, attach_target);
504*e8d8bef9SDimitry Andric   else if (!Inputs.empty())
505*e8d8bef9SDimitry Andric     handle_launch(gdb_server, Inputs);
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric   // Print version info.
5089dba64beSDimitry Andric   printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
5110b57cec5SDimitry Andric                   progname, subcommand, named_pipe_path.c_str(),
5120b57cec5SDimitry Andric                   unnamed_pipe, connection_fd);
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   if (!gdb_server.IsConnected()) {
5150b57cec5SDimitry Andric     fprintf(stderr, "no connection information provided, unable to run\n");
5160b57cec5SDimitry Andric     return 1;
5170b57cec5SDimitry Andric   }
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   Status ret = mainloop.Run();
5200b57cec5SDimitry Andric   if (ret.Fail()) {
5210b57cec5SDimitry Andric     fprintf(stderr, "lldb-server terminating due to error: %s\n",
5220b57cec5SDimitry Andric             ret.AsCString());
5230b57cec5SDimitry Andric     return 1;
5240b57cec5SDimitry Andric   }
5250b57cec5SDimitry Andric   fprintf(stderr, "lldb-server exiting...\n");
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric   return 0;
5280b57cec5SDimitry Andric }
529