blob: b7f7950d4ccfadbf9d7e16764ba442789d0b251e [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
10#include <errno.h>
Zachary Turner98688922014-08-06 18:16:26 +000011#if defined(__APPLE__)
12#include <netinet/in.h>
13#endif
Greg Claytonb43767a2011-03-22 01:34:44 +000014#include <signal.h>
15#include <stdint.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
Robert Flacka0e70cd2015-03-25 12:51:31 +000019#include <sys/wait.h>
Greg Claytonb43767a2011-03-22 01:34:44 +000020
Oleksiy Vyalov298be462015-07-06 18:05:19 +000021#include <fstream>
Greg Claytond314e812011-03-23 00:09:55 +000022
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000023#include "llvm/Support/FileSystem.h"
24#include "llvm/Support/FileUtilities.h"
25
Kate Stoneb9c1b512016-09-06 20:57:50 +000026#include "Acceptor.h"
27#include "LLDBServerUtilities.h"
28#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
29#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
Zachary Turner93a66fc2014-10-06 21:22:36 +000030#include "lldb/Host/ConnectionFileDescriptor.h"
Zachary Turner98688922014-08-06 18:16:26 +000031#include "lldb/Host/HostGetOpt.h"
Greg Claytonfb909312013-11-23 01:58:15 +000032#include "lldb/Host/OptionParser.h"
Oleksiy Vyalove98628c2015-10-15 23:54:09 +000033#include "lldb/Host/common/TCPSocket.h"
Zachary Turner5713a052017-03-22 18:40:07 +000034#include "lldb/Utility/FileSpec.h"
Zachary Turner97206d52017-05-12 04:51:55 +000035#include "lldb/Utility/Status.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000036
Greg Claytond314e812011-03-23 00:09:55 +000037using namespace lldb;
38using namespace lldb_private;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000039using namespace lldb_private::lldb_server;
Tamas Berghammerdb264a62015-03-31 09:52:22 +000040using namespace lldb_private::process_gdb_remote;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000041using namespace llvm;
Greg Claytond314e812011-03-23 00:09:55 +000042
Greg Claytonb43767a2011-03-22 01:34:44 +000043//----------------------------------------------------------------------
Greg Claytonb7ad58a2013-04-04 20:35:24 +000044// option descriptors for getopt_long_only()
Greg Claytonb43767a2011-03-22 01:34:44 +000045//----------------------------------------------------------------------
46
Tamas Berghammerc2c3d712015-02-18 15:39:41 +000047static int g_debug = 0;
48static int g_verbose = 0;
Robert Flacka0e70cd2015-03-25 12:51:31 +000049static int g_server = 0;
Greg Claytonb43767a2011-03-22 01:34:44 +000050
Kate Stoneb9c1b512016-09-06 20:57:50 +000051static struct option g_long_options[] = {
52 {"debug", no_argument, &g_debug, 1},
53 {"verbose", no_argument, &g_verbose, 1},
54 {"log-file", required_argument, NULL, 'l'},
55 {"log-channels", required_argument, NULL, 'c'},
56 {"listen", required_argument, NULL, 'L'},
57 {"port-offset", required_argument, NULL, 'p'},
58 {"gdbserver-port", required_argument, NULL, 'P'},
59 {"min-gdbserver-port", required_argument, NULL, 'm'},
60 {"max-gdbserver-port", required_argument, NULL, 'M'},
61 {"socket-file", required_argument, NULL, 'f'},
62 {"server", no_argument, &g_server, 1},
63 {NULL, 0, NULL, 0}};
Greg Claytonb43767a2011-03-22 01:34:44 +000064
Kate Stoneb9c1b512016-09-06 20:57:50 +000065#if defined(__APPLE__)
66#define LOW_PORT (IPPORT_RESERVED)
67#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
Greg Clayton29b8fc42013-11-21 01:44:58 +000068#else
Kate Stoneb9c1b512016-09-06 20:57:50 +000069#define LOW_PORT (1024u)
70#define HIGH_PORT (49151u)
Greg Clayton29b8fc42013-11-21 01:44:58 +000071#endif
72
Greg Claytonb43767a2011-03-22 01:34:44 +000073//----------------------------------------------------------------------
74// Watch for signals
75//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000076static void signal_handler(int signo) {
77 switch (signo) {
78 case SIGHUP:
79 // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
80 // And we should not call exit() here because it results in the global
81 // destructors
82 // to be invoked and wreaking havoc on the threads still running.
83 Host::SystemLog(Host::eSystemLogWarning,
84 "SIGHUP received, exiting lldb-server...\n");
85 abort();
86 break;
87 }
Greg Claytonb43767a2011-03-22 01:34:44 +000088}
89
Kate Stoneb9c1b512016-09-06 20:57:50 +000090static void display_usage(const char *progname, const char *subcommand) {
91 fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels "
92 "log-channel-list] [--port-file port-file-path] --server "
93 "--listen port\n",
94 progname, subcommand);
95 exit(0);
Daniel Maleae0f8f572013-08-26 23:57:52 +000096}
97
Zachary Turner97206d52017-05-12 04:51:55 +000098static Status save_socket_id_to_file(const std::string &socket_id,
99 const FileSpec &file_spec) {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000100 FileSpec temp_file_spec(file_spec.GetDirectory().AsCString());
Zachary Turner97206d52017-05-12 04:51:55 +0000101 Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 if (error.Fail())
Zachary Turner97206d52017-05-12 04:51:55 +0000103 return Status("Failed to create directory %s: %s",
104 temp_file_spec.GetCString(), error.AsCString());
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000105
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000106 llvm::SmallString<64> temp_file_path;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107 temp_file_spec.AppendPathComponent("port-file.%%%%%%");
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000108 int FD;
109 auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetPath(), FD,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 temp_file_path);
111 if (err_code)
Zachary Turner97206d52017-05-12 04:51:55 +0000112 return Status("Failed to create temp file: %s", err_code.message().c_str());
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000113
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000114 llvm::FileRemover tmp_file_remover(temp_file_path);
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000115
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116 {
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000117 llvm::raw_fd_ostream temp_file(FD, true);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118 temp_file << socket_id;
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000119 temp_file.close();
120 if (temp_file.has_error())
Zachary Turner97206d52017-05-12 04:51:55 +0000121 return Status("Failed to write to port file.");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000122 }
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000123
Pavel Labathe3ad2e22017-03-21 13:49:50 +0000124 err_code = llvm::sys::fs::rename(temp_file_path, file_spec.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 if (err_code)
Zachary Turner97206d52017-05-12 04:51:55 +0000126 return Status("Failed to rename file %s to %s: %s", temp_file_path.c_str(),
127 file_spec.GetPath().c_str(), err_code.message().c_str());
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000128
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 tmp_file_remover.releaseFile();
Zachary Turner97206d52017-05-12 04:51:55 +0000130 return Status();
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000131}
132
Greg Claytonb43767a2011-03-22 01:34:44 +0000133//----------------------------------------------------------------------
134// main
135//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136int main_platform(int argc, char *argv[]) {
137 const char *progname = argv[0];
138 const char *subcommand = argv[1];
139 argc--;
140 argv++;
141 signal(SIGPIPE, SIG_IGN);
142 signal(SIGHUP, signal_handler);
143 int long_option_index = 0;
Zachary Turner97206d52017-05-12 04:51:55 +0000144 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000145 std::string listen_host_port;
146 int ch;
Greg Clayton5fb8f792013-12-02 19:35:49 +0000147
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 std::string log_file;
149 StringRef
150 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000151
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
153 int min_gdbserver_port = 0;
154 int max_gdbserver_port = 0;
155 uint16_t port_offset = 0;
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000156
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157 FileSpec socket_file;
158 bool show_usage = false;
159 int option_error = 0;
160 int socket_error = -1;
161
162 std::string short_options(OptionParser::GetShortOptionString(g_long_options));
163
Greg Claytond4724cf2013-11-22 18:55:04 +0000164#if __GLIBC__
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165 optind = 0;
Greg Claytond4724cf2013-11-22 18:55:04 +0000166#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 optreset = 1;
168 optind = 1;
Greg Claytond4724cf2013-11-22 18:55:04 +0000169#endif
170
Kate Stoneb9c1b512016-09-06 20:57:50 +0000171 while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
172 g_long_options, &long_option_index)) != -1) {
173 switch (ch) {
174 case 0: // Any optional that auto set themselves will return 0
175 break;
Greg Claytonb43767a2011-03-22 01:34:44 +0000176
Kate Stoneb9c1b512016-09-06 20:57:50 +0000177 case 'L':
178 listen_host_port.append(optarg);
179 break;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000180
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 case 'l': // Set Log File
182 if (optarg && optarg[0])
183 log_file.assign(optarg);
184 break;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000185
Kate Stoneb9c1b512016-09-06 20:57:50 +0000186 case 'c': // Log Channels
187 if (optarg && optarg[0])
188 log_channels = StringRef(optarg);
189 break;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000190
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191 case 'f': // Socket file
192 if (optarg && optarg[0])
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000193 socket_file.SetFile(optarg, FileSpec::Style::native);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 break;
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000195
Kate Stoneb9c1b512016-09-06 20:57:50 +0000196 case 'p': {
Pavel Labathef7aff52017-07-05 14:54:46 +0000197 if (!llvm::to_integer(optarg, port_offset)) {
198 llvm::errs() << "error: invalid port offset string " << optarg << "\n";
Kate Stoneb9c1b512016-09-06 20:57:50 +0000199 option_error = 4;
Pavel Labathef7aff52017-07-05 14:54:46 +0000200 break;
201 }
Pavel Labath21fb07b2017-07-06 11:43:25 +0000202 if (port_offset < LOW_PORT || port_offset > HIGH_PORT) {
Pavel Labathef7aff52017-07-05 14:54:46 +0000203 llvm::errs() << llvm::formatv("error: port offset {0} is not in the "
204 "valid user port range of {1} - {2}\n",
205 port_offset, LOW_PORT, HIGH_PORT);
206 option_error = 5;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000207 }
208 } break;
Greg Clayton5fb8f792013-12-02 19:35:49 +0000209
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210 case 'P':
211 case 'm':
212 case 'M': {
Pavel Labathef7aff52017-07-05 14:54:46 +0000213 uint16_t portnum;
214 if (!llvm::to_integer(optarg, portnum)) {
215 llvm::errs() << "error: invalid port number string " << optarg << "\n";
Kate Stoneb9c1b512016-09-06 20:57:50 +0000216 option_error = 2;
Pavel Labathef7aff52017-07-05 14:54:46 +0000217 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218 }
Pavel Labath21fb07b2017-07-06 11:43:25 +0000219 if (portnum < LOW_PORT || portnum > HIGH_PORT) {
Pavel Labathef7aff52017-07-05 14:54:46 +0000220 llvm::errs() << llvm::formatv("error: port number {0} is not in the "
221 "valid user port range of {1} - {2}\n",
222 portnum, LOW_PORT, HIGH_PORT);
223 option_error = 1;
224 break;
225 }
226 if (ch == 'P')
227 gdbserver_portmap[portnum] = LLDB_INVALID_PROCESS_ID;
228 else if (ch == 'm')
229 min_gdbserver_port = portnum;
230 else
231 max_gdbserver_port = portnum;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000232 } break;
233
234 case 'h': /* fall-through is intentional */
235 case '?':
236 show_usage = true;
237 break;
238 }
239 }
240
241 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
242 return -1;
243
244 // Make a port map for a port range that was specified.
245 if (min_gdbserver_port < max_gdbserver_port) {
246 for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port)
247 gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID;
248 } else if (min_gdbserver_port != max_gdbserver_port) {
249 fprintf(stderr, "error: --min-gdbserver-port (%u) is greater than "
250 "--max-gdbserver-port (%u)\n",
251 min_gdbserver_port, max_gdbserver_port);
252 option_error = 3;
253 }
254
255 // Print usage and exit if no listening port is specified.
256 if (listen_host_port.empty())
257 show_usage = true;
258
259 if (show_usage || option_error) {
260 display_usage(progname, subcommand);
261 exit(option_error);
262 }
263
264 // Skip any options we consumed with getopt_long_only.
265 argc -= optind;
266 argv += optind;
267 lldb_private::Args inferior_arguments;
268 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
269
270 const bool children_inherit_listen_socket = false;
271 // the test suite makes many connections in parallel, let's not miss any.
272 // The highest this should get reasonably is a function of the number
273 // of target CPUs. For now, let's just use 100.
274 const int backlog = 100;
275
276 std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
277 listen_host_port, children_inherit_listen_socket, error));
278 if (error.Fail()) {
279 fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
280 exit(socket_error);
281 }
282
283 error = acceptor_up->Listen(backlog);
284 if (error.Fail()) {
285 printf("failed to listen: %s\n", error.AsCString());
286 exit(socket_error);
287 }
288 if (socket_file) {
289 error =
290 save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
291 if (error.Fail()) {
292 fprintf(stderr, "failed to write socket id to %s: %s\n",
293 socket_file.GetPath().c_str(), error.AsCString());
294 return 1;
295 }
296 }
297
298 do {
299 GDBRemoteCommunicationServerPlatform platform(
300 acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
301
302 if (port_offset > 0)
303 platform.SetPortOffset(port_offset);
304
305 if (!gdbserver_portmap.empty()) {
306 platform.SetPortMap(std::move(gdbserver_portmap));
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000307 }
Greg Claytonb43767a2011-03-22 01:34:44 +0000308
Kate Stoneb9c1b512016-09-06 20:57:50 +0000309 const bool children_inherit_accept_socket = true;
310 Connection *conn = nullptr;
311 error = acceptor_up->Accept(children_inherit_accept_socket, conn);
312 if (error.Fail()) {
313 printf("error: %s\n", error.AsCString());
314 exit(socket_error);
315 }
316 printf("Connection established.\n");
317 if (g_server) {
318 // Collect child zombie processes.
319 while (waitpid(-1, nullptr, WNOHANG) > 0)
320 ;
321 if (fork()) {
322 // Parent doesn't need a connection to the lldb client
323 delete conn;
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000324
Kate Stoneb9c1b512016-09-06 20:57:50 +0000325 // Parent will continue to listen for new connections.
326 continue;
327 } else {
328 // Child process will handle the connection and exit.
329 g_server = 0;
330 // Listening socket is owned by parent process.
331 acceptor_up.release();
332 }
333 } else {
334 // If not running as a server, this process will not accept
335 // connections while a connection is active.
336 acceptor_up.reset();
337 }
338 platform.SetConnection(conn);
Greg Claytond4724cf2013-11-22 18:55:04 +0000339
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340 if (platform.IsConnected()) {
341 if (inferior_arguments.GetArgumentCount() > 0) {
342 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
343 uint16_t port = 0;
344 std::string socket_name;
Zachary Turner97206d52017-05-12 04:51:55 +0000345 Status error = platform.LaunchGDBServer(inferior_arguments,
346 "", // hostname
347 pid, port, socket_name);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348 if (error.Success())
349 platform.SetPendingGdbServer(pid, port, socket_name);
Robert Flacka0e70cd2015-03-25 12:51:31 +0000350 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000351 fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
352 }
353
354 // After we connected, we need to get an initial ack from...
355 if (platform.HandshakeWithClient()) {
356 bool interrupt = false;
357 bool done = false;
358 while (!interrupt && !done) {
Pavel Labath1eff73c2016-11-24 10:54:49 +0000359 if (platform.GetPacketAndSendResponse(llvm::None, error, interrupt,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000360 done) !=
361 GDBRemoteCommunication::PacketResult::Success)
362 break;
Robert Flacka0e70cd2015-03-25 12:51:31 +0000363 }
Robert Flacka0e70cd2015-03-25 12:51:31 +0000364
Kate Stoneb9c1b512016-09-06 20:57:50 +0000365 if (error.Fail()) {
366 fprintf(stderr, "error: %s\n", error.AsCString());
Robert Flacka0e70cd2015-03-25 12:51:31 +0000367 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000368 } else {
369 fprintf(stderr, "error: handshake with client failed\n");
370 }
371 }
372 } while (g_server);
Greg Claytonb43767a2011-03-22 01:34:44 +0000373
Kate Stoneb9c1b512016-09-06 20:57:50 +0000374 fprintf(stderr, "lldb-server exiting...\n");
Daniel Maleae0f8f572013-08-26 23:57:52 +0000375
Kate Stoneb9c1b512016-09-06 20:57:50 +0000376 return 0;
Greg Claytonb43767a2011-03-22 01:34:44 +0000377}