1//===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <cerrno>
10#include <cstdint>
11#include <cstdio>
12#include <cstdlib>
13#include <cstring>
14
15#ifndef _WIN32
16#include <csignal>
17#include <unistd.h>
18#endif
19
20#include "LLDBServerUtilities.h"
21#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
22#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
23#include "lldb/Host/Config.h"
24#include "lldb/Host/ConnectionFileDescriptor.h"
25#include "lldb/Host/FileSystem.h"
26#include "lldb/Host/Pipe.h"
27#include "lldb/Host/Socket.h"
28#include "lldb/Host/common/NativeProcessProtocol.h"
29#include "lldb/Target/Process.h"
30#include "lldb/Utility/LLDBLog.h"
31#include "lldb/Utility/Status.h"
32#include "llvm/ADT/StringRef.h"
33#include "llvm/Option/ArgList.h"
34#include "llvm/Option/OptTable.h"
35#include "llvm/Option/Option.h"
36#include "llvm/Support/Errno.h"
37#include "llvm/Support/Error.h"
38#include "llvm/Support/WithColor.h"
39
40#if defined(__linux__)
41#include "Plugins/Process/Linux/NativeProcessLinux.h"
42#elif defined(__FreeBSD__)
43#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
44#elif defined(__NetBSD__)
45#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
46#elif defined(_WIN32)
47#include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
48#endif
49
50#ifndef LLGS_PROGRAM_NAME
51#define LLGS_PROGRAM_NAME "lldb-server"
52#endif
53
54#ifndef LLGS_VERSION_STR
55#define LLGS_VERSION_STR "local_build"
56#endif
57
58using namespace llvm;
59using namespace lldb;
60using namespace lldb_private;
61using namespace lldb_private::lldb_server;
62using namespace lldb_private::process_gdb_remote;
63
64namespace {
65#if defined(__linux__)
66typedef process_linux::NativeProcessLinux::Manager NativeProcessManager;
67#elif defined(__FreeBSD__)
68typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager;
69#elif defined(__NetBSD__)
70typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager;
71#elif defined(_WIN32)
72typedef NativeProcessWindows::Manager NativeProcessManager;
73#else
74// Dummy implementation to make sure the code compiles
75class NativeProcessManager : public NativeProcessProtocol::Manager {
76public:
77  NativeProcessManager(MainLoop &mainloop)
78      : NativeProcessProtocol::Manager(mainloop) {}
79
80  llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
81  Launch(ProcessLaunchInfo &launch_info,
82         NativeProcessProtocol::NativeDelegate &native_delegate) override {
83    llvm_unreachable("Not implemented");
84  }
85  llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
86  Attach(lldb::pid_t pid,
87         NativeProcessProtocol::NativeDelegate &native_delegate) override {
88    llvm_unreachable("Not implemented");
89  }
90};
91#endif
92}
93
94#ifndef _WIN32
95// Watch for signals
96static int g_sighup_received_count = 0;
97
98static void sighup_handler(MainLoopBase &mainloop) {
99  ++g_sighup_received_count;
100
101  Log *log = GetLog(LLDBLog::Process);
102  LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)",
103            __FUNCTION__, g_sighup_received_count);
104
105  if (g_sighup_received_count >= 2)
106    mainloop.RequestTermination();
107}
108#endif // #ifndef _WIN32
109
110void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server,
111                          lldb::pid_t pid) {
112  Status error = gdb_server.AttachToProcess(pid);
113  if (error.Fail()) {
114    fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid,
115            error.AsCString());
116    exit(1);
117  }
118}
119
120void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server,
121                                   const std::string &process_name) {
122  // FIXME implement.
123}
124
125void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server,
126                   const std::string &attach_target) {
127  assert(!attach_target.empty() && "attach_target cannot be empty");
128
129  // First check if the attach_target is convertible to a long. If so, we'll use
130  // it as a pid.
131  char *end_p = nullptr;
132  const long int pid = strtol(attach_target.c_str(), &end_p, 10);
133
134  // We'll call it a match if the entire argument is consumed.
135  if (end_p &&
136      static_cast<size_t>(end_p - attach_target.c_str()) ==
137          attach_target.size())
138    handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid));
139  else
140    handle_attach_to_process_name(gdb_server, attach_target);
141}
142
143void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server,
144                   llvm::ArrayRef<llvm::StringRef> Arguments) {
145  ProcessLaunchInfo info;
146  info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug |
147                      eLaunchFlagDisableASLR);
148  info.SetArguments(Args(Arguments), true);
149
150  llvm::SmallString<64> cwd;
151  if (std::error_code ec = llvm::sys::fs::current_path(cwd)) {
152    llvm::errs() << "Error getting current directory: " << ec.message() << "\n";
153    exit(1);
154  }
155  FileSpec cwd_spec(cwd);
156  FileSystem::Instance().Resolve(cwd_spec);
157  info.SetWorkingDirectory(cwd_spec);
158  info.GetEnvironment() = Host::GetEnvironment();
159
160  gdb_server.SetLaunchInfo(info);
161
162  Status error = gdb_server.LaunchProcess();
163  if (error.Fail()) {
164    llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n",
165                                  Arguments[0], error);
166    exit(1);
167  }
168}
169
170Status writeSocketIdToPipe(Pipe &port_pipe, llvm::StringRef socket_id) {
171  size_t bytes_written = 0;
172  // Write the port number as a C string with the NULL terminator.
173  return port_pipe.Write(socket_id.data(), socket_id.size() + 1, bytes_written);
174}
175
176Status writeSocketIdToPipe(const char *const named_pipe_path,
177                           llvm::StringRef socket_id) {
178  Pipe port_name_pipe;
179  // Wait for 10 seconds for pipe to be opened.
180  auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
181                                                      std::chrono::seconds{10});
182  if (error.Fail())
183    return error;
184  return writeSocketIdToPipe(port_name_pipe, socket_id);
185}
186
187Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
188                           llvm::StringRef socket_id) {
189  Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
190  return writeSocketIdToPipe(port_pipe, socket_id);
191}
192
193void ConnectToRemote(MainLoop &mainloop,
194                     GDBRemoteCommunicationServerLLGS &gdb_server,
195                     bool reverse_connect, llvm::StringRef host_and_port,
196                     const char *const progname, const char *const subcommand,
197                     const char *const named_pipe_path, pipe_t unnamed_pipe,
198                     int connection_fd) {
199  Status error;
200
201  std::unique_ptr<Connection> connection_up;
202  std::string url;
203
204  if (connection_fd != -1) {
205    url = llvm::formatv("fd://{0}", connection_fd).str();
206
207    // Create the connection.
208#if LLDB_ENABLE_POSIX && !defined _WIN32
209    ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC);
210#endif
211  } else if (!host_and_port.empty()) {
212    llvm::Expected<std::string> url_exp =
213        LLGSArgToURL(host_and_port, reverse_connect);
214    if (!url_exp) {
215      llvm::errs() << llvm::formatv("error: invalid host:port or URL '{0}': "
216                                    "{1}\n",
217                                    host_and_port,
218                                    llvm::toString(url_exp.takeError()));
219      exit(-1);
220    }
221
222    url = std::move(url_exp.get());
223  }
224
225  if (!url.empty()) {
226    // Create the connection or server.
227    std::unique_ptr<ConnectionFileDescriptor> conn_fd_up{
228        new ConnectionFileDescriptor};
229    auto connection_result = conn_fd_up->Connect(
230        url,
231        [named_pipe_path, unnamed_pipe](llvm::StringRef socket_id) {
232          // If we have a named pipe to write the socket id back to, do that
233          // now.
234          if (named_pipe_path && named_pipe_path[0]) {
235            Status error = writeSocketIdToPipe(named_pipe_path, socket_id);
236            if (error.Fail())
237              llvm::errs() << llvm::formatv(
238                  "failed to write to the named peipe '{0}': {1}\n",
239                  named_pipe_path, error.AsCString());
240          }
241          // If we have an unnamed pipe to write the socket id back to, do
242          // that now.
243          else if (unnamed_pipe != LLDB_INVALID_PIPE) {
244            Status error = writeSocketIdToPipe(unnamed_pipe, socket_id);
245            if (error.Fail())
246              llvm::errs() << llvm::formatv(
247                  "failed to write to the unnamed pipe: {0}\n", error);
248          }
249        },
250        &error);
251
252    if (error.Fail()) {
253      llvm::errs() << llvm::formatv(
254          "error: failed to connect to client at '{0}': {1}\n", url, error);
255      exit(-1);
256    }
257    if (connection_result != eConnectionStatusSuccess) {
258      llvm::errs() << llvm::formatv(
259          "error: failed to connect to client at '{0}' "
260          "(connection status: {1})\n",
261          url, static_cast<int>(connection_result));
262      exit(-1);
263    }
264    connection_up = std::move(conn_fd_up);
265  }
266  error = gdb_server.InitializeConnection(std::move(connection_up));
267  if (error.Fail()) {
268    llvm::errs() << llvm::formatv("failed to initialize connection\n", error);
269    exit(-1);
270  }
271  llvm::outs() << "Connection established.\n";
272}
273
274namespace {
275using namespace llvm::opt;
276
277enum ID {
278  OPT_INVALID = 0, // This is not an option ID.
279#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
280#include "LLGSOptions.inc"
281#undef OPTION
282};
283
284#define PREFIX(NAME, VALUE)                                                    \
285  constexpr llvm::StringLiteral NAME##_init[] = VALUE;                         \
286  constexpr llvm::ArrayRef<llvm::StringLiteral> NAME(                          \
287      NAME##_init, std::size(NAME##_init) - 1);
288#include "LLGSOptions.inc"
289#undef PREFIX
290
291static constexpr opt::OptTable::Info InfoTable[] = {
292#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
293#include "LLGSOptions.inc"
294#undef OPTION
295};
296
297class LLGSOptTable : public opt::GenericOptTable {
298public:
299  LLGSOptTable() : opt::GenericOptTable(InfoTable) {}
300
301  void PrintHelp(llvm::StringRef Name) {
302    std::string Usage =
303        (Name + " [options] [[host]:port] [[--] program args...]").str();
304    OptTable::printHelp(llvm::outs(), Usage.c_str(), "lldb-server");
305    llvm::outs() << R"(
306DESCRIPTION
307  lldb-server connects to the LLDB client, which drives the debugging session.
308  If no connection options are given, the [host]:port argument must be present
309  and will denote the address that lldb-server will listen on. [host] defaults
310  to "localhost" if empty. Port can be zero, in which case the port number will
311  be chosen dynamically and written to destinations given by --named-pipe and
312  --pipe arguments.
313
314  If no target is selected at startup, lldb-server can be directed by the LLDB
315  client to launch or attach to a process.
316
317)";
318  }
319};
320} // namespace
321
322int main_gdbserver(int argc, char *argv[]) {
323  Status error;
324  MainLoop mainloop;
325#ifndef _WIN32
326  // Setup signal handlers first thing.
327  signal(SIGPIPE, SIG_IGN);
328  MainLoop::SignalHandleUP sighup_handle =
329      mainloop.RegisterSignal(SIGHUP, sighup_handler, error);
330#endif
331
332  const char *progname = argv[0];
333  const char *subcommand = argv[1];
334  std::string attach_target;
335  std::string named_pipe_path;
336  std::string log_file;
337  StringRef
338      log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
339  lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE;
340  bool reverse_connect = false;
341  int connection_fd = -1;
342
343  // ProcessLaunchInfo launch_info;
344  ProcessAttachInfo attach_info;
345
346  LLGSOptTable Opts;
347  llvm::BumpPtrAllocator Alloc;
348  llvm::StringSaver Saver(Alloc);
349  bool HasError = false;
350  opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN,
351                                          Saver, [&](llvm::StringRef Msg) {
352                                            WithColor::error() << Msg << "\n";
353                                            HasError = true;
354                                          });
355  std::string Name =
356      (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str();
357  std::string HelpText =
358      "Use '" + Name + " --help' for a complete list of options.\n";
359  if (HasError) {
360    llvm::errs() << HelpText;
361    return 1;
362  }
363
364  if (Args.hasArg(OPT_help)) {
365    Opts.PrintHelp(Name);
366    return 0;
367  }
368
369#ifndef _WIN32
370  if (Args.hasArg(OPT_setsid)) {
371    // Put llgs into a new session. Terminals group processes
372    // into sessions and when a special terminal key sequences
373    // (like control+c) are typed they can cause signals to go out to
374    // all processes in a session. Using this --setsid (-S) option
375    // will cause debugserver to run in its own sessions and be free
376    // from such issues.
377    //
378    // This is useful when llgs is spawned from a command
379    // line application that uses llgs to do the debugging,
380    // yet that application doesn't want llgs receiving the
381    // signals sent to the session (i.e. dying when anyone hits ^C).
382    {
383      const ::pid_t new_sid = setsid();
384      if (new_sid == -1) {
385        WithColor::warning()
386            << llvm::formatv("failed to set new session id for {0} ({1})\n",
387                             LLGS_PROGRAM_NAME, llvm::sys::StrError());
388      }
389    }
390  }
391#endif
392
393  log_file = Args.getLastArgValue(OPT_log_file).str();
394  log_channels = Args.getLastArgValue(OPT_log_channels);
395  named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str();
396  reverse_connect = Args.hasArg(OPT_reverse_connect);
397  attach_target = Args.getLastArgValue(OPT_attach).str();
398  if (Args.hasArg(OPT_pipe)) {
399    uint64_t Arg;
400    if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) {
401      WithColor::error() << "invalid '--pipe' argument\n" << HelpText;
402      return 1;
403    }
404    unnamed_pipe = (pipe_t)Arg;
405  }
406  if (Args.hasArg(OPT_fd)) {
407    if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), connection_fd)) {
408      WithColor::error() << "invalid '--fd' argument\n" << HelpText;
409      return 1;
410    }
411  }
412
413  if (!LLDBServerUtilities::SetupLogging(
414          log_file, log_channels,
415          LLDB_LOG_OPTION_PREPEND_TIMESTAMP |
416              LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION))
417    return -1;
418
419  std::vector<llvm::StringRef> Inputs;
420  for (opt::Arg *Arg : Args.filtered(OPT_INPUT))
421    Inputs.push_back(Arg->getValue());
422  if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) {
423    for (const char *Val : Arg->getValues())
424      Inputs.push_back(Val);
425  }
426  if (Inputs.empty() && connection_fd == -1) {
427    WithColor::error() << "no connection arguments\n" << HelpText;
428    return 1;
429  }
430
431  NativeProcessManager manager(mainloop);
432  GDBRemoteCommunicationServerLLGS gdb_server(mainloop, manager);
433
434  llvm::StringRef host_and_port;
435  if (!Inputs.empty()) {
436    host_and_port = Inputs.front();
437    Inputs.erase(Inputs.begin());
438  }
439
440  // Any arguments left over are for the program that we need to launch. If
441  // there
442  // are no arguments, then the GDB server will start up and wait for an 'A'
443  // packet
444  // to launch a program, or a vAttach packet to attach to an existing process,
445  // unless
446  // explicitly asked to attach with the --attach={pid|program_name} form.
447  if (!attach_target.empty())
448    handle_attach(gdb_server, attach_target);
449  else if (!Inputs.empty())
450    handle_launch(gdb_server, Inputs);
451
452  // Print version info.
453  printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
454
455  ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
456                  progname, subcommand, named_pipe_path.c_str(),
457                  unnamed_pipe, connection_fd);
458
459  if (!gdb_server.IsConnected()) {
460    fprintf(stderr, "no connection information provided, unable to run\n");
461    return 1;
462  }
463
464  Status ret = mainloop.Run();
465  if (ret.Fail()) {
466    fprintf(stderr, "lldb-server terminating due to error: %s\n",
467            ret.AsCString());
468    return 1;
469  }
470  fprintf(stderr, "lldb-server exiting...\n");
471
472  return 0;
473}
474