blob: 022c558352b034fd36073ef220393853dcc20b89 [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
16#include <cstring>
17#include <chrono>
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"
Tamas Berghammere13c2732015-02-11 10:29:30 +000026#include "lldb/Core/StreamString.h"
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000027#include "lldb/Core/StructuredData.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000028#include "lldb/Host/Config.h"
29#include "lldb/Host/ConnectionFileDescriptor.h"
30#include "lldb/Host/Host.h"
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000031#include "lldb/Host/HostInfo.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000032#include "lldb/Host/StringConvert.h"
33#include "lldb/Target/FileAction.h"
34#include "lldb/Target/Platform.h"
35#include "lldb/Target/Process.h"
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000036#include "lldb/Target/UnixSignals.h"
Tamas Berghammerccd6cff2015-12-08 14:08:19 +000037#include "lldb/Utility/JSON.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//----------------------------------------------------------------------
Oleksiy Vyalov14857122015-10-28 19:49:50 +000050GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol,
51 const char* socket_scheme) :
Tamas Berghammere13c2732015-02-11 10:29:30 +000052 GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"),
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000053 m_socket_protocol(socket_protocol),
Oleksiy Vyalov14857122015-10-28 19:49:50 +000054 m_socket_scheme(socket_scheme),
Pavel Labath6e4f19d2015-07-29 12:33:31 +000055 m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
Tamas Berghammere13c2732015-02-11 10:29:30 +000056 m_platform_sp (Platform::GetHostPlatform ()),
57 m_port_map (),
Tamas Berghammerccd6cff2015-12-08 14:08:19 +000058 m_port_offset(0),
59 m_pending_gdb_server{ LLDB_INVALID_PROCESS_ID, 0, "" }
Tamas Berghammere13c2732015-02-11 10:29:30 +000060{
61 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
62 &GDBRemoteCommunicationServerPlatform::Handle_qC);
63 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
64 &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
65 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
66 &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
Tamas Berghammerccd6cff2015-12-08 14:08:19 +000067 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer,
68 &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer);
Pavel Labath6e4f19d2015-07-29 12:33:31 +000069 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
70 &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);
Tamas Berghammere13c2732015-02-11 10:29:30 +000071 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
72 &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
73 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
74 &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000075 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
76 &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
Tamas Berghammere13c2732015-02-11 10:29:30 +000077
78 RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
79 [this](StringExtractorGDBRemote packet,
80 Error &error,
81 bool &interrupt,
82 bool &quit)
83 {
84 error.SetErrorString("interrupt received");
85 interrupt = true;
86 return PacketResult::Success;
87 });
88}
89
90//----------------------------------------------------------------------
91// Destructor
92//----------------------------------------------------------------------
93GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform()
94{
95}
96
Tamas Berghammerccd6cff2015-12-08 14:08:19 +000097Error
98GDBRemoteCommunicationServerPlatform::LaunchGDBServer(const lldb_private::Args& args,
99 std::string hostname,
100 lldb::pid_t& pid,
101 uint16_t& port,
102 std::string& socket_name)
Tamas Berghammere13c2732015-02-11 10:29:30 +0000103{
Tamas Berghammere13c2732015-02-11 10:29:30 +0000104 if (port == UINT16_MAX)
105 port = GetNextAvailablePort();
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000106
Tamas Berghammere13c2732015-02-11 10:29:30 +0000107 // Spawn a new thread to accept the port that gets bound after
108 // binding to port 0 (zero).
109
110 // ignore the hostname send from the remote end, just use the ip address
111 // that we're currently communicating with as the hostname
112
113 // Spawn a debugserver and try to get the port it listens to.
114 ProcessLaunchInfo debugserver_launch_info;
115 if (hostname.empty())
116 hostname = "127.0.0.1";
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000117
118 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
Tamas Berghammere13c2732015-02-11 10:29:30 +0000119 if (log)
Vince Harron8b335672015-05-12 01:10:56 +0000120 log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000121
122 // Do not run in a new session so that it can not linger after the
123 // platform closes.
124 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
125 debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
126
127 std::string platform_scheme;
128 std::string platform_ip;
129 int platform_port;
130 std::string platform_path;
131 bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path);
Bruce Mitchener8a67bf72015-07-24 00:23:29 +0000132 UNUSED_IF_ASSERT_DISABLED(ok);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000133 assert(ok);
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000134
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000135 std::ostringstream url;
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000136 uint16_t* port_ptr = &port;
137 if (m_socket_protocol == Socket::ProtocolTcp)
138 url << platform_ip << ":" << port;
139 else
140 {
141 socket_name = GetDomainSocketPath("gdbserver").GetPath();
142 url << socket_name;
143 port_ptr = nullptr;
144 }
145
146 Error error = StartDebugserverProcess (url.str().c_str(),
Greg Clayton6988abc2015-10-19 20:44:01 +0000147 nullptr,
148 debugserver_launch_info,
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000149 port_ptr,
150 args);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000151
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000152 pid = debugserver_launch_info.GetProcessID();
153 if (pid != LLDB_INVALID_PROCESS_ID)
Tamas Berghammere13c2732015-02-11 10:29:30 +0000154 {
155 Mutex::Locker locker (m_spawned_pids_mutex);
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000156 m_spawned_pids.insert(pid);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000157 if (port > 0)
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000158 AssociatePortWithProcess(port, pid);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000159 }
160 else
161 {
162 if (port > 0)
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000163 FreePort(port);
164 }
165 return error;
166}
167
168GDBRemoteCommunication::PacketResult
169GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
170{
171#ifdef _WIN32
172 return SendErrorResponse(9);
173#else
174 // Spawn a local debugserver as a platform so we can then attach or launch
175 // a process...
176
177 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
178 if (log)
179 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__);
180
181 ConnectionFileDescriptor file_conn;
182 std::string hostname;
183 packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
184 std::string name;
185 std::string value;
186 uint16_t port = UINT16_MAX;
187 while (packet.GetNameColonValue(name, value))
188 {
189 if (name.compare ("host") == 0)
190 hostname.swap(value);
191 else if (name.compare ("port") == 0)
192 port = StringConvert::ToUInt32(value.c_str(), 0, 0);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000193 }
194
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000195 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
196 std::string socket_name;
197 Error error = LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name);
198 if (error.Fail())
Tamas Berghammere13c2732015-02-11 10:29:30 +0000199 {
200 if (log)
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000201 log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
202 return SendErrorResponse(9);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000203 }
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000204
205 if (log)
206 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid);
207
208 StreamGDBRemote response;
209 response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
210 if (!socket_name.empty())
Tamas Berghammere13c2732015-02-11 10:29:30 +0000211 {
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000212 response.PutCString("socket_name:");
213 response.PutCStringAsRawHex8(socket_name.c_str());
214 response.PutChar(';');
Tamas Berghammere13c2732015-02-11 10:29:30 +0000215 }
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000216
217 PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize());
218 if (packet_result != PacketResult::Success)
219 {
220 if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
221 ::kill (debugserver_pid, SIGINT);
222 }
223 return packet_result;
Tamas Berghammere13c2732015-02-11 10:29:30 +0000224#endif
225}
226
227GDBRemoteCommunication::PacketResult
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000228GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer (StringExtractorGDBRemote &packet)
229{
230 if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID)
231 return SendErrorResponse(4);
232
233 JSONObject::SP server_sp = std::make_shared<JSONObject>();
234 server_sp->SetObject("port", std::make_shared<JSONNumber>(m_pending_gdb_server.port));
235 if (!m_pending_gdb_server.socket_name.empty())
236 server_sp->SetObject("socket_name",
237 std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str()));
238
239 JSONArray server_list;
240 server_list.AppendObject(server_sp);
241
242 StreamGDBRemote response;
243 server_list.Write(response);
244
245 StreamGDBRemote escaped_response;
246 escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
247 return SendPacketNoLock(escaped_response.GetData(), escaped_response.GetSize());
248}
249
250GDBRemoteCommunication::PacketResult
Pavel Labath6e4f19d2015-07-29 12:33:31 +0000251GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
252{
253 packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
254
255 lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
256
257 // verify that we know anything about this pid.
258 // Scope for locker
259 {
260 Mutex::Locker locker (m_spawned_pids_mutex);
261 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
262 {
263 // not a pid we know about
264 return SendErrorResponse (10);
265 }
266 }
267
268 // go ahead and attempt to kill the spawned process
269 if (KillSpawnedProcess (pid))
270 return SendOKResponse ();
271 else
272 return SendErrorResponse (11);
273}
274
275bool
276GDBRemoteCommunicationServerPlatform::KillSpawnedProcess (lldb::pid_t pid)
277{
278 // make sure we know about this process
279 {
280 Mutex::Locker locker (m_spawned_pids_mutex);
281 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
282 return false;
283 }
284
285 // first try a SIGTERM (standard kill)
286 Host::Kill (pid, SIGTERM);
287
288 // check if that worked
289 for (size_t i=0; i<10; ++i)
290 {
291 {
292 Mutex::Locker locker (m_spawned_pids_mutex);
293 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
294 {
295 // it is now killed
296 return true;
297 }
298 }
299 usleep (10000);
300 }
301
302 // check one more time after the final usleep
303 {
304 Mutex::Locker locker (m_spawned_pids_mutex);
305 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
306 return true;
307 }
308
309 // the launched process still lives. Now try killing it again,
310 // this time with an unblockable signal.
311 Host::Kill (pid, SIGKILL);
312
313 for (size_t i=0; i<10; ++i)
314 {
315 {
316 Mutex::Locker locker (m_spawned_pids_mutex);
317 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
318 {
319 // it is now killed
320 return true;
321 }
322 }
323 usleep (10000);
324 }
325
326 // check one more time after the final usleep
327 // Scope for locker
328 {
329 Mutex::Locker locker (m_spawned_pids_mutex);
330 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
331 return true;
332 }
333
334 // no luck - the process still lives
335 return false;
336}
337
338GDBRemoteCommunication::PacketResult
Tamas Berghammere13c2732015-02-11 10:29:30 +0000339GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
340{
341 lldb::pid_t pid = m_process_launch_info.GetProcessID ();
342 m_process_launch_info.Clear ();
343
344 if (pid == LLDB_INVALID_PROCESS_ID)
345 return SendErrorResponse (1);
346
347 ProcessInstanceInfo proc_info;
348 if (!Host::GetProcessInfo (pid, proc_info))
349 return SendErrorResponse (1);
350
351 StreamString response;
352 CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
353 return SendPacketNoLock (response.GetData (), response.GetSize ());
354}
355
356GDBRemoteCommunication::PacketResult
357GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
358{
359 // If this packet is sent to a platform, then change the current working directory
360
361 char cwd[PATH_MAX];
362 if (getcwd(cwd, sizeof(cwd)) == NULL)
363 return SendErrorResponse(errno);
364
365 StreamString response;
366 response.PutBytesAsRawHex8(cwd, strlen(cwd));
367 return SendPacketNoLock(response.GetData(), response.GetSize());
368}
369
370GDBRemoteCommunication::PacketResult
371GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
372{
373 packet.SetFilePos (::strlen ("QSetWorkingDir:"));
374 std::string path;
375 packet.GetHexByteString (path);
376
Tamas Berghammere13c2732015-02-11 10:29:30 +0000377 // If this packet is sent to a platform, then change the current working directory
378 if (::chdir(path.c_str()) != 0)
379 return SendErrorResponse (errno);
380 return SendOKResponse ();
Tamas Berghammere13c2732015-02-11 10:29:30 +0000381}
382
383GDBRemoteCommunication::PacketResult
384GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet)
385{
386 // NOTE: lldb should now be using qProcessInfo for process IDs. This path here
387 // should not be used. It is reporting process id instead of thread id. The
388 // correct answer doesn't seem to make much sense for lldb-platform.
389 // CONSIDER: flip to "unsupported".
390 lldb::pid_t pid = m_process_launch_info.GetProcessID();
391
392 StreamString response;
393 response.Printf("QC%" PRIx64, pid);
394
395 // If we launch a process and this GDB server is acting as a platform,
396 // then we need to clear the process launch state so we can start
397 // launching another process. In order to launch a process a bunch or
398 // packets need to be sent: environment packets, working directory,
399 // disable ASLR, and many more settings. When we launch a process we
400 // then need to know when to clear this information. Currently we are
401 // selecting the 'qC' packet as that packet which seems to make the most
402 // sense.
403 if (pid != LLDB_INVALID_PROCESS_ID)
404 {
405 m_process_launch_info.Clear();
406 }
407
408 return SendPacketNoLock (response.GetData(), response.GetSize());
409}
410
Chaoren Lin98d0a4b2015-07-14 01:09:28 +0000411GDBRemoteCommunication::PacketResult
412GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(StringExtractorGDBRemote &packet)
413{
414 StructuredData::Array signal_array;
415
416 const auto &signals = Host::GetUnixSignals();
417 for (auto signo = signals->GetFirstSignalNumber();
418 signo != LLDB_INVALID_SIGNAL_NUMBER;
419 signo = signals->GetNextSignalNumber(signo))
420 {
421 auto dictionary = std::make_shared<StructuredData::Dictionary>();
422
423 dictionary->AddIntegerItem("signo", signo);
424 dictionary->AddStringItem("name", signals->GetSignalAsCString(signo));
425
426 bool suppress, stop, notify;
427 signals->GetSignalInfo(signo, suppress, stop, notify);
428 dictionary->AddBooleanItem("suppress", suppress);
429 dictionary->AddBooleanItem("stop", stop);
430 dictionary->AddBooleanItem("notify", notify);
431
432 signal_array.Push(dictionary);
433 }
434
435 StreamString response;
436 signal_array.Dump(response);
437 return SendPacketNoLock(response.GetData(), response.GetSize());
438}
439
Tamas Berghammere13c2732015-02-11 10:29:30 +0000440bool
441GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid)
442{
443 Mutex::Locker locker (m_spawned_pids_mutex);
444 FreePortForProcess(pid);
445 return m_spawned_pids.erase(pid) > 0;
446}
447
448bool
449GDBRemoteCommunicationServerPlatform::ReapDebugserverProcess (void *callback_baton,
450 lldb::pid_t pid,
451 bool exited,
452 int signal, // Zero for no signal
453 int status) // Exit value of process if signal is zero
454{
455 GDBRemoteCommunicationServerPlatform *server = (GDBRemoteCommunicationServerPlatform *)callback_baton;
456 server->DebugserverProcessReaped (pid);
457 return true;
458}
459
Tamas Berghammerdb264a62015-03-31 09:52:22 +0000460Error
Tamas Berghammere13c2732015-02-11 10:29:30 +0000461GDBRemoteCommunicationServerPlatform::LaunchProcess ()
462{
463 if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
Tamas Berghammerdb264a62015-03-31 09:52:22 +0000464 return Error ("%s: no process command line specified to launch", __FUNCTION__);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000465
466 // specify the process monitor if not already set. This should
467 // generally be what happens since we need to reap started
468 // processes.
469 if (!m_process_launch_info.GetMonitorProcessCallback ())
470 m_process_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
471
Tamas Berghammerdb264a62015-03-31 09:52:22 +0000472 Error error = m_platform_sp->LaunchProcess (m_process_launch_info);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000473 if (!error.Success ())
474 {
475 fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
476 return error;
477 }
478
479 printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID());
480
481 // add to list of spawned processes. On an lldb-gdbserver, we
482 // would expect there to be only one.
483 const auto pid = m_process_launch_info.GetProcessID();
484 if (pid != LLDB_INVALID_PROCESS_ID)
485 {
486 // add to spawned pids
487 Mutex::Locker locker (m_spawned_pids_mutex);
488 m_spawned_pids.insert(pid);
489 }
490
491 return error;
492}
493
494void
495GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map)
496{
497 m_port_map = port_map;
498}
499
500uint16_t
501GDBRemoteCommunicationServerPlatform::GetNextAvailablePort ()
502{
503 if (m_port_map.empty())
504 return 0; // Bind to port zero and get a port, we didn't have any limitations
505
506 for (auto &pair : m_port_map)
507 {
508 if (pair.second == LLDB_INVALID_PROCESS_ID)
509 {
510 pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
511 return pair.first;
512 }
513 }
514 return UINT16_MAX;
515}
516
517bool
518GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess (uint16_t port, lldb::pid_t pid)
519{
520 PortMap::iterator pos = m_port_map.find(port);
521 if (pos != m_port_map.end())
522 {
523 pos->second = pid;
524 return true;
525 }
526 return false;
527}
528
529bool
530GDBRemoteCommunicationServerPlatform::FreePort (uint16_t port)
531{
532 PortMap::iterator pos = m_port_map.find(port);
533 if (pos != m_port_map.end())
534 {
535 pos->second = LLDB_INVALID_PROCESS_ID;
536 return true;
537 }
538 return false;
539}
540
541bool
542GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid)
543{
544 if (!m_port_map.empty())
545 {
546 for (auto &pair : m_port_map)
547 {
548 if (pair.second == pid)
549 {
550 pair.second = LLDB_INVALID_PROCESS_ID;
551 return true;
552 }
553 }
554 }
555 return false;
556}
557
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000558const FileSpec&
559GDBRemoteCommunicationServerPlatform::GetDomainSocketDir()
560{
561 static FileSpec g_domainsocket_dir;
562 static std::once_flag g_once_flag;
563
564 std::call_once(g_once_flag, []() {
565 const char* domainsocket_dir_env = ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
566 if (domainsocket_dir_env != nullptr)
567 g_domainsocket_dir = FileSpec(domainsocket_dir_env, false);
568 else
569 HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir);
570 });
571
572 return g_domainsocket_dir;
573}
574
575FileSpec
576GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char* prefix)
577{
578 llvm::SmallString<PATH_MAX> socket_path;
579 llvm::SmallString<PATH_MAX> socket_name((llvm::StringRef(prefix) + ".%%%%%%").str());
580
581 FileSpec socket_path_spec(GetDomainSocketDir());
582 socket_path_spec.AppendPathComponent(socket_name.c_str());
583
584 llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path);
585 return FileSpec(socket_path.c_str(), false);
586}
587
Tamas Berghammere13c2732015-02-11 10:29:30 +0000588void
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000589GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset)
Tamas Berghammere13c2732015-02-11 10:29:30 +0000590{
591 m_port_offset = port_offset;
592}
Tamas Berghammerccd6cff2015-12-08 14:08:19 +0000593
594void
595GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(lldb::pid_t pid,
596 uint16_t port,
597 const std::string& socket_name)
598{
599 m_pending_gdb_server.pid = pid;
600 m_pending_gdb_server.port = port;
601 m_pending_gdb_server.socket_name = socket_name;
602}