1254721Semaste//===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#ifndef liblldb_GDBRemoteCommunication_h_
10254721Semaste#define liblldb_GDBRemoteCommunication_h_
11254721Semaste
12344779Sdim#include "GDBRemoteCommunicationHistory.h"
13344779Sdim
14314564Sdim#include <condition_variable>
15314564Sdim#include <mutex>
16314564Sdim#include <queue>
17254721Semaste#include <string>
18296417Sdim#include <vector>
19254721Semaste
20254721Semaste#include "lldb/Core/Communication.h"
21353358Sdim#include "lldb/Host/Config.h"
22280031Sdim#include "lldb/Host/HostThread.h"
23341825Sdim#include "lldb/Utility/Args.h"
24344779Sdim#include "lldb/Utility/Listener.h"
25344779Sdim#include "lldb/Utility/Predicate.h"
26344779Sdim#include "lldb/Utility/StringExtractorGDBRemote.h"
27314564Sdim#include "lldb/lldb-public.h"
28254721Semaste
29288943Sdimnamespace lldb_private {
30360784Sdimnamespace repro {
31360784Sdimclass PacketRecorder;
32360784Sdim}
33288943Sdimnamespace process_gdb_remote {
34288943Sdim
35353358Sdimenum GDBStoppointType {
36314564Sdim  eStoppointInvalid = -1,
37314564Sdim  eBreakpointSoftware = 0,
38314564Sdim  eBreakpointHardware,
39314564Sdim  eWatchpointWrite,
40314564Sdim  eWatchpointRead,
41314564Sdim  eWatchpointReadWrite
42353358Sdim};
43288943Sdim
44314564Sdimenum class CompressionType {
45314564Sdim  None = 0,    // no compression
46314564Sdim  ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's
47314564Sdim               // libcompression
48314564Sdim  LZFSE,       // an Apple compression scheme, requires Apple's libcompression
49314564Sdim  LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with
50314564Sdim       // https://code.google.com/p/lz4/
51314564Sdim  LZMA, // Lempel���Ziv���Markov chain algorithm
52288943Sdim};
53288943Sdim
54254721Semasteclass ProcessGDBRemote;
55254721Semaste
56314564Sdimclass GDBRemoteCommunication : public Communication {
57254721Semastepublic:
58314564Sdim  enum {
59314564Sdim    eBroadcastBitRunPacketSent = kLoUserBroadcastBit,
60314564Sdim    eBroadcastBitGdbReadThreadGotNotify =
61314564Sdim        kLoUserBroadcastBit << 1 // Sent when we received a notify packet.
62314564Sdim  };
63288943Sdim
64314564Sdim  enum class PacketType { Invalid = 0, Standard, Notify };
65288943Sdim
66314564Sdim  enum class PacketResult {
67314564Sdim    Success = 0,        // Success
68321369Sdim    ErrorSendFailed,    // Status sending the packet
69314564Sdim    ErrorSendAck,       // Didn't get an ack back after sending a packet
70321369Sdim    ErrorReplyFailed,   // Status getting the reply
71314564Sdim    ErrorReplyTimeout,  // Timed out waiting for reply
72314564Sdim    ErrorReplyInvalid,  // Got a reply but it wasn't valid for the packet that
73314564Sdim                        // was sent
74314564Sdim    ErrorReplyAck,      // Sending reply ack failed
75314564Sdim    ErrorDisconnected,  // We were disconnected
76314564Sdim    ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet
77314564Sdim                        // request
78314564Sdim  };
79288943Sdim
80314564Sdim  // Class to change the timeout for a given scope and restore it to the
81314564Sdim  // original value when the
82314564Sdim  // created ScopedTimeout object got out of scope
83314564Sdim  class ScopedTimeout {
84314564Sdim  public:
85314564Sdim    ScopedTimeout(GDBRemoteCommunication &gdb_comm,
86314564Sdim                  std::chrono::seconds timeout);
87314564Sdim    ~ScopedTimeout();
88288943Sdim
89314564Sdim  private:
90314564Sdim    GDBRemoteCommunication &m_gdb_comm;
91314564Sdim    std::chrono::seconds m_saved_timeout;
92321369Sdim    // Don't ever reduce the timeout for a packet, only increase it. If the
93321369Sdim    // requested timeout if less than the current timeout, we don't set it
94321369Sdim    // and won't need to restore it.
95321369Sdim    bool m_timeout_modified;
96314564Sdim  };
97288943Sdim
98314564Sdim  GDBRemoteCommunication(const char *comm_name, const char *listener_name);
99254721Semaste
100314564Sdim  ~GDBRemoteCommunication() override;
101254721Semaste
102314564Sdim  PacketResult GetAck();
103254721Semaste
104314564Sdim  size_t SendAck();
105254721Semaste
106314564Sdim  size_t SendNack();
107254721Semaste
108314564Sdim  char CalculcateChecksum(llvm::StringRef payload);
109254721Semaste
110314564Sdim  PacketType CheckForPacket(const uint8_t *src, size_t src_len,
111314564Sdim                            StringExtractorGDBRemote &packet);
112254721Semaste
113314564Sdim  bool GetSendAcks() { return m_send_acks; }
114296417Sdim
115314564Sdim  // Set the global packet timeout.
116314564Sdim  //
117314564Sdim  // For clients, this is the timeout that gets used when sending
118314564Sdim  // packets and waiting for responses. For servers, this is used when waiting
119314564Sdim  // for ACKs.
120314564Sdim  std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) {
121314564Sdim    const auto old_packet_timeout = m_packet_timeout;
122314564Sdim    m_packet_timeout = packet_timeout;
123314564Sdim    return old_packet_timeout;
124314564Sdim  }
125254721Semaste
126314564Sdim  std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; }
127254721Semaste
128314564Sdim  // Start a debugserver instance on the current host using the
129314564Sdim  // supplied connection URL.
130321369Sdim  Status StartDebugserverProcess(
131314564Sdim      const char *url,
132314564Sdim      Platform *platform, // If non nullptr, then check with the platform for
133314564Sdim                          // the GDB server binary if it can't be located
134314564Sdim      ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args,
135314564Sdim      int pass_comm_fd); // Communication file descriptor to pass during
136314564Sdim                         // fork/exec to avoid having to connect/accept
137254721Semaste
138314564Sdim  void DumpHistory(Stream &strm);
139254721Semaste
140360784Sdim  void SetPacketRecorder(repro::PacketRecorder *recorder);
141360784Sdim
142344779Sdim  static llvm::Error ConnectLocally(GDBRemoteCommunication &client,
143344779Sdim                                    GDBRemoteCommunication &server);
144344779Sdim
145314564Sdimprotected:
146314564Sdim  std::chrono::seconds m_packet_timeout;
147314564Sdim  uint32_t m_echo_number;
148314564Sdim  LazyBool m_supports_qEcho;
149344779Sdim  GDBRemoteCommunicationHistory m_history;
150314564Sdim  bool m_send_acks;
151314564Sdim  bool m_is_platform; // Set to true if this class represents a platform,
152314564Sdim                      // false if this class represents a debug session for
153314564Sdim                      // a single process
154254721Semaste
155314564Sdim  CompressionType m_compression_type;
156288943Sdim
157314564Sdim  PacketResult SendPacketNoLock(llvm::StringRef payload);
158344779Sdim  PacketResult SendRawPacketNoLock(llvm::StringRef payload,
159344779Sdim                                   bool skip_ack = false);
160288943Sdim
161314564Sdim  PacketResult ReadPacket(StringExtractorGDBRemote &response,
162314564Sdim                          Timeout<std::micro> timeout, bool sync_on_timeout);
163254721Semaste
164341825Sdim  PacketResult ReadPacketWithOutputSupport(
165341825Sdim      StringExtractorGDBRemote &response, Timeout<std::micro> timeout,
166341825Sdim      bool sync_on_timeout,
167341825Sdim      llvm::function_ref<void(llvm::StringRef)> output_callback);
168341825Sdim
169314564Sdim  // Pop a packet from the queue in a thread safe manner
170314564Sdim  PacketResult PopPacketFromQueue(StringExtractorGDBRemote &response,
171314564Sdim                                  Timeout<std::micro> timeout);
172254721Semaste
173314564Sdim  PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response,
174314564Sdim                                   Timeout<std::micro> timeout,
175314564Sdim                                   bool sync_on_timeout);
176288943Sdim
177314564Sdim  bool CompressionIsEnabled() {
178314564Sdim    return m_compression_type != CompressionType::None;
179314564Sdim  }
180288943Sdim
181314564Sdim  // If compression is enabled, decompress the packet in m_bytes and update
182314564Sdim  // m_bytes with the uncompressed version.
183314564Sdim  // Returns 'true' packet was decompressed and m_bytes is the now-decompressed
184314564Sdim  // text.
185314564Sdim  // Returns 'false' if unable to decompress or if the checksum was invalid.
186314564Sdim  //
187314564Sdim  // NB: Once the packet has been decompressed, checksum cannot be computed
188314564Sdim  // based
189314564Sdim  // on m_bytes.  The checksum was for the compressed packet.
190314564Sdim  bool DecompressPacket();
191254721Semaste
192321369Sdim  Status StartListenThread(const char *hostname = "127.0.0.1",
193321369Sdim                           uint16_t port = 0);
194254721Semaste
195314564Sdim  bool JoinListenThread();
196262528Semaste
197314564Sdim  static lldb::thread_result_t ListenThread(lldb::thread_arg_t arg);
198288943Sdim
199314564Sdim  // GDB-Remote read thread
200314564Sdim  //  . this thread constantly tries to read from the communication
201314564Sdim  //    class and stores all packets received in a queue.  The usual
202314564Sdim  //    threads read requests simply pop packets off the queue in the
203314564Sdim  //    usual order.
204314564Sdim  //    This setup allows us to intercept and handle async packets, such
205314564Sdim  //    as the notify packet.
206288943Sdim
207314564Sdim  // This method is defined as part of communication.h
208314564Sdim  // when the read thread gets any bytes it will pass them on to this function
209314564Sdim  void AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast,
210314564Sdim                          lldb::ConnectionStatus status) override;
211314564Sdim
212254721Semasteprivate:
213314564Sdim  std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue
214314564Sdim  std::mutex m_packet_queue_mutex; // Mutex for accessing queue
215314564Sdim  std::condition_variable
216314564Sdim      m_condition_queue_not_empty; // Condition variable to wait for packets
217288943Sdim
218314564Sdim  HostThread m_listen_thread;
219314564Sdim  std::string m_listen_url;
220262528Semaste
221353358Sdim#if defined(HAVE_LIBCOMPRESSION)
222353358Sdim  CompressionType m_decompression_scratch_type = CompressionType::None;
223353358Sdim  void *m_decompression_scratch = nullptr;
224353358Sdim#endif
225344779Sdim
226314564Sdim  DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication);
227254721Semaste};
228254721Semaste
229288943Sdim} // namespace process_gdb_remote
230288943Sdim} // namespace lldb_private
231288943Sdim
232327952Sdimnamespace llvm {
233327952Sdimtemplate <>
234327952Sdimstruct format_provider<
235327952Sdim    lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult> {
236327952Sdim  static void format(const lldb_private::process_gdb_remote::
237327952Sdim                         GDBRemoteCommunication::PacketResult &state,
238327952Sdim                     raw_ostream &Stream, StringRef Style);
239327952Sdim};
240327952Sdim} // namespace llvm
241327952Sdim
242296417Sdim#endif // liblldb_GDBRemoteCommunication_h_
243