560 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			560 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- GDBRemoteCommunicationServerPlatform.cpp ----------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "GDBRemoteCommunicationServerPlatform.h"
 | |
| 
 | |
| #include <errno.h>
 | |
| 
 | |
| // C Includes
 | |
| // C++ Includes
 | |
| #include <cstring>
 | |
| #include <chrono>
 | |
| #include <mutex>
 | |
| #include <sstream>
 | |
| 
 | |
| // Other libraries and framework includes
 | |
| #include "llvm/Support/FileSystem.h"
 | |
| 
 | |
| #include "lldb/Core/Log.h"
 | |
| #include "lldb/Core/StreamGDBRemote.h"
 | |
| #include "lldb/Core/StreamString.h"
 | |
| #include "lldb/Core/StructuredData.h"
 | |
| #include "lldb/Host/Config.h"
 | |
| #include "lldb/Host/ConnectionFileDescriptor.h"
 | |
| #include "lldb/Host/Host.h"
 | |
| #include "lldb/Host/HostInfo.h"
 | |
| #include "lldb/Host/StringConvert.h"
 | |
| #include "lldb/Target/FileAction.h"
 | |
| #include "lldb/Target/Platform.h"
 | |
| #include "lldb/Target/Process.h"
 | |
| #include "lldb/Target/UnixSignals.h"
 | |
| 
 | |
| // Project includes
 | |
| #include "Utility/StringExtractorGDBRemote.h"
 | |
| #include "Utility/UriParser.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| using namespace lldb_private::process_gdb_remote;
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // GDBRemoteCommunicationServerPlatform constructor
 | |
| //----------------------------------------------------------------------
 | |
| GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol,
 | |
|                                                                            const char* socket_scheme) :
 | |
|     GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"),
 | |
|     m_socket_protocol(socket_protocol),
 | |
|     m_socket_scheme(socket_scheme),
 | |
|     m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
 | |
|     m_platform_sp (Platform::GetHostPlatform ()),
 | |
|     m_port_map (),
 | |
|     m_port_offset(0)
 | |
| {
 | |
|     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
 | |
|                                   &GDBRemoteCommunicationServerPlatform::Handle_qC);
 | |
|     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
 | |
|                                   &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
 | |
|     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
 | |
|                                   &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
 | |
|     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
 | |
|                                   &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);
 | |
|     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
 | |
|                                   &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
 | |
|     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
 | |
|                                   &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
 | |
|     RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
 | |
|                                   &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
 | |
| 
 | |
|     RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
 | |
|                           [this](StringExtractorGDBRemote packet,
 | |
|                                  Error &error,
 | |
|                                  bool &interrupt,
 | |
|                                  bool &quit)
 | |
|                           {
 | |
|                               error.SetErrorString("interrupt received");
 | |
|                               interrupt = true;
 | |
|                               return PacketResult::Success;
 | |
|                           });
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // Destructor
 | |
| //----------------------------------------------------------------------
 | |
| GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform()
 | |
| {
 | |
| }
 | |
| 
 | |
| GDBRemoteCommunication::PacketResult
 | |
| GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
 | |
| {
 | |
| #ifdef _WIN32
 | |
|     return SendErrorResponse(9);
 | |
| #else
 | |
|     // Spawn a local debugserver as a platform so we can then attach or launch
 | |
|     // a process...
 | |
| 
 | |
|     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
 | |
|     if (log)
 | |
|         log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__);
 | |
| 
 | |
|     // Sleep and wait a bit for debugserver to start to listen...
 | |
|     ConnectionFileDescriptor file_conn;
 | |
|     std::string hostname;
 | |
|     // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
 | |
|     // with the TMPDIR environment variable
 | |
|     packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
 | |
|     std::string name;
 | |
|     std::string value;
 | |
|     uint16_t port = UINT16_MAX;
 | |
|     while (packet.GetNameColonValue(name, value))
 | |
|     {
 | |
|         if (name.compare ("host") == 0)
 | |
|             hostname.swap(value);
 | |
|         else if (name.compare ("port") == 0)
 | |
|             port = StringConvert::ToUInt32(value.c_str(), 0, 0);
 | |
|     }
 | |
|     if (port == UINT16_MAX)
 | |
|         port = GetNextAvailablePort();
 | |
| 
 | |
|     // Spawn a new thread to accept the port that gets bound after
 | |
|     // binding to port 0 (zero).
 | |
| 
 | |
|     // ignore the hostname send from the remote end, just use the ip address
 | |
|     // that we're currently communicating with as the hostname
 | |
| 
 | |
|     // Spawn a debugserver and try to get the port it listens to.
 | |
|     ProcessLaunchInfo debugserver_launch_info;
 | |
|     if (hostname.empty())
 | |
|         hostname = "127.0.0.1";
 | |
|     if (log)
 | |
|         log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port);
 | |
| 
 | |
|     // Do not run in a new session so that it can not linger after the
 | |
|     // platform closes.
 | |
|     debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
 | |
|     debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
 | |
| 
 | |
|     std::string platform_scheme;
 | |
|     std::string platform_ip;
 | |
|     int platform_port;
 | |
|     std::string platform_path;
 | |
|     bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path);
 | |
|     UNUSED_IF_ASSERT_DISABLED(ok);
 | |
|     assert(ok);
 | |
| 
 | |
|     std::string socket_name;
 | |
|     std::ostringstream url;
 | |
| 
 | |
|     uint16_t* port_ptr = &port;
 | |
|     url << m_socket_scheme << "://";
 | |
|     if (m_socket_protocol == Socket::ProtocolTcp)
 | |
|         url << platform_ip << ":" << port;
 | |
|     else
 | |
|     {
 | |
|         socket_name = GetDomainSocketPath("gdbserver").GetPath();
 | |
|         url << socket_name;
 | |
|         port_ptr = nullptr;
 | |
|     }
 | |
| 
 | |
|     Error error = StartDebugserverProcess (url.str().c_str(),
 | |
|                                            nullptr,
 | |
|                                            debugserver_launch_info,
 | |
|                                            port_ptr);
 | |
| 
 | |
|     lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
 | |
| 
 | |
| 
 | |
|     if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
 | |
|     {
 | |
|         Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|         m_spawned_pids.insert(debugserver_pid);
 | |
|         if (port > 0)
 | |
|             AssociatePortWithProcess(port, debugserver_pid);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         if (port > 0)
 | |
|             FreePort (port);
 | |
|     }
 | |
| 
 | |
|     if (error.Success())
 | |
|     {
 | |
|         if (log)
 | |
|             log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid);
 | |
| 
 | |
|         StreamGDBRemote response;
 | |
|         response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
 | |
|         if (!socket_name.empty())
 | |
|         {
 | |
|             response.PutCString("socket_name:");
 | |
|             response.PutCStringAsRawHex8(socket_name.c_str());
 | |
|             response.PutChar(';');
 | |
|         }
 | |
| 
 | |
|         PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize());
 | |
|         if (packet_result != PacketResult::Success)
 | |
|         {
 | |
|             if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
 | |
|                 ::kill (debugserver_pid, SIGINT);
 | |
|         }
 | |
|         return packet_result;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         if (log)
 | |
|             log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
 | |
|     }
 | |
|     return SendErrorResponse (9);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| GDBRemoteCommunication::PacketResult
 | |
| GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
 | |
| {
 | |
|     packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
 | |
| 
 | |
|     lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
 | |
| 
 | |
|     // verify that we know anything about this pid.
 | |
|     // Scope for locker
 | |
|     {
 | |
|         Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|         if (m_spawned_pids.find(pid) == m_spawned_pids.end())
 | |
|         {
 | |
|             // not a pid we know about
 | |
|             return SendErrorResponse (10);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // go ahead and attempt to kill the spawned process
 | |
|     if (KillSpawnedProcess (pid))
 | |
|         return SendOKResponse ();
 | |
|     else
 | |
|         return SendErrorResponse (11);
 | |
| }
 | |
| 
 | |
| bool
 | |
| GDBRemoteCommunicationServerPlatform::KillSpawnedProcess (lldb::pid_t pid)
 | |
| {
 | |
|     // make sure we know about this process
 | |
|     {
 | |
|         Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|         if (m_spawned_pids.find(pid) == m_spawned_pids.end())
 | |
|             return false;
 | |
|     }
 | |
| 
 | |
|     // first try a SIGTERM (standard kill)
 | |
|     Host::Kill (pid, SIGTERM);
 | |
| 
 | |
|     // check if that worked
 | |
|     for (size_t i=0; i<10; ++i)
 | |
|     {
 | |
|         {
 | |
|             Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|             if (m_spawned_pids.find(pid) == m_spawned_pids.end())
 | |
|             {
 | |
|                 // it is now killed
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
|         usleep (10000);
 | |
|     }
 | |
| 
 | |
|     // check one more time after the final usleep
 | |
|     {
 | |
|         Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|         if (m_spawned_pids.find(pid) == m_spawned_pids.end())
 | |
|             return true;
 | |
|     }
 | |
| 
 | |
|     // the launched process still lives.  Now try killing it again,
 | |
|     // this time with an unblockable signal.
 | |
|     Host::Kill (pid, SIGKILL);
 | |
| 
 | |
|     for (size_t i=0; i<10; ++i)
 | |
|     {
 | |
|         {
 | |
|             Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|             if (m_spawned_pids.find(pid) == m_spawned_pids.end())
 | |
|             {
 | |
|                 // it is now killed
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
|         usleep (10000);
 | |
|     }
 | |
| 
 | |
|     // check one more time after the final usleep
 | |
|     // Scope for locker
 | |
|     {
 | |
|         Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|         if (m_spawned_pids.find(pid) == m_spawned_pids.end())
 | |
|             return true;
 | |
|     }
 | |
| 
 | |
|     // no luck - the process still lives
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| GDBRemoteCommunication::PacketResult
 | |
| GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
 | |
| {
 | |
|     lldb::pid_t pid = m_process_launch_info.GetProcessID ();
 | |
|     m_process_launch_info.Clear ();
 | |
| 
 | |
|     if (pid == LLDB_INVALID_PROCESS_ID)
 | |
|         return SendErrorResponse (1);
 | |
| 
 | |
|     ProcessInstanceInfo proc_info;
 | |
|     if (!Host::GetProcessInfo (pid, proc_info))
 | |
|         return SendErrorResponse (1);
 | |
| 
 | |
|     StreamString response;
 | |
|     CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
 | |
|     return SendPacketNoLock (response.GetData (), response.GetSize ());
 | |
| }
 | |
| 
 | |
| GDBRemoteCommunication::PacketResult
 | |
| GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
 | |
| {
 | |
|     // If this packet is sent to a platform, then change the current working directory
 | |
| 
 | |
|     char cwd[PATH_MAX];
 | |
|     if (getcwd(cwd, sizeof(cwd)) == NULL)
 | |
|         return SendErrorResponse(errno);
 | |
| 
 | |
|     StreamString response;
 | |
|     response.PutBytesAsRawHex8(cwd, strlen(cwd));
 | |
|     return SendPacketNoLock(response.GetData(), response.GetSize());
 | |
| }
 | |
| 
 | |
| GDBRemoteCommunication::PacketResult
 | |
| GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
 | |
| {
 | |
|     packet.SetFilePos (::strlen ("QSetWorkingDir:"));
 | |
|     std::string path;
 | |
|     packet.GetHexByteString (path);
 | |
| 
 | |
|     // If this packet is sent to a platform, then change the current working directory
 | |
|     if (::chdir(path.c_str()) != 0)
 | |
|         return SendErrorResponse (errno);
 | |
|     return SendOKResponse ();
 | |
| }
 | |
| 
 | |
| GDBRemoteCommunication::PacketResult
 | |
| GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet)
 | |
| {
 | |
|     // NOTE: lldb should now be using qProcessInfo for process IDs.  This path here
 | |
|     // should not be used.  It is reporting process id instead of thread id.  The
 | |
|     // correct answer doesn't seem to make much sense for lldb-platform.
 | |
|     // CONSIDER: flip to "unsupported".
 | |
|     lldb::pid_t pid = m_process_launch_info.GetProcessID();
 | |
| 
 | |
|     StreamString response;
 | |
|     response.Printf("QC%" PRIx64, pid);
 | |
| 
 | |
|     // If we launch a process and this GDB server is acting as a platform,
 | |
|     // then we need to clear the process launch state so we can start
 | |
|     // launching another process. In order to launch a process a bunch or
 | |
|     // packets need to be sent: environment packets, working directory,
 | |
|     // disable ASLR, and many more settings. When we launch a process we
 | |
|     // then need to know when to clear this information. Currently we are
 | |
|     // selecting the 'qC' packet as that packet which seems to make the most
 | |
|     // sense.
 | |
|     if (pid != LLDB_INVALID_PROCESS_ID)
 | |
|     {
 | |
|         m_process_launch_info.Clear();
 | |
|     }
 | |
| 
 | |
|     return SendPacketNoLock (response.GetData(), response.GetSize());
 | |
| }
 | |
| 
 | |
| GDBRemoteCommunication::PacketResult
 | |
| GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(StringExtractorGDBRemote &packet)
 | |
| {
 | |
|     StructuredData::Array signal_array;
 | |
| 
 | |
|     const auto &signals = Host::GetUnixSignals();
 | |
|     for (auto signo = signals->GetFirstSignalNumber();
 | |
|          signo != LLDB_INVALID_SIGNAL_NUMBER;
 | |
|          signo = signals->GetNextSignalNumber(signo))
 | |
|     {
 | |
|         auto dictionary = std::make_shared<StructuredData::Dictionary>();
 | |
| 
 | |
|         dictionary->AddIntegerItem("signo", signo);
 | |
|         dictionary->AddStringItem("name", signals->GetSignalAsCString(signo));
 | |
| 
 | |
|         bool suppress, stop, notify;
 | |
|         signals->GetSignalInfo(signo, suppress, stop, notify);
 | |
|         dictionary->AddBooleanItem("suppress", suppress);
 | |
|         dictionary->AddBooleanItem("stop", stop);
 | |
|         dictionary->AddBooleanItem("notify", notify);
 | |
| 
 | |
|         signal_array.Push(dictionary);
 | |
|     }
 | |
| 
 | |
|     StreamString response;
 | |
|     signal_array.Dump(response);
 | |
|     return SendPacketNoLock(response.GetData(), response.GetSize());
 | |
| }
 | |
| 
 | |
| bool
 | |
| GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid)
 | |
| {
 | |
|     Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|     FreePortForProcess(pid);
 | |
|     return m_spawned_pids.erase(pid) > 0;
 | |
| }
 | |
| 
 | |
| bool
 | |
| GDBRemoteCommunicationServerPlatform::ReapDebugserverProcess (void *callback_baton,
 | |
|                                                    lldb::pid_t pid,
 | |
|                                                    bool exited,
 | |
|                                                    int signal,    // Zero for no signal
 | |
|                                                    int status)    // Exit value of process if signal is zero
 | |
| {
 | |
|     GDBRemoteCommunicationServerPlatform *server = (GDBRemoteCommunicationServerPlatform *)callback_baton;
 | |
|     server->DebugserverProcessReaped (pid);
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| Error
 | |
| GDBRemoteCommunicationServerPlatform::LaunchProcess ()
 | |
| {
 | |
|     if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
 | |
|         return Error ("%s: no process command line specified to launch", __FUNCTION__);
 | |
| 
 | |
|     // specify the process monitor if not already set.  This should
 | |
|     // generally be what happens since we need to reap started
 | |
|     // processes.
 | |
|     if (!m_process_launch_info.GetMonitorProcessCallback ())
 | |
|         m_process_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
 | |
| 
 | |
|     Error error = m_platform_sp->LaunchProcess (m_process_launch_info);
 | |
|     if (!error.Success ())
 | |
|     {
 | |
|         fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
 | |
|         return error;
 | |
|     }
 | |
| 
 | |
|     printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID());
 | |
| 
 | |
|     // add to list of spawned processes.  On an lldb-gdbserver, we
 | |
|     // would expect there to be only one.
 | |
|     const auto pid = m_process_launch_info.GetProcessID();
 | |
|     if (pid != LLDB_INVALID_PROCESS_ID)
 | |
|     {
 | |
|         // add to spawned pids
 | |
|         Mutex::Locker locker (m_spawned_pids_mutex);
 | |
|         m_spawned_pids.insert(pid);
 | |
|     }
 | |
| 
 | |
|     return error;
 | |
| }
 | |
| 
 | |
| void
 | |
| GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map)
 | |
| {
 | |
|     m_port_map = port_map;
 | |
| }
 | |
| 
 | |
| uint16_t
 | |
| GDBRemoteCommunicationServerPlatform::GetNextAvailablePort ()
 | |
| {
 | |
|     if (m_port_map.empty())
 | |
|         return 0; // Bind to port zero and get a port, we didn't have any limitations
 | |
| 
 | |
|     for (auto &pair : m_port_map)
 | |
|     {
 | |
|         if (pair.second == LLDB_INVALID_PROCESS_ID)
 | |
|         {
 | |
|             pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
 | |
|             return pair.first;
 | |
|         }
 | |
|     }
 | |
|     return UINT16_MAX;
 | |
| }
 | |
| 
 | |
| bool
 | |
| GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess (uint16_t port, lldb::pid_t pid)
 | |
| {
 | |
|     PortMap::iterator pos = m_port_map.find(port);
 | |
|     if (pos != m_port_map.end())
 | |
|     {
 | |
|         pos->second = pid;
 | |
|         return true;
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| bool
 | |
| GDBRemoteCommunicationServerPlatform::FreePort (uint16_t port)
 | |
| {
 | |
|     PortMap::iterator pos = m_port_map.find(port);
 | |
|     if (pos != m_port_map.end())
 | |
|     {
 | |
|         pos->second = LLDB_INVALID_PROCESS_ID;
 | |
|         return true;
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| bool
 | |
| GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid)
 | |
| {
 | |
|     if (!m_port_map.empty())
 | |
|     {
 | |
|         for (auto &pair : m_port_map)
 | |
|         {
 | |
|             if (pair.second == pid)
 | |
|             {
 | |
|                 pair.second = LLDB_INVALID_PROCESS_ID;
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| const FileSpec&
 | |
| GDBRemoteCommunicationServerPlatform::GetDomainSocketDir()
 | |
| {
 | |
|     static FileSpec g_domainsocket_dir;
 | |
|     static std::once_flag g_once_flag;
 | |
| 
 | |
|     std::call_once(g_once_flag, []() {
 | |
|         const char* domainsocket_dir_env = ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
 | |
|         if (domainsocket_dir_env != nullptr)
 | |
|             g_domainsocket_dir = FileSpec(domainsocket_dir_env, false);
 | |
|         else
 | |
|             HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir);
 | |
|     });
 | |
| 
 | |
|     return g_domainsocket_dir;
 | |
| }
 | |
| 
 | |
| FileSpec
 | |
| GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char* prefix)
 | |
| {
 | |
|     llvm::SmallString<PATH_MAX> socket_path;
 | |
|     llvm::SmallString<PATH_MAX> socket_name((llvm::StringRef(prefix) + ".%%%%%%").str());
 | |
| 
 | |
|     FileSpec socket_path_spec(GetDomainSocketDir());
 | |
|     socket_path_spec.AppendPathComponent(socket_name.c_str());
 | |
| 
 | |
|     llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path);
 | |
|     return FileSpec(socket_path.c_str(), false);
 | |
| }
 | |
| 
 | |
| void
 | |
| GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset)
 | |
| {
 | |
|     m_port_offset = port_offset;
 | |
| }
 |