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