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
22namespace lldb_private {
23namespace process_gdb_remote {
24
25class GDBRemoteCommunicationServerPlatform
26 : public GDBRemoteCommunicationServerCommon {
27public:
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
99protected:
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
131private:
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

source code of lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h