[Flang][OpenMP]Add parsing support for DISPATCH construct (#121982)
[llvm-project.git] / lldb / tools / lldb-server / lldb-platform.cpp
blob880b45b989b9c7fec2725fc1660eef8621e9b70b
1 //===-- lldb-platform.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 //===----------------------------------------------------------------------===//
9 #include <cerrno>
10 #if defined(__APPLE__)
11 #include <netinet/in.h>
12 #endif
13 #include <csignal>
14 #include <cstdint>
15 #include <cstdio>
16 #include <cstdlib>
17 #include <cstring>
18 #if !defined(_WIN32)
19 #include <sys/wait.h>
20 #endif
21 #include <fstream>
22 #include <optional>
24 #include "llvm/Support/FileSystem.h"
25 #include "llvm/Support/ScopedPrinter.h"
26 #include "llvm/Support/WithColor.h"
27 #include "llvm/Support/raw_ostream.h"
29 #include "LLDBServerUtilities.h"
30 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
31 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
32 #include "lldb/Host/ConnectionFileDescriptor.h"
33 #include "lldb/Host/HostGetOpt.h"
34 #include "lldb/Host/MainLoop.h"
35 #include "lldb/Host/OptionParser.h"
36 #include "lldb/Host/Socket.h"
37 #include "lldb/Host/common/TCPSocket.h"
38 #if LLDB_ENABLE_POSIX
39 #include "lldb/Host/posix/DomainSocket.h"
40 #endif
41 #include "lldb/Utility/FileSpec.h"
42 #include "lldb/Utility/LLDBLog.h"
43 #include "lldb/Utility/Status.h"
44 #include "lldb/Utility/UriParser.h"
46 using namespace lldb;
47 using namespace lldb_private;
48 using namespace lldb_private::lldb_server;
49 using namespace lldb_private::process_gdb_remote;
50 using namespace llvm;
52 // The test suite makes many connections in parallel, let's not miss any.
53 // The highest this should get reasonably is a function of the number
54 // of target CPUs. For now, let's just use 100.
55 static const int backlog = 100;
56 static const int socket_error = -1;
57 static int g_debug = 0;
58 static int g_verbose = 0;
59 static int g_server = 0;
61 // option descriptors for getopt_long_only()
62 static struct option g_long_options[] = {
63 {"debug", no_argument, &g_debug, 1},
64 {"verbose", no_argument, &g_verbose, 1},
65 {"log-file", required_argument, nullptr, 'l'},
66 {"log-channels", required_argument, nullptr, 'c'},
67 {"listen", required_argument, nullptr, 'L'},
68 {"gdbserver-port", required_argument, nullptr, 'P'},
69 {"min-gdbserver-port", required_argument, nullptr, 'm'},
70 {"max-gdbserver-port", required_argument, nullptr, 'M'},
71 {"socket-file", required_argument, nullptr, 'f'},
72 {"server", no_argument, &g_server, 1},
73 {"child-platform-fd", required_argument, nullptr, 2},
74 {nullptr, 0, nullptr, 0}};
76 #if defined(__APPLE__)
77 #define LOW_PORT (IPPORT_RESERVED)
78 #define HIGH_PORT (IPPORT_HIFIRSTAUTO)
79 #else
80 #define LOW_PORT (1024u)
81 #define HIGH_PORT (49151u)
82 #endif
84 #if !defined(_WIN32)
85 // Watch for signals
86 static void signal_handler(int signo) {
87 switch (signo) {
88 case SIGHUP:
89 // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
90 // And we should not call exit() here because it results in the global
91 // destructors to be invoked and wreaking havoc on the threads still
92 // running.
93 llvm::errs() << "SIGHUP received, exiting lldb-server...\n";
94 abort();
95 break;
98 #endif
100 static void display_usage(const char *progname, const char *subcommand) {
101 fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels "
102 "log-channel-list] [--port-file port-file-path] --server "
103 "--listen port\n",
104 progname, subcommand);
105 exit(0);
108 static Status parse_listen_host_port(Socket::SocketProtocol &protocol,
109 const std::string &listen_host_port,
110 std::string &address,
111 uint16_t &platform_port,
112 std::string &gdb_address,
113 const uint16_t gdbserver_port) {
114 std::string hostname;
115 // Try to match socket name as URL - e.g., tcp://localhost:5555
116 if (std::optional<URI> uri = URI::Parse(listen_host_port)) {
117 if (!Socket::FindProtocolByScheme(uri->scheme.str().c_str(), protocol)) {
118 return Status::FromErrorStringWithFormat(
119 "Unknown protocol scheme \"%s\".", uri->scheme.str().c_str());
121 if (protocol == Socket::ProtocolTcp) {
122 hostname = uri->hostname;
123 if (uri->port) {
124 platform_port = *(uri->port);
126 } else
127 address = listen_host_port.substr(uri->scheme.size() + strlen("://"));
128 } else {
129 // Try to match socket name as $host:port - e.g., localhost:5555
130 llvm::Expected<Socket::HostAndPort> host_port =
131 Socket::DecodeHostAndPort(listen_host_port);
132 if (!llvm::errorToBool(host_port.takeError())) {
133 protocol = Socket::ProtocolTcp;
134 hostname = host_port->hostname;
135 platform_port = host_port->port;
136 } else
137 address = listen_host_port;
140 if (protocol == Socket::ProtocolTcp) {
141 if (platform_port != 0 && platform_port == gdbserver_port) {
142 return Status::FromErrorStringWithFormat(
143 "The same platform and gdb ports %u.", platform_port);
145 address = llvm::formatv("[{0}]:{1}", hostname, platform_port).str();
146 gdb_address = llvm::formatv("[{0}]:{1}", hostname, gdbserver_port).str();
147 } else {
148 if (gdbserver_port) {
149 return Status::FromErrorStringWithFormat(
150 "--gdbserver-port %u is redundant for non-tcp protocol %s.",
151 gdbserver_port, Socket::FindSchemeByProtocol(protocol));
154 return Status();
157 static Status save_socket_id_to_file(const std::string &socket_id,
158 const FileSpec &file_spec) {
159 FileSpec temp_file_spec(file_spec.GetDirectory().GetStringRef());
160 Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
161 if (error.Fail())
162 return Status::FromErrorStringWithFormat(
163 "Failed to create directory %s: %s", temp_file_spec.GetPath().c_str(),
164 error.AsCString());
166 Status status;
167 if (auto Err = llvm::writeToOutput(file_spec.GetPath(),
168 [&socket_id](llvm::raw_ostream &OS) {
169 OS << socket_id;
170 return llvm::Error::success();
172 return Status::FromErrorStringWithFormat(
173 "Failed to atomically write file %s: %s", file_spec.GetPath().c_str(),
174 llvm::toString(std::move(Err)).c_str());
175 return status;
178 static Status ListenGdbConnectionsIfNeeded(
179 const Socket::SocketProtocol protocol, std::unique_ptr<TCPSocket> &gdb_sock,
180 const std::string &gdb_address, uint16_t &gdbserver_port) {
181 if (protocol != Socket::ProtocolTcp)
182 return Status();
184 gdb_sock = std::make_unique<TCPSocket>(/*should_close=*/true);
185 Status error = gdb_sock->Listen(gdb_address, backlog);
186 if (error.Fail())
187 return error;
189 if (gdbserver_port == 0)
190 gdbserver_port = gdb_sock->GetLocalPortNumber();
192 return Status();
195 static llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
196 AcceptGdbConnectionsIfNeeded(const Socket::SocketProtocol protocol,
197 std::unique_ptr<TCPSocket> &gdb_sock,
198 MainLoop &main_loop, const uint16_t gdbserver_port,
199 const lldb_private::Args &args) {
200 if (protocol != Socket::ProtocolTcp)
201 return std::vector<MainLoopBase::ReadHandleUP>();
203 return gdb_sock->Accept(main_loop, [gdbserver_port,
204 &args](std::unique_ptr<Socket> sock_up) {
205 Log *log = GetLog(LLDBLog::Platform);
206 Status error;
207 SharedSocket shared_socket(sock_up.get(), error);
208 if (error.Fail()) {
209 LLDB_LOGF(log, "gdbserver SharedSocket failed: %s", error.AsCString());
210 return;
212 lldb::pid_t child_pid = LLDB_INVALID_PROCESS_ID;
213 std::string socket_name;
214 GDBRemoteCommunicationServerPlatform platform(Socket::ProtocolTcp,
215 gdbserver_port);
216 error = platform.LaunchGDBServer(args, child_pid, socket_name,
217 shared_socket.GetSendableFD());
218 if (error.Success() && child_pid != LLDB_INVALID_PROCESS_ID) {
219 error = shared_socket.CompleteSending(child_pid);
220 if (error.Fail()) {
221 Host::Kill(child_pid, SIGTERM);
222 LLDB_LOGF(log, "gdbserver CompleteSending failed: %s",
223 error.AsCString());
224 return;
230 static void client_handle(GDBRemoteCommunicationServerPlatform &platform,
231 const lldb_private::Args &args) {
232 if (!platform.IsConnected())
233 return;
235 if (args.GetArgumentCount() > 0) {
236 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
237 std::string socket_name;
238 Status error = platform.LaunchGDBServer(args, pid, socket_name,
239 SharedSocket::kInvalidFD);
240 if (error.Success())
241 platform.SetPendingGdbServer(socket_name);
242 else
243 fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
246 bool interrupt = false;
247 bool done = false;
248 Status error;
249 while (!interrupt && !done) {
250 if (platform.GetPacketAndSendResponse(std::nullopt, error, interrupt,
251 done) !=
252 GDBRemoteCommunication::PacketResult::Success)
253 break;
256 printf("Disconnected.\n");
259 static Status spawn_process(const char *progname, const Socket *conn_socket,
260 uint16_t gdb_port, const lldb_private::Args &args,
261 const std::string &log_file,
262 const StringRef log_channels, MainLoop &main_loop) {
263 Status error;
264 SharedSocket shared_socket(conn_socket, error);
265 if (error.Fail())
266 return error;
268 ProcessLaunchInfo launch_info;
270 FileSpec self_spec(progname, FileSpec::Style::native);
271 launch_info.SetExecutableFile(self_spec, true);
272 Args &self_args = launch_info.GetArguments();
273 self_args.AppendArgument(llvm::StringRef("platform"));
274 self_args.AppendArgument(llvm::StringRef("--child-platform-fd"));
275 self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD()));
276 #ifndef _WIN32
277 launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(),
278 (int)shared_socket.GetSendableFD());
279 #endif
280 if (gdb_port) {
281 self_args.AppendArgument(llvm::StringRef("--gdbserver-port"));
282 self_args.AppendArgument(llvm::to_string(gdb_port));
284 if (!log_file.empty()) {
285 self_args.AppendArgument(llvm::StringRef("--log-file"));
286 self_args.AppendArgument(log_file);
288 if (!log_channels.empty()) {
289 self_args.AppendArgument(llvm::StringRef("--log-channels"));
290 self_args.AppendArgument(log_channels);
292 if (args.GetArgumentCount() > 0) {
293 self_args.AppendArgument("--");
294 self_args.AppendArguments(args);
297 launch_info.SetLaunchInSeparateProcessGroup(false);
299 if (g_server)
300 launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {});
301 else
302 launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) {
303 main_loop.AddPendingCallback(
304 [](MainLoopBase &loop) { loop.RequestTermination(); });
307 // Copy the current environment.
308 launch_info.GetEnvironment() = Host::GetEnvironment();
310 launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
312 // Close STDIN, STDOUT and STDERR.
313 launch_info.AppendCloseFileAction(STDIN_FILENO);
314 launch_info.AppendCloseFileAction(STDOUT_FILENO);
315 launch_info.AppendCloseFileAction(STDERR_FILENO);
317 // Redirect STDIN, STDOUT and STDERR to "/dev/null".
318 launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);
319 launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);
320 launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);
322 std::string cmd;
323 self_args.GetCommandString(cmd);
325 error = Host::LaunchProcess(launch_info);
326 if (error.Fail())
327 return error;
329 lldb::pid_t child_pid = launch_info.GetProcessID();
330 if (child_pid == LLDB_INVALID_PROCESS_ID)
331 return Status::FromErrorString("invalid pid");
333 LLDB_LOG(GetLog(LLDBLog::Platform), "lldb-platform launched '{0}', pid={1}",
334 cmd, child_pid);
336 error = shared_socket.CompleteSending(child_pid);
337 if (error.Fail()) {
338 Host::Kill(child_pid, SIGTERM);
339 return error;
342 return Status();
345 // main
346 int main_platform(int argc, char *argv[]) {
347 const char *progname = argv[0];
348 const char *subcommand = argv[1];
349 argc--;
350 argv++;
351 #if !defined(_WIN32)
352 signal(SIGPIPE, SIG_IGN);
353 signal(SIGHUP, signal_handler);
354 #endif
355 int long_option_index = 0;
356 Status error;
357 std::string listen_host_port;
358 int ch;
360 std::string log_file;
361 StringRef
362 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
364 shared_fd_t fd = SharedSocket::kInvalidFD;
366 uint16_t gdbserver_port = 0;
368 FileSpec socket_file;
369 bool show_usage = false;
370 int option_error = 0;
372 std::string short_options(OptionParser::GetShortOptionString(g_long_options));
374 #if __GLIBC__
375 optind = 0;
376 #else
377 optreset = 1;
378 optind = 1;
379 #endif
381 while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
382 g_long_options, &long_option_index)) != -1) {
383 switch (ch) {
384 case 0: // Any optional that auto set themselves will return 0
385 break;
387 case 'L':
388 listen_host_port.append(optarg);
389 break;
391 case 'l': // Set Log File
392 if (optarg && optarg[0])
393 log_file.assign(optarg);
394 break;
396 case 'c': // Log Channels
397 if (optarg && optarg[0])
398 log_channels = StringRef(optarg);
399 break;
401 case 'f': // Socket file
402 if (optarg && optarg[0])
403 socket_file.SetFile(optarg, FileSpec::Style::native);
404 break;
406 case 'P':
407 case 'm':
408 case 'M': {
409 uint16_t portnum;
410 if (!llvm::to_integer(optarg, portnum)) {
411 WithColor::error() << "invalid port number string " << optarg << "\n";
412 option_error = 2;
413 break;
415 // Note the condition gdbserver_port > HIGH_PORT is valid in case of using
416 // --child-platform-fd. Check gdbserver_port later.
417 if (ch == 'P')
418 gdbserver_port = portnum;
419 else if (gdbserver_port == 0)
420 gdbserver_port = portnum;
421 } break;
423 case 2: {
424 uint64_t _fd;
425 if (!llvm::to_integer(optarg, _fd)) {
426 WithColor::error() << "invalid fd " << optarg << "\n";
427 option_error = 6;
428 } else
429 fd = (shared_fd_t)_fd;
430 } break;
432 case 'h': /* fall-through is intentional */
433 case '?':
434 show_usage = true;
435 break;
439 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
440 return -1;
442 // Print usage and exit if no listening port is specified.
443 if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD)
444 show_usage = true;
446 if (show_usage || option_error) {
447 display_usage(progname, subcommand);
448 exit(option_error);
451 // Skip any options we consumed with getopt_long_only.
452 argc -= optind;
453 argv += optind;
454 lldb_private::Args inferior_arguments;
455 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
457 Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain;
459 if (fd != SharedSocket::kInvalidFD) {
460 // Child process will handle the connection and exit.
461 if (gdbserver_port)
462 protocol = Socket::ProtocolTcp;
464 Log *log = GetLog(LLDBLog::Platform);
466 NativeSocket sockfd;
467 error = SharedSocket::GetNativeSocket(fd, sockfd);
468 if (error.Fail()) {
469 LLDB_LOGF(log, "lldb-platform child: %s", error.AsCString());
470 return socket_error;
473 GDBRemoteCommunicationServerPlatform platform(protocol, gdbserver_port);
474 Socket *socket;
475 if (protocol == Socket::ProtocolTcp)
476 socket = new TCPSocket(sockfd, /*should_close=*/true);
477 else {
478 #if LLDB_ENABLE_POSIX
479 socket = new DomainSocket(sockfd, /*should_close=*/true);
480 #else
481 WithColor::error() << "lldb-platform child: Unix domain sockets are not "
482 "supported on this platform.";
483 return socket_error;
484 #endif
486 platform.SetConnection(
487 std::unique_ptr<Connection>(new ConnectionFileDescriptor(socket)));
488 client_handle(platform, inferior_arguments);
489 return 0;
492 if (gdbserver_port != 0 &&
493 (gdbserver_port < LOW_PORT || gdbserver_port > HIGH_PORT)) {
494 WithColor::error() << llvm::formatv("Port number {0} is not in the "
495 "valid user port range of {1} - {2}\n",
496 gdbserver_port, LOW_PORT, HIGH_PORT);
497 return 1;
500 std::string address;
501 std::string gdb_address;
502 uint16_t platform_port = 0;
503 error = parse_listen_host_port(protocol, listen_host_port, address,
504 platform_port, gdb_address, gdbserver_port);
505 if (error.Fail()) {
506 printf("Failed to parse listen address: %s\n", error.AsCString());
507 return socket_error;
510 std::unique_ptr<Socket> platform_sock = Socket::Create(protocol, error);
511 if (error.Fail()) {
512 printf("Failed to create platform socket: %s\n", error.AsCString());
513 return socket_error;
515 error = platform_sock->Listen(address, backlog);
516 if (error.Fail()) {
517 printf("Failed to listen platform: %s\n", error.AsCString());
518 return socket_error;
520 if (protocol == Socket::ProtocolTcp && platform_port == 0)
521 platform_port =
522 static_cast<TCPSocket *>(platform_sock.get())->GetLocalPortNumber();
524 if (socket_file) {
525 error = save_socket_id_to_file(
526 protocol == Socket::ProtocolTcp
527 ? (platform_port ? llvm::to_string(platform_port) : "")
528 : address,
529 socket_file);
530 if (error.Fail()) {
531 fprintf(stderr, "failed to write socket id to %s: %s\n",
532 socket_file.GetPath().c_str(), error.AsCString());
533 return 1;
537 std::unique_ptr<TCPSocket> gdb_sock;
538 // Update gdbserver_port if it is still 0 and protocol is tcp.
539 error = ListenGdbConnectionsIfNeeded(protocol, gdb_sock, gdb_address,
540 gdbserver_port);
541 if (error.Fail()) {
542 printf("Failed to listen gdb: %s\n", error.AsCString());
543 return socket_error;
546 MainLoop main_loop;
548 llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles =
549 platform_sock->Accept(
550 main_loop, [progname, gdbserver_port, &inferior_arguments, log_file,
551 log_channels, &main_loop,
552 &platform_handles](std::unique_ptr<Socket> sock_up) {
553 printf("Connection established.\n");
554 Status error = spawn_process(progname, sock_up.get(),
555 gdbserver_port, inferior_arguments,
556 log_file, log_channels, main_loop);
557 if (error.Fail()) {
558 Log *log = GetLog(LLDBLog::Platform);
559 LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());
560 WithColor::error()
561 << "spawn_process failed: " << error.AsCString() << "\n";
562 if (!g_server)
563 main_loop.RequestTermination();
565 if (!g_server)
566 platform_handles->clear();
568 if (!platform_handles) {
569 printf("Failed to accept platform: %s\n",
570 llvm::toString(platform_handles.takeError()).c_str());
571 return socket_error;
574 llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles =
575 AcceptGdbConnectionsIfNeeded(protocol, gdb_sock, main_loop,
576 gdbserver_port, inferior_arguments);
577 if (!gdb_handles) {
578 printf("Failed to accept gdb: %s\n",
579 llvm::toString(gdb_handles.takeError()).c_str());
580 return socket_error;
583 main_loop.Run();
586 fprintf(stderr, "lldb-server exiting...\n");
588 return 0;