10b57cec5SDimitry Andric //===-- GDBRemoteCommunicationServerPlatform.h ------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
95ffd83dbSDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H
105ffd83dbSDimitry Andric #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include <map>
130b57cec5SDimitry Andric #include <mutex>
14*bdd1243dSDimitry Andric #include <optional>
150b57cec5SDimitry Andric #include <set>
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "GDBRemoteCommunicationServerCommon.h"
180b57cec5SDimitry Andric #include "lldb/Host/Socket.h"
190b57cec5SDimitry Andric 
20e8d8bef9SDimitry Andric #include "llvm/Support/Error.h"
21e8d8bef9SDimitry Andric 
220b57cec5SDimitry Andric namespace lldb_private {
230b57cec5SDimitry Andric namespace process_gdb_remote {
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric class GDBRemoteCommunicationServerPlatform
260b57cec5SDimitry Andric     : public GDBRemoteCommunicationServerCommon {
270b57cec5SDimitry Andric public:
28e8d8bef9SDimitry Andric   class PortMap {
29e8d8bef9SDimitry Andric   public:
30e8d8bef9SDimitry Andric     // This class is used to restrict the range of ports that
31e8d8bef9SDimitry Andric     // platform created debugserver/gdbserver processes will
32e8d8bef9SDimitry Andric     // communicate on.
33e8d8bef9SDimitry Andric 
34e8d8bef9SDimitry Andric     // Construct an empty map, where empty means any port is allowed.
35e8d8bef9SDimitry Andric     PortMap() = default;
36e8d8bef9SDimitry Andric 
37e8d8bef9SDimitry Andric     // Make a port map with a range of free ports
38e8d8bef9SDimitry Andric     // from min_port to max_port-1.
39e8d8bef9SDimitry Andric     PortMap(uint16_t min_port, uint16_t max_port);
40e8d8bef9SDimitry Andric 
41e8d8bef9SDimitry Andric     // Add a port to the map. If it is already in the map do not modify
42e8d8bef9SDimitry Andric     // its mapping. (used ports remain used, new ports start as free)
43e8d8bef9SDimitry Andric     void AllowPort(uint16_t port);
44e8d8bef9SDimitry Andric 
45e8d8bef9SDimitry Andric     // If we are using a port map where we can only use certain ports,
46e8d8bef9SDimitry Andric     // get the next available port.
47e8d8bef9SDimitry Andric     //
48e8d8bef9SDimitry Andric     // If we are using a port map and we are out of ports, return an error.
49e8d8bef9SDimitry Andric     //
50e8d8bef9SDimitry Andric     // If we aren't using a port map, return 0 to indicate we should bind to
51e8d8bef9SDimitry Andric     // port 0 and then figure out which port we used.
52e8d8bef9SDimitry Andric     llvm::Expected<uint16_t> GetNextAvailablePort();
53e8d8bef9SDimitry Andric 
54e8d8bef9SDimitry Andric     // Tie a port to a process ID. Returns false if the port is not in the port
55e8d8bef9SDimitry Andric     // map. If the port is already in use it will be moved to the given pid.
56e8d8bef9SDimitry Andric     // FIXME: This is and GetNextAvailablePort make create a race condition if
57e8d8bef9SDimitry Andric     // the portmap is shared between processes.
58e8d8bef9SDimitry Andric     bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid);
59e8d8bef9SDimitry Andric 
60e8d8bef9SDimitry Andric     // Free the given port. Returns false if the port is not in the map.
61e8d8bef9SDimitry Andric     bool FreePort(uint16_t port);
62e8d8bef9SDimitry Andric 
63e8d8bef9SDimitry Andric     // Free the port associated with the given pid. Returns false if there is
64e8d8bef9SDimitry Andric     // no port associated with the pid.
65e8d8bef9SDimitry Andric     bool FreePortForProcess(lldb::pid_t pid);
66e8d8bef9SDimitry Andric 
67e8d8bef9SDimitry Andric     // Returns true if there are no ports in the map, regardless of the state
68e8d8bef9SDimitry Andric     // of those ports. Meaning a map with 1 used port is not empty.
69e8d8bef9SDimitry Andric     bool empty() const;
70e8d8bef9SDimitry Andric 
71e8d8bef9SDimitry Andric   private:
72e8d8bef9SDimitry Andric     std::map<uint16_t, lldb::pid_t> m_port_map;
73e8d8bef9SDimitry Andric   };
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   GDBRemoteCommunicationServerPlatform(
760b57cec5SDimitry Andric       const Socket::SocketProtocol socket_protocol, const char *socket_scheme);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   ~GDBRemoteCommunicationServerPlatform() override;
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   Status LaunchProcess() override;
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   // Set both ports to zero to let the platform automatically bind to
830b57cec5SDimitry Andric   // a port chosen by the OS.
840b57cec5SDimitry Andric   void SetPortMap(PortMap &&port_map);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   void SetPortOffset(uint16_t port_offset);
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   void SetInferiorArguments(const lldb_private::Args &args);
890b57cec5SDimitry Andric 
90e8d8bef9SDimitry Andric   // Set port if you want to use a specific port number.
91e8d8bef9SDimitry Andric   // Otherwise port will be set to the port that was chosen for you.
920b57cec5SDimitry Andric   Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname,
93*bdd1243dSDimitry Andric                          lldb::pid_t &pid, std::optional<uint16_t> &port,
940b57cec5SDimitry Andric                          std::string &socket_name);
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   void SetPendingGdbServer(lldb::pid_t pid, uint16_t port,
970b57cec5SDimitry Andric                            const std::string &socket_name);
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric protected:
1000b57cec5SDimitry Andric   const Socket::SocketProtocol m_socket_protocol;
1010b57cec5SDimitry Andric   const std::string m_socket_scheme;
1020b57cec5SDimitry Andric   std::recursive_mutex m_spawned_pids_mutex;
1030b57cec5SDimitry Andric   std::set<lldb::pid_t> m_spawned_pids;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   PortMap m_port_map;
1060b57cec5SDimitry Andric   uint16_t m_port_offset;
1070b57cec5SDimitry Andric   struct {
1080b57cec5SDimitry Andric     lldb::pid_t pid;
1090b57cec5SDimitry Andric     uint16_t port;
1100b57cec5SDimitry Andric     std::string socket_name;
1110b57cec5SDimitry Andric   } m_pending_gdb_server;
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   PacketResult Handle_qLaunchGDBServer(StringExtractorGDBRemote &packet);
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   PacketResult Handle_qQueryGDBServer(StringExtractorGDBRemote &packet);
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet);
1180b57cec5SDimitry Andric 
119e8d8bef9SDimitry Andric   PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet);
120e8d8bef9SDimitry Andric 
1210b57cec5SDimitry Andric   PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet);
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   PacketResult Handle_qC(StringExtractorGDBRemote &packet);
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   PacketResult Handle_jSignalsInfo(StringExtractorGDBRemote &packet);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric private:
1320b57cec5SDimitry Andric   bool KillSpawnedProcess(lldb::pid_t pid);
1330b57cec5SDimitry Andric 
13481ad6265SDimitry Andric   void DebugserverProcessReaped(lldb::pid_t pid);
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   static const FileSpec &GetDomainSocketDir();
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   static FileSpec GetDomainSocketPath(const char *prefix);
1390b57cec5SDimitry Andric 
1405ffd83dbSDimitry Andric   GDBRemoteCommunicationServerPlatform(
1415ffd83dbSDimitry Andric       const GDBRemoteCommunicationServerPlatform &) = delete;
1425ffd83dbSDimitry Andric   const GDBRemoteCommunicationServerPlatform &
1435ffd83dbSDimitry Andric   operator=(const GDBRemoteCommunicationServerPlatform &) = delete;
1440b57cec5SDimitry Andric };
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric } // namespace process_gdb_remote
1470b57cec5SDimitry Andric } // namespace lldb_private
1480b57cec5SDimitry Andric 
1495ffd83dbSDimitry Andric #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H
150