1 //===-- GDBRemoteCommunicationServerPlatform.cpp --------------------------===// 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 "GDBRemoteCommunicationServerPlatform.h" 10 11 #include <errno.h> 12 13 #include <chrono> 14 #include <csignal> 15 #include <cstring> 16 #include <mutex> 17 #include <sstream> 18 #include <thread> 19 20 #include "llvm/Support/FileSystem.h" 21 #include "llvm/Support/JSON.h" 22 #include "llvm/Support/Threading.h" 23 24 #include "lldb/Host/Config.h" 25 #include "lldb/Host/ConnectionFileDescriptor.h" 26 #include "lldb/Host/FileAction.h" 27 #include "lldb/Host/Host.h" 28 #include "lldb/Host/HostInfo.h" 29 #include "lldb/Interpreter/CommandCompletions.h" 30 #include "lldb/Target/Platform.h" 31 #include "lldb/Target/UnixSignals.h" 32 #include "lldb/Utility/GDBRemote.h" 33 #include "lldb/Utility/Log.h" 34 #include "lldb/Utility/StreamString.h" 35 #include "lldb/Utility/StructuredData.h" 36 #include "lldb/Utility/TildeExpressionResolver.h" 37 #include "lldb/Utility/UriParser.h" 38 39 #include "lldb/Utility/StringExtractorGDBRemote.h" 40 41 using namespace lldb; 42 using namespace lldb_private::process_gdb_remote; 43 using namespace lldb_private; 44 45 GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port, 46 uint16_t max_port) { 47 for (; min_port < max_port; ++min_port) 48 m_port_map[min_port] = LLDB_INVALID_PROCESS_ID; 49 } 50 51 void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) { 52 // Do not modify existing mappings 53 m_port_map.insert({port, LLDB_INVALID_PROCESS_ID}); 54 } 55 56 llvm::Expected<uint16_t> 57 GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() { 58 if (m_port_map.empty()) 59 return 0; // Bind to port zero and get a port, we didn't have any 60 // limitations 61 62 for (auto &pair : m_port_map) { 63 if (pair.second == LLDB_INVALID_PROCESS_ID) { 64 pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; 65 return pair.first; 66 } 67 } 68 return llvm::createStringError(llvm::inconvertibleErrorCode(), 69 "No free port found in port map"); 70 } 71 72 bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess( 73 uint16_t port, lldb::pid_t pid) { 74 auto pos = m_port_map.find(port); 75 if (pos != m_port_map.end()) { 76 pos->second = pid; 77 return true; 78 } 79 return false; 80 } 81 82 bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) { 83 std::map<uint16_t, lldb::pid_t>::iterator pos = m_port_map.find(port); 84 if (pos != m_port_map.end()) { 85 pos->second = LLDB_INVALID_PROCESS_ID; 86 return true; 87 } 88 return false; 89 } 90 91 bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess( 92 lldb::pid_t pid) { 93 if (!m_port_map.empty()) { 94 for (auto &pair : m_port_map) { 95 if (pair.second == pid) { 96 pair.second = LLDB_INVALID_PROCESS_ID; 97 return true; 98 } 99 } 100 } 101 return false; 102 } 103 104 bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const { 105 return m_port_map.empty(); 106 } 107 108 // GDBRemoteCommunicationServerPlatform constructor 109 GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( 110 const Socket::SocketProtocol socket_protocol, const char *socket_scheme) 111 : GDBRemoteCommunicationServerCommon("gdb-remote.server", 112 "gdb-remote.server.rx_packet"), 113 m_socket_protocol(socket_protocol), m_socket_scheme(socket_scheme), 114 m_spawned_pids_mutex(), m_port_map(), m_port_offset(0) { 115 m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID; 116 m_pending_gdb_server.port = 0; 117 118 RegisterMemberFunctionHandler( 119 StringExtractorGDBRemote::eServerPacketType_qC, 120 &GDBRemoteCommunicationServerPlatform::Handle_qC); 121 RegisterMemberFunctionHandler( 122 StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, 123 &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); 124 RegisterMemberFunctionHandler( 125 StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, 126 &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); 127 RegisterMemberFunctionHandler( 128 StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, 129 &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); 130 RegisterMemberFunctionHandler( 131 StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, 132 &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); 133 RegisterMemberFunctionHandler( 134 StringExtractorGDBRemote::eServerPacketType_qProcessInfo, 135 &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); 136 RegisterMemberFunctionHandler( 137 StringExtractorGDBRemote::eServerPacketType_qPathComplete, 138 &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete); 139 RegisterMemberFunctionHandler( 140 StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, 141 &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); 142 RegisterMemberFunctionHandler( 143 StringExtractorGDBRemote::eServerPacketType_jSignalsInfo, 144 &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo); 145 146 RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, 147 [](StringExtractorGDBRemote packet, Status &error, 148 bool &interrupt, bool &quit) { 149 error.SetErrorString("interrupt received"); 150 interrupt = true; 151 return PacketResult::Success; 152 }); 153 } 154 155 // Destructor 156 GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {} 157 158 Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( 159 const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid, 160 llvm::Optional<uint16_t> &port, std::string &socket_name) { 161 if (!port) { 162 llvm::Expected<uint16_t> available_port = m_port_map.GetNextAvailablePort(); 163 if (available_port) 164 port = *available_port; 165 else 166 return Status(available_port.takeError()); 167 } 168 169 // Spawn a new thread to accept the port that gets bound after binding to 170 // port 0 (zero). 171 172 // ignore the hostname send from the remote end, just use the ip address that 173 // we're currently communicating with as the hostname 174 175 // Spawn a debugserver and try to get the port it listens to. 176 ProcessLaunchInfo debugserver_launch_info; 177 if (hostname.empty()) 178 hostname = "127.0.0.1"; 179 180 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 181 LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(), 182 *port); 183 184 // Do not run in a new session so that it can not linger after the platform 185 // closes. 186 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); 187 debugserver_launch_info.SetMonitorProcessCallback( 188 std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, 189 this, std::placeholders::_1), 190 false); 191 192 std::ostringstream url; 193 // debugserver does not accept the URL scheme prefix. 194 #if !defined(__APPLE__) 195 url << m_socket_scheme << "://"; 196 #endif 197 uint16_t *port_ptr = port.getPointer(); 198 if (m_socket_protocol == Socket::ProtocolTcp) { 199 llvm::StringRef platform_scheme; 200 llvm::StringRef platform_ip; 201 int platform_port; 202 llvm::StringRef platform_path; 203 std::string platform_uri = GetConnection()->GetURI(); 204 bool ok = UriParser::Parse(platform_uri, platform_scheme, platform_ip, 205 platform_port, platform_path); 206 UNUSED_IF_ASSERT_DISABLED(ok); 207 assert(ok); 208 url << '[' << platform_ip.str() << "]:" << *port; 209 } else { 210 socket_name = GetDomainSocketPath("gdbserver").GetPath(); 211 url << socket_name; 212 port_ptr = nullptr; 213 } 214 215 Status error = StartDebugserverProcess( 216 url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1); 217 218 pid = debugserver_launch_info.GetProcessID(); 219 if (pid != LLDB_INVALID_PROCESS_ID) { 220 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 221 m_spawned_pids.insert(pid); 222 if (*port > 0) 223 m_port_map.AssociatePortWithProcess(*port, pid); 224 } else { 225 if (*port > 0) 226 m_port_map.FreePort(*port); 227 } 228 return error; 229 } 230 231 GDBRemoteCommunication::PacketResult 232 GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( 233 StringExtractorGDBRemote &packet) { 234 // Spawn a local debugserver as a platform so we can then attach or launch a 235 // process... 236 237 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 238 LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called", 239 __FUNCTION__); 240 241 ConnectionFileDescriptor file_conn; 242 std::string hostname; 243 packet.SetFilePos(::strlen("qLaunchGDBServer;")); 244 llvm::StringRef name; 245 llvm::StringRef value; 246 llvm::Optional<uint16_t> port; 247 while (packet.GetNameColonValue(name, value)) { 248 if (name.equals("host")) 249 hostname = std::string(value); 250 else if (name.equals("port")) { 251 // Make the Optional valid so we can use its value 252 port = 0; 253 value.getAsInteger(0, port.getValue()); 254 } 255 } 256 257 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; 258 std::string socket_name; 259 Status error = 260 LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); 261 if (error.Fail()) { 262 LLDB_LOGF(log, 263 "GDBRemoteCommunicationServerPlatform::%s() debugserver " 264 "launch failed: %s", 265 __FUNCTION__, error.AsCString()); 266 return SendErrorResponse(9); 267 } 268 269 LLDB_LOGF(log, 270 "GDBRemoteCommunicationServerPlatform::%s() debugserver " 271 "launched successfully as pid %" PRIu64, 272 __FUNCTION__, debugserver_pid); 273 274 StreamGDBRemote response; 275 assert(port); 276 response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, 277 *port + m_port_offset); 278 if (!socket_name.empty()) { 279 response.PutCString("socket_name:"); 280 response.PutStringAsRawHex8(socket_name); 281 response.PutChar(';'); 282 } 283 284 PacketResult packet_result = SendPacketNoLock(response.GetString()); 285 if (packet_result != PacketResult::Success) { 286 if (debugserver_pid != LLDB_INVALID_PROCESS_ID) 287 Host::Kill(debugserver_pid, SIGINT); 288 } 289 return packet_result; 290 } 291 292 GDBRemoteCommunication::PacketResult 293 GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer( 294 StringExtractorGDBRemote &packet) { 295 namespace json = llvm::json; 296 297 if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) 298 return SendErrorResponse(4); 299 300 json::Object server{{"port", m_pending_gdb_server.port}}; 301 302 if (!m_pending_gdb_server.socket_name.empty()) 303 server.try_emplace("socket_name", m_pending_gdb_server.socket_name); 304 305 json::Array server_list; 306 server_list.push_back(std::move(server)); 307 308 StreamGDBRemote response; 309 response.AsRawOstream() << std::move(server_list); 310 311 StreamGDBRemote escaped_response; 312 escaped_response.PutEscapedBytes(response.GetString().data(), 313 response.GetSize()); 314 return SendPacketNoLock(escaped_response.GetString()); 315 } 316 317 GDBRemoteCommunication::PacketResult 318 GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess( 319 StringExtractorGDBRemote &packet) { 320 packet.SetFilePos(::strlen("qKillSpawnedProcess:")); 321 322 lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); 323 324 // verify that we know anything about this pid. Scope for locker 325 { 326 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 327 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { 328 // not a pid we know about 329 return SendErrorResponse(10); 330 } 331 } 332 333 // go ahead and attempt to kill the spawned process 334 if (KillSpawnedProcess(pid)) 335 return SendOKResponse(); 336 else 337 return SendErrorResponse(11); 338 } 339 340 bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) { 341 // make sure we know about this process 342 { 343 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 344 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 345 return false; 346 } 347 348 // first try a SIGTERM (standard kill) 349 Host::Kill(pid, SIGTERM); 350 351 // check if that worked 352 for (size_t i = 0; i < 10; ++i) { 353 { 354 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 355 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { 356 // it is now killed 357 return true; 358 } 359 } 360 std::this_thread::sleep_for(std::chrono::milliseconds(10)); 361 } 362 363 { 364 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 365 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 366 return true; 367 } 368 369 // the launched process still lives. Now try killing it again, this time 370 // with an unblockable signal. 371 Host::Kill(pid, SIGKILL); 372 373 for (size_t i = 0; i < 10; ++i) { 374 { 375 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 376 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { 377 // it is now killed 378 return true; 379 } 380 } 381 std::this_thread::sleep_for(std::chrono::milliseconds(10)); 382 } 383 384 // check one more time after the final sleep 385 { 386 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 387 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 388 return true; 389 } 390 391 // no luck - the process still lives 392 return false; 393 } 394 395 GDBRemoteCommunication::PacketResult 396 GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo( 397 StringExtractorGDBRemote &packet) { 398 lldb::pid_t pid = m_process_launch_info.GetProcessID(); 399 m_process_launch_info.Clear(); 400 401 if (pid == LLDB_INVALID_PROCESS_ID) 402 return SendErrorResponse(1); 403 404 ProcessInstanceInfo proc_info; 405 if (!Host::GetProcessInfo(pid, proc_info)) 406 return SendErrorResponse(1); 407 408 StreamString response; 409 CreateProcessInfoResponse_DebugServerStyle(proc_info, response); 410 return SendPacketNoLock(response.GetString()); 411 } 412 413 GDBRemoteCommunication::PacketResult 414 GDBRemoteCommunicationServerPlatform::Handle_qPathComplete( 415 StringExtractorGDBRemote &packet) { 416 packet.SetFilePos(::strlen("qPathComplete:")); 417 const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1); 418 if (packet.GetChar() != ',') 419 return SendErrorResponse(85); 420 std::string path; 421 packet.GetHexByteString(path); 422 423 StringList matches; 424 StandardTildeExpressionResolver resolver; 425 if (only_dir) 426 CommandCompletions::DiskDirectories(path, matches, resolver); 427 else 428 CommandCompletions::DiskFiles(path, matches, resolver); 429 430 StreamString response; 431 response.PutChar('M'); 432 llvm::StringRef separator; 433 std::sort(matches.begin(), matches.end()); 434 for (const auto &match : matches) { 435 response << separator; 436 separator = ","; 437 // encode result strings into hex bytes to avoid unexpected error caused by 438 // special characters like '$'. 439 response.PutStringAsRawHex8(match.c_str()); 440 } 441 442 return SendPacketNoLock(response.GetString()); 443 } 444 445 GDBRemoteCommunication::PacketResult 446 GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir( 447 StringExtractorGDBRemote &packet) { 448 449 llvm::SmallString<64> cwd; 450 if (std::error_code ec = llvm::sys::fs::current_path(cwd)) 451 return SendErrorResponse(ec.value()); 452 453 StreamString response; 454 response.PutBytesAsRawHex8(cwd.data(), cwd.size()); 455 return SendPacketNoLock(response.GetString()); 456 } 457 458 GDBRemoteCommunication::PacketResult 459 GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir( 460 StringExtractorGDBRemote &packet) { 461 packet.SetFilePos(::strlen("QSetWorkingDir:")); 462 std::string path; 463 packet.GetHexByteString(path); 464 465 if (std::error_code ec = llvm::sys::fs::set_current_path(path)) 466 return SendErrorResponse(ec.value()); 467 return SendOKResponse(); 468 } 469 470 GDBRemoteCommunication::PacketResult 471 GDBRemoteCommunicationServerPlatform::Handle_qC( 472 StringExtractorGDBRemote &packet) { 473 // NOTE: lldb should now be using qProcessInfo for process IDs. This path 474 // here 475 // should not be used. It is reporting process id instead of thread id. The 476 // correct answer doesn't seem to make much sense for lldb-platform. 477 // CONSIDER: flip to "unsupported". 478 lldb::pid_t pid = m_process_launch_info.GetProcessID(); 479 480 StreamString response; 481 response.Printf("QC%" PRIx64, pid); 482 483 // If we launch a process and this GDB server is acting as a platform, then 484 // we need to clear the process launch state so we can start launching 485 // another process. In order to launch a process a bunch or packets need to 486 // be sent: environment packets, working directory, disable ASLR, and many 487 // more settings. When we launch a process we then need to know when to clear 488 // this information. Currently we are selecting the 'qC' packet as that 489 // packet which seems to make the most sense. 490 if (pid != LLDB_INVALID_PROCESS_ID) { 491 m_process_launch_info.Clear(); 492 } 493 494 return SendPacketNoLock(response.GetString()); 495 } 496 497 GDBRemoteCommunication::PacketResult 498 GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( 499 StringExtractorGDBRemote &packet) { 500 StructuredData::Array signal_array; 501 502 lldb::UnixSignalsSP signals = UnixSignals::CreateForHost(); 503 for (auto signo = signals->GetFirstSignalNumber(); 504 signo != LLDB_INVALID_SIGNAL_NUMBER; 505 signo = signals->GetNextSignalNumber(signo)) { 506 auto dictionary = std::make_shared<StructuredData::Dictionary>(); 507 508 dictionary->AddIntegerItem("signo", signo); 509 dictionary->AddStringItem("name", signals->GetSignalAsCString(signo)); 510 511 bool suppress, stop, notify; 512 signals->GetSignalInfo(signo, suppress, stop, notify); 513 dictionary->AddBooleanItem("suppress", suppress); 514 dictionary->AddBooleanItem("stop", stop); 515 dictionary->AddBooleanItem("notify", notify); 516 517 signal_array.Push(dictionary); 518 } 519 520 StreamString response; 521 signal_array.Dump(response); 522 return SendPacketNoLock(response.GetString()); 523 } 524 525 bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( 526 lldb::pid_t pid) { 527 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 528 m_port_map.FreePortForProcess(pid); 529 m_spawned_pids.erase(pid); 530 return true; 531 } 532 533 Status GDBRemoteCommunicationServerPlatform::LaunchProcess() { 534 if (!m_process_launch_info.GetArguments().GetArgumentCount()) 535 return Status("%s: no process command line specified to launch", 536 __FUNCTION__); 537 538 // specify the process monitor if not already set. This should generally be 539 // what happens since we need to reap started processes. 540 if (!m_process_launch_info.GetMonitorProcessCallback()) 541 m_process_launch_info.SetMonitorProcessCallback( 542 std::bind( 543 &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, 544 this, std::placeholders::_1), 545 false); 546 547 Status error = Host::LaunchProcess(m_process_launch_info); 548 if (!error.Success()) { 549 fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__, 550 m_process_launch_info.GetArguments().GetArgumentAtIndex(0)); 551 return error; 552 } 553 554 printf("Launched '%s' as process %" PRIu64 "...\n", 555 m_process_launch_info.GetArguments().GetArgumentAtIndex(0), 556 m_process_launch_info.GetProcessID()); 557 558 // add to list of spawned processes. On an lldb-gdbserver, we would expect 559 // there to be only one. 560 const auto pid = m_process_launch_info.GetProcessID(); 561 if (pid != LLDB_INVALID_PROCESS_ID) { 562 // add to spawned pids 563 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); 564 m_spawned_pids.insert(pid); 565 } 566 567 return error; 568 } 569 570 void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) { 571 m_port_map = port_map; 572 } 573 574 const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { 575 static FileSpec g_domainsocket_dir; 576 static llvm::once_flag g_once_flag; 577 578 llvm::call_once(g_once_flag, []() { 579 const char *domainsocket_dir_env = 580 ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); 581 if (domainsocket_dir_env != nullptr) 582 g_domainsocket_dir = FileSpec(domainsocket_dir_env); 583 else 584 g_domainsocket_dir = HostInfo::GetProcessTempDir(); 585 }); 586 587 return g_domainsocket_dir; 588 } 589 590 FileSpec 591 GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) { 592 llvm::SmallString<128> socket_path; 593 llvm::SmallString<128> socket_name( 594 (llvm::StringRef(prefix) + ".%%%%%%").str()); 595 596 FileSpec socket_path_spec(GetDomainSocketDir()); 597 socket_path_spec.AppendPathComponent(socket_name.c_str()); 598 599 llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); 600 return FileSpec(socket_path.c_str()); 601 } 602 603 void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { 604 m_port_offset = port_offset; 605 } 606 607 void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer( 608 lldb::pid_t pid, uint16_t port, const std::string &socket_name) { 609 m_pending_gdb_server.pid = pid; 610 m_pending_gdb_server.port = port; 611 m_pending_gdb_server.socket_name = socket_name; 612 } 613