GDBRemoteCommunication.h revision 321369
1254721Semaste//===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#ifndef liblldb_GDBRemoteCommunication_h_
11254721Semaste#define liblldb_GDBRemoteCommunication_h_
12254721Semaste
13254721Semaste// C Includes
14254721Semaste// C++ Includes
15314564Sdim#include <condition_variable>
16314564Sdim#include <mutex>
17314564Sdim#include <queue>
18254721Semaste#include <string>
19296417Sdim#include <vector>
20254721Semaste
21254721Semaste// Other libraries and framework includes
22254721Semaste// Project includes
23254721Semaste#include "lldb/Core/Communication.h"
24254721Semaste#include "lldb/Core/Listener.h"
25280031Sdim#include "lldb/Host/HostThread.h"
26254721Semaste#include "lldb/Host/Predicate.h"
27296417Sdim#include "lldb/Interpreter/Args.h"
28314564Sdim#include "lldb/lldb-public.h"
29254721Semaste
30254721Semaste#include "Utility/StringExtractorGDBRemote.h"
31254721Semaste
32288943Sdimnamespace lldb_private {
33288943Sdimnamespace process_gdb_remote {
34288943Sdim
35314564Sdimtypedef enum {
36314564Sdim  eStoppointInvalid = -1,
37314564Sdim  eBreakpointSoftware = 0,
38314564Sdim  eBreakpointHardware,
39314564Sdim  eWatchpointWrite,
40314564Sdim  eWatchpointRead,
41314564Sdim  eWatchpointReadWrite
42288943Sdim} GDBStoppointType;
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  //------------------------------------------------------------------
116314564Sdim  // Set the global packet timeout.
117314564Sdim  //
118314564Sdim  // For clients, this is the timeout that gets used when sending
119314564Sdim  // packets and waiting for responses. For servers, this is used when waiting
120314564Sdim  // for ACKs.
121314564Sdim  //------------------------------------------------------------------
122314564Sdim  std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) {
123314564Sdim    const auto old_packet_timeout = m_packet_timeout;
124314564Sdim    m_packet_timeout = packet_timeout;
125314564Sdim    return old_packet_timeout;
126314564Sdim  }
127254721Semaste
128314564Sdim  std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; }
129254721Semaste
130314564Sdim  //------------------------------------------------------------------
131314564Sdim  // Start a debugserver instance on the current host using the
132314564Sdim  // supplied connection URL.
133314564Sdim  //------------------------------------------------------------------
134321369Sdim  Status StartDebugserverProcess(
135314564Sdim      const char *url,
136314564Sdim      Platform *platform, // If non nullptr, then check with the platform for
137314564Sdim                          // the GDB server binary if it can't be located
138314564Sdim      ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args,
139314564Sdim      int pass_comm_fd); // Communication file descriptor to pass during
140314564Sdim                         // fork/exec to avoid having to connect/accept
141254721Semaste
142314564Sdim  void DumpHistory(Stream &strm);
143254721Semaste
144314564Sdimprotected:
145314564Sdim  class History {
146314564Sdim  public:
147314564Sdim    enum PacketType {
148314564Sdim      ePacketTypeInvalid = 0,
149314564Sdim      ePacketTypeSend,
150314564Sdim      ePacketTypeRecv
151314564Sdim    };
152296417Sdim
153314564Sdim    struct Entry {
154314564Sdim      Entry()
155314564Sdim          : packet(), type(ePacketTypeInvalid), bytes_transmitted(0),
156314564Sdim            packet_idx(0), tid(LLDB_INVALID_THREAD_ID) {}
157254721Semaste
158314564Sdim      void Clear() {
159314564Sdim        packet.clear();
160314564Sdim        type = ePacketTypeInvalid;
161314564Sdim        bytes_transmitted = 0;
162314564Sdim        packet_idx = 0;
163314564Sdim        tid = LLDB_INVALID_THREAD_ID;
164314564Sdim      }
165314564Sdim      std::string packet;
166314564Sdim      PacketType type;
167314564Sdim      uint32_t bytes_transmitted;
168314564Sdim      uint32_t packet_idx;
169314564Sdim      lldb::tid_t tid;
170314564Sdim    };
171254721Semaste
172314564Sdim    History(uint32_t size);
173254721Semaste
174314564Sdim    ~History();
175254721Semaste
176314564Sdim    // For single char packets for ack, nack and /x03
177314564Sdim    void AddPacket(char packet_char, PacketType type,
178254721Semaste                   uint32_t bytes_transmitted);
179296417Sdim
180314564Sdim    void AddPacket(const std::string &src, uint32_t src_len, PacketType type,
181254721Semaste                   uint32_t bytes_transmitted);
182254721Semaste
183314564Sdim    void Dump(Stream &strm) const;
184254721Semaste
185314564Sdim    void Dump(Log *log) const;
186254721Semaste
187314564Sdim    bool DidDumpToLog() const { return m_dumped_to_log; }
188254721Semaste
189314564Sdim  protected:
190314564Sdim    uint32_t GetFirstSavedPacketIndex() const {
191314564Sdim      if (m_total_packet_count < m_packets.size())
192314564Sdim        return 0;
193314564Sdim      else
194314564Sdim        return m_curr_idx + 1;
195314564Sdim    }
196254721Semaste
197314564Sdim    uint32_t GetNumPacketsInHistory() const {
198314564Sdim      if (m_total_packet_count < m_packets.size())
199314564Sdim        return m_total_packet_count;
200314564Sdim      else
201314564Sdim        return (uint32_t)m_packets.size();
202314564Sdim    }
203254721Semaste
204314564Sdim    uint32_t GetNextIndex() {
205314564Sdim      ++m_total_packet_count;
206314564Sdim      const uint32_t idx = m_curr_idx;
207314564Sdim      m_curr_idx = NormalizeIndex(idx + 1);
208314564Sdim      return idx;
209314564Sdim    }
210254721Semaste
211314564Sdim    uint32_t NormalizeIndex(uint32_t i) const { return i % m_packets.size(); }
212296417Sdim
213314564Sdim    std::vector<Entry> m_packets;
214314564Sdim    uint32_t m_curr_idx;
215314564Sdim    uint32_t m_total_packet_count;
216314564Sdim    mutable bool m_dumped_to_log;
217314564Sdim  };
218254721Semaste
219314564Sdim  std::chrono::seconds m_packet_timeout;
220314564Sdim  uint32_t m_echo_number;
221314564Sdim  LazyBool m_supports_qEcho;
222314564Sdim  History m_history;
223314564Sdim  bool m_send_acks;
224314564Sdim  bool m_is_platform; // Set to true if this class represents a platform,
225314564Sdim                      // false if this class represents a debug session for
226314564Sdim                      // a single process
227254721Semaste
228314564Sdim  CompressionType m_compression_type;
229288943Sdim
230314564Sdim  PacketResult SendPacketNoLock(llvm::StringRef payload);
231288943Sdim
232314564Sdim  PacketResult ReadPacket(StringExtractorGDBRemote &response,
233314564Sdim                          Timeout<std::micro> timeout, bool sync_on_timeout);
234254721Semaste
235314564Sdim  // Pop a packet from the queue in a thread safe manner
236314564Sdim  PacketResult PopPacketFromQueue(StringExtractorGDBRemote &response,
237314564Sdim                                  Timeout<std::micro> timeout);
238254721Semaste
239314564Sdim  PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response,
240314564Sdim                                   Timeout<std::micro> timeout,
241314564Sdim                                   bool sync_on_timeout);
242288943Sdim
243314564Sdim  bool CompressionIsEnabled() {
244314564Sdim    return m_compression_type != CompressionType::None;
245314564Sdim  }
246288943Sdim
247314564Sdim  // If compression is enabled, decompress the packet in m_bytes and update
248314564Sdim  // m_bytes with the uncompressed version.
249314564Sdim  // Returns 'true' packet was decompressed and m_bytes is the now-decompressed
250314564Sdim  // text.
251314564Sdim  // Returns 'false' if unable to decompress or if the checksum was invalid.
252314564Sdim  //
253314564Sdim  // NB: Once the packet has been decompressed, checksum cannot be computed
254314564Sdim  // based
255314564Sdim  // on m_bytes.  The checksum was for the compressed packet.
256314564Sdim  bool DecompressPacket();
257254721Semaste
258321369Sdim  Status StartListenThread(const char *hostname = "127.0.0.1",
259321369Sdim                           uint16_t port = 0);
260254721Semaste
261314564Sdim  bool JoinListenThread();
262262528Semaste
263314564Sdim  static lldb::thread_result_t ListenThread(lldb::thread_arg_t arg);
264288943Sdim
265314564Sdim  // GDB-Remote read thread
266314564Sdim  //  . this thread constantly tries to read from the communication
267314564Sdim  //    class and stores all packets received in a queue.  The usual
268314564Sdim  //    threads read requests simply pop packets off the queue in the
269314564Sdim  //    usual order.
270314564Sdim  //    This setup allows us to intercept and handle async packets, such
271314564Sdim  //    as the notify packet.
272288943Sdim
273314564Sdim  // This method is defined as part of communication.h
274314564Sdim  // when the read thread gets any bytes it will pass them on to this function
275314564Sdim  void AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast,
276314564Sdim                          lldb::ConnectionStatus status) override;
277314564Sdim
278254721Semasteprivate:
279314564Sdim  std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue
280314564Sdim  std::mutex m_packet_queue_mutex; // Mutex for accessing queue
281314564Sdim  std::condition_variable
282314564Sdim      m_condition_queue_not_empty; // Condition variable to wait for packets
283288943Sdim
284314564Sdim  HostThread m_listen_thread;
285314564Sdim  std::string m_listen_url;
286262528Semaste
287314564Sdim  DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication);
288254721Semaste};
289254721Semaste
290288943Sdim} // namespace process_gdb_remote
291288943Sdim} // namespace lldb_private
292288943Sdim
293296417Sdim#endif // liblldb_GDBRemoteCommunication_h_
294