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 //===----------------------------------------------------------------------===// 8 9 #include <errno.h> 10 #if defined(__APPLE__) 11 #include <netinet/in.h> 12 #endif 13 #include <signal.h> 14 #include <stdint.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #if !defined(_WIN32) 19 #include <sys/wait.h> 20 #endif 21 #include <fstream> 22 23 #include "llvm/Support/FileSystem.h" 24 #include "llvm/Support/FileUtilities.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 #include "Acceptor.h" 28 #include "LLDBServerUtilities.h" 29 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h" 30 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" 31 #include "lldb/Host/ConnectionFileDescriptor.h" 32 #include "lldb/Host/HostGetOpt.h" 33 #include "lldb/Host/OptionParser.h" 34 #include "lldb/Host/common/TCPSocket.h" 35 #include "lldb/Utility/FileSpec.h" 36 #include "lldb/Utility/Status.h" 37 38 using namespace lldb; 39 using namespace lldb_private; 40 using namespace lldb_private::lldb_server; 41 using namespace lldb_private::process_gdb_remote; 42 using namespace llvm; 43 44 // option descriptors for getopt_long_only() 45 46 static int g_debug = 0; 47 static int g_verbose = 0; 48 static int g_server = 0; 49 50 static struct option g_long_options[] = { 51 {"debug", no_argument, &g_debug, 1}, 52 {"verbose", no_argument, &g_verbose, 1}, 53 {"log-file", required_argument, nullptr, 'l'}, 54 {"log-channels", required_argument, nullptr, 'c'}, 55 {"listen", required_argument, nullptr, 'L'}, 56 {"port-offset", required_argument, nullptr, 'p'}, 57 {"gdbserver-port", required_argument, nullptr, 'P'}, 58 {"min-gdbserver-port", required_argument, nullptr, 'm'}, 59 {"max-gdbserver-port", required_argument, nullptr, 'M'}, 60 {"socket-file", required_argument, nullptr, 'f'}, 61 {"server", no_argument, &g_server, 1}, 62 {nullptr, 0, nullptr, 0}}; 63 64 #if defined(__APPLE__) 65 #define LOW_PORT (IPPORT_RESERVED) 66 #define HIGH_PORT (IPPORT_HIFIRSTAUTO) 67 #else 68 #define LOW_PORT (1024u) 69 #define HIGH_PORT (49151u) 70 #endif 71 72 #if !defined(_WIN32) 73 // Watch for signals 74 static void signal_handler(int signo) { 75 switch (signo) { 76 case SIGHUP: 77 // Use SIGINT first, if that does not work, use SIGHUP as a last resort. 78 // And we should not call exit() here because it results in the global 79 // destructors 80 // to be invoked and wreaking havoc on the threads still running. 81 Host::SystemLog(Host::eSystemLogWarning, 82 "SIGHUP received, exiting lldb-server...\n"); 83 abort(); 84 break; 85 } 86 } 87 #endif 88 89 static void display_usage(const char *progname, const char *subcommand) { 90 fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels " 91 "log-channel-list] [--port-file port-file-path] --server " 92 "--listen port\n", 93 progname, subcommand); 94 exit(0); 95 } 96 97 static Status save_socket_id_to_file(const std::string &socket_id, 98 const FileSpec &file_spec) { 99 FileSpec temp_file_spec(file_spec.GetDirectory().GetStringRef()); 100 Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath())); 101 if (error.Fail()) 102 return Status("Failed to create directory %s: %s", 103 temp_file_spec.GetCString(), error.AsCString()); 104 105 llvm::SmallString<64> temp_file_path; 106 temp_file_spec.AppendPathComponent("port-file.%%%%%%"); 107 temp_file_path = temp_file_spec.GetPath(); 108 109 Status status; 110 if (auto Err = 111 handleErrors(llvm::writeFileAtomically( 112 temp_file_path, file_spec.GetPath(), socket_id), 113 [&status, &file_spec](const AtomicFileWriteError &E) { 114 std::string ErrorMsgBuffer; 115 llvm::raw_string_ostream S(ErrorMsgBuffer); 116 E.log(S); 117 118 switch (E.Error) { 119 case atomic_write_error::failed_to_create_uniq_file: 120 status = Status("Failed to create temp file: %s", 121 ErrorMsgBuffer.c_str()); 122 break; 123 case atomic_write_error::output_stream_error: 124 status = Status("Failed to write to port file."); 125 break; 126 case atomic_write_error::failed_to_rename_temp_file: 127 status = Status("Failed to rename file %s to %s: %s", 128 ErrorMsgBuffer.c_str(), 129 file_spec.GetPath().c_str(), 130 ErrorMsgBuffer.c_str()); 131 break; 132 } 133 })) { 134 return Status("Failed to atomically write file %s", 135 file_spec.GetPath().c_str()); 136 } 137 return status; 138 } 139 140 // main 141 int main_platform(int argc, char *argv[]) { 142 const char *progname = argv[0]; 143 const char *subcommand = argv[1]; 144 argc--; 145 argv++; 146 #if !defined(_WIN32) 147 signal(SIGPIPE, SIG_IGN); 148 signal(SIGHUP, signal_handler); 149 #endif 150 int long_option_index = 0; 151 Status error; 152 std::string listen_host_port; 153 int ch; 154 155 std::string log_file; 156 StringRef 157 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" 158 159 GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap; 160 int min_gdbserver_port = 0; 161 int max_gdbserver_port = 0; 162 uint16_t port_offset = 0; 163 164 FileSpec socket_file; 165 bool show_usage = false; 166 int option_error = 0; 167 int socket_error = -1; 168 169 std::string short_options(OptionParser::GetShortOptionString(g_long_options)); 170 171 #if __GLIBC__ 172 optind = 0; 173 #else 174 optreset = 1; 175 optind = 1; 176 #endif 177 178 while ((ch = getopt_long_only(argc, argv, short_options.c_str(), 179 g_long_options, &long_option_index)) != -1) { 180 switch (ch) { 181 case 0: // Any optional that auto set themselves will return 0 182 break; 183 184 case 'L': 185 listen_host_port.append(optarg); 186 break; 187 188 case 'l': // Set Log File 189 if (optarg && optarg[0]) 190 log_file.assign(optarg); 191 break; 192 193 case 'c': // Log Channels 194 if (optarg && optarg[0]) 195 log_channels = StringRef(optarg); 196 break; 197 198 case 'f': // Socket file 199 if (optarg && optarg[0]) 200 socket_file.SetFile(optarg, FileSpec::Style::native); 201 break; 202 203 case 'p': { 204 if (!llvm::to_integer(optarg, port_offset)) { 205 llvm::errs() << "error: invalid port offset string " << optarg << "\n"; 206 option_error = 4; 207 break; 208 } 209 if (port_offset < LOW_PORT || port_offset > HIGH_PORT) { 210 llvm::errs() << llvm::formatv("error: port offset {0} is not in the " 211 "valid user port range of {1} - {2}\n", 212 port_offset, LOW_PORT, HIGH_PORT); 213 option_error = 5; 214 } 215 } break; 216 217 case 'P': 218 case 'm': 219 case 'M': { 220 uint16_t portnum; 221 if (!llvm::to_integer(optarg, portnum)) { 222 llvm::errs() << "error: invalid port number string " << optarg << "\n"; 223 option_error = 2; 224 break; 225 } 226 if (portnum < LOW_PORT || portnum > HIGH_PORT) { 227 llvm::errs() << llvm::formatv("error: port number {0} is not in the " 228 "valid user port range of {1} - {2}\n", 229 portnum, LOW_PORT, HIGH_PORT); 230 option_error = 1; 231 break; 232 } 233 if (ch == 'P') 234 gdbserver_portmap.AllowPort(portnum); 235 else if (ch == 'm') 236 min_gdbserver_port = portnum; 237 else 238 max_gdbserver_port = portnum; 239 } break; 240 241 case 'h': /* fall-through is intentional */ 242 case '?': 243 show_usage = true; 244 break; 245 } 246 } 247 248 if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0)) 249 return -1; 250 251 // Make a port map for a port range that was specified. 252 if (min_gdbserver_port && min_gdbserver_port < max_gdbserver_port) { 253 gdbserver_portmap = GDBRemoteCommunicationServerPlatform::PortMap( 254 min_gdbserver_port, max_gdbserver_port); 255 } else if (min_gdbserver_port || max_gdbserver_port) { 256 fprintf(stderr, "error: --min-gdbserver-port (%u) is not lower than " 257 "--max-gdbserver-port (%u)\n", 258 min_gdbserver_port, max_gdbserver_port); 259 option_error = 3; 260 } 261 262 // Print usage and exit if no listening port is specified. 263 if (listen_host_port.empty()) 264 show_usage = true; 265 266 if (show_usage || option_error) { 267 display_usage(progname, subcommand); 268 exit(option_error); 269 } 270 271 // Skip any options we consumed with getopt_long_only. 272 argc -= optind; 273 argv += optind; 274 lldb_private::Args inferior_arguments; 275 inferior_arguments.SetArguments(argc, const_cast<const char **>(argv)); 276 277 const bool children_inherit_listen_socket = false; 278 // the test suite makes many connections in parallel, let's not miss any. 279 // The highest this should get reasonably is a function of the number 280 // of target CPUs. For now, let's just use 100. 281 const int backlog = 100; 282 283 std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create( 284 listen_host_port, children_inherit_listen_socket, error)); 285 if (error.Fail()) { 286 fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); 287 exit(socket_error); 288 } 289 290 error = acceptor_up->Listen(backlog); 291 if (error.Fail()) { 292 printf("failed to listen: %s\n", error.AsCString()); 293 exit(socket_error); 294 } 295 if (socket_file) { 296 error = 297 save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); 298 if (error.Fail()) { 299 fprintf(stderr, "failed to write socket id to %s: %s\n", 300 socket_file.GetPath().c_str(), error.AsCString()); 301 return 1; 302 } 303 } 304 305 do { 306 GDBRemoteCommunicationServerPlatform platform( 307 acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); 308 309 if (port_offset > 0) 310 platform.SetPortOffset(port_offset); 311 312 if (!gdbserver_portmap.empty()) { 313 platform.SetPortMap(std::move(gdbserver_portmap)); 314 } 315 316 const bool children_inherit_accept_socket = true; 317 Connection *conn = nullptr; 318 error = acceptor_up->Accept(children_inherit_accept_socket, conn); 319 if (error.Fail()) { 320 printf("error: %s\n", error.AsCString()); 321 exit(socket_error); 322 } 323 printf("Connection established.\n"); 324 if (g_server) { 325 // Collect child zombie processes. 326 #if !defined(_WIN32) 327 while (waitpid(-1, nullptr, WNOHANG) > 0) 328 ; 329 #endif 330 if (fork()) { 331 // Parent doesn't need a connection to the lldb client 332 delete conn; 333 334 // Parent will continue to listen for new connections. 335 continue; 336 } else { 337 // Child process will handle the connection and exit. 338 g_server = 0; 339 // Listening socket is owned by parent process. 340 acceptor_up.release(); 341 } 342 } else { 343 // If not running as a server, this process will not accept 344 // connections while a connection is active. 345 acceptor_up.reset(); 346 } 347 platform.SetConnection(std::unique_ptr<Connection>(conn)); 348 349 if (platform.IsConnected()) { 350 if (inferior_arguments.GetArgumentCount() > 0) { 351 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 352 llvm::Optional<uint16_t> port = 0; 353 std::string socket_name; 354 Status error = platform.LaunchGDBServer(inferior_arguments, 355 "", // hostname 356 pid, port, socket_name); 357 if (error.Success()) 358 platform.SetPendingGdbServer(pid, *port, socket_name); 359 else 360 fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); 361 } 362 363 // After we connected, we need to get an initial ack from... 364 if (platform.HandshakeWithClient()) { 365 bool interrupt = false; 366 bool done = false; 367 while (!interrupt && !done) { 368 if (platform.GetPacketAndSendResponse(llvm::None, error, interrupt, 369 done) != 370 GDBRemoteCommunication::PacketResult::Success) 371 break; 372 } 373 374 if (error.Fail()) { 375 fprintf(stderr, "error: %s\n", error.AsCString()); 376 } 377 } else { 378 fprintf(stderr, "error: handshake with client failed\n"); 379 } 380 } 381 } while (g_server); 382 383 fprintf(stderr, "lldb-server exiting...\n"); 384 385 return 0; 386 } 387