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" 3081ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 310b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 320b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 33e8d8bef9SDimitry Andric #include "llvm/Option/ArgList.h" 34e8d8bef9SDimitry Andric #include "llvm/Option/OptTable.h" 35e8d8bef9SDimitry Andric #include "llvm/Option/Option.h" 360b57cec5SDimitry Andric #include "llvm/Support/Errno.h" 3706c3fb27SDimitry Andric #include "llvm/Support/Error.h" 38e8d8bef9SDimitry Andric #include "llvm/Support/WithColor.h" 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric #if defined(__linux__) 410b57cec5SDimitry Andric #include "Plugins/Process/Linux/NativeProcessLinux.h" 42e8d8bef9SDimitry Andric #elif defined(__FreeBSD__) 43d409305fSDimitry Andric #include "Plugins/Process/FreeBSD/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__) 6606c3fb27SDimitry Andric typedef process_linux::NativeProcessLinux::Manager NativeProcessManager; 67e8d8bef9SDimitry Andric #elif defined(__FreeBSD__) 6806c3fb27SDimitry Andric typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; 690b57cec5SDimitry Andric #elif defined(__NetBSD__) 7006c3fb27SDimitry Andric typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; 719dba64beSDimitry Andric #elif defined(_WIN32) 7206c3fb27SDimitry Andric typedef NativeProcessWindows::Manager NativeProcessManager; 730b57cec5SDimitry Andric #else 740b57cec5SDimitry Andric // Dummy implementation to make sure the code compiles 7506c3fb27SDimitry Andric class NativeProcessManager : public NativeProcessProtocol::Manager { 760b57cec5SDimitry Andric public: 7706c3fb27SDimitry Andric NativeProcessManager(MainLoop &mainloop) 7806c3fb27SDimitry Andric : NativeProcessProtocol::Manager(mainloop) {} 7906c3fb27SDimitry Andric 800b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 810b57cec5SDimitry Andric Launch(ProcessLaunchInfo &launch_info, 8206c3fb27SDimitry Andric NativeProcessProtocol::NativeDelegate &native_delegate) override { 830b57cec5SDimitry Andric llvm_unreachable("Not implemented"); 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 8606c3fb27SDimitry Andric Attach(lldb::pid_t pid, 8706c3fb27SDimitry Andric NativeProcessProtocol::NativeDelegate &native_delegate) override { 880b57cec5SDimitry Andric llvm_unreachable("Not implemented"); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric }; 910b57cec5SDimitry Andric #endif 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 949dba64beSDimitry Andric #ifndef _WIN32 950b57cec5SDimitry Andric // Watch for signals 960b57cec5SDimitry Andric static int g_sighup_received_count = 0; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric static void sighup_handler(MainLoopBase &mainloop) { 990b57cec5SDimitry Andric ++g_sighup_received_count; 1000b57cec5SDimitry Andric 10181ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Process); 1029dba64beSDimitry Andric LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)", 1030b57cec5SDimitry Andric __FUNCTION__, g_sighup_received_count); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric if (g_sighup_received_count >= 2) 1060b57cec5SDimitry Andric mainloop.RequestTermination(); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric #endif // #ifndef _WIN32 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server, 1110b57cec5SDimitry Andric lldb::pid_t pid) { 1120b57cec5SDimitry Andric Status error = gdb_server.AttachToProcess(pid); 1130b57cec5SDimitry Andric if (error.Fail()) { 1140b57cec5SDimitry Andric fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, 1150b57cec5SDimitry Andric error.AsCString()); 1160b57cec5SDimitry Andric exit(1); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server, 1210b57cec5SDimitry Andric const std::string &process_name) { 1220b57cec5SDimitry Andric // FIXME implement. 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server, 1260b57cec5SDimitry Andric const std::string &attach_target) { 1270b57cec5SDimitry Andric assert(!attach_target.empty() && "attach_target cannot be empty"); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // First check if the attach_target is convertible to a long. If so, we'll use 1300b57cec5SDimitry Andric // it as a pid. 1310b57cec5SDimitry Andric char *end_p = nullptr; 1320b57cec5SDimitry Andric const long int pid = strtol(attach_target.c_str(), &end_p, 10); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric // We'll call it a match if the entire argument is consumed. 1350b57cec5SDimitry Andric if (end_p && 1360b57cec5SDimitry Andric static_cast<size_t>(end_p - attach_target.c_str()) == 1370b57cec5SDimitry Andric attach_target.size()) 1380b57cec5SDimitry Andric handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid)); 1390b57cec5SDimitry Andric else 1400b57cec5SDimitry Andric handle_attach_to_process_name(gdb_server, attach_target); 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric 143e8d8bef9SDimitry Andric void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, 144e8d8bef9SDimitry Andric llvm::ArrayRef<llvm::StringRef> Arguments) { 1450b57cec5SDimitry Andric ProcessLaunchInfo info; 1460b57cec5SDimitry Andric info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug | 1470b57cec5SDimitry Andric eLaunchFlagDisableASLR); 148e8d8bef9SDimitry Andric info.SetArguments(Args(Arguments), true); 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric llvm::SmallString<64> cwd; 1510b57cec5SDimitry Andric if (std::error_code ec = llvm::sys::fs::current_path(cwd)) { 1520b57cec5SDimitry Andric llvm::errs() << "Error getting current directory: " << ec.message() << "\n"; 1530b57cec5SDimitry Andric exit(1); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric FileSpec cwd_spec(cwd); 1560b57cec5SDimitry Andric FileSystem::Instance().Resolve(cwd_spec); 1570b57cec5SDimitry Andric info.SetWorkingDirectory(cwd_spec); 1580b57cec5SDimitry Andric info.GetEnvironment() = Host::GetEnvironment(); 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric gdb_server.SetLaunchInfo(info); 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric Status error = gdb_server.LaunchProcess(); 1630b57cec5SDimitry Andric if (error.Fail()) { 1640b57cec5SDimitry Andric llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n", 165e8d8bef9SDimitry Andric Arguments[0], error); 1660b57cec5SDimitry Andric exit(1); 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 170349cc55cSDimitry Andric Status writeSocketIdToPipe(Pipe &port_pipe, llvm::StringRef socket_id) { 1710b57cec5SDimitry Andric size_t bytes_written = 0; 1720b57cec5SDimitry Andric // Write the port number as a C string with the NULL terminator. 173349cc55cSDimitry Andric return port_pipe.Write(socket_id.data(), socket_id.size() + 1, bytes_written); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric Status writeSocketIdToPipe(const char *const named_pipe_path, 177349cc55cSDimitry Andric llvm::StringRef socket_id) { 1780b57cec5SDimitry Andric Pipe port_name_pipe; 1790b57cec5SDimitry Andric // Wait for 10 seconds for pipe to be opened. 1800b57cec5SDimitry Andric auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false, 1810b57cec5SDimitry Andric std::chrono::seconds{10}); 1820b57cec5SDimitry Andric if (error.Fail()) 1830b57cec5SDimitry Andric return error; 1840b57cec5SDimitry Andric return writeSocketIdToPipe(port_name_pipe, socket_id); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe, 188349cc55cSDimitry Andric llvm::StringRef socket_id) { 1890b57cec5SDimitry Andric Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe}; 1900b57cec5SDimitry Andric return writeSocketIdToPipe(port_pipe, socket_id); 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric void ConnectToRemote(MainLoop &mainloop, 1940b57cec5SDimitry Andric GDBRemoteCommunicationServerLLGS &gdb_server, 195e8d8bef9SDimitry Andric bool reverse_connect, llvm::StringRef host_and_port, 1960b57cec5SDimitry Andric const char *const progname, const char *const subcommand, 1970b57cec5SDimitry Andric const char *const named_pipe_path, pipe_t unnamed_pipe, 1980b57cec5SDimitry Andric int connection_fd) { 1990b57cec5SDimitry Andric Status error; 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric std::unique_ptr<Connection> connection_up; 202349cc55cSDimitry Andric std::string url; 203349cc55cSDimitry Andric 2040b57cec5SDimitry Andric if (connection_fd != -1) { 205349cc55cSDimitry Andric url = llvm::formatv("fd://{0}", connection_fd).str(); 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric // Create the connection. 208480093f4SDimitry Andric #if LLDB_ENABLE_POSIX && !defined _WIN32 2090b57cec5SDimitry Andric ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC); 2100b57cec5SDimitry Andric #endif 211e8d8bef9SDimitry Andric } else if (!host_and_port.empty()) { 212349cc55cSDimitry Andric llvm::Expected<std::string> url_exp = 213349cc55cSDimitry Andric LLGSArgToURL(host_and_port, reverse_connect); 214349cc55cSDimitry Andric if (!url_exp) { 215349cc55cSDimitry Andric llvm::errs() << llvm::formatv("error: invalid host:port or URL '{0}': " 216349cc55cSDimitry Andric "{1}\n", 217349cc55cSDimitry Andric host_and_port, 218349cc55cSDimitry Andric llvm::toString(url_exp.takeError())); 2190b57cec5SDimitry Andric exit(-1); 2200b57cec5SDimitry Andric } 221349cc55cSDimitry Andric 222349cc55cSDimitry Andric url = std::move(url_exp.get()); 2230b57cec5SDimitry Andric } 224349cc55cSDimitry Andric 225349cc55cSDimitry Andric if (!url.empty()) { 226349cc55cSDimitry Andric // Create the connection or server. 227349cc55cSDimitry Andric std::unique_ptr<ConnectionFileDescriptor> conn_fd_up{ 228349cc55cSDimitry Andric new ConnectionFileDescriptor}; 229349cc55cSDimitry Andric auto connection_result = conn_fd_up->Connect( 230349cc55cSDimitry Andric url, 231349cc55cSDimitry Andric [named_pipe_path, unnamed_pipe](llvm::StringRef socket_id) { 232349cc55cSDimitry Andric // If we have a named pipe to write the socket id back to, do that 233349cc55cSDimitry Andric // now. 2340b57cec5SDimitry Andric if (named_pipe_path && named_pipe_path[0]) { 235349cc55cSDimitry Andric Status error = writeSocketIdToPipe(named_pipe_path, socket_id); 2360b57cec5SDimitry Andric if (error.Fail()) 237349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 238*0fca6ea1SDimitry Andric "failed to write to the named pipe '{0}': {1}\n", 2390b57cec5SDimitry Andric named_pipe_path, error.AsCString()); 2400b57cec5SDimitry Andric } 241349cc55cSDimitry Andric // If we have an unnamed pipe to write the socket id back to, do 242349cc55cSDimitry Andric // that now. 2430b57cec5SDimitry Andric else if (unnamed_pipe != LLDB_INVALID_PIPE) { 244349cc55cSDimitry Andric Status error = writeSocketIdToPipe(unnamed_pipe, socket_id); 2450b57cec5SDimitry Andric if (error.Fail()) 246349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 247349cc55cSDimitry Andric "failed to write to the unnamed pipe: {0}\n", error); 2480b57cec5SDimitry Andric } 249349cc55cSDimitry Andric }, 250349cc55cSDimitry Andric &error); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric if (error.Fail()) { 253349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 254349cc55cSDimitry Andric "error: failed to connect to client at '{0}': {1}\n", url, error); 255349cc55cSDimitry Andric exit(-1); 2560b57cec5SDimitry Andric } 257349cc55cSDimitry Andric if (connection_result != eConnectionStatusSuccess) { 258349cc55cSDimitry Andric llvm::errs() << llvm::formatv( 259349cc55cSDimitry Andric "error: failed to connect to client at '{0}' " 260349cc55cSDimitry Andric "(connection status: {1})\n", 261349cc55cSDimitry Andric url, static_cast<int>(connection_result)); 262349cc55cSDimitry Andric exit(-1); 2630b57cec5SDimitry Andric } 264349cc55cSDimitry Andric connection_up = std::move(conn_fd_up); 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric error = gdb_server.InitializeConnection(std::move(connection_up)); 2670b57cec5SDimitry Andric if (error.Fail()) { 268349cc55cSDimitry Andric llvm::errs() << llvm::formatv("failed to initialize connection\n", error); 2690b57cec5SDimitry Andric exit(-1); 2700b57cec5SDimitry Andric } 271349cc55cSDimitry Andric llvm::outs() << "Connection established.\n"; 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 274e8d8bef9SDimitry Andric namespace { 2755f757f3fSDimitry Andric using namespace llvm::opt; 2765f757f3fSDimitry Andric 277e8d8bef9SDimitry Andric enum ID { 278e8d8bef9SDimitry Andric OPT_INVALID = 0, // This is not an option ID. 2795f757f3fSDimitry Andric #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 280e8d8bef9SDimitry Andric #include "LLGSOptions.inc" 281e8d8bef9SDimitry Andric #undef OPTION 282e8d8bef9SDimitry Andric }; 283e8d8bef9SDimitry Andric 284bdd1243dSDimitry Andric #define PREFIX(NAME, VALUE) \ 285bdd1243dSDimitry Andric constexpr llvm::StringLiteral NAME##_init[] = VALUE; \ 286bdd1243dSDimitry Andric constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \ 287bdd1243dSDimitry Andric NAME##_init, std::size(NAME##_init) - 1); 288e8d8bef9SDimitry Andric #include "LLGSOptions.inc" 289e8d8bef9SDimitry Andric #undef PREFIX 290e8d8bef9SDimitry Andric 291bdd1243dSDimitry Andric static constexpr opt::OptTable::Info InfoTable[] = { 2925f757f3fSDimitry Andric #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 293e8d8bef9SDimitry Andric #include "LLGSOptions.inc" 294e8d8bef9SDimitry Andric #undef OPTION 295e8d8bef9SDimitry Andric }; 296e8d8bef9SDimitry Andric 297bdd1243dSDimitry Andric class LLGSOptTable : public opt::GenericOptTable { 298e8d8bef9SDimitry Andric public: 299bdd1243dSDimitry Andric LLGSOptTable() : opt::GenericOptTable(InfoTable) {} 300e8d8bef9SDimitry Andric 301e8d8bef9SDimitry Andric void PrintHelp(llvm::StringRef Name) { 302e8d8bef9SDimitry Andric std::string Usage = 303e8d8bef9SDimitry Andric (Name + " [options] [[host]:port] [[--] program args...]").str(); 304fe6060f1SDimitry Andric OptTable::printHelp(llvm::outs(), Usage.c_str(), "lldb-server"); 305e8d8bef9SDimitry Andric llvm::outs() << R"( 306e8d8bef9SDimitry Andric DESCRIPTION 307e8d8bef9SDimitry Andric lldb-server connects to the LLDB client, which drives the debugging session. 308e8d8bef9SDimitry Andric If no connection options are given, the [host]:port argument must be present 309e8d8bef9SDimitry Andric and will denote the address that lldb-server will listen on. [host] defaults 310e8d8bef9SDimitry Andric to "localhost" if empty. Port can be zero, in which case the port number will 311e8d8bef9SDimitry Andric be chosen dynamically and written to destinations given by --named-pipe and 312e8d8bef9SDimitry Andric --pipe arguments. 313e8d8bef9SDimitry Andric 314e8d8bef9SDimitry Andric If no target is selected at startup, lldb-server can be directed by the LLDB 315e8d8bef9SDimitry Andric client to launch or attach to a process. 316e8d8bef9SDimitry Andric 317e8d8bef9SDimitry Andric )"; 318e8d8bef9SDimitry Andric } 319e8d8bef9SDimitry Andric }; 320e8d8bef9SDimitry Andric } // namespace 321e8d8bef9SDimitry Andric 3220b57cec5SDimitry Andric int main_gdbserver(int argc, char *argv[]) { 3230b57cec5SDimitry Andric Status error; 3240b57cec5SDimitry Andric MainLoop mainloop; 3250b57cec5SDimitry Andric #ifndef _WIN32 3260b57cec5SDimitry Andric // Setup signal handlers first thing. 3270b57cec5SDimitry Andric signal(SIGPIPE, SIG_IGN); 3280b57cec5SDimitry Andric MainLoop::SignalHandleUP sighup_handle = 3290b57cec5SDimitry Andric mainloop.RegisterSignal(SIGHUP, sighup_handler, error); 3300b57cec5SDimitry Andric #endif 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric const char *progname = argv[0]; 3330b57cec5SDimitry Andric const char *subcommand = argv[1]; 3340b57cec5SDimitry Andric std::string attach_target; 3350b57cec5SDimitry Andric std::string named_pipe_path; 3360b57cec5SDimitry Andric std::string log_file; 3370b57cec5SDimitry Andric StringRef 3380b57cec5SDimitry Andric log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" 3390b57cec5SDimitry Andric lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE; 3400b57cec5SDimitry Andric bool reverse_connect = false; 3410b57cec5SDimitry Andric int connection_fd = -1; 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric // ProcessLaunchInfo launch_info; 3440b57cec5SDimitry Andric ProcessAttachInfo attach_info; 3450b57cec5SDimitry Andric 346e8d8bef9SDimitry Andric LLGSOptTable Opts; 347e8d8bef9SDimitry Andric llvm::BumpPtrAllocator Alloc; 348e8d8bef9SDimitry Andric llvm::StringSaver Saver(Alloc); 349e8d8bef9SDimitry Andric bool HasError = false; 350e8d8bef9SDimitry Andric opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN, 351e8d8bef9SDimitry Andric Saver, [&](llvm::StringRef Msg) { 352e8d8bef9SDimitry Andric WithColor::error() << Msg << "\n"; 353e8d8bef9SDimitry Andric HasError = true; 354e8d8bef9SDimitry Andric }); 355e8d8bef9SDimitry Andric std::string Name = 356e8d8bef9SDimitry Andric (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str(); 357e8d8bef9SDimitry Andric std::string HelpText = 358e8d8bef9SDimitry Andric "Use '" + Name + " --help' for a complete list of options.\n"; 359e8d8bef9SDimitry Andric if (HasError) { 360e8d8bef9SDimitry Andric llvm::errs() << HelpText; 361e8d8bef9SDimitry Andric return 1; 362e8d8bef9SDimitry Andric } 3630b57cec5SDimitry Andric 364e8d8bef9SDimitry Andric if (Args.hasArg(OPT_help)) { 365e8d8bef9SDimitry Andric Opts.PrintHelp(Name); 366e8d8bef9SDimitry Andric return 0; 367e8d8bef9SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric #ifndef _WIN32 370e8d8bef9SDimitry Andric if (Args.hasArg(OPT_setsid)) { 3710b57cec5SDimitry Andric // Put llgs into a new session. Terminals group processes 3720b57cec5SDimitry Andric // into sessions and when a special terminal key sequences 3730b57cec5SDimitry Andric // (like control+c) are typed they can cause signals to go out to 3740b57cec5SDimitry Andric // all processes in a session. Using this --setsid (-S) option 3750b57cec5SDimitry Andric // will cause debugserver to run in its own sessions and be free 3760b57cec5SDimitry Andric // from such issues. 3770b57cec5SDimitry Andric // 3780b57cec5SDimitry Andric // This is useful when llgs is spawned from a command 3790b57cec5SDimitry Andric // line application that uses llgs to do the debugging, 3800b57cec5SDimitry Andric // yet that application doesn't want llgs receiving the 3810b57cec5SDimitry Andric // signals sent to the session (i.e. dying when anyone hits ^C). 3820b57cec5SDimitry Andric { 3830b57cec5SDimitry Andric const ::pid_t new_sid = setsid(); 3840b57cec5SDimitry Andric if (new_sid == -1) { 385e8d8bef9SDimitry Andric WithColor::warning() 386e8d8bef9SDimitry Andric << llvm::formatv("failed to set new session id for {0} ({1})\n", 387e8d8bef9SDimitry Andric LLGS_PROGRAM_NAME, llvm::sys::StrError()); 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric } 390e8d8bef9SDimitry Andric } 3910b57cec5SDimitry Andric #endif 3920b57cec5SDimitry Andric 393e8d8bef9SDimitry Andric log_file = Args.getLastArgValue(OPT_log_file).str(); 394e8d8bef9SDimitry Andric log_channels = Args.getLastArgValue(OPT_log_channels); 395e8d8bef9SDimitry Andric named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str(); 396e8d8bef9SDimitry Andric reverse_connect = Args.hasArg(OPT_reverse_connect); 397e8d8bef9SDimitry Andric attach_target = Args.getLastArgValue(OPT_attach).str(); 398e8d8bef9SDimitry Andric if (Args.hasArg(OPT_pipe)) { 399e8d8bef9SDimitry Andric uint64_t Arg; 400e8d8bef9SDimitry Andric if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) { 401e8d8bef9SDimitry Andric WithColor::error() << "invalid '--pipe' argument\n" << HelpText; 402e8d8bef9SDimitry Andric return 1; 4030b57cec5SDimitry Andric } 404e8d8bef9SDimitry Andric unnamed_pipe = (pipe_t)Arg; 4050b57cec5SDimitry Andric } 406e8d8bef9SDimitry Andric if (Args.hasArg(OPT_fd)) { 407e8d8bef9SDimitry Andric if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), connection_fd)) { 408e8d8bef9SDimitry Andric WithColor::error() << "invalid '--fd' argument\n" << HelpText; 409e8d8bef9SDimitry Andric return 1; 410e8d8bef9SDimitry Andric } 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric if (!LLDBServerUtilities::SetupLogging( 4140b57cec5SDimitry Andric log_file, log_channels, 4150b57cec5SDimitry Andric LLDB_LOG_OPTION_PREPEND_TIMESTAMP | 4160b57cec5SDimitry Andric LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION)) 4170b57cec5SDimitry Andric return -1; 4180b57cec5SDimitry Andric 419e8d8bef9SDimitry Andric std::vector<llvm::StringRef> Inputs; 420e8d8bef9SDimitry Andric for (opt::Arg *Arg : Args.filtered(OPT_INPUT)) 421e8d8bef9SDimitry Andric Inputs.push_back(Arg->getValue()); 422e8d8bef9SDimitry Andric if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) { 423e8d8bef9SDimitry Andric for (const char *Val : Arg->getValues()) 424e8d8bef9SDimitry Andric Inputs.push_back(Val); 4250b57cec5SDimitry Andric } 426e8d8bef9SDimitry Andric if (Inputs.empty() && connection_fd == -1) { 427e8d8bef9SDimitry Andric WithColor::error() << "no connection arguments\n" << HelpText; 428e8d8bef9SDimitry Andric return 1; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 43106c3fb27SDimitry Andric NativeProcessManager manager(mainloop); 43206c3fb27SDimitry Andric GDBRemoteCommunicationServerLLGS gdb_server(mainloop, manager); 4330b57cec5SDimitry Andric 434e8d8bef9SDimitry Andric llvm::StringRef host_and_port; 435e8d8bef9SDimitry Andric if (!Inputs.empty()) { 436e8d8bef9SDimitry Andric host_and_port = Inputs.front(); 437e8d8bef9SDimitry Andric Inputs.erase(Inputs.begin()); 438e8d8bef9SDimitry Andric } 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric // Any arguments left over are for the program that we need to launch. If 4410b57cec5SDimitry Andric // there 4420b57cec5SDimitry Andric // are no arguments, then the GDB server will start up and wait for an 'A' 4430b57cec5SDimitry Andric // packet 4440b57cec5SDimitry Andric // to launch a program, or a vAttach packet to attach to an existing process, 4450b57cec5SDimitry Andric // unless 4460b57cec5SDimitry Andric // explicitly asked to attach with the --attach={pid|program_name} form. 4470b57cec5SDimitry Andric if (!attach_target.empty()) 4480b57cec5SDimitry Andric handle_attach(gdb_server, attach_target); 449e8d8bef9SDimitry Andric else if (!Inputs.empty()) 450e8d8bef9SDimitry Andric handle_launch(gdb_server, Inputs); 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric // Print version info. 4539dba64beSDimitry Andric printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR); 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port, 4560b57cec5SDimitry Andric progname, subcommand, named_pipe_path.c_str(), 4570b57cec5SDimitry Andric unnamed_pipe, connection_fd); 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric if (!gdb_server.IsConnected()) { 4600b57cec5SDimitry Andric fprintf(stderr, "no connection information provided, unable to run\n"); 4610b57cec5SDimitry Andric return 1; 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric Status ret = mainloop.Run(); 4650b57cec5SDimitry Andric if (ret.Fail()) { 4660b57cec5SDimitry Andric fprintf(stderr, "lldb-server terminating due to error: %s\n", 4670b57cec5SDimitry Andric ret.AsCString()); 4680b57cec5SDimitry Andric return 1; 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric fprintf(stderr, "lldb-server exiting...\n"); 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric return 0; 4730b57cec5SDimitry Andric } 474