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