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

source code of lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp