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