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