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 9fe6060f1SDimitry Andric #include <cerrno> 10fe6060f1SDimitry Andric #include <cstdint> 11fe6060f1SDimitry Andric #include <cstdio> 12fe6060f1SDimitry Andric #include <cstdlib> 13fe6060f1SDimitry Andric #include <cstring> 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #ifndef _WIN32 16fe6060f1SDimitry Andric #include <csignal> 170b57cec5SDimitry Andric #include <unistd.h> 180b57cec5SDimitry Andric #endif 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "LLDBServerUtilities.h" 210b57cec5SDimitry Andric #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h" 220b57cec5SDimitry Andric #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" 23480093f4SDimitry Andric #include "lldb/Host/Config.h" 240b57cec5SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h" 250b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h" 260b57cec5SDimitry Andric #include "lldb/Host/Pipe.h" 270b57cec5SDimitry Andric #include "lldb/Host/Socket.h" 280b57cec5SDimitry Andric #include "lldb/Host/common/NativeProcessProtocol.h" 290b57cec5SDimitry Andric #include "lldb/Target/Process.h" 300b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 310b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 32e8d8bef9SDimitry Andric #include "llvm/Option/ArgList.h" 33e8d8bef9SDimitry Andric #include "llvm/Option/OptTable.h" 34e8d8bef9SDimitry Andric #include "llvm/Option/Option.h" 350b57cec5SDimitry Andric #include "llvm/Support/Errno.h" 36e8d8bef9SDimitry Andric #include "llvm/Support/WithColor.h" 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric #if defined(__linux__) 390b57cec5SDimitry Andric #include "Plugins/Process/Linux/NativeProcessLinux.h" 40e8d8bef9SDimitry Andric #elif defined(__FreeBSD__) 41d409305fSDimitry Andric #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" 420b57cec5SDimitry Andric #elif defined(__NetBSD__) 430b57cec5SDimitry Andric #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" 449dba64beSDimitry Andric #elif defined(_WIN32) 459dba64beSDimitry Andric #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" 460b57cec5SDimitry Andric #endif 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric #ifndef LLGS_PROGRAM_NAME 490b57cec5SDimitry Andric #define LLGS_PROGRAM_NAME "lldb-server" 500b57cec5SDimitry Andric #endif 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric #ifndef LLGS_VERSION_STR 530b57cec5SDimitry Andric #define LLGS_VERSION_STR "local_build" 540b57cec5SDimitry Andric #endif 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric using namespace llvm; 570b57cec5SDimitry Andric using namespace lldb; 580b57cec5SDimitry Andric using namespace lldb_private; 590b57cec5SDimitry Andric using namespace lldb_private::lldb_server; 600b57cec5SDimitry Andric using namespace lldb_private::process_gdb_remote; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric namespace { 630b57cec5SDimitry Andric #if defined(__linux__) 640b57cec5SDimitry Andric typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory; 65e8d8bef9SDimitry Andric #elif defined(__FreeBSD__) 66e8d8bef9SDimitry Andric typedef process_freebsd::NativeProcessFreeBSD::Factory NativeProcessFactory; 670b57cec5SDimitry Andric #elif defined(__NetBSD__) 680b57cec5SDimitry Andric typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory; 699dba64beSDimitry Andric #elif defined(_WIN32) 709dba64beSDimitry Andric typedef NativeProcessWindows::Factory NativeProcessFactory; 710b57cec5SDimitry Andric #else 720b57cec5SDimitry Andric // Dummy implementation to make sure the code compiles 730b57cec5SDimitry Andric class NativeProcessFactory : public NativeProcessProtocol::Factory { 740b57cec5SDimitry Andric public: 750b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 760b57cec5SDimitry Andric Launch(ProcessLaunchInfo &launch_info, 770b57cec5SDimitry Andric NativeProcessProtocol::NativeDelegate &delegate, 780b57cec5SDimitry Andric MainLoop &mainloop) const override { 790b57cec5SDimitry Andric llvm_unreachable("Not implemented"); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 820b57cec5SDimitry Andric Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate, 830b57cec5SDimitry Andric MainLoop &mainloop) const override { 840b57cec5SDimitry Andric llvm_unreachable("Not implemented"); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric }; 870b57cec5SDimitry Andric #endif 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 909dba64beSDimitry Andric #ifndef _WIN32 910b57cec5SDimitry Andric // Watch for signals 920b57cec5SDimitry Andric static int g_sighup_received_count = 0; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric static void sighup_handler(MainLoopBase &mainloop) { 950b57cec5SDimitry Andric ++g_sighup_received_count; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); 989dba64beSDimitry Andric LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)", 990b57cec5SDimitry Andric __FUNCTION__, g_sighup_received_count); 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric if (g_sighup_received_count >= 2) 1020b57cec5SDimitry Andric mainloop.RequestTermination(); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric #endif // #ifndef _WIN32 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server, 1070b57cec5SDimitry Andric lldb::pid_t pid) { 1080b57cec5SDimitry Andric Status error = gdb_server.AttachToProcess(pid); 1090b57cec5SDimitry Andric if (error.Fail()) { 1100b57cec5SDimitry Andric fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, 1110b57cec5SDimitry Andric error.AsCString()); 1120b57cec5SDimitry Andric exit(1); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server, 1170b57cec5SDimitry Andric const std::string &process_name) { 1180b57cec5SDimitry Andric // FIXME implement. 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server, 1220b57cec5SDimitry Andric const std::string &attach_target) { 1230b57cec5SDimitry Andric assert(!attach_target.empty() && "attach_target cannot be empty"); 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric // First check if the attach_target is convertible to a long. If so, we'll use 1260b57cec5SDimitry Andric // it as a pid. 1270b57cec5SDimitry Andric char *end_p = nullptr; 1280b57cec5SDimitry Andric const long int pid = strtol(attach_target.c_str(), &end_p, 10); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // We'll call it a match if the entire argument is consumed. 1310b57cec5SDimitry Andric if (end_p && 1320b57cec5SDimitry Andric static_cast<size_t>(end_p - attach_target.c_str()) == 1330b57cec5SDimitry Andric attach_target.size()) 1340b57cec5SDimitry Andric handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid)); 1350b57cec5SDimitry Andric else 1360b57cec5SDimitry Andric handle_attach_to_process_name(gdb_server, attach_target); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 139e8d8bef9SDimitry Andric void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, 140e8d8bef9SDimitry Andric llvm::ArrayRef<llvm::StringRef> Arguments) { 1410b57cec5SDimitry Andric ProcessLaunchInfo info; 1420b57cec5SDimitry Andric info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug | 1430b57cec5SDimitry Andric eLaunchFlagDisableASLR); 144e8d8bef9SDimitry Andric info.SetArguments(Args(Arguments), true); 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric llvm::SmallString<64> cwd; 1470b57cec5SDimitry Andric if (std::error_code ec = llvm::sys::fs::current_path(cwd)) { 1480b57cec5SDimitry Andric llvm::errs() << "Error getting current directory: " << ec.message() << "\n"; 1490b57cec5SDimitry Andric exit(1); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric FileSpec cwd_spec(cwd); 1520b57cec5SDimitry Andric FileSystem::Instance().Resolve(cwd_spec); 1530b57cec5SDimitry Andric info.SetWorkingDirectory(cwd_spec); 1540b57cec5SDimitry Andric info.GetEnvironment() = Host::GetEnvironment(); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric gdb_server.SetLaunchInfo(info); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric Status error = gdb_server.LaunchProcess(); 1590b57cec5SDimitry Andric if (error.Fail()) { 1600b57cec5SDimitry Andric llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n", 161e8d8bef9SDimitry Andric Arguments[0], error); 1620b57cec5SDimitry Andric exit(1); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 166*349cc55cSDimitry Andric Status writeSocketIdToPipe(Pipe &port_pipe, llvm::StringRef socket_id) { 1670b57cec5SDimitry Andric size_t bytes_written = 0; 1680b57cec5SDimitry Andric // Write the port number as a C string with the NULL terminator. 169*349cc55cSDimitry Andric return port_pipe.Write(socket_id.data(), socket_id.size() + 1, bytes_written); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric Status writeSocketIdToPipe(const char *const named_pipe_path, 173*349cc55cSDimitry Andric llvm::StringRef socket_id) { 1740b57cec5SDimitry Andric Pipe port_name_pipe; 1750b57cec5SDimitry Andric // Wait for 10 seconds for pipe to be opened. 1760b57cec5SDimitry Andric auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false, 1770b57cec5SDimitry Andric std::chrono::seconds{10}); 1780b57cec5SDimitry Andric if (error.Fail()) 1790b57cec5SDimitry Andric return error; 1800b57cec5SDimitry Andric return writeSocketIdToPipe(port_name_pipe, socket_id); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe, 184*349cc55cSDimitry Andric llvm::StringRef socket_id) { 1850b57cec5SDimitry Andric Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe}; 1860b57cec5SDimitry Andric return writeSocketIdToPipe(port_pipe, socket_id); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric void ConnectToRemote(MainLoop &mainloop, 1900b57cec5SDimitry Andric GDBRemoteCommunicationServerLLGS &gdb_server, 191e8d8bef9SDimitry Andric bool reverse_connect, llvm::StringRef host_and_port, 1920b57cec5SDimitry Andric const char *const progname, const char *const subcommand, 1930b57cec5SDimitry Andric const char *const named_pipe_path, pipe_t unnamed_pipe, 1940b57cec5SDimitry Andric int connection_fd) { 1950b57cec5SDimitry Andric Status error; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric std::unique_ptr<Connection> connection_up; 198*349cc55cSDimitry Andric std::string url; 199*349cc55cSDimitry Andric 2000b57cec5SDimitry Andric if (connection_fd != -1) { 201*349cc55cSDimitry Andric url = llvm::formatv("fd://{0}", connection_fd).str(); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric // Create the connection. 204480093f4SDimitry Andric #if LLDB_ENABLE_POSIX && !defined _WIN32 2050b57cec5SDimitry Andric ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC); 2060b57cec5SDimitry Andric #endif 207e8d8bef9SDimitry Andric } else if (!host_and_port.empty()) { 208*349cc55cSDimitry Andric llvm::Expected<std::string> url_exp = 209*349cc55cSDimitry Andric LLGSArgToURL(host_and_port, reverse_connect); 210*349cc55cSDimitry Andric if (!url_exp) { 211*349cc55cSDimitry Andric llvm::errs() << llvm::formatv("error: invalid host:port or URL '{0}': " 212*349cc55cSDimitry Andric "{1}\n", 213*349cc55cSDimitry Andric host_and_port, 214*349cc55cSDimitry Andric llvm::toString(url_exp.takeError())); 2150b57cec5SDimitry Andric exit(-1); 2160b57cec5SDimitry Andric } 217*349cc55cSDimitry Andric 218*349cc55cSDimitry Andric url = std::move(url_exp.get()); 2190b57cec5SDimitry Andric } 220*349cc55cSDimitry Andric 221*349cc55cSDimitry Andric if (!url.empty()) { 222*349cc55cSDimitry Andric // Create the connection or server. 223*349cc55cSDimitry Andric std::unique_ptr<ConnectionFileDescriptor> conn_fd_up{ 224*349cc55cSDimitry Andric new ConnectionFileDescriptor}; 225*349cc55cSDimitry Andric auto connection_result = conn_fd_up->Connect( 226*349cc55cSDimitry Andric url, 227*349cc55cSDimitry Andric [named_pipe_path, unnamed_pipe](llvm::StringRef socket_id) { 228*349cc55cSDimitry Andric // If we have a named pipe to write the socket id back to, do that 229*349cc55cSDimitry Andric // now. 2300b57cec5SDimitry Andric if (named_pipe_path && named_pipe_path[0]) { 231*349cc55cSDimitry Andric Status error = writeSocketIdToPipe(named_pipe_path, socket_id); 2320b57cec5SDimitry Andric if (error.Fail()) 233*349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 234*349cc55cSDimitry Andric "failed to write to the named peipe '{0}': {1}\n", 2350b57cec5SDimitry Andric named_pipe_path, error.AsCString()); 2360b57cec5SDimitry Andric } 237*349cc55cSDimitry Andric // If we have an unnamed pipe to write the socket id back to, do 238*349cc55cSDimitry Andric // that now. 2390b57cec5SDimitry Andric else if (unnamed_pipe != LLDB_INVALID_PIPE) { 240*349cc55cSDimitry Andric Status error = writeSocketIdToPipe(unnamed_pipe, socket_id); 2410b57cec5SDimitry Andric if (error.Fail()) 242*349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 243*349cc55cSDimitry Andric "failed to write to the unnamed pipe: {0}\n", error); 2440b57cec5SDimitry Andric } 245*349cc55cSDimitry Andric }, 246*349cc55cSDimitry Andric &error); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric if (error.Fail()) { 249*349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 250*349cc55cSDimitry Andric "error: failed to connect to client at '{0}': {1}\n", url, error); 251*349cc55cSDimitry Andric exit(-1); 2520b57cec5SDimitry Andric } 253*349cc55cSDimitry Andric if (connection_result != eConnectionStatusSuccess) { 254*349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 255*349cc55cSDimitry Andric "error: failed to connect to client at '{0}' " 256*349cc55cSDimitry Andric "(connection status: {1})\n", 257*349cc55cSDimitry Andric url, static_cast<int>(connection_result)); 258*349cc55cSDimitry Andric exit(-1); 2590b57cec5SDimitry Andric } 260*349cc55cSDimitry Andric connection_up = std::move(conn_fd_up); 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric error = gdb_server.InitializeConnection(std::move(connection_up)); 2630b57cec5SDimitry Andric if (error.Fail()) { 264*349cc55cSDimitry Andric llvm::errs() << llvm::formatv("failed to initialize connection\n", error); 2650b57cec5SDimitry Andric exit(-1); 2660b57cec5SDimitry Andric } 267*349cc55cSDimitry Andric llvm::outs() << "Connection established.\n"; 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 270e8d8bef9SDimitry Andric namespace { 271e8d8bef9SDimitry Andric enum ID { 272e8d8bef9SDimitry Andric OPT_INVALID = 0, // This is not an option ID. 273e8d8bef9SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 274e8d8bef9SDimitry Andric HELPTEXT, METAVAR, VALUES) \ 275e8d8bef9SDimitry Andric OPT_##ID, 276e8d8bef9SDimitry Andric #include "LLGSOptions.inc" 277e8d8bef9SDimitry Andric #undef OPTION 278e8d8bef9SDimitry Andric }; 279e8d8bef9SDimitry Andric 280e8d8bef9SDimitry Andric #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 281e8d8bef9SDimitry Andric #include "LLGSOptions.inc" 282e8d8bef9SDimitry Andric #undef PREFIX 283e8d8bef9SDimitry Andric 284e8d8bef9SDimitry Andric const opt::OptTable::Info InfoTable[] = { 285e8d8bef9SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 286e8d8bef9SDimitry Andric HELPTEXT, METAVAR, VALUES) \ 287e8d8bef9SDimitry Andric { \ 288e8d8bef9SDimitry Andric PREFIX, NAME, HELPTEXT, \ 289e8d8bef9SDimitry Andric METAVAR, OPT_##ID, opt::Option::KIND##Class, \ 290e8d8bef9SDimitry Andric PARAM, FLAGS, OPT_##GROUP, \ 291e8d8bef9SDimitry Andric OPT_##ALIAS, ALIASARGS, VALUES}, 292e8d8bef9SDimitry Andric #include "LLGSOptions.inc" 293e8d8bef9SDimitry Andric #undef OPTION 294e8d8bef9SDimitry Andric }; 295e8d8bef9SDimitry Andric 296e8d8bef9SDimitry Andric class LLGSOptTable : public opt::OptTable { 297e8d8bef9SDimitry Andric public: 298e8d8bef9SDimitry Andric LLGSOptTable() : OptTable(InfoTable) {} 299e8d8bef9SDimitry Andric 300e8d8bef9SDimitry Andric void PrintHelp(llvm::StringRef Name) { 301e8d8bef9SDimitry Andric std::string Usage = 302e8d8bef9SDimitry Andric (Name + " [options] [[host]:port] [[--] program args...]").str(); 303fe6060f1SDimitry Andric OptTable::printHelp(llvm::outs(), Usage.c_str(), "lldb-server"); 304e8d8bef9SDimitry Andric llvm::outs() << R"( 305e8d8bef9SDimitry Andric DESCRIPTION 306e8d8bef9SDimitry Andric lldb-server connects to the LLDB client, which drives the debugging session. 307e8d8bef9SDimitry Andric If no connection options are given, the [host]:port argument must be present 308e8d8bef9SDimitry Andric and will denote the address that lldb-server will listen on. [host] defaults 309e8d8bef9SDimitry Andric to "localhost" if empty. Port can be zero, in which case the port number will 310e8d8bef9SDimitry Andric be chosen dynamically and written to destinations given by --named-pipe and 311e8d8bef9SDimitry Andric --pipe arguments. 312e8d8bef9SDimitry Andric 313e8d8bef9SDimitry Andric If no target is selected at startup, lldb-server can be directed by the LLDB 314e8d8bef9SDimitry Andric client to launch or attach to a process. 315e8d8bef9SDimitry Andric 316e8d8bef9SDimitry Andric )"; 317e8d8bef9SDimitry Andric } 318e8d8bef9SDimitry Andric }; 319e8d8bef9SDimitry Andric } // namespace 320e8d8bef9SDimitry Andric 3210b57cec5SDimitry Andric int main_gdbserver(int argc, char *argv[]) { 3220b57cec5SDimitry Andric Status error; 3230b57cec5SDimitry Andric MainLoop mainloop; 3240b57cec5SDimitry Andric #ifndef _WIN32 3250b57cec5SDimitry Andric // Setup signal handlers first thing. 3260b57cec5SDimitry Andric signal(SIGPIPE, SIG_IGN); 3270b57cec5SDimitry Andric MainLoop::SignalHandleUP sighup_handle = 3280b57cec5SDimitry Andric mainloop.RegisterSignal(SIGHUP, sighup_handler, error); 3290b57cec5SDimitry Andric #endif 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric const char *progname = argv[0]; 3320b57cec5SDimitry Andric const char *subcommand = argv[1]; 3330b57cec5SDimitry Andric std::string attach_target; 3340b57cec5SDimitry Andric std::string named_pipe_path; 3350b57cec5SDimitry Andric std::string log_file; 3360b57cec5SDimitry Andric StringRef 3370b57cec5SDimitry Andric log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" 3380b57cec5SDimitry Andric lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE; 3390b57cec5SDimitry Andric bool reverse_connect = false; 3400b57cec5SDimitry Andric int connection_fd = -1; 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric // ProcessLaunchInfo launch_info; 3430b57cec5SDimitry Andric ProcessAttachInfo attach_info; 3440b57cec5SDimitry Andric 345e8d8bef9SDimitry Andric LLGSOptTable Opts; 346e8d8bef9SDimitry Andric llvm::BumpPtrAllocator Alloc; 347e8d8bef9SDimitry Andric llvm::StringSaver Saver(Alloc); 348e8d8bef9SDimitry Andric bool HasError = false; 349e8d8bef9SDimitry Andric opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN, 350e8d8bef9SDimitry Andric Saver, [&](llvm::StringRef Msg) { 351e8d8bef9SDimitry Andric WithColor::error() << Msg << "\n"; 352e8d8bef9SDimitry Andric HasError = true; 353e8d8bef9SDimitry Andric }); 354e8d8bef9SDimitry Andric std::string Name = 355e8d8bef9SDimitry Andric (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str(); 356e8d8bef9SDimitry Andric std::string HelpText = 357e8d8bef9SDimitry Andric "Use '" + Name + " --help' for a complete list of options.\n"; 358e8d8bef9SDimitry Andric if (HasError) { 359e8d8bef9SDimitry Andric llvm::errs() << HelpText; 360e8d8bef9SDimitry Andric return 1; 361e8d8bef9SDimitry Andric } 3620b57cec5SDimitry Andric 363e8d8bef9SDimitry Andric if (Args.hasArg(OPT_help)) { 364e8d8bef9SDimitry Andric Opts.PrintHelp(Name); 365e8d8bef9SDimitry Andric return 0; 366e8d8bef9SDimitry Andric } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric #ifndef _WIN32 369e8d8bef9SDimitry Andric if (Args.hasArg(OPT_setsid)) { 3700b57cec5SDimitry Andric // Put llgs into a new session. Terminals group processes 3710b57cec5SDimitry Andric // into sessions and when a special terminal key sequences 3720b57cec5SDimitry Andric // (like control+c) are typed they can cause signals to go out to 3730b57cec5SDimitry Andric // all processes in a session. Using this --setsid (-S) option 3740b57cec5SDimitry Andric // will cause debugserver to run in its own sessions and be free 3750b57cec5SDimitry Andric // from such issues. 3760b57cec5SDimitry Andric // 3770b57cec5SDimitry Andric // This is useful when llgs is spawned from a command 3780b57cec5SDimitry Andric // line application that uses llgs to do the debugging, 3790b57cec5SDimitry Andric // yet that application doesn't want llgs receiving the 3800b57cec5SDimitry Andric // signals sent to the session (i.e. dying when anyone hits ^C). 3810b57cec5SDimitry Andric { 3820b57cec5SDimitry Andric const ::pid_t new_sid = setsid(); 3830b57cec5SDimitry Andric if (new_sid == -1) { 384e8d8bef9SDimitry Andric WithColor::warning() 385e8d8bef9SDimitry Andric << llvm::formatv("failed to set new session id for {0} ({1})\n", 386e8d8bef9SDimitry Andric LLGS_PROGRAM_NAME, llvm::sys::StrError()); 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric } 389e8d8bef9SDimitry Andric } 3900b57cec5SDimitry Andric #endif 3910b57cec5SDimitry Andric 392e8d8bef9SDimitry Andric log_file = Args.getLastArgValue(OPT_log_file).str(); 393e8d8bef9SDimitry Andric log_channels = Args.getLastArgValue(OPT_log_channels); 394e8d8bef9SDimitry Andric named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str(); 395e8d8bef9SDimitry Andric reverse_connect = Args.hasArg(OPT_reverse_connect); 396e8d8bef9SDimitry Andric attach_target = Args.getLastArgValue(OPT_attach).str(); 397e8d8bef9SDimitry Andric if (Args.hasArg(OPT_pipe)) { 398e8d8bef9SDimitry Andric uint64_t Arg; 399e8d8bef9SDimitry Andric if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) { 400e8d8bef9SDimitry Andric WithColor::error() << "invalid '--pipe' argument\n" << HelpText; 401e8d8bef9SDimitry Andric return 1; 4020b57cec5SDimitry Andric } 403e8d8bef9SDimitry Andric unnamed_pipe = (pipe_t)Arg; 4040b57cec5SDimitry Andric } 405e8d8bef9SDimitry Andric if (Args.hasArg(OPT_fd)) { 406e8d8bef9SDimitry Andric if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), connection_fd)) { 407e8d8bef9SDimitry Andric WithColor::error() << "invalid '--fd' argument\n" << HelpText; 408e8d8bef9SDimitry Andric return 1; 409e8d8bef9SDimitry Andric } 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric if (!LLDBServerUtilities::SetupLogging( 4130b57cec5SDimitry Andric log_file, log_channels, 4140b57cec5SDimitry Andric LLDB_LOG_OPTION_PREPEND_TIMESTAMP | 4150b57cec5SDimitry Andric LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION)) 4160b57cec5SDimitry Andric return -1; 4170b57cec5SDimitry Andric 418e8d8bef9SDimitry Andric std::vector<llvm::StringRef> Inputs; 419e8d8bef9SDimitry Andric for (opt::Arg *Arg : Args.filtered(OPT_INPUT)) 420e8d8bef9SDimitry Andric Inputs.push_back(Arg->getValue()); 421e8d8bef9SDimitry Andric if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) { 422e8d8bef9SDimitry Andric for (const char *Val : Arg->getValues()) 423e8d8bef9SDimitry Andric Inputs.push_back(Val); 4240b57cec5SDimitry Andric } 425e8d8bef9SDimitry Andric if (Inputs.empty() && connection_fd == -1) { 426e8d8bef9SDimitry Andric WithColor::error() << "no connection arguments\n" << HelpText; 427e8d8bef9SDimitry Andric return 1; 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric NativeProcessFactory factory; 4310b57cec5SDimitry Andric GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory); 4320b57cec5SDimitry Andric 433e8d8bef9SDimitry Andric llvm::StringRef host_and_port; 434e8d8bef9SDimitry Andric if (!Inputs.empty()) { 435e8d8bef9SDimitry Andric host_and_port = Inputs.front(); 436e8d8bef9SDimitry Andric Inputs.erase(Inputs.begin()); 437e8d8bef9SDimitry Andric } 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric // Any arguments left over are for the program that we need to launch. If 4400b57cec5SDimitry Andric // there 4410b57cec5SDimitry Andric // are no arguments, then the GDB server will start up and wait for an 'A' 4420b57cec5SDimitry Andric // packet 4430b57cec5SDimitry Andric // to launch a program, or a vAttach packet to attach to an existing process, 4440b57cec5SDimitry Andric // unless 4450b57cec5SDimitry Andric // explicitly asked to attach with the --attach={pid|program_name} form. 4460b57cec5SDimitry Andric if (!attach_target.empty()) 4470b57cec5SDimitry Andric handle_attach(gdb_server, attach_target); 448e8d8bef9SDimitry Andric else if (!Inputs.empty()) 449e8d8bef9SDimitry Andric handle_launch(gdb_server, Inputs); 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric // Print version info. 4529dba64beSDimitry Andric printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR); 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port, 4550b57cec5SDimitry Andric progname, subcommand, named_pipe_path.c_str(), 4560b57cec5SDimitry Andric unnamed_pipe, connection_fd); 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric if (!gdb_server.IsConnected()) { 4590b57cec5SDimitry Andric fprintf(stderr, "no connection information provided, unable to run\n"); 4600b57cec5SDimitry Andric return 1; 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric Status ret = mainloop.Run(); 4640b57cec5SDimitry Andric if (ret.Fail()) { 4650b57cec5SDimitry Andric fprintf(stderr, "lldb-server terminating due to error: %s\n", 4660b57cec5SDimitry Andric ret.AsCString()); 4670b57cec5SDimitry Andric return 1; 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric fprintf(stderr, "lldb-server exiting...\n"); 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric return 0; 4720b57cec5SDimitry Andric } 473