1*0b57cec5SDimitry Andric //===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include <errno.h> 10*0b57cec5SDimitry Andric #include <stdint.h> 11*0b57cec5SDimitry Andric #include <stdio.h> 12*0b57cec5SDimitry Andric #include <stdlib.h> 13*0b57cec5SDimitry Andric #include <string.h> 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #ifndef _WIN32 16*0b57cec5SDimitry Andric #include <signal.h> 17*0b57cec5SDimitry Andric #include <unistd.h> 18*0b57cec5SDimitry Andric #endif 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric #include "Acceptor.h" 22*0b57cec5SDimitry Andric #include "LLDBServerUtilities.h" 23*0b57cec5SDimitry Andric #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h" 24*0b57cec5SDimitry Andric #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" 25*0b57cec5SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h" 26*0b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h" 27*0b57cec5SDimitry Andric #include "lldb/Host/HostGetOpt.h" 28*0b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h" 29*0b57cec5SDimitry Andric #include "lldb/Host/Pipe.h" 30*0b57cec5SDimitry Andric #include "lldb/Host/Socket.h" 31*0b57cec5SDimitry Andric #include "lldb/Host/StringConvert.h" 32*0b57cec5SDimitry Andric #include "lldb/Host/common/NativeProcessProtocol.h" 33*0b57cec5SDimitry Andric #include "lldb/Target/Process.h" 34*0b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 35*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 36*0b57cec5SDimitry Andric #include "llvm/Support/Errno.h" 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric #if defined(__linux__) 39*0b57cec5SDimitry Andric #include "Plugins/Process/Linux/NativeProcessLinux.h" 40*0b57cec5SDimitry Andric #elif defined(__NetBSD__) 41*0b57cec5SDimitry Andric #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" 42*0b57cec5SDimitry Andric #endif 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric #ifndef LLGS_PROGRAM_NAME 45*0b57cec5SDimitry Andric #define LLGS_PROGRAM_NAME "lldb-server" 46*0b57cec5SDimitry Andric #endif 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric #ifndef LLGS_VERSION_STR 49*0b57cec5SDimitry Andric #define LLGS_VERSION_STR "local_build" 50*0b57cec5SDimitry Andric #endif 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric using namespace llvm; 53*0b57cec5SDimitry Andric using namespace lldb; 54*0b57cec5SDimitry Andric using namespace lldb_private; 55*0b57cec5SDimitry Andric using namespace lldb_private::lldb_server; 56*0b57cec5SDimitry Andric using namespace lldb_private::process_gdb_remote; 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric namespace { 59*0b57cec5SDimitry Andric #if defined(__linux__) 60*0b57cec5SDimitry Andric typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory; 61*0b57cec5SDimitry Andric #elif defined(__NetBSD__) 62*0b57cec5SDimitry Andric typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory; 63*0b57cec5SDimitry Andric #else 64*0b57cec5SDimitry Andric // Dummy implementation to make sure the code compiles 65*0b57cec5SDimitry Andric class NativeProcessFactory : public NativeProcessProtocol::Factory { 66*0b57cec5SDimitry Andric public: 67*0b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 68*0b57cec5SDimitry Andric Launch(ProcessLaunchInfo &launch_info, 69*0b57cec5SDimitry Andric NativeProcessProtocol::NativeDelegate &delegate, 70*0b57cec5SDimitry Andric MainLoop &mainloop) const override { 71*0b57cec5SDimitry Andric llvm_unreachable("Not implemented"); 72*0b57cec5SDimitry Andric } 73*0b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 74*0b57cec5SDimitry Andric Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate, 75*0b57cec5SDimitry Andric MainLoop &mainloop) const override { 76*0b57cec5SDimitry Andric llvm_unreachable("Not implemented"); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric }; 79*0b57cec5SDimitry Andric #endif 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric // option descriptors for getopt_long_only() 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric static int g_debug = 0; 85*0b57cec5SDimitry Andric static int g_verbose = 0; 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric static struct option g_long_options[] = { 88*0b57cec5SDimitry Andric {"debug", no_argument, &g_debug, 1}, 89*0b57cec5SDimitry Andric {"verbose", no_argument, &g_verbose, 1}, 90*0b57cec5SDimitry Andric {"log-file", required_argument, nullptr, 'l'}, 91*0b57cec5SDimitry Andric {"log-channels", required_argument, nullptr, 'c'}, 92*0b57cec5SDimitry Andric {"attach", required_argument, nullptr, 'a'}, 93*0b57cec5SDimitry Andric {"named-pipe", required_argument, nullptr, 'N'}, 94*0b57cec5SDimitry Andric {"pipe", required_argument, nullptr, 'U'}, 95*0b57cec5SDimitry Andric {"native-regs", no_argument, nullptr, 96*0b57cec5SDimitry Andric 'r'}, // Specify to use the native registers instead of the gdb defaults 97*0b57cec5SDimitry Andric // for the architecture. NOTE: this is a do-nothing arg as it's 98*0b57cec5SDimitry Andric // behavior is default now. FIXME remove call from lldb-platform. 99*0b57cec5SDimitry Andric {"reverse-connect", no_argument, nullptr, 100*0b57cec5SDimitry Andric 'R'}, // Specifies that llgs attaches to the client address:port rather 101*0b57cec5SDimitry Andric // than llgs listening for a connection from address on port. 102*0b57cec5SDimitry Andric {"setsid", no_argument, nullptr, 103*0b57cec5SDimitry Andric 'S'}, // Call setsid() to make llgs run in its own session. 104*0b57cec5SDimitry Andric {"fd", required_argument, nullptr, 'F'}, 105*0b57cec5SDimitry Andric {nullptr, 0, nullptr, 0}}; 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric // Watch for signals 108*0b57cec5SDimitry Andric static int g_sighup_received_count = 0; 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric #ifndef _WIN32 111*0b57cec5SDimitry Andric static void sighup_handler(MainLoopBase &mainloop) { 112*0b57cec5SDimitry Andric ++g_sighup_received_count; 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); 115*0b57cec5SDimitry Andric if (log) 116*0b57cec5SDimitry Andric log->Printf("lldb-server:%s swallowing SIGHUP (receive count=%d)", 117*0b57cec5SDimitry Andric __FUNCTION__, g_sighup_received_count); 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric if (g_sighup_received_count >= 2) 120*0b57cec5SDimitry Andric mainloop.RequestTermination(); 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric #endif // #ifndef _WIN32 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric static void display_usage(const char *progname, const char *subcommand) { 125*0b57cec5SDimitry Andric fprintf(stderr, "Usage:\n %s %s " 126*0b57cec5SDimitry Andric "[--log-file log-file-name] " 127*0b57cec5SDimitry Andric "[--log-channels log-channel-list] " 128*0b57cec5SDimitry Andric "[--setsid] " 129*0b57cec5SDimitry Andric "[--fd file-descriptor]" 130*0b57cec5SDimitry Andric "[--named-pipe named-pipe-path] " 131*0b57cec5SDimitry Andric "[--native-regs] " 132*0b57cec5SDimitry Andric "[--attach pid] " 133*0b57cec5SDimitry Andric "[[HOST]:PORT] " 134*0b57cec5SDimitry Andric "[-- PROGRAM ARG1 ARG2 ...]\n", 135*0b57cec5SDimitry Andric progname, subcommand); 136*0b57cec5SDimitry Andric } 137*0b57cec5SDimitry Andric 138*0b57cec5SDimitry Andric void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server, 139*0b57cec5SDimitry Andric lldb::pid_t pid) { 140*0b57cec5SDimitry Andric Status error = gdb_server.AttachToProcess(pid); 141*0b57cec5SDimitry Andric if (error.Fail()) { 142*0b57cec5SDimitry Andric fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, 143*0b57cec5SDimitry Andric error.AsCString()); 144*0b57cec5SDimitry Andric exit(1); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server, 149*0b57cec5SDimitry Andric const std::string &process_name) { 150*0b57cec5SDimitry Andric // FIXME implement. 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server, 154*0b57cec5SDimitry Andric const std::string &attach_target) { 155*0b57cec5SDimitry Andric assert(!attach_target.empty() && "attach_target cannot be empty"); 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric // First check if the attach_target is convertible to a long. If so, we'll use 158*0b57cec5SDimitry Andric // it as a pid. 159*0b57cec5SDimitry Andric char *end_p = nullptr; 160*0b57cec5SDimitry Andric const long int pid = strtol(attach_target.c_str(), &end_p, 10); 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric // We'll call it a match if the entire argument is consumed. 163*0b57cec5SDimitry Andric if (end_p && 164*0b57cec5SDimitry Andric static_cast<size_t>(end_p - attach_target.c_str()) == 165*0b57cec5SDimitry Andric attach_target.size()) 166*0b57cec5SDimitry Andric handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid)); 167*0b57cec5SDimitry Andric else 168*0b57cec5SDimitry Andric handle_attach_to_process_name(gdb_server, attach_target); 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, int argc, 172*0b57cec5SDimitry Andric const char *const argv[]) { 173*0b57cec5SDimitry Andric ProcessLaunchInfo info; 174*0b57cec5SDimitry Andric info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug | 175*0b57cec5SDimitry Andric eLaunchFlagDisableASLR); 176*0b57cec5SDimitry Andric info.SetArguments(const_cast<const char **>(argv), true); 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric llvm::SmallString<64> cwd; 179*0b57cec5SDimitry Andric if (std::error_code ec = llvm::sys::fs::current_path(cwd)) { 180*0b57cec5SDimitry Andric llvm::errs() << "Error getting current directory: " << ec.message() << "\n"; 181*0b57cec5SDimitry Andric exit(1); 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric FileSpec cwd_spec(cwd); 184*0b57cec5SDimitry Andric FileSystem::Instance().Resolve(cwd_spec); 185*0b57cec5SDimitry Andric info.SetWorkingDirectory(cwd_spec); 186*0b57cec5SDimitry Andric info.GetEnvironment() = Host::GetEnvironment(); 187*0b57cec5SDimitry Andric 188*0b57cec5SDimitry Andric gdb_server.SetLaunchInfo(info); 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric Status error = gdb_server.LaunchProcess(); 191*0b57cec5SDimitry Andric if (error.Fail()) { 192*0b57cec5SDimitry Andric llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n", 193*0b57cec5SDimitry Andric argv[0], error); 194*0b57cec5SDimitry Andric exit(1); 195*0b57cec5SDimitry Andric } 196*0b57cec5SDimitry Andric } 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric Status writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) { 199*0b57cec5SDimitry Andric size_t bytes_written = 0; 200*0b57cec5SDimitry Andric // Write the port number as a C string with the NULL terminator. 201*0b57cec5SDimitry Andric return port_pipe.Write(socket_id.c_str(), socket_id.size() + 1, 202*0b57cec5SDimitry Andric bytes_written); 203*0b57cec5SDimitry Andric } 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric Status writeSocketIdToPipe(const char *const named_pipe_path, 206*0b57cec5SDimitry Andric const std::string &socket_id) { 207*0b57cec5SDimitry Andric Pipe port_name_pipe; 208*0b57cec5SDimitry Andric // Wait for 10 seconds for pipe to be opened. 209*0b57cec5SDimitry Andric auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false, 210*0b57cec5SDimitry Andric std::chrono::seconds{10}); 211*0b57cec5SDimitry Andric if (error.Fail()) 212*0b57cec5SDimitry Andric return error; 213*0b57cec5SDimitry Andric return writeSocketIdToPipe(port_name_pipe, socket_id); 214*0b57cec5SDimitry Andric } 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe, 217*0b57cec5SDimitry Andric const std::string &socket_id) { 218*0b57cec5SDimitry Andric Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe}; 219*0b57cec5SDimitry Andric return writeSocketIdToPipe(port_pipe, socket_id); 220*0b57cec5SDimitry Andric } 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric void ConnectToRemote(MainLoop &mainloop, 223*0b57cec5SDimitry Andric GDBRemoteCommunicationServerLLGS &gdb_server, 224*0b57cec5SDimitry Andric bool reverse_connect, const char *const host_and_port, 225*0b57cec5SDimitry Andric const char *const progname, const char *const subcommand, 226*0b57cec5SDimitry Andric const char *const named_pipe_path, pipe_t unnamed_pipe, 227*0b57cec5SDimitry Andric int connection_fd) { 228*0b57cec5SDimitry Andric Status error; 229*0b57cec5SDimitry Andric 230*0b57cec5SDimitry Andric std::unique_ptr<Connection> connection_up; 231*0b57cec5SDimitry Andric if (connection_fd != -1) { 232*0b57cec5SDimitry Andric // Build the connection string. 233*0b57cec5SDimitry Andric char connection_url[512]; 234*0b57cec5SDimitry Andric snprintf(connection_url, sizeof(connection_url), "fd://%d", connection_fd); 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric // Create the connection. 237*0b57cec5SDimitry Andric #if !defined LLDB_DISABLE_POSIX && !defined _WIN32 238*0b57cec5SDimitry Andric ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC); 239*0b57cec5SDimitry Andric #endif 240*0b57cec5SDimitry Andric connection_up.reset(new ConnectionFileDescriptor); 241*0b57cec5SDimitry Andric auto connection_result = connection_up->Connect(connection_url, &error); 242*0b57cec5SDimitry Andric if (connection_result != eConnectionStatusSuccess) { 243*0b57cec5SDimitry Andric fprintf(stderr, "error: failed to connect to client at '%s' " 244*0b57cec5SDimitry Andric "(connection status: %d)\n", 245*0b57cec5SDimitry Andric connection_url, static_cast<int>(connection_result)); 246*0b57cec5SDimitry Andric exit(-1); 247*0b57cec5SDimitry Andric } 248*0b57cec5SDimitry Andric if (error.Fail()) { 249*0b57cec5SDimitry Andric fprintf(stderr, "error: failed to connect to client at '%s': %s\n", 250*0b57cec5SDimitry Andric connection_url, error.AsCString()); 251*0b57cec5SDimitry Andric exit(-1); 252*0b57cec5SDimitry Andric } 253*0b57cec5SDimitry Andric } else if (host_and_port && host_and_port[0]) { 254*0b57cec5SDimitry Andric // Parse out host and port. 255*0b57cec5SDimitry Andric std::string final_host_and_port; 256*0b57cec5SDimitry Andric std::string connection_host; 257*0b57cec5SDimitry Andric std::string connection_port; 258*0b57cec5SDimitry Andric uint32_t connection_portno = 0; 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric // If host_and_port starts with ':', default the host to be "localhost" and 261*0b57cec5SDimitry Andric // expect the remainder to be the port. 262*0b57cec5SDimitry Andric if (host_and_port[0] == ':') 263*0b57cec5SDimitry Andric final_host_and_port.append("localhost"); 264*0b57cec5SDimitry Andric final_host_and_port.append(host_and_port); 265*0b57cec5SDimitry Andric 266*0b57cec5SDimitry Andric const std::string::size_type colon_pos = final_host_and_port.find(':'); 267*0b57cec5SDimitry Andric if (colon_pos != std::string::npos) { 268*0b57cec5SDimitry Andric connection_host = final_host_and_port.substr(0, colon_pos); 269*0b57cec5SDimitry Andric connection_port = final_host_and_port.substr(colon_pos + 1); 270*0b57cec5SDimitry Andric connection_portno = StringConvert::ToUInt32(connection_port.c_str(), 0); 271*0b57cec5SDimitry Andric } 272*0b57cec5SDimitry Andric 273*0b57cec5SDimitry Andric 274*0b57cec5SDimitry Andric if (reverse_connect) { 275*0b57cec5SDimitry Andric // llgs will connect to the gdb-remote client. 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric // Ensure we have a port number for the connection. 278*0b57cec5SDimitry Andric if (connection_portno == 0) { 279*0b57cec5SDimitry Andric fprintf(stderr, "error: port number must be specified on when using " 280*0b57cec5SDimitry Andric "reverse connect\n"); 281*0b57cec5SDimitry Andric exit(1); 282*0b57cec5SDimitry Andric } 283*0b57cec5SDimitry Andric 284*0b57cec5SDimitry Andric // Build the connection string. 285*0b57cec5SDimitry Andric char connection_url[512]; 286*0b57cec5SDimitry Andric snprintf(connection_url, sizeof(connection_url), "connect://%s", 287*0b57cec5SDimitry Andric final_host_and_port.c_str()); 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric // Create the connection. 290*0b57cec5SDimitry Andric connection_up.reset(new ConnectionFileDescriptor); 291*0b57cec5SDimitry Andric auto connection_result = connection_up->Connect(connection_url, &error); 292*0b57cec5SDimitry Andric if (connection_result != eConnectionStatusSuccess) { 293*0b57cec5SDimitry Andric fprintf(stderr, "error: failed to connect to client at '%s' " 294*0b57cec5SDimitry Andric "(connection status: %d)\n", 295*0b57cec5SDimitry Andric connection_url, static_cast<int>(connection_result)); 296*0b57cec5SDimitry Andric exit(-1); 297*0b57cec5SDimitry Andric } 298*0b57cec5SDimitry Andric if (error.Fail()) { 299*0b57cec5SDimitry Andric fprintf(stderr, "error: failed to connect to client at '%s': %s\n", 300*0b57cec5SDimitry Andric connection_url, error.AsCString()); 301*0b57cec5SDimitry Andric exit(-1); 302*0b57cec5SDimitry Andric } 303*0b57cec5SDimitry Andric } else { 304*0b57cec5SDimitry Andric std::unique_ptr<Acceptor> acceptor_up( 305*0b57cec5SDimitry Andric Acceptor::Create(final_host_and_port, false, error)); 306*0b57cec5SDimitry Andric if (error.Fail()) { 307*0b57cec5SDimitry Andric fprintf(stderr, "failed to create acceptor: %s\n", error.AsCString()); 308*0b57cec5SDimitry Andric exit(1); 309*0b57cec5SDimitry Andric } 310*0b57cec5SDimitry Andric error = acceptor_up->Listen(1); 311*0b57cec5SDimitry Andric if (error.Fail()) { 312*0b57cec5SDimitry Andric fprintf(stderr, "failed to listen: %s\n", error.AsCString()); 313*0b57cec5SDimitry Andric exit(1); 314*0b57cec5SDimitry Andric } 315*0b57cec5SDimitry Andric const std::string socket_id = acceptor_up->GetLocalSocketId(); 316*0b57cec5SDimitry Andric if (!socket_id.empty()) { 317*0b57cec5SDimitry Andric // If we have a named pipe to write the socket id back to, do that now. 318*0b57cec5SDimitry Andric if (named_pipe_path && named_pipe_path[0]) { 319*0b57cec5SDimitry Andric error = writeSocketIdToPipe(named_pipe_path, socket_id); 320*0b57cec5SDimitry Andric if (error.Fail()) 321*0b57cec5SDimitry Andric fprintf(stderr, "failed to write to the named pipe \'%s\': %s\n", 322*0b57cec5SDimitry Andric named_pipe_path, error.AsCString()); 323*0b57cec5SDimitry Andric } 324*0b57cec5SDimitry Andric // If we have an unnamed pipe to write the socket id back to, do that 325*0b57cec5SDimitry Andric // now. 326*0b57cec5SDimitry Andric else if (unnamed_pipe != LLDB_INVALID_PIPE) { 327*0b57cec5SDimitry Andric error = writeSocketIdToPipe(unnamed_pipe, socket_id); 328*0b57cec5SDimitry Andric if (error.Fail()) 329*0b57cec5SDimitry Andric fprintf(stderr, "failed to write to the unnamed pipe: %s\n", 330*0b57cec5SDimitry Andric error.AsCString()); 331*0b57cec5SDimitry Andric } 332*0b57cec5SDimitry Andric } else { 333*0b57cec5SDimitry Andric fprintf(stderr, 334*0b57cec5SDimitry Andric "unable to get the socket id for the listening connection\n"); 335*0b57cec5SDimitry Andric } 336*0b57cec5SDimitry Andric 337*0b57cec5SDimitry Andric Connection *conn = nullptr; 338*0b57cec5SDimitry Andric error = acceptor_up->Accept(false, conn); 339*0b57cec5SDimitry Andric if (error.Fail()) { 340*0b57cec5SDimitry Andric printf("failed to accept new connection: %s\n", error.AsCString()); 341*0b57cec5SDimitry Andric exit(1); 342*0b57cec5SDimitry Andric } 343*0b57cec5SDimitry Andric connection_up.reset(conn); 344*0b57cec5SDimitry Andric } 345*0b57cec5SDimitry Andric } 346*0b57cec5SDimitry Andric error = gdb_server.InitializeConnection(std::move(connection_up)); 347*0b57cec5SDimitry Andric if (error.Fail()) { 348*0b57cec5SDimitry Andric fprintf(stderr, "Failed to initialize connection: %s\n", 349*0b57cec5SDimitry Andric error.AsCString()); 350*0b57cec5SDimitry Andric exit(-1); 351*0b57cec5SDimitry Andric } 352*0b57cec5SDimitry Andric printf("Connection established.\n"); 353*0b57cec5SDimitry Andric } 354*0b57cec5SDimitry Andric 355*0b57cec5SDimitry Andric // main 356*0b57cec5SDimitry Andric int main_gdbserver(int argc, char *argv[]) { 357*0b57cec5SDimitry Andric Status error; 358*0b57cec5SDimitry Andric MainLoop mainloop; 359*0b57cec5SDimitry Andric #ifndef _WIN32 360*0b57cec5SDimitry Andric // Setup signal handlers first thing. 361*0b57cec5SDimitry Andric signal(SIGPIPE, SIG_IGN); 362*0b57cec5SDimitry Andric MainLoop::SignalHandleUP sighup_handle = 363*0b57cec5SDimitry Andric mainloop.RegisterSignal(SIGHUP, sighup_handler, error); 364*0b57cec5SDimitry Andric #endif 365*0b57cec5SDimitry Andric 366*0b57cec5SDimitry Andric const char *progname = argv[0]; 367*0b57cec5SDimitry Andric const char *subcommand = argv[1]; 368*0b57cec5SDimitry Andric argc--; 369*0b57cec5SDimitry Andric argv++; 370*0b57cec5SDimitry Andric int long_option_index = 0; 371*0b57cec5SDimitry Andric int ch; 372*0b57cec5SDimitry Andric std::string attach_target; 373*0b57cec5SDimitry Andric std::string named_pipe_path; 374*0b57cec5SDimitry Andric std::string log_file; 375*0b57cec5SDimitry Andric StringRef 376*0b57cec5SDimitry Andric log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" 377*0b57cec5SDimitry Andric lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE; 378*0b57cec5SDimitry Andric bool reverse_connect = false; 379*0b57cec5SDimitry Andric int connection_fd = -1; 380*0b57cec5SDimitry Andric 381*0b57cec5SDimitry Andric // ProcessLaunchInfo launch_info; 382*0b57cec5SDimitry Andric ProcessAttachInfo attach_info; 383*0b57cec5SDimitry Andric 384*0b57cec5SDimitry Andric bool show_usage = false; 385*0b57cec5SDimitry Andric int option_error = 0; 386*0b57cec5SDimitry Andric #if __GLIBC__ 387*0b57cec5SDimitry Andric optind = 0; 388*0b57cec5SDimitry Andric #else 389*0b57cec5SDimitry Andric optreset = 1; 390*0b57cec5SDimitry Andric optind = 1; 391*0b57cec5SDimitry Andric #endif 392*0b57cec5SDimitry Andric 393*0b57cec5SDimitry Andric std::string short_options(OptionParser::GetShortOptionString(g_long_options)); 394*0b57cec5SDimitry Andric 395*0b57cec5SDimitry Andric while ((ch = getopt_long_only(argc, argv, short_options.c_str(), 396*0b57cec5SDimitry Andric g_long_options, &long_option_index)) != -1) { 397*0b57cec5SDimitry Andric switch (ch) { 398*0b57cec5SDimitry Andric case 0: // Any optional that auto set themselves will return 0 399*0b57cec5SDimitry Andric break; 400*0b57cec5SDimitry Andric 401*0b57cec5SDimitry Andric case 'l': // Set Log File 402*0b57cec5SDimitry Andric if (optarg && optarg[0]) 403*0b57cec5SDimitry Andric log_file.assign(optarg); 404*0b57cec5SDimitry Andric break; 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric case 'c': // Log Channels 407*0b57cec5SDimitry Andric if (optarg && optarg[0]) 408*0b57cec5SDimitry Andric log_channels = StringRef(optarg); 409*0b57cec5SDimitry Andric break; 410*0b57cec5SDimitry Andric 411*0b57cec5SDimitry Andric case 'N': // named pipe 412*0b57cec5SDimitry Andric if (optarg && optarg[0]) 413*0b57cec5SDimitry Andric named_pipe_path = optarg; 414*0b57cec5SDimitry Andric break; 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric case 'U': // unnamed pipe 417*0b57cec5SDimitry Andric if (optarg && optarg[0]) 418*0b57cec5SDimitry Andric unnamed_pipe = (pipe_t)StringConvert::ToUInt64(optarg, -1); 419*0b57cec5SDimitry Andric break; 420*0b57cec5SDimitry Andric 421*0b57cec5SDimitry Andric case 'r': 422*0b57cec5SDimitry Andric // Do nothing, native regs is the default these days 423*0b57cec5SDimitry Andric break; 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric case 'R': 426*0b57cec5SDimitry Andric reverse_connect = true; 427*0b57cec5SDimitry Andric break; 428*0b57cec5SDimitry Andric 429*0b57cec5SDimitry Andric case 'F': 430*0b57cec5SDimitry Andric connection_fd = StringConvert::ToUInt32(optarg, -1); 431*0b57cec5SDimitry Andric break; 432*0b57cec5SDimitry Andric 433*0b57cec5SDimitry Andric #ifndef _WIN32 434*0b57cec5SDimitry Andric case 'S': 435*0b57cec5SDimitry Andric // Put llgs into a new session. Terminals group processes 436*0b57cec5SDimitry Andric // into sessions and when a special terminal key sequences 437*0b57cec5SDimitry Andric // (like control+c) are typed they can cause signals to go out to 438*0b57cec5SDimitry Andric // all processes in a session. Using this --setsid (-S) option 439*0b57cec5SDimitry Andric // will cause debugserver to run in its own sessions and be free 440*0b57cec5SDimitry Andric // from such issues. 441*0b57cec5SDimitry Andric // 442*0b57cec5SDimitry Andric // This is useful when llgs is spawned from a command 443*0b57cec5SDimitry Andric // line application that uses llgs to do the debugging, 444*0b57cec5SDimitry Andric // yet that application doesn't want llgs receiving the 445*0b57cec5SDimitry Andric // signals sent to the session (i.e. dying when anyone hits ^C). 446*0b57cec5SDimitry Andric { 447*0b57cec5SDimitry Andric const ::pid_t new_sid = setsid(); 448*0b57cec5SDimitry Andric if (new_sid == -1) { 449*0b57cec5SDimitry Andric llvm::errs() << llvm::formatv( 450*0b57cec5SDimitry Andric "failed to set new session id for {0} ({1})\n", LLGS_PROGRAM_NAME, 451*0b57cec5SDimitry Andric llvm::sys::StrError()); 452*0b57cec5SDimitry Andric } 453*0b57cec5SDimitry Andric } 454*0b57cec5SDimitry Andric break; 455*0b57cec5SDimitry Andric #endif 456*0b57cec5SDimitry Andric 457*0b57cec5SDimitry Andric case 'a': // attach {pid|process_name} 458*0b57cec5SDimitry Andric if (optarg && optarg[0]) 459*0b57cec5SDimitry Andric attach_target = optarg; 460*0b57cec5SDimitry Andric break; 461*0b57cec5SDimitry Andric 462*0b57cec5SDimitry Andric case 'h': /* fall-through is intentional */ 463*0b57cec5SDimitry Andric case '?': 464*0b57cec5SDimitry Andric show_usage = true; 465*0b57cec5SDimitry Andric break; 466*0b57cec5SDimitry Andric } 467*0b57cec5SDimitry Andric } 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric if (show_usage || option_error) { 470*0b57cec5SDimitry Andric display_usage(progname, subcommand); 471*0b57cec5SDimitry Andric exit(option_error); 472*0b57cec5SDimitry Andric } 473*0b57cec5SDimitry Andric 474*0b57cec5SDimitry Andric if (!LLDBServerUtilities::SetupLogging( 475*0b57cec5SDimitry Andric log_file, log_channels, 476*0b57cec5SDimitry Andric LLDB_LOG_OPTION_PREPEND_TIMESTAMP | 477*0b57cec5SDimitry Andric LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION)) 478*0b57cec5SDimitry Andric return -1; 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric Log *log(lldb_private::GetLogIfAnyCategoriesSet(GDBR_LOG_PROCESS)); 481*0b57cec5SDimitry Andric if (log) { 482*0b57cec5SDimitry Andric log->Printf("lldb-server launch"); 483*0b57cec5SDimitry Andric for (int i = 0; i < argc; i++) { 484*0b57cec5SDimitry Andric log->Printf("argv[%i] = '%s'", i, argv[i]); 485*0b57cec5SDimitry Andric } 486*0b57cec5SDimitry Andric } 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric // Skip any options we consumed with getopt_long_only. 489*0b57cec5SDimitry Andric argc -= optind; 490*0b57cec5SDimitry Andric argv += optind; 491*0b57cec5SDimitry Andric 492*0b57cec5SDimitry Andric if (argc == 0 && connection_fd == -1) { 493*0b57cec5SDimitry Andric fputs("No arguments\n", stderr); 494*0b57cec5SDimitry Andric display_usage(progname, subcommand); 495*0b57cec5SDimitry Andric exit(255); 496*0b57cec5SDimitry Andric } 497*0b57cec5SDimitry Andric 498*0b57cec5SDimitry Andric NativeProcessFactory factory; 499*0b57cec5SDimitry Andric GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory); 500*0b57cec5SDimitry Andric 501*0b57cec5SDimitry Andric const char *const host_and_port = argv[0]; 502*0b57cec5SDimitry Andric argc -= 1; 503*0b57cec5SDimitry Andric argv += 1; 504*0b57cec5SDimitry Andric 505*0b57cec5SDimitry Andric // Any arguments left over are for the program that we need to launch. If 506*0b57cec5SDimitry Andric // there 507*0b57cec5SDimitry Andric // are no arguments, then the GDB server will start up and wait for an 'A' 508*0b57cec5SDimitry Andric // packet 509*0b57cec5SDimitry Andric // to launch a program, or a vAttach packet to attach to an existing process, 510*0b57cec5SDimitry Andric // unless 511*0b57cec5SDimitry Andric // explicitly asked to attach with the --attach={pid|program_name} form. 512*0b57cec5SDimitry Andric if (!attach_target.empty()) 513*0b57cec5SDimitry Andric handle_attach(gdb_server, attach_target); 514*0b57cec5SDimitry Andric else if (argc > 0) 515*0b57cec5SDimitry Andric handle_launch(gdb_server, argc, argv); 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric // Print version info. 518*0b57cec5SDimitry Andric printf("%s-%s", LLGS_PROGRAM_NAME, LLGS_VERSION_STR); 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port, 521*0b57cec5SDimitry Andric progname, subcommand, named_pipe_path.c_str(), 522*0b57cec5SDimitry Andric unnamed_pipe, connection_fd); 523*0b57cec5SDimitry Andric 524*0b57cec5SDimitry Andric if (!gdb_server.IsConnected()) { 525*0b57cec5SDimitry Andric fprintf(stderr, "no connection information provided, unable to run\n"); 526*0b57cec5SDimitry Andric display_usage(progname, subcommand); 527*0b57cec5SDimitry Andric return 1; 528*0b57cec5SDimitry Andric } 529*0b57cec5SDimitry Andric 530*0b57cec5SDimitry Andric Status ret = mainloop.Run(); 531*0b57cec5SDimitry Andric if (ret.Fail()) { 532*0b57cec5SDimitry Andric fprintf(stderr, "lldb-server terminating due to error: %s\n", 533*0b57cec5SDimitry Andric ret.AsCString()); 534*0b57cec5SDimitry Andric return 1; 535*0b57cec5SDimitry Andric } 536*0b57cec5SDimitry Andric fprintf(stderr, "lldb-server exiting...\n"); 537*0b57cec5SDimitry Andric 538*0b57cec5SDimitry Andric return 0; 539*0b57cec5SDimitry Andric } 540