1 | //===-- GDBRemoteCommunication.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_GDBREMOTECOMMUNICATION_H |
10 | #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H |
11 | |
12 | #include "GDBRemoteCommunicationHistory.h" |
13 | |
14 | #include <condition_variable> |
15 | #include <future> |
16 | #include <mutex> |
17 | #include <queue> |
18 | #include <string> |
19 | #include <vector> |
20 | |
21 | #include "lldb/Core/Communication.h" |
22 | #include "lldb/Host/Config.h" |
23 | #include "lldb/Host/HostThread.h" |
24 | #include "lldb/Utility/Args.h" |
25 | #include "lldb/Utility/Listener.h" |
26 | #include "lldb/Utility/Predicate.h" |
27 | #include "lldb/Utility/StringExtractorGDBRemote.h" |
28 | #include "lldb/lldb-public.h" |
29 | |
30 | namespace lldb_private { |
31 | namespace repro { |
32 | class PacketRecorder; |
33 | } |
34 | namespace process_gdb_remote { |
35 | |
36 | enum GDBStoppointType { |
37 | eStoppointInvalid = -1, |
38 | eBreakpointSoftware = 0, |
39 | eBreakpointHardware, |
40 | eWatchpointWrite, |
41 | eWatchpointRead, |
42 | eWatchpointReadWrite |
43 | }; |
44 | |
45 | enum class CompressionType { |
46 | None = 0, // no compression |
47 | ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's |
48 | // libcompression |
49 | LZFSE, // an Apple compression scheme, requires Apple's libcompression |
50 | LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with |
51 | // https://code.google.com/p/lz4/ |
52 | LZMA, // Lempel–Ziv–Markov chain algorithm |
53 | }; |
54 | |
55 | // Data included in the vFile:fstat packet. |
56 | // https://sourceware.org/gdb/onlinedocs/gdb/struct-stat.html#struct-stat |
57 | struct GDBRemoteFStatData { |
58 | llvm::support::ubig32_t gdb_st_dev; |
59 | llvm::support::ubig32_t gdb_st_ino; |
60 | llvm::support::ubig32_t gdb_st_mode; |
61 | llvm::support::ubig32_t gdb_st_nlink; |
62 | llvm::support::ubig32_t gdb_st_uid; |
63 | llvm::support::ubig32_t gdb_st_gid; |
64 | llvm::support::ubig32_t gdb_st_rdev; |
65 | llvm::support::ubig64_t gdb_st_size; |
66 | llvm::support::ubig64_t gdb_st_blksize; |
67 | llvm::support::ubig64_t gdb_st_blocks; |
68 | llvm::support::ubig32_t gdb_st_atime; |
69 | llvm::support::ubig32_t gdb_st_mtime; |
70 | llvm::support::ubig32_t gdb_st_ctime; |
71 | }; |
72 | static_assert(sizeof(GDBRemoteFStatData) == 64, |
73 | "size of GDBRemoteFStatData is not 64" ); |
74 | |
75 | enum GDBErrno { |
76 | #define HANDLE_ERRNO(name, value) GDB_##name = value, |
77 | #include "Plugins/Process/gdb-remote/GDBRemoteErrno.def" |
78 | GDB_EUNKNOWN = 9999 |
79 | }; |
80 | |
81 | class ProcessGDBRemote; |
82 | |
83 | class GDBRemoteCommunication : public Communication { |
84 | public: |
85 | enum class PacketType { Invalid = 0, Standard, Notify }; |
86 | |
87 | enum class PacketResult { |
88 | Success = 0, // Success |
89 | ErrorSendFailed, // Status sending the packet |
90 | ErrorSendAck, // Didn't get an ack back after sending a packet |
91 | ErrorReplyFailed, // Status getting the reply |
92 | ErrorReplyTimeout, // Timed out waiting for reply |
93 | ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that |
94 | // was sent |
95 | ErrorReplyAck, // Sending reply ack failed |
96 | ErrorDisconnected, // We were disconnected |
97 | ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet |
98 | // request |
99 | }; |
100 | |
101 | // Class to change the timeout for a given scope and restore it to the |
102 | // original value when the |
103 | // created ScopedTimeout object got out of scope |
104 | class ScopedTimeout { |
105 | public: |
106 | ScopedTimeout(GDBRemoteCommunication &gdb_comm, |
107 | std::chrono::seconds timeout); |
108 | ~ScopedTimeout(); |
109 | |
110 | private: |
111 | GDBRemoteCommunication &m_gdb_comm; |
112 | std::chrono::seconds m_saved_timeout; |
113 | // Don't ever reduce the timeout for a packet, only increase it. If the |
114 | // requested timeout if less than the current timeout, we don't set it |
115 | // and won't need to restore it. |
116 | bool m_timeout_modified; |
117 | }; |
118 | |
119 | GDBRemoteCommunication(); |
120 | |
121 | ~GDBRemoteCommunication() override; |
122 | |
123 | PacketResult GetAck(); |
124 | |
125 | size_t SendAck(); |
126 | |
127 | size_t SendNack(); |
128 | |
129 | char CalculcateChecksum(llvm::StringRef payload); |
130 | |
131 | PacketType (const uint8_t *src, size_t src_len, |
132 | StringExtractorGDBRemote &packet); |
133 | |
134 | bool GetSendAcks() { return m_send_acks; } |
135 | |
136 | // Set the global packet timeout. |
137 | // |
138 | // For clients, this is the timeout that gets used when sending |
139 | // packets and waiting for responses. For servers, this is used when waiting |
140 | // for ACKs. |
141 | std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) { |
142 | const auto old_packet_timeout = m_packet_timeout; |
143 | m_packet_timeout = packet_timeout; |
144 | return old_packet_timeout; |
145 | } |
146 | |
147 | std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; } |
148 | |
149 | // Start a debugserver instance on the current host using the |
150 | // supplied connection URL. |
151 | Status StartDebugserverProcess( |
152 | const char *url, |
153 | Platform *platform, // If non nullptr, then check with the platform for |
154 | // the GDB server binary if it can't be located |
155 | ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args, |
156 | int pass_comm_fd); // Communication file descriptor to pass during |
157 | // fork/exec to avoid having to connect/accept |
158 | |
159 | void DumpHistory(Stream &strm); |
160 | |
161 | void SetPacketRecorder(repro::PacketRecorder *recorder); |
162 | |
163 | static llvm::Error ConnectLocally(GDBRemoteCommunication &client, |
164 | GDBRemoteCommunication &server); |
165 | |
166 | /// Expand GDB run-length encoding. |
167 | static std::string ExpandRLE(std::string); |
168 | |
169 | protected: |
170 | std::chrono::seconds m_packet_timeout; |
171 | uint32_t m_echo_number; |
172 | LazyBool m_supports_qEcho; |
173 | GDBRemoteCommunicationHistory m_history; |
174 | bool m_send_acks; |
175 | bool m_is_platform; // Set to true if this class represents a platform, |
176 | // false if this class represents a debug session for |
177 | // a single process |
178 | |
179 | std::string m_bytes; |
180 | std::recursive_mutex m_bytes_mutex; |
181 | CompressionType m_compression_type; |
182 | |
183 | PacketResult SendPacketNoLock(llvm::StringRef payload); |
184 | PacketResult SendNotificationPacketNoLock(llvm::StringRef notify_type, |
185 | std::deque<std::string>& queue, |
186 | llvm::StringRef payload); |
187 | PacketResult SendRawPacketNoLock(llvm::StringRef payload, |
188 | bool skip_ack = false); |
189 | |
190 | PacketResult (StringExtractorGDBRemote &response, |
191 | Timeout<std::micro> timeout, bool sync_on_timeout); |
192 | |
193 | PacketResult (StringExtractorGDBRemote &response, |
194 | Timeout<std::micro> timeout, |
195 | bool sync_on_timeout); |
196 | |
197 | bool CompressionIsEnabled() { |
198 | return m_compression_type != CompressionType::None; |
199 | } |
200 | |
201 | // If compression is enabled, decompress the packet in m_bytes and update |
202 | // m_bytes with the uncompressed version. |
203 | // Returns 'true' packet was decompressed and m_bytes is the now-decompressed |
204 | // text. |
205 | // Returns 'false' if unable to decompress or if the checksum was invalid. |
206 | // |
207 | // NB: Once the packet has been decompressed, checksum cannot be computed |
208 | // based |
209 | // on m_bytes. The checksum was for the compressed packet. |
210 | bool DecompressPacket(); |
211 | |
212 | Status StartListenThread(const char *hostname = "127.0.0.1" , |
213 | uint16_t port = 0); |
214 | |
215 | bool JoinListenThread(); |
216 | |
217 | lldb::thread_result_t ListenThread(); |
218 | |
219 | private: |
220 | // Promise used to grab the port number from listening thread |
221 | std::promise<uint16_t> m_port_promise; |
222 | |
223 | HostThread m_listen_thread; |
224 | std::string m_listen_url; |
225 | |
226 | #if defined(HAVE_LIBCOMPRESSION) |
227 | CompressionType m_decompression_scratch_type = CompressionType::None; |
228 | void *m_decompression_scratch = nullptr; |
229 | #endif |
230 | |
231 | GDBRemoteCommunication(const GDBRemoteCommunication &) = delete; |
232 | const GDBRemoteCommunication & |
233 | operator=(const GDBRemoteCommunication &) = delete; |
234 | }; |
235 | |
236 | } // namespace process_gdb_remote |
237 | } // namespace lldb_private |
238 | |
239 | namespace llvm { |
240 | template <> |
241 | struct format_provider< |
242 | lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult> { |
243 | static void format(const lldb_private::process_gdb_remote:: |
244 | GDBRemoteCommunication::PacketResult &state, |
245 | raw_ostream &Stream, StringRef Style); |
246 | }; |
247 | } // namespace llvm |
248 | |
249 | #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H |
250 | |