blob: 8d45682566b984c83d4aa2e4b4f32c41d11d0a0a [file] [log] [blame]
Greg Claytonb43767a2011-03-22 01:34:44 +00001//===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Greg Claytond314e812011-03-23 00:09:55 +000010// C Includes
Greg Claytonb43767a2011-03-22 01:34:44 +000011#include <errno.h>
Zachary Turner98688922014-08-06 18:16:26 +000012#if defined(__APPLE__)
13#include <netinet/in.h>
14#endif
Greg Claytonb43767a2011-03-22 01:34:44 +000015#include <signal.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
Robert Flacka0e70cd2015-03-25 12:51:31 +000020#include <sys/wait.h>
Greg Claytonb43767a2011-03-22 01:34:44 +000021
Greg Claytond314e812011-03-23 00:09:55 +000022// C++ Includes
Oleksiy Vyalov298be462015-07-06 18:05:19 +000023#include <fstream>
Greg Claytond314e812011-03-23 00:09:55 +000024
25// Other libraries and framework includes
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000026#include "llvm/Support/FileSystem.h"
27#include "llvm/Support/FileUtilities.h"
28
Kate Stoneb9c1b512016-09-06 20:57:50 +000029#include "Acceptor.h"
30#include "LLDBServerUtilities.h"
31#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
32#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
Zachary Turner93a66fc2014-10-06 21:22:36 +000033#include "lldb/Host/ConnectionFileDescriptor.h"
Zachary Turner98688922014-08-06 18:16:26 +000034#include "lldb/Host/HostGetOpt.h"
Greg Claytonfb909312013-11-23 01:58:15 +000035#include "lldb/Host/OptionParser.h"
Oleksiy Vyalove98628c2015-10-15 23:54:09 +000036#include "lldb/Host/common/TCPSocket.h"
Zachary Turner5713a052017-03-22 18:40:07 +000037#include "lldb/Utility/FileSpec.h"
Zachary Turner97206d52017-05-12 04:51:55 +000038#include "lldb/Utility/Status.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000039
Greg Claytond314e812011-03-23 00:09:55 +000040using namespace lldb;
41using namespace lldb_private;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000042using namespace lldb_private::lldb_server;
Tamas Berghammerdb264a62015-03-31 09:52:22 +000043using namespace lldb_private::process_gdb_remote;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000044using namespace llvm;
Greg Claytond314e812011-03-23 00:09:55 +000045
Greg Claytonb43767a2011-03-22 01:34:44 +000046//----------------------------------------------------------------------
Greg Claytonb7ad58a2013-04-04 20:35:24 +000047// option descriptors for getopt_long_only()
Greg Claytonb43767a2011-03-22 01:34:44 +000048//----------------------------------------------------------------------
49
Tamas Berghammerc2c3d712015-02-18 15:39:41 +000050static int g_debug = 0;
51static int g_verbose = 0;
Robert Flacka0e70cd2015-03-25 12:51:31 +000052static int g_server = 0;
Greg Claytonb43767a2011-03-22 01:34:44 +000053
Kate Stoneb9c1b512016-09-06 20:57:50 +000054static 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},
66 {NULL, 0, NULL, 0}};
Greg Claytonb43767a2011-03-22 01:34:44 +000067
Kate Stoneb9c1b512016-09-06 20:57:50 +000068#if defined(__APPLE__)
69#define LOW_PORT (IPPORT_RESERVED)
70#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
Greg Clayton29b8fc42013-11-21 01:44:58 +000071#else
Kate Stoneb9c1b512016-09-06 20:57:50 +000072#define LOW_PORT (1024u)
73#define HIGH_PORT (49151u)
Greg Clayton29b8fc42013-11-21 01:44:58 +000074#endif
75
Greg Claytonb43767a2011-03-22 01:34:44 +000076//----------------------------------------------------------------------
77// Watch for signals
78//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000079static void signal_handler(int signo) {
80 switch (signo) {
81 case SIGHUP:
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
84 // destructors
85 // to be invoked and wreaking havoc on the threads still running.
86 Host::SystemLog(Host::eSystemLogWarning,
87 "SIGHUP received, exiting lldb-server...\n");
88 abort();
89 break;
90 }
Greg Claytonb43767a2011-03-22 01:34:44 +000091}
92
Kate Stoneb9c1b512016-09-06 20:57:50 +000093static 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 "
96 "--listen port\n",
97 progname, subcommand);
98 exit(0);
Daniel Maleae0f8f572013-08-26 23:57:52 +000099}
100
Zachary Turner97206d52017-05-12 04:51:55 +0000101static Status save_socket_id_to_file(const std::string &socket_id,
102 const FileSpec &file_spec) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103 FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false);
Zachary Turner97206d52017-05-12 04:51:55 +0000104 Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105 if (error.Fail())
Zachary Turner97206d52017-05-12 04:51:55 +0000106 return Status("Failed to create directory %s: %s",
107 temp_file_spec.GetCString(), error.AsCString());
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000108
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000109 llvm::SmallString<64> temp_file_path;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 temp_file_spec.AppendPathComponent("port-file.%%%%%%");
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000111 int FD;
112 auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetPath(), FD,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 temp_file_path);
114 if (err_code)
Zachary Turner97206d52017-05-12 04:51:55 +0000115 return Status("Failed to create temp file: %s", err_code.message().c_str());
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000116
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000117 llvm::FileRemover tmp_file_remover(temp_file_path);
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000118
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119 {
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000120 llvm::raw_fd_ostream temp_file(FD, true);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121 temp_file << socket_id;
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000122 temp_file.close();
123 if (temp_file.has_error())
Zachary Turner97206d52017-05-12 04:51:55 +0000124 return Status("Failed to write to port file.");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 }
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000126
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000127 err_code = llvm::sys::fs::rename(temp_file_path, file_spec.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 if (err_code)
Zachary Turner97206d52017-05-12 04:51:55 +0000129 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());
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000131
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 tmp_file_remover.releaseFile();
Zachary Turner97206d52017-05-12 04:51:55 +0000133 return Status();
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000134}
135
Greg Claytonb43767a2011-03-22 01:34:44 +0000136//----------------------------------------------------------------------
137// main
138//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139int main_platform(int argc, char *argv[]) {
140 const char *progname = argv[0];
141 const char *subcommand = argv[1];
142 argc--;
143 argv++;
144 signal(SIGPIPE, SIG_IGN);
145 signal(SIGHUP, signal_handler);
146 int long_option_index = 0;
Zachary Turner97206d52017-05-12 04:51:55 +0000147 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 std::string listen_host_port;
149 int ch;
Greg Clayton5fb8f792013-12-02 19:35:49 +0000150
Kate Stoneb9c1b512016-09-06 20:57:50 +0000151 std::string log_file;
152 StringRef
153 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000154
Kate Stoneb9c1b512016-09-06 20:57:50 +0000155 GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
156 int min_gdbserver_port = 0;
157 int max_gdbserver_port = 0;
158 uint16_t port_offset = 0;
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000159
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 FileSpec socket_file;
161 bool show_usage = false;
162 int option_error = 0;
163 int socket_error = -1;
164
165 std::string short_options(OptionParser::GetShortOptionString(g_long_options));
166
Greg Claytond4724cf2013-11-22 18:55:04 +0000167#if __GLIBC__
Kate Stoneb9c1b512016-09-06 20:57:50 +0000168 optind = 0;
Greg Claytond4724cf2013-11-22 18:55:04 +0000169#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 optreset = 1;
171 optind = 1;
Greg Claytond4724cf2013-11-22 18:55:04 +0000172#endif
173
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174 while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
175 g_long_options, &long_option_index)) != -1) {
176 switch (ch) {
177 case 0: // Any optional that auto set themselves will return 0
178 break;
Greg Claytonb43767a2011-03-22 01:34:44 +0000179
Kate Stoneb9c1b512016-09-06 20:57:50 +0000180 case 'L':
181 listen_host_port.append(optarg);
182 break;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000183
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184 case 'l': // Set Log File
185 if (optarg && optarg[0])
186 log_file.assign(optarg);
187 break;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000188
Kate Stoneb9c1b512016-09-06 20:57:50 +0000189 case 'c': // Log Channels
190 if (optarg && optarg[0])
191 log_channels = StringRef(optarg);
192 break;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000193
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 case 'f': // Socket file
195 if (optarg && optarg[0])
196 socket_file.SetFile(optarg, false);
197 break;
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000198
Kate Stoneb9c1b512016-09-06 20:57:50 +0000199 case 'p': {
200 char *end = NULL;
201 long tmp_port_offset = strtoul(optarg, &end, 0);
202 if (end && *end == '\0') {
203 if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT) {
204 port_offset = (uint16_t)tmp_port_offset;
205 } else {
206 fprintf(stderr, "error: port offset %li is not in the valid user "
207 "port range of %u - %u\n",
208 tmp_port_offset, LOW_PORT, HIGH_PORT);
209 option_error = 5;
Greg Claytonb43767a2011-03-22 01:34:44 +0000210 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000211 } else {
212 fprintf(stderr, "error: invalid port offset string %s\n", optarg);
213 option_error = 4;
214 }
215 } break;
Greg Clayton5fb8f792013-12-02 19:35:49 +0000216
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217 case 'P':
218 case 'm':
219 case 'M': {
220 char *end = NULL;
221 long portnum = strtoul(optarg, &end, 0);
222 if (end && *end == '\0') {
223 if (LOW_PORT <= portnum && portnum <= HIGH_PORT) {
224 if (ch == 'P')
225 gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID;
226 else if (ch == 'm')
227 min_gdbserver_port = portnum;
228 else
229 max_gdbserver_port = portnum;
230 } else {
231 fprintf(stderr, "error: port number %li is not in the valid user "
232 "port range of %u - %u\n",
233 portnum, LOW_PORT, HIGH_PORT);
234 option_error = 1;
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000235 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000236 } else {
237 fprintf(stderr, "error: invalid port number string %s\n", optarg);
238 option_error = 2;
239 }
240 } break;
241
242 case 'h': /* fall-through is intentional */
243 case '?':
244 show_usage = true;
245 break;
246 }
247 }
248
249 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
250 return -1;
251
252 // Make a port map for a port range that was specified.
253 if (min_gdbserver_port < max_gdbserver_port) {
254 for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port)
255 gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID;
256 } else if (min_gdbserver_port != max_gdbserver_port) {
257 fprintf(stderr, "error: --min-gdbserver-port (%u) is greater than "
258 "--max-gdbserver-port (%u)\n",
259 min_gdbserver_port, max_gdbserver_port);
260 option_error = 3;
261 }
262
263 // Print usage and exit if no listening port is specified.
264 if (listen_host_port.empty())
265 show_usage = true;
266
267 if (show_usage || option_error) {
268 display_usage(progname, subcommand);
269 exit(option_error);
270 }
271
272 // Skip any options we consumed with getopt_long_only.
273 argc -= optind;
274 argv += optind;
275 lldb_private::Args inferior_arguments;
276 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
277
278 const bool children_inherit_listen_socket = false;
279 // the test suite makes many connections in parallel, let's not miss any.
280 // The highest this should get reasonably is a function of the number
281 // of target CPUs. For now, let's just use 100.
282 const int backlog = 100;
283
284 std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
285 listen_host_port, children_inherit_listen_socket, error));
286 if (error.Fail()) {
287 fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
288 exit(socket_error);
289 }
290
291 error = acceptor_up->Listen(backlog);
292 if (error.Fail()) {
293 printf("failed to listen: %s\n", error.AsCString());
294 exit(socket_error);
295 }
296 if (socket_file) {
297 error =
298 save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
299 if (error.Fail()) {
300 fprintf(stderr, "failed to write socket id to %s: %s\n",
301 socket_file.GetPath().c_str(), error.AsCString());
302 return 1;
303 }
304 }
305
306 do {
307 GDBRemoteCommunicationServerPlatform platform(
308 acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
309
310 if (port_offset > 0)
311 platform.SetPortOffset(port_offset);
312
313 if (!gdbserver_portmap.empty()) {
314 platform.SetPortMap(std::move(gdbserver_portmap));
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000315 }
Greg Claytonb43767a2011-03-22 01:34:44 +0000316
Kate Stoneb9c1b512016-09-06 20:57:50 +0000317 const bool children_inherit_accept_socket = true;
318 Connection *conn = nullptr;
319 error = acceptor_up->Accept(children_inherit_accept_socket, conn);
320 if (error.Fail()) {
321 printf("error: %s\n", error.AsCString());
322 exit(socket_error);
323 }
324 printf("Connection established.\n");
325 if (g_server) {
326 // Collect child zombie processes.
327 while (waitpid(-1, nullptr, WNOHANG) > 0)
328 ;
329 if (fork()) {
330 // Parent doesn't need a connection to the lldb client
331 delete conn;
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000332
Kate Stoneb9c1b512016-09-06 20:57:50 +0000333 // Parent will continue to listen for new connections.
334 continue;
335 } else {
336 // Child process will handle the connection and exit.
337 g_server = 0;
338 // Listening socket is owned by parent process.
339 acceptor_up.release();
340 }
341 } else {
342 // If not running as a server, this process will not accept
343 // connections while a connection is active.
344 acceptor_up.reset();
345 }
346 platform.SetConnection(conn);
Greg Claytond4724cf2013-11-22 18:55:04 +0000347
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348 if (platform.IsConnected()) {
349 if (inferior_arguments.GetArgumentCount() > 0) {
350 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
351 uint16_t port = 0;
352 std::string socket_name;
Zachary Turner97206d52017-05-12 04:51:55 +0000353 Status error = platform.LaunchGDBServer(inferior_arguments,
354 "", // hostname
355 pid, port, socket_name);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000356 if (error.Success())
357 platform.SetPendingGdbServer(pid, port, socket_name);
Robert Flacka0e70cd2015-03-25 12:51:31 +0000358 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000359 fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
360 }
361
362 // After we connected, we need to get an initial ack from...
363 if (platform.HandshakeWithClient()) {
364 bool interrupt = false;
365 bool done = false;
366 while (!interrupt && !done) {
Pavel Labath1eff73c2016-11-24 10:54:49 +0000367 if (platform.GetPacketAndSendResponse(llvm::None, error, interrupt,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000368 done) !=
369 GDBRemoteCommunication::PacketResult::Success)
370 break;
Robert Flacka0e70cd2015-03-25 12:51:31 +0000371 }
Robert Flacka0e70cd2015-03-25 12:51:31 +0000372
Kate Stoneb9c1b512016-09-06 20:57:50 +0000373 if (error.Fail()) {
374 fprintf(stderr, "error: %s\n", error.AsCString());
Robert Flacka0e70cd2015-03-25 12:51:31 +0000375 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000376 } else {
377 fprintf(stderr, "error: handshake with client failed\n");
378 }
379 }
380 } while (g_server);
Greg Claytonb43767a2011-03-22 01:34:44 +0000381
Kate Stoneb9c1b512016-09-06 20:57:50 +0000382 fprintf(stderr, "lldb-server exiting...\n");
Daniel Maleae0f8f572013-08-26 23:57:52 +0000383
Kate Stoneb9c1b512016-09-06 20:57:50 +0000384 return 0;
Greg Claytonb43767a2011-03-22 01:34:44 +0000385}