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