1 | //===-- GDBRemoteCommunicationServerPlatform.h ------------------*- C++ -*-===// |
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 | #ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H |
10 | #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H |
11 | |
12 | #include <map> |
13 | #include <mutex> |
14 | #include <optional> |
15 | #include <set> |
16 | |
17 | #include "GDBRemoteCommunicationServerCommon.h" |
18 | #include "lldb/Host/Socket.h" |
19 | |
20 | #include "llvm/Support/Error.h" |
21 | |
22 | namespace lldb_private { |
23 | namespace process_gdb_remote { |
24 | |
25 | class GDBRemoteCommunicationServerPlatform |
26 | : public GDBRemoteCommunicationServerCommon { |
27 | public: |
28 | class PortMap { |
29 | public: |
30 | // This class is used to restrict the range of ports that |
31 | // platform created debugserver/gdbserver processes will |
32 | // communicate on. |
33 | |
34 | // Construct an empty map, where empty means any port is allowed. |
35 | PortMap() = default; |
36 | |
37 | // Make a port map with a range of free ports |
38 | // from min_port to max_port-1. |
39 | PortMap(uint16_t min_port, uint16_t max_port); |
40 | |
41 | // Add a port to the map. If it is already in the map do not modify |
42 | // its mapping. (used ports remain used, new ports start as free) |
43 | void AllowPort(uint16_t port); |
44 | |
45 | // If we are using a port map where we can only use certain ports, |
46 | // get the next available port. |
47 | // |
48 | // If we are using a port map and we are out of ports, return an error. |
49 | // |
50 | // If we aren't using a port map, return 0 to indicate we should bind to |
51 | // port 0 and then figure out which port we used. |
52 | llvm::Expected<uint16_t> GetNextAvailablePort(); |
53 | |
54 | // Tie a port to a process ID. Returns false if the port is not in the port |
55 | // map. If the port is already in use it will be moved to the given pid. |
56 | // FIXME: This is and GetNextAvailablePort make create a race condition if |
57 | // the portmap is shared between processes. |
58 | bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid); |
59 | |
60 | // Free the given port. Returns false if the port is not in the map. |
61 | bool FreePort(uint16_t port); |
62 | |
63 | // Free the port associated with the given pid. Returns false if there is |
64 | // no port associated with the pid. |
65 | bool FreePortForProcess(lldb::pid_t pid); |
66 | |
67 | // Returns true if there are no ports in the map, regardless of the state |
68 | // of those ports. Meaning a map with 1 used port is not empty. |
69 | bool empty() const; |
70 | |
71 | private: |
72 | std::map<uint16_t, lldb::pid_t> m_port_map; |
73 | }; |
74 | |
75 | GDBRemoteCommunicationServerPlatform( |
76 | const Socket::SocketProtocol socket_protocol, const char *socket_scheme); |
77 | |
78 | ~GDBRemoteCommunicationServerPlatform() override; |
79 | |
80 | Status LaunchProcess() override; |
81 | |
82 | // Set both ports to zero to let the platform automatically bind to |
83 | // a port chosen by the OS. |
84 | void SetPortMap(PortMap &&port_map); |
85 | |
86 | void SetPortOffset(uint16_t port_offset); |
87 | |
88 | void SetInferiorArguments(const lldb_private::Args &args); |
89 | |
90 | // Set port if you want to use a specific port number. |
91 | // Otherwise port will be set to the port that was chosen for you. |
92 | Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname, |
93 | lldb::pid_t &pid, std::optional<uint16_t> &port, |
94 | std::string &socket_name); |
95 | |
96 | void SetPendingGdbServer(lldb::pid_t pid, uint16_t port, |
97 | const std::string &socket_name); |
98 | |
99 | protected: |
100 | const Socket::SocketProtocol m_socket_protocol; |
101 | const std::string m_socket_scheme; |
102 | std::recursive_mutex m_spawned_pids_mutex; |
103 | std::set<lldb::pid_t> m_spawned_pids; |
104 | |
105 | PortMap m_port_map; |
106 | uint16_t m_port_offset; |
107 | struct { |
108 | lldb::pid_t pid; |
109 | uint16_t port; |
110 | std::string socket_name; |
111 | } m_pending_gdb_server; |
112 | |
113 | PacketResult Handle_qLaunchGDBServer(StringExtractorGDBRemote &packet); |
114 | |
115 | PacketResult Handle_qQueryGDBServer(StringExtractorGDBRemote &packet); |
116 | |
117 | PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet); |
118 | |
119 | PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet); |
120 | |
121 | PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); |
122 | |
123 | PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); |
124 | |
125 | PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet); |
126 | |
127 | PacketResult Handle_qC(StringExtractorGDBRemote &packet); |
128 | |
129 | PacketResult Handle_jSignalsInfo(StringExtractorGDBRemote &packet); |
130 | |
131 | private: |
132 | bool KillSpawnedProcess(lldb::pid_t pid); |
133 | |
134 | void DebugserverProcessReaped(lldb::pid_t pid); |
135 | |
136 | static const FileSpec &GetDomainSocketDir(); |
137 | |
138 | static FileSpec GetDomainSocketPath(const char *prefix); |
139 | |
140 | GDBRemoteCommunicationServerPlatform( |
141 | const GDBRemoteCommunicationServerPlatform &) = delete; |
142 | const GDBRemoteCommunicationServerPlatform & |
143 | operator=(const GDBRemoteCommunicationServerPlatform &) = delete; |
144 | }; |
145 | |
146 | } // namespace process_gdb_remote |
147 | } // namespace lldb_private |
148 | |
149 | #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H |
150 | |