blob: 7751eeea72d704543e219d7ce90e60401534184e [file] [log] [blame]
Tamas Berghammere13c2732015-02-11 10:29:30 +00001//===-- GDBRemoteCommunicationServerPlatform.cpp ----------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "GDBRemoteCommunicationServerPlatform.h"
11
12#include <errno.h>
13
14// C Includes
15// C++ Includes
Tamas Berghammere13c2732015-02-11 10:29:30 +000016#include <chrono>
Kate Stoneb9c1b512016-09-06 20:57:50 +000017#include <cstring>
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000018#include <mutex>
19#include <sstream>
Tamas Berghammere13c2732015-02-11 10:29:30 +000020
21// Other libraries and framework includes
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000022#include "llvm/Support/FileSystem.h"
23
Tamas Berghammere13c2732015-02-11 10:29:30 +000024#include "lldb/Core/Log.h"
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000025#include "lldb/Core/StreamGDBRemote.h"
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000026#include "lldb/Core/StructuredData.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000027#include "lldb/Host/Config.h"
28#include "lldb/Host/ConnectionFileDescriptor.h"
29#include "lldb/Host/Host.h"
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000030#include "lldb/Host/HostInfo.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000031#include "lldb/Host/StringConvert.h"
32#include "lldb/Target/FileAction.h"
33#include "lldb/Target/Platform.h"
34#include "lldb/Target/Process.h"
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000035#include "lldb/Target/UnixSignals.h"
Tamas Berghammerccd6cff2015-12-08 14:08:19 +000036#include "lldb/Utility/JSON.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000037#include "lldb/Utility/StreamString.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000038
39// Project includes
40#include "Utility/StringExtractorGDBRemote.h"
41#include "Utility/UriParser.h"
42
43using namespace lldb;
44using namespace lldb_private;
Tamas Berghammerdb264a62015-03-31 09:52:22 +000045using namespace lldb_private::process_gdb_remote;
Tamas Berghammere13c2732015-02-11 10:29:30 +000046
47//----------------------------------------------------------------------
48// GDBRemoteCommunicationServerPlatform constructor
49//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000050GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
51 const Socket::SocketProtocol socket_protocol, const char *socket_scheme)
52 : GDBRemoteCommunicationServerCommon("gdb-remote.server",
53 "gdb-remote.server.rx_packet"),
54 m_socket_protocol(socket_protocol), m_socket_scheme(socket_scheme),
55 m_spawned_pids_mutex(), m_port_map(), m_port_offset(0) {
56 m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID;
57 m_pending_gdb_server.port = 0;
Tamas Berghammer372810f2015-12-08 14:27:40 +000058
Kate Stoneb9c1b512016-09-06 20:57:50 +000059 RegisterMemberFunctionHandler(
60 StringExtractorGDBRemote::eServerPacketType_qC,
61 &GDBRemoteCommunicationServerPlatform::Handle_qC);
62 RegisterMemberFunctionHandler(
63 StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
64 &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
65 RegisterMemberFunctionHandler(
66 StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
67 &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
68 RegisterMemberFunctionHandler(
69 StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer,
70 &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer);
71 RegisterMemberFunctionHandler(
72 StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
73 &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);
74 RegisterMemberFunctionHandler(
75 StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
76 &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
77 RegisterMemberFunctionHandler(
78 StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
79 &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
80 RegisterMemberFunctionHandler(
81 StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
82 &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
Tamas Berghammere13c2732015-02-11 10:29:30 +000083
Kate Stoneb9c1b512016-09-06 20:57:50 +000084 RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
85 [this](StringExtractorGDBRemote packet, Error &error,
86 bool &interrupt, bool &quit) {
87 error.SetErrorString("interrupt received");
88 interrupt = true;
89 return PacketResult::Success;
90 });
Tamas Berghammere13c2732015-02-11 10:29:30 +000091}
92
93//----------------------------------------------------------------------
94// Destructor
95//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000096GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {}
Tamas Berghammere13c2732015-02-11 10:29:30 +000097
Kate Stoneb9c1b512016-09-06 20:57:50 +000098Error GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
99 const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
100 uint16_t &port, std::string &socket_name) {
101 if (port == UINT16_MAX)
102 port = GetNextAvailablePort();
Tamas Berghammere13c2732015-02-11 10:29:30 +0000103
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 // Spawn a new thread to accept the port that gets bound after
105 // binding to port 0 (zero).
Tamas Berghammere13c2732015-02-11 10:29:30 +0000106
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107 // ignore the hostname send from the remote end, just use the ip address
108 // that we're currently communicating with as the hostname
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 // Spawn a debugserver and try to get the port it listens to.
111 ProcessLaunchInfo debugserver_launch_info;
112 if (hostname.empty())
113 hostname = "127.0.0.1";
Tamas Berghammere13c2732015-02-11 10:29:30 +0000114
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
116 if (log)
117 log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000118
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119 // Do not run in a new session so that it can not linger after the
120 // platform closes.
121 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
122 debugserver_launch_info.SetMonitorProcessCallback(
123 std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped,
124 this, std::placeholders::_1),
125 false);
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000126
Zachary Turner245f7fd2016-11-17 01:38:02 +0000127 llvm::StringRef platform_scheme;
128 llvm::StringRef platform_ip;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 int platform_port;
Zachary Turner245f7fd2016-11-17 01:38:02 +0000130 llvm::StringRef platform_path;
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000131 bool ok = UriParser::Parse(GetConnection()->GetURI(), platform_scheme,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 platform_ip, platform_port, platform_path);
133 UNUSED_IF_ASSERT_DISABLED(ok);
134 assert(ok);
135
136 std::ostringstream url;
137// debugserver does not accept the URL scheme prefix.
Todd Fiala873a2ab2016-05-27 04:04:52 +0000138#if !defined(__APPLE__)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 url << m_socket_scheme << "://";
Todd Fiala873a2ab2016-05-27 04:04:52 +0000140#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141 uint16_t *port_ptr = &port;
142 if (m_socket_protocol == Socket::ProtocolTcp)
Zachary Turner245f7fd2016-11-17 01:38:02 +0000143 url << platform_ip.str() << ":" << port;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000144 else {
145 socket_name = GetDomainSocketPath("gdbserver").GetPath();
146 url << socket_name;
147 port_ptr = nullptr;
148 }
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000149
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 Error error = StartDebugserverProcess(
151 url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000152
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153 pid = debugserver_launch_info.GetProcessID();
154 if (pid != LLDB_INVALID_PROCESS_ID) {
Saleem Abdulrasool16ff8602016-05-18 01:59:10 +0000155 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156 m_spawned_pids.insert(pid);
157 if (port > 0)
158 AssociatePortWithProcess(port, pid);
159 } else {
160 if (port > 0)
161 FreePort(port);
162 }
163 return error;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000164}
165
Kate Stoneb9c1b512016-09-06 20:57:50 +0000166GDBRemoteCommunication::PacketResult
167GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
168 StringExtractorGDBRemote &packet) {
169#ifdef _WIN32
170 return SendErrorResponse(9);
171#else
172 // Spawn a local debugserver as a platform so we can then attach or launch
173 // a process...
Tamas Berghammere13c2732015-02-11 10:29:30 +0000174
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
176 if (log)
177 log->Printf("GDBRemoteCommunicationServerPlatform::%s() called",
178 __FUNCTION__);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000179
Kate Stoneb9c1b512016-09-06 20:57:50 +0000180 ConnectionFileDescriptor file_conn;
181 std::string hostname;
182 packet.SetFilePos(::strlen("qLaunchGDBServer;"));
183 llvm::StringRef name;
184 llvm::StringRef value;
185 uint16_t port = UINT16_MAX;
186 while (packet.GetNameColonValue(name, value)) {
187 if (name.equals("host"))
188 hostname = value;
189 else if (name.equals("port"))
190 value.getAsInteger(0, port);
191 }
192
193 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
194 std::string socket_name;
195 Error error =
196 LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name);
197 if (error.Fail()) {
198 if (log)
199 log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver "
200 "launch failed: %s",
201 __FUNCTION__, error.AsCString());
202 return SendErrorResponse(9);
203 }
204
205 if (log)
206 log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver "
207 "launched successfully as pid %" PRIu64,
208 __FUNCTION__, debugserver_pid);
209
210 StreamGDBRemote response;
211 response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid,
212 port + m_port_offset);
213 if (!socket_name.empty()) {
214 response.PutCString("socket_name:");
215 response.PutCStringAsRawHex8(socket_name.c_str());
216 response.PutChar(';');
217 }
218
219 PacketResult packet_result = SendPacketNoLock(response.GetString());
220 if (packet_result != PacketResult::Success) {
221 if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
222 ::kill(debugserver_pid, SIGINT);
223 }
224 return packet_result;
225#endif
226}
227
228GDBRemoteCommunication::PacketResult
229GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer(
230 StringExtractorGDBRemote &packet) {
231 if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID)
232 return SendErrorResponse(4);
233
234 JSONObject::SP server_sp = std::make_shared<JSONObject>();
235 server_sp->SetObject("port",
236 std::make_shared<JSONNumber>(m_pending_gdb_server.port));
237 if (!m_pending_gdb_server.socket_name.empty())
238 server_sp->SetObject(
239 "socket_name",
240 std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str()));
241
242 JSONArray server_list;
243 server_list.AppendObject(server_sp);
244
245 StreamGDBRemote response;
246 server_list.Write(response);
247
248 StreamGDBRemote escaped_response;
Zachary Turnerc1564272016-11-16 21:15:24 +0000249 escaped_response.PutEscapedBytes(response.GetString().data(),
250 response.GetSize());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000251 return SendPacketNoLock(escaped_response.GetString());
252}
253
254GDBRemoteCommunication::PacketResult
255GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess(
256 StringExtractorGDBRemote &packet) {
257 packet.SetFilePos(::strlen("qKillSpawnedProcess:"));
258
259 lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
260
261 // verify that we know anything about this pid.
262 // Scope for locker
263 {
264 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
265 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
266 // not a pid we know about
267 return SendErrorResponse(10);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000268 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269 }
Tamas Berghammere13c2732015-02-11 10:29:30 +0000270
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271 // go ahead and attempt to kill the spawned process
272 if (KillSpawnedProcess(pid))
273 return SendOKResponse();
274 else
275 return SendErrorResponse(11);
276}
Tamas Berghammere13c2732015-02-11 10:29:30 +0000277
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) {
279 // make sure we know about this process
280 {
281 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
282 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
283 return false;
284 }
285
286 // first try a SIGTERM (standard kill)
287 Host::Kill(pid, SIGTERM);
288
289 // check if that worked
290 for (size_t i = 0; i < 10; ++i) {
Tamas Berghammere13c2732015-02-11 10:29:30 +0000291 {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000292 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
293 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
294 // it is now killed
295 return true;
296 }
Tamas Berghammere13c2732015-02-11 10:29:30 +0000297 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298 usleep(10000);
299 }
Tamas Berghammere13c2732015-02-11 10:29:30 +0000300
Kate Stoneb9c1b512016-09-06 20:57:50 +0000301 // check one more time after the final usleep
302 {
303 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
304 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
305 return true;
306 }
307
308 // the launched process still lives. Now try killing it again,
309 // this time with an unblockable signal.
310 Host::Kill(pid, SIGKILL);
311
312 for (size_t i = 0; i < 10; ++i) {
313 {
314 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
315 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
316 // it is now killed
317 return true;
318 }
319 }
320 usleep(10000);
321 }
322
323 // check one more time after the final usleep
324 // 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 return true;
329 }
330
331 // no luck - the process still lives
332 return false;
333}
334
335GDBRemoteCommunication::PacketResult
336GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
337 StringExtractorGDBRemote &packet) {
338 lldb::pid_t pid = m_process_launch_info.GetProcessID();
339 m_process_launch_info.Clear();
340
341 if (pid == LLDB_INVALID_PROCESS_ID)
342 return SendErrorResponse(1);
343
344 ProcessInstanceInfo proc_info;
345 if (!Host::GetProcessInfo(pid, proc_info))
346 return SendErrorResponse(1);
347
348 StreamString response;
349 CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
350 return SendPacketNoLock(response.GetString());
351}
352
353GDBRemoteCommunication::PacketResult
354GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
355 StringExtractorGDBRemote &packet) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000356
Pavel Labath1d5855b2017-01-23 15:56:45 +0000357 llvm::SmallString<64> cwd;
358 if (std::error_code ec = llvm::sys::fs::current_path(cwd))
359 return SendErrorResponse(ec.value());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000360
361 StreamString response;
Pavel Labath1d5855b2017-01-23 15:56:45 +0000362 response.PutBytesAsRawHex8(cwd.data(), cwd.size());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000363 return SendPacketNoLock(response.GetString());
364}
365
366GDBRemoteCommunication::PacketResult
367GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir(
368 StringExtractorGDBRemote &packet) {
369 packet.SetFilePos(::strlen("QSetWorkingDir:"));
370 std::string path;
371 packet.GetHexByteString(path);
372
Pavel Labath2d0c5b02017-01-25 11:10:52 +0000373 if (std::error_code ec = llvm::sys::fs::set_current_path(path))
374 return SendErrorResponse(ec.value());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000375 return SendOKResponse();
376}
377
378GDBRemoteCommunication::PacketResult
379GDBRemoteCommunicationServerPlatform::Handle_qC(
380 StringExtractorGDBRemote &packet) {
381 // NOTE: lldb should now be using qProcessInfo for process IDs. This path
382 // here
383 // should not be used. It is reporting process id instead of thread id. The
384 // correct answer doesn't seem to make much sense for lldb-platform.
385 // CONSIDER: flip to "unsupported".
386 lldb::pid_t pid = m_process_launch_info.GetProcessID();
387
388 StreamString response;
389 response.Printf("QC%" PRIx64, pid);
390
391 // If we launch a process and this GDB server is acting as a platform,
392 // then we need to clear the process launch state so we can start
393 // launching another process. In order to launch a process a bunch or
394 // packets need to be sent: environment packets, working directory,
395 // disable ASLR, and many more settings. When we launch a process we
396 // then need to know when to clear this information. Currently we are
397 // selecting the 'qC' packet as that packet which seems to make the most
398 // sense.
399 if (pid != LLDB_INVALID_PROCESS_ID) {
400 m_process_launch_info.Clear();
401 }
402
403 return SendPacketNoLock(response.GetString());
404}
405
406GDBRemoteCommunication::PacketResult
407GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(
408 StringExtractorGDBRemote &packet) {
409 StructuredData::Array signal_array;
410
411 const auto &signals = Host::GetUnixSignals();
412 for (auto signo = signals->GetFirstSignalNumber();
413 signo != LLDB_INVALID_SIGNAL_NUMBER;
414 signo = signals->GetNextSignalNumber(signo)) {
415 auto dictionary = std::make_shared<StructuredData::Dictionary>();
416
417 dictionary->AddIntegerItem("signo", signo);
418 dictionary->AddStringItem("name", signals->GetSignalAsCString(signo));
419
420 bool suppress, stop, notify;
421 signals->GetSignalInfo(signo, suppress, stop, notify);
422 dictionary->AddBooleanItem("suppress", suppress);
423 dictionary->AddBooleanItem("stop", stop);
424 dictionary->AddBooleanItem("notify", notify);
425
426 signal_array.Push(dictionary);
427 }
428
429 StreamString response;
430 signal_array.Dump(response);
431 return SendPacketNoLock(response.GetString());
432}
433
434bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(
435 lldb::pid_t pid) {
436 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
437 FreePortForProcess(pid);
438 m_spawned_pids.erase(pid);
439 return true;
440}
441
442Error GDBRemoteCommunicationServerPlatform::LaunchProcess() {
443 if (!m_process_launch_info.GetArguments().GetArgumentCount())
444 return Error("%s: no process command line specified to launch",
445 __FUNCTION__);
446
447 // specify the process monitor if not already set. This should
448 // generally be what happens since we need to reap started
449 // processes.
450 if (!m_process_launch_info.GetMonitorProcessCallback())
451 m_process_launch_info.SetMonitorProcessCallback(
452 std::bind(
453 &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped,
454 this, std::placeholders::_1),
455 false);
456
457 Error error = Host::LaunchProcess(m_process_launch_info);
458 if (!error.Success()) {
459 fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,
460 m_process_launch_info.GetArguments().GetArgumentAtIndex(0));
Tamas Berghammere13c2732015-02-11 10:29:30 +0000461 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000462 }
463
464 printf("Launched '%s' as process %" PRIu64 "...\n",
465 m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
466 m_process_launch_info.GetProcessID());
467
468 // add to list of spawned processes. On an lldb-gdbserver, we
469 // would expect there to be only one.
470 const auto pid = m_process_launch_info.GetProcessID();
471 if (pid != LLDB_INVALID_PROCESS_ID) {
472 // add to spawned pids
473 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
474 m_spawned_pids.insert(pid);
475 }
476
477 return error;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000478}
479
Kate Stoneb9c1b512016-09-06 20:57:50 +0000480void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) {
481 m_port_map = port_map;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000482}
483
Kate Stoneb9c1b512016-09-06 20:57:50 +0000484uint16_t GDBRemoteCommunicationServerPlatform::GetNextAvailablePort() {
485 if (m_port_map.empty())
486 return 0; // Bind to port zero and get a port, we didn't have any
487 // limitations
Tamas Berghammere13c2732015-02-11 10:29:30 +0000488
Kate Stoneb9c1b512016-09-06 20:57:50 +0000489 for (auto &pair : m_port_map) {
490 if (pair.second == LLDB_INVALID_PROCESS_ID) {
491 pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
492 return pair.first;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000493 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000494 }
495 return UINT16_MAX;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000496}
497
Kate Stoneb9c1b512016-09-06 20:57:50 +0000498bool GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess(
499 uint16_t port, lldb::pid_t pid) {
500 PortMap::iterator pos = m_port_map.find(port);
501 if (pos != m_port_map.end()) {
502 pos->second = pid;
503 return true;
504 }
505 return false;
506}
507
508bool GDBRemoteCommunicationServerPlatform::FreePort(uint16_t port) {
509 PortMap::iterator pos = m_port_map.find(port);
510 if (pos != m_port_map.end()) {
511 pos->second = LLDB_INVALID_PROCESS_ID;
512 return true;
513 }
514 return false;
515}
516
517bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) {
518 if (!m_port_map.empty()) {
519 for (auto &pair : m_port_map) {
520 if (pair.second == pid) {
521 pair.second = LLDB_INVALID_PROCESS_ID;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000522 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000523 }
Tamas Berghammere13c2732015-02-11 10:29:30 +0000524 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000525 }
526 return false;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000527}
528
Kate Stoneb9c1b512016-09-06 20:57:50 +0000529const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {
530 static FileSpec g_domainsocket_dir;
531 static std::once_flag g_once_flag;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000532
Kate Stoneb9c1b512016-09-06 20:57:50 +0000533 std::call_once(g_once_flag, []() {
534 const char *domainsocket_dir_env =
535 ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
536 if (domainsocket_dir_env != nullptr)
537 g_domainsocket_dir = FileSpec(domainsocket_dir_env, false);
538 else
539 HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir);
540 });
Tamas Berghammere13c2732015-02-11 10:29:30 +0000541
Kate Stoneb9c1b512016-09-06 20:57:50 +0000542 return g_domainsocket_dir;
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000543}
544
545FileSpec
Kate Stoneb9c1b512016-09-06 20:57:50 +0000546GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) {
547 llvm::SmallString<PATH_MAX> socket_path;
548 llvm::SmallString<PATH_MAX> socket_name(
549 (llvm::StringRef(prefix) + ".%%%%%%").str());
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000550
Kate Stoneb9c1b512016-09-06 20:57:50 +0000551 FileSpec socket_path_spec(GetDomainSocketDir());
552 socket_path_spec.AppendPathComponent(socket_name.c_str());
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000553
Kate Stoneb9c1b512016-09-06 20:57:50 +0000554 llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path);
555 return FileSpec(socket_path.c_str(), false);
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000556}
557
Kate Stoneb9c1b512016-09-06 20:57:50 +0000558void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) {
559 m_port_offset = port_offset;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000560}
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000561
Kate Stoneb9c1b512016-09-06 20:57:50 +0000562void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(
563 lldb::pid_t pid, uint16_t port, const std::string &socket_name) {
564 m_pending_gdb_server.pid = pid;
565 m_pending_gdb_server.port = port;
566 m_pending_gdb_server.socket_name = socket_name;
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000567}