1 //===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 #if defined(__APPLE__)
13 #include <netinet/in.h>
25 // Other libraries and framework includes
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/FileUtilities.h"
30 #include "LLDBServerUtilities.h"
31 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
32 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
33 #include "lldb/Host/ConnectionFileDescriptor.h"
34 #include "lldb/Host/HostGetOpt.h"
35 #include "lldb/Host/OptionParser.h"
36 #include "lldb/Host/common/TCPSocket.h"
37 #include "lldb/Utility/FileSpec.h"
38 #include "lldb/Utility/Status.h"
41 using namespace lldb_private;
42 using namespace lldb_private::lldb_server;
43 using namespace lldb_private::process_gdb_remote;
46 //----------------------------------------------------------------------
47 // option descriptors for getopt_long_only()
48 //----------------------------------------------------------------------
50 static int g_debug = 0;
51 static int g_verbose = 0;
52 static int g_server = 0;
54 static struct option g_long_options[] = {
55 {"debug", no_argument, &g_debug, 1},
56 {"verbose", no_argument, &g_verbose, 1},
57 {"log-file", required_argument, NULL, 'l'},
58 {"log-channels", required_argument, NULL, 'c'},
59 {"listen", required_argument, NULL, 'L'},
60 {"port-offset", required_argument, NULL, 'p'},
61 {"gdbserver-port", required_argument, NULL, 'P'},
62 {"min-gdbserver-port", required_argument, NULL, 'm'},
63 {"max-gdbserver-port", required_argument, NULL, 'M'},
64 {"socket-file", required_argument, NULL, 'f'},
65 {"server", no_argument, &g_server, 1},
68 #if defined(__APPLE__)
69 #define LOW_PORT (IPPORT_RESERVED)
70 #define HIGH_PORT (IPPORT_HIFIRSTAUTO)
72 #define LOW_PORT (1024u)
73 #define HIGH_PORT (49151u)
76 //----------------------------------------------------------------------
78 //----------------------------------------------------------------------
79 static void signal_handler(int signo) {
82 // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
83 // And we should not call exit() here because it results in the global
85 // to be invoked and wreaking havoc on the threads still running.
86 Host::SystemLog(Host::eSystemLogWarning,
87 "SIGHUP received, exiting lldb-server...\n");
93 static void display_usage(const char *progname, const char *subcommand) {
94 fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels "
95 "log-channel-list] [--port-file port-file-path] --server "
97 progname, subcommand);
101 static Status save_socket_id_to_file(const std::string &socket_id,
102 const FileSpec &file_spec) {
103 FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false);
104 Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
106 return Status("Failed to create directory %s: %s",
107 temp_file_spec.GetCString(), error.AsCString());
109 llvm::SmallString<64> temp_file_path;
110 temp_file_spec.AppendPathComponent("port-file.%%%%%%");
112 auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetPath(), FD,
115 return Status("Failed to create temp file: %s", err_code.message().c_str());
117 llvm::FileRemover tmp_file_remover(temp_file_path);
120 llvm::raw_fd_ostream temp_file(FD, true);
121 temp_file << socket_id;
123 if (temp_file.has_error())
124 return Status("Failed to write to port file.");
127 err_code = llvm::sys::fs::rename(temp_file_path, file_spec.GetPath());
129 return Status("Failed to rename file %s to %s: %s", temp_file_path.c_str(),
130 file_spec.GetPath().c_str(), err_code.message().c_str());
132 tmp_file_remover.releaseFile();
136 //----------------------------------------------------------------------
138 //----------------------------------------------------------------------
139 int main_platform(int argc, char *argv[]) {
140 const char *progname = argv[0];
141 const char *subcommand = argv[1];
144 signal(SIGPIPE, SIG_IGN);
145 signal(SIGHUP, signal_handler);
146 int long_option_index = 0;
148 std::string listen_host_port;
151 std::string log_file;
153 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
155 GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
156 int min_gdbserver_port = 0;
157 int max_gdbserver_port = 0;
158 uint16_t port_offset = 0;
160 FileSpec socket_file;
161 bool show_usage = false;
162 int option_error = 0;
163 int socket_error = -1;
165 std::string short_options(OptionParser::GetShortOptionString(g_long_options));
174 while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
175 g_long_options, &long_option_index)) != -1) {
177 case 0: // Any optional that auto set themselves will return 0
181 listen_host_port.append(optarg);
184 case 'l': // Set Log File
185 if (optarg && optarg[0])
186 log_file.assign(optarg);
189 case 'c': // Log Channels
190 if (optarg && optarg[0])
191 log_channels = StringRef(optarg);
194 case 'f': // Socket file
195 if (optarg && optarg[0])
196 socket_file.SetFile(optarg, false);
200 if (!llvm::to_integer(optarg, port_offset)) {
201 llvm::errs() << "error: invalid port offset string " << optarg << "\n";
205 if (port_offset < LOW_PORT || port_offset > HIGH_PORT) {
206 llvm::errs() << llvm::formatv("error: port offset {0} is not in the "
207 "valid user port range of {1} - {2}\n",
208 port_offset, LOW_PORT, HIGH_PORT);
217 if (!llvm::to_integer(optarg, portnum)) {
218 llvm::errs() << "error: invalid port number string " << optarg << "\n";
222 if (portnum < LOW_PORT || portnum > HIGH_PORT) {
223 llvm::errs() << llvm::formatv("error: port number {0} is not in the "
224 "valid user port range of {1} - {2}\n",
225 portnum, LOW_PORT, HIGH_PORT);
230 gdbserver_portmap[portnum] = LLDB_INVALID_PROCESS_ID;
232 min_gdbserver_port = portnum;
234 max_gdbserver_port = portnum;
237 case 'h': /* fall-through is intentional */
244 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
247 // Make a port map for a port range that was specified.
248 if (min_gdbserver_port < max_gdbserver_port) {
249 for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port)
250 gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID;
251 } else if (min_gdbserver_port != max_gdbserver_port) {
252 fprintf(stderr, "error: --min-gdbserver-port (%u) is greater than "
253 "--max-gdbserver-port (%u)\n",
254 min_gdbserver_port, max_gdbserver_port);
258 // Print usage and exit if no listening port is specified.
259 if (listen_host_port.empty())
262 if (show_usage || option_error) {
263 display_usage(progname, subcommand);
267 // Skip any options we consumed with getopt_long_only.
270 lldb_private::Args inferior_arguments;
271 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
273 const bool children_inherit_listen_socket = false;
274 // the test suite makes many connections in parallel, let's not miss any.
275 // The highest this should get reasonably is a function of the number
276 // of target CPUs. For now, let's just use 100.
277 const int backlog = 100;
279 std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
280 listen_host_port, children_inherit_listen_socket, error));
282 fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
286 error = acceptor_up->Listen(backlog);
288 printf("failed to listen: %s\n", error.AsCString());
293 save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
295 fprintf(stderr, "failed to write socket id to %s: %s\n",
296 socket_file.GetPath().c_str(), error.AsCString());
302 GDBRemoteCommunicationServerPlatform platform(
303 acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
306 platform.SetPortOffset(port_offset);
308 if (!gdbserver_portmap.empty()) {
309 platform.SetPortMap(std::move(gdbserver_portmap));
312 const bool children_inherit_accept_socket = true;
313 Connection *conn = nullptr;
314 error = acceptor_up->Accept(children_inherit_accept_socket, conn);
316 printf("error: %s\n", error.AsCString());
319 printf("Connection established.\n");
321 // Collect child zombie processes.
322 while (waitpid(-1, nullptr, WNOHANG) > 0)
325 // Parent doesn't need a connection to the lldb client
328 // Parent will continue to listen for new connections.
331 // Child process will handle the connection and exit.
333 // Listening socket is owned by parent process.
334 acceptor_up.release();
337 // If not running as a server, this process will not accept
338 // connections while a connection is active.
341 platform.SetConnection(conn);
343 if (platform.IsConnected()) {
344 if (inferior_arguments.GetArgumentCount() > 0) {
345 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
347 std::string socket_name;
348 Status error = platform.LaunchGDBServer(inferior_arguments,
350 pid, port, socket_name);
352 platform.SetPendingGdbServer(pid, port, socket_name);
354 fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
357 // After we connected, we need to get an initial ack from...
358 if (platform.HandshakeWithClient()) {
359 bool interrupt = false;
361 while (!interrupt && !done) {
362 if (platform.GetPacketAndSendResponse(llvm::None, error, interrupt,
364 GDBRemoteCommunication::PacketResult::Success)
369 fprintf(stderr, "error: %s\n", error.AsCString());
372 fprintf(stderr, "error: handshake with client failed\n");
377 fprintf(stderr, "lldb-server exiting...\n");