blob: eb2ae01089dfda1f05a9d5d3db97ab7e1ae619d8 [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
26#include "lldb/Core/Error.h"
Zachary Turner93a66fc2014-10-06 21:22:36 +000027#include "lldb/Host/ConnectionFileDescriptor.h"
Oleksiy Vyalov298be462015-07-06 18:05:19 +000028#include "lldb/Host/FileSpec.h"
29#include "lldb/Host/FileSystem.h"
Zachary Turner98688922014-08-06 18:16:26 +000030#include "lldb/Host/HostGetOpt.h"
Greg Claytonfb909312013-11-23 01:58:15 +000031#include "lldb/Host/OptionParser.h"
Robert Flacka0e70cd2015-03-25 12:51:31 +000032#include "lldb/Host/Socket.h"
Oleksiy Vyalov298be462015-07-06 18:05:19 +000033#include "llvm/Support/FileSystem.h"
34#include "llvm/Support/FileUtilities.h"
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000035#include "LLDBServerUtilities.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000036#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
Greg Clayton1cb64962011-03-24 04:28:38 +000037#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000038
Greg Claytond314e812011-03-23 00:09:55 +000039using namespace lldb;
40using namespace lldb_private;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000041using namespace lldb_private::lldb_server;
Tamas Berghammerdb264a62015-03-31 09:52:22 +000042using namespace lldb_private::process_gdb_remote;
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000043using namespace llvm;
Greg Claytond314e812011-03-23 00:09:55 +000044
Greg Claytonb43767a2011-03-22 01:34:44 +000045//----------------------------------------------------------------------
Greg Claytonb7ad58a2013-04-04 20:35:24 +000046// option descriptors for getopt_long_only()
Greg Claytonb43767a2011-03-22 01:34:44 +000047//----------------------------------------------------------------------
48
Tamas Berghammerc2c3d712015-02-18 15:39:41 +000049static int g_debug = 0;
50static int g_verbose = 0;
Robert Flacka0e70cd2015-03-25 12:51:31 +000051static int g_server = 0;
Greg Claytonb43767a2011-03-22 01:34:44 +000052
53static struct option g_long_options[] =
54{
55 { "debug", no_argument, &g_debug, 1 },
56 { "verbose", no_argument, &g_verbose, 1 },
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +000057 { "log-file", required_argument, NULL, 'l' },
58 { "log-channels", required_argument, NULL, 'c' },
Greg Claytond314e812011-03-23 00:09:55 +000059 { "listen", required_argument, NULL, 'L' },
Greg Claytond4724cf2013-11-22 18:55:04 +000060 { "port-offset", required_argument, NULL, 'p' },
61 { "gdbserver-port", required_argument, NULL, 'P' },
Greg Clayton29b8fc42013-11-21 01:44:58 +000062 { "min-gdbserver-port", required_argument, NULL, 'm' },
63 { "max-gdbserver-port", required_argument, NULL, 'M' },
Oleksiy Vyalov298be462015-07-06 18:05:19 +000064 { "port-file", required_argument, NULL, 'f' },
Robert Flacka0e70cd2015-03-25 12:51:31 +000065 { "server", no_argument, &g_server, 1 },
Greg Claytonb43767a2011-03-22 01:34:44 +000066 { NULL, 0, NULL, 0 }
67};
68
Greg Clayton29b8fc42013-11-21 01:44:58 +000069#if defined (__APPLE__)
70#define LOW_PORT (IPPORT_RESERVED)
71#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
72#else
73#define LOW_PORT (1024u)
74#define HIGH_PORT (49151u)
75#endif
76
Greg Claytonb43767a2011-03-22 01:34:44 +000077//----------------------------------------------------------------------
78// Watch for signals
79//----------------------------------------------------------------------
Tamas Berghammerc2c3d712015-02-18 15:39:41 +000080static void
Greg Claytonb43767a2011-03-22 01:34:44 +000081signal_handler(int signo)
82{
83 switch (signo)
84 {
Daniel Maleae0f8f572013-08-26 23:57:52 +000085 case SIGHUP:
86 // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
87 // And we should not call exit() here because it results in the global destructors
88 // to be invoked and wreaking havoc on the threads still running.
Robert Flack8cc4cf12015-03-06 14:36:33 +000089 Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-server...\n");
Daniel Maleae0f8f572013-08-26 23:57:52 +000090 abort();
91 break;
Greg Claytonb43767a2011-03-22 01:34:44 +000092 }
93}
94
Daniel Maleae0f8f572013-08-26 23:57:52 +000095static void
Tamas Berghammerc2c3d712015-02-18 15:39:41 +000096display_usage (const char *progname, const char *subcommand)
Daniel Maleae0f8f572013-08-26 23:57:52 +000097{
Oleksiy Vyalov298be462015-07-06 18:05:19 +000098 fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels log-channel-list] [--port-file port-file-path] --server --listen port\n", progname, subcommand);
Daniel Maleae0f8f572013-08-26 23:57:52 +000099 exit(0);
100}
101
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000102static Error
103save_port_to_file(const uint16_t port, const FileSpec &port_file_spec)
104{
105 const ConstString& port_file_dir = port_file_spec.GetDirectory();
106 auto error = FileSystem::MakeDirectory(
107 FileSpec(port_file_dir.AsCString(), false), eFilePermissionsDirectoryDefault);
108 if (error.Fail())
109 return Error("Failed to create directory %s: %s", port_file_dir.AsCString(), error.AsCString());
110
111 llvm::SmallString<PATH_MAX> temp_file_path;
112 auto err_code = llvm::sys::fs::createTemporaryFile(
113 port_file_spec.GetPath().c_str(), "", temp_file_path);
114 if (err_code)
115 return Error("Failed to create temp file: %s", err_code.message().c_str());
116
117 llvm::FileRemover tmp_file_remover(temp_file_path.c_str());
118
119 {
120 std::ofstream temp_file(temp_file_path.c_str(), std::ios::out);
121 if (!temp_file.is_open())
122 return Error("Failed to open temp file %s", temp_file_path.c_str());
123 temp_file << port;
124 }
125
126 err_code = llvm::sys::fs::rename(temp_file_path.c_str(), port_file_spec.GetPath().c_str());
127 if (err_code)
128 return Error("Failed to rename file %s to %s: %s",
129 temp_file_path.c_str(), port_file_spec.GetPath().c_str(), err_code.message().c_str());
130
131 tmp_file_remover.releaseFile();
132 return Error();
133}
134
Greg Claytonb43767a2011-03-22 01:34:44 +0000135//----------------------------------------------------------------------
136// main
137//----------------------------------------------------------------------
138int
Tamas Berghammerc2c3d712015-02-18 15:39:41 +0000139main_platform (int argc, char *argv[])
Greg Claytonb43767a2011-03-22 01:34:44 +0000140{
Daniel Maleae0f8f572013-08-26 23:57:52 +0000141 const char *progname = argv[0];
Tamas Berghammerc2c3d712015-02-18 15:39:41 +0000142 const char *subcommand = argv[1];
143 argc--;
144 argv++;
Greg Claytonfb909312013-11-23 01:58:15 +0000145 signal (SIGPIPE, SIG_IGN);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000146 signal (SIGHUP, signal_handler);
Greg Claytonb43767a2011-03-22 01:34:44 +0000147 int long_option_index = 0;
Greg Clayton9b1e1cd2011-04-04 18:18:57 +0000148 Error error;
Greg Clayton73bf5db2011-06-17 01:22:15 +0000149 std::string listen_host_port;
Greg Clayton9d3d6882011-10-31 23:51:19 +0000150 int ch;
Greg Clayton5fb8f792013-12-02 19:35:49 +0000151
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000152 std::string log_file;
153 StringRef log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000154
Tamas Berghammere13c2732015-02-11 10:29:30 +0000155 GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
Greg Clayton29b8fc42013-11-21 01:44:58 +0000156 int min_gdbserver_port = 0;
157 int max_gdbserver_port = 0;
Greg Claytond4724cf2013-11-22 18:55:04 +0000158 uint16_t port_offset = 0;
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000159
160 FileSpec port_file;
Greg Clayton29b8fc42013-11-21 01:44:58 +0000161 bool show_usage = false;
162 int option_error = 0;
Robert Flacka0e70cd2015-03-25 12:51:31 +0000163 int socket_error = -1;
Greg Clayton9b1e1cd2011-04-04 18:18:57 +0000164
Greg Claytonfb909312013-11-23 01:58:15 +0000165 std::string short_options(OptionParser::GetShortOptionString(g_long_options));
166
Greg Claytond4724cf2013-11-22 18:55:04 +0000167#if __GLIBC__
168 optind = 0;
169#else
170 optreset = 1;
171 optind = 1;
172#endif
173
Greg Claytonfb909312013-11-23 01:58:15 +0000174 while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1)
Greg Claytonb43767a2011-03-22 01:34:44 +0000175 {
Greg Claytonb43767a2011-03-22 01:34:44 +0000176 switch (ch)
177 {
178 case 0: // Any optional that auto set themselves will return 0
179 break;
180
Greg Claytond314e812011-03-23 00:09:55 +0000181 case 'L':
Greg Clayton73bf5db2011-06-17 01:22:15 +0000182 listen_host_port.append (optarg);
Greg Claytond314e812011-03-23 00:09:55 +0000183 break;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000184
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000185 case 'l': // Set Log File
186 if (optarg && optarg[0])
187 log_file.assign(optarg);
188 break;
189
190 case 'c': // Log Channels
191 if (optarg && optarg[0])
192 log_channels = StringRef(optarg);
193 break;
194
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000195 case 'f': // Port file
196 if (optarg && optarg[0])
197 port_file.SetFile(optarg, false);
198 break;
199
Greg Clayton29b8fc42013-11-21 01:44:58 +0000200 case 'p':
Greg Claytond4724cf2013-11-22 18:55:04 +0000201 {
202 char *end = NULL;
203 long tmp_port_offset = strtoul(optarg, &end, 0);
204 if (end && *end == '\0')
205 {
206 if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT)
207 {
208 port_offset = (uint16_t)tmp_port_offset;
209 }
210 else
211 {
212 fprintf (stderr, "error: port offset %li is not in the valid user port range of %u - %u\n", tmp_port_offset, LOW_PORT, HIGH_PORT);
213 option_error = 5;
214 }
215 }
216 else
217 {
218 fprintf (stderr, "error: invalid port offset string %s\n", optarg);
219 option_error = 4;
220 }
221 }
222 break;
223
224 case 'P':
Greg Clayton29b8fc42013-11-21 01:44:58 +0000225 case 'm':
226 case 'M':
227 {
228 char *end = NULL;
229 long portnum = strtoul(optarg, &end, 0);
230 if (end && *end == '\0')
231 {
232 if (LOW_PORT <= portnum && portnum <= HIGH_PORT)
233 {
Greg Claytond4724cf2013-11-22 18:55:04 +0000234 if (ch == 'P')
Greg Clayton29b8fc42013-11-21 01:44:58 +0000235 gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID;
236 else if (ch == 'm')
237 min_gdbserver_port = portnum;
238 else
239 max_gdbserver_port = portnum;
240 }
241 else
242 {
243 fprintf (stderr, "error: port number %li is not in the valid user port range of %u - %u\n", portnum, LOW_PORT, HIGH_PORT);
244 option_error = 1;
245 }
246 }
247 else
248 {
249 fprintf (stderr, "error: invalid port number string %s\n", optarg);
250 option_error = 2;
251 }
252 }
253 break;
Greg Clayton5fb8f792013-12-02 19:35:49 +0000254
Daniel Maleae0f8f572013-08-26 23:57:52 +0000255 case 'h': /* fall-through is intentional */
256 case '?':
Greg Clayton29b8fc42013-11-21 01:44:58 +0000257 show_usage = true;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000258 break;
Greg Claytonb43767a2011-03-22 01:34:44 +0000259 }
260 }
Greg Clayton5fb8f792013-12-02 19:35:49 +0000261
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000262 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
263 return -1;
264
Greg Clayton29b8fc42013-11-21 01:44:58 +0000265 // Make a port map for a port range that was specified.
266 if (min_gdbserver_port < max_gdbserver_port)
267 {
268 for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port)
269 gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID;
270 }
271 else if (min_gdbserver_port != max_gdbserver_port)
272 {
273 fprintf (stderr, "error: --min-gdbserver-port (%u) is greater than --max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port);
274 option_error = 3;
Greg Clayton29b8fc42013-11-21 01:44:58 +0000275 }
276
Daniel Maleae0f8f572013-08-26 23:57:52 +0000277 // Print usage and exit if no listening port is specified.
278 if (listen_host_port.empty())
Greg Clayton29b8fc42013-11-21 01:44:58 +0000279 show_usage = true;
280
281 if (show_usage || option_error)
282 {
Tamas Berghammerc2c3d712015-02-18 15:39:41 +0000283 display_usage(progname, subcommand);
Greg Clayton29b8fc42013-11-21 01:44:58 +0000284 exit(option_error);
285 }
Greg Claytonb43767a2011-03-22 01:34:44 +0000286
Robert Flacka0e70cd2015-03-25 12:51:31 +0000287 std::unique_ptr<Socket> listening_socket_up;
288 Socket *socket = nullptr;
Robert Flacka0e70cd2015-03-25 12:51:31 +0000289 const bool children_inherit_listen_socket = false;
Vince Harron33aea902015-03-31 00:27:10 +0000290
291 // the test suite makes many connections in parallel, let's not miss any.
292 // The highest this should get reasonably is a function of the number
293 // of target CPUs. For now, let's just use 100
294 const int backlog = 100;
295 error = Socket::TcpListen(listen_host_port.c_str(), children_inherit_listen_socket, socket, NULL, backlog);
Robert Flacka0e70cd2015-03-25 12:51:31 +0000296 if (error.Fail())
297 {
298 printf("error: %s\n", error.AsCString());
299 exit(socket_error);
300 }
301 listening_socket_up.reset(socket);
Vince Harron218353d2015-05-26 03:08:05 +0000302 printf ("Listening for a connection from %u...\n", listening_socket_up->GetLocalPortNumber());
Oleksiy Vyalov298be462015-07-06 18:05:19 +0000303 if (port_file)
304 {
305 error = save_port_to_file(listening_socket_up->GetLocalPortNumber(), port_file);
306 if (error.Fail())
307 {
308 fprintf(stderr, "failed to write port to %s: %s", port_file.GetPath().c_str(), error.AsCString());
309 return 1;
310 }
311 }
Greg Claytonb43767a2011-03-22 01:34:44 +0000312
Daniel Maleae0f8f572013-08-26 23:57:52 +0000313 do {
Tamas Berghammere13c2732015-02-11 10:29:30 +0000314 GDBRemoteCommunicationServerPlatform platform;
Greg Clayton29b8fc42013-11-21 01:44:58 +0000315
Greg Claytond4724cf2013-11-22 18:55:04 +0000316 if (port_offset > 0)
Tamas Berghammere13c2732015-02-11 10:29:30 +0000317 platform.SetPortOffset(port_offset);
Greg Claytond4724cf2013-11-22 18:55:04 +0000318
Greg Clayton29b8fc42013-11-21 01:44:58 +0000319 if (!gdbserver_portmap.empty())
320 {
Tamas Berghammere13c2732015-02-11 10:29:30 +0000321 platform.SetPortMap(std::move(gdbserver_portmap));
Greg Clayton29b8fc42013-11-21 01:44:58 +0000322 }
323
Robert Flacka0e70cd2015-03-25 12:51:31 +0000324 const bool children_inherit_accept_socket = true;
325 socket = nullptr;
326 error = listening_socket_up->BlockingAccept(listen_host_port.c_str(), children_inherit_accept_socket, socket);
327 if (error.Fail())
Greg Claytond314e812011-03-23 00:09:55 +0000328 {
Robert Flacka0e70cd2015-03-25 12:51:31 +0000329 printf ("error: %s\n", error.AsCString());
330 exit(socket_error);
331 }
332 printf ("Connection established.\n");
333 if (g_server)
334 {
335 // Collect child zombie processes.
336 while (waitpid(-1, nullptr, WNOHANG) > 0);
337 if (fork())
Greg Claytond314e812011-03-23 00:09:55 +0000338 {
Vince Harronf1e69992015-03-31 00:24:51 +0000339 // Parent doesn't need a connection to the lldb client
340 delete socket;
341 socket = nullptr;
342
Robert Flacka0e70cd2015-03-25 12:51:31 +0000343 // Parent will continue to listen for new connections.
344 continue;
Daniel Maleae0f8f572013-08-26 23:57:52 +0000345 }
Robert Flacka0e70cd2015-03-25 12:51:31 +0000346 else
Daniel Maleae0f8f572013-08-26 23:57:52 +0000347 {
Robert Flacka0e70cd2015-03-25 12:51:31 +0000348 // Child process will handle the connection and exit.
349 g_server = 0;
350 // Listening socket is owned by parent process.
351 listening_socket_up.release();
Greg Claytond314e812011-03-23 00:09:55 +0000352 }
353 }
Robert Flacka0e70cd2015-03-25 12:51:31 +0000354 else
355 {
356 // If not running as a server, this process will not accept
357 // connections while a connection is active.
358 listening_socket_up.reset();
359 }
360 platform.SetConnection (new ConnectionFileDescriptor(socket));
361
362 if (platform.IsConnected())
363 {
364 // After we connected, we need to get an initial ack from...
365 if (platform.HandshakeWithClient(&error))
366 {
367 bool interrupt = false;
368 bool done = false;
369 while (!interrupt && !done)
370 {
371 if (platform.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success)
372 break;
373 }
374
375 if (error.Fail())
376 {
377 fprintf(stderr, "error: %s\n", error.AsCString());
378 }
379 }
380 else
381 {
382 fprintf(stderr, "error: handshake with client failed\n");
383 }
384 }
385 } while (g_server);
Greg Claytonb43767a2011-03-22 01:34:44 +0000386
Robert Flack8cc4cf12015-03-06 14:36:33 +0000387 fprintf(stderr, "lldb-server exiting...\n");
Daniel Maleae0f8f572013-08-26 23:57:52 +0000388
Greg Claytonb43767a2011-03-22 01:34:44 +0000389 return 0;
390}