|  | //===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef liblldb_GDBRemoteCommunication_h_ | 
|  | #define liblldb_GDBRemoteCommunication_h_ | 
|  |  | 
|  | // C Includes | 
|  | // C++ Includes | 
|  | #include <list> | 
|  | #include <string> | 
|  |  | 
|  | // Other libraries and framework includes | 
|  | // Project includes | 
|  | #include "lldb/lldb-public.h" | 
|  | #include "lldb/Core/Communication.h" | 
|  | #include "lldb/Core/Listener.h" | 
|  | #include "lldb/Host/Mutex.h" | 
|  | #include "lldb/Host/Predicate.h" | 
|  | #include "lldb/Host/TimeValue.h" | 
|  |  | 
|  | #include "Utility/StringExtractorGDBRemote.h" | 
|  |  | 
|  | class ProcessGDBRemote; | 
|  |  | 
|  | class GDBRemoteCommunication : public lldb_private::Communication | 
|  | { | 
|  | public: | 
|  | enum | 
|  | { | 
|  | eBroadcastBitRunPacketSent = kLoUserBroadcastBit | 
|  | }; | 
|  |  | 
|  | enum class PacketResult | 
|  | { | 
|  | Success = 0,        // Success | 
|  | ErrorSendFailed,    // Error sending the packet | 
|  | ErrorSendAck,       // Didn't get an ack back after sending a packet | 
|  | ErrorReplyFailed,   // Error getting the reply | 
|  | ErrorReplyTimeout,  // Timed out waiting for reply | 
|  | ErrorReplyInvalid,  // Got a reply but it wasn't valid for the packet that was sent | 
|  | ErrorReplyAck,      // Sending reply ack failed | 
|  | ErrorDisconnected,  // We were disconnected | 
|  | ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request | 
|  | }; | 
|  | //------------------------------------------------------------------ | 
|  | // Constructors and Destructors | 
|  | //------------------------------------------------------------------ | 
|  | GDBRemoteCommunication(const char *comm_name, | 
|  | const char *listener_name, | 
|  | bool is_platform); | 
|  |  | 
|  | virtual | 
|  | ~GDBRemoteCommunication(); | 
|  |  | 
|  | PacketResult | 
|  | GetAck (); | 
|  |  | 
|  | size_t | 
|  | SendAck (); | 
|  |  | 
|  | size_t | 
|  | SendNack (); | 
|  |  | 
|  | char | 
|  | CalculcateChecksum (const char *payload, | 
|  | size_t payload_length); | 
|  |  | 
|  | bool | 
|  | GetSequenceMutex (lldb_private::Mutex::Locker& locker, const char *failure_message = NULL); | 
|  |  | 
|  | bool | 
|  | CheckForPacket (const uint8_t *src, | 
|  | size_t src_len, | 
|  | StringExtractorGDBRemote &packet); | 
|  | bool | 
|  | IsRunning() const | 
|  | { | 
|  | return m_public_is_running.GetValue(); | 
|  | } | 
|  |  | 
|  | bool | 
|  | GetSendAcks () | 
|  | { | 
|  | return m_send_acks; | 
|  | } | 
|  |  | 
|  | //------------------------------------------------------------------ | 
|  | // Client and server must implement these pure virtual functions | 
|  | //------------------------------------------------------------------ | 
|  | virtual bool | 
|  | GetThreadSuffixSupported () = 0; | 
|  |  | 
|  | //------------------------------------------------------------------ | 
|  | // Set the global packet timeout. | 
|  | // | 
|  | // For clients, this is the timeout that gets used when sending | 
|  | // packets and waiting for responses. For servers, this might not | 
|  | // get used, and if it doesn't this should be moved to the | 
|  | // GDBRemoteCommunicationClient. | 
|  | //------------------------------------------------------------------ | 
|  | uint32_t | 
|  | SetPacketTimeout (uint32_t packet_timeout) | 
|  | { | 
|  | const uint32_t old_packet_timeout = m_packet_timeout; | 
|  | m_packet_timeout = packet_timeout; | 
|  | return old_packet_timeout; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | GetPacketTimeoutInMicroSeconds () const | 
|  | { | 
|  | return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec; | 
|  | } | 
|  | //------------------------------------------------------------------ | 
|  | // Start a debugserver instance on the current host using the | 
|  | // supplied connection URL. | 
|  | //------------------------------------------------------------------ | 
|  | lldb_private::Error | 
|  | StartDebugserverProcess (const char *hostname, | 
|  | uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit | 
|  | lldb_private::ProcessLaunchInfo &launch_info, | 
|  | uint16_t &out_port); | 
|  |  | 
|  | void | 
|  | DumpHistory(lldb_private::Stream &strm); | 
|  |  | 
|  | protected: | 
|  |  | 
|  | class History | 
|  | { | 
|  | public: | 
|  | enum PacketType | 
|  | { | 
|  | ePacketTypeInvalid = 0, | 
|  | ePacketTypeSend, | 
|  | ePacketTypeRecv | 
|  | }; | 
|  |  | 
|  | struct Entry | 
|  | { | 
|  | Entry() : | 
|  | packet(), | 
|  | type (ePacketTypeInvalid), | 
|  | bytes_transmitted (0), | 
|  | packet_idx (0), | 
|  | tid (LLDB_INVALID_THREAD_ID) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | Clear () | 
|  | { | 
|  | packet.clear(); | 
|  | type = ePacketTypeInvalid; | 
|  | bytes_transmitted = 0; | 
|  | packet_idx = 0; | 
|  | tid = LLDB_INVALID_THREAD_ID; | 
|  | } | 
|  | std::string packet; | 
|  | PacketType type; | 
|  | uint32_t bytes_transmitted; | 
|  | uint32_t packet_idx; | 
|  | lldb::tid_t tid; | 
|  | }; | 
|  |  | 
|  | History (uint32_t size); | 
|  |  | 
|  | ~History (); | 
|  |  | 
|  | // For single char packets for ack, nack and /x03 | 
|  | void | 
|  | AddPacket (char packet_char, | 
|  | PacketType type, | 
|  | uint32_t bytes_transmitted); | 
|  | void | 
|  | AddPacket (const std::string &src, | 
|  | uint32_t src_len, | 
|  | PacketType type, | 
|  | uint32_t bytes_transmitted); | 
|  |  | 
|  | void | 
|  | Dump (lldb_private::Stream &strm) const; | 
|  |  | 
|  | void | 
|  | Dump (lldb_private::Log *log) const; | 
|  |  | 
|  | bool | 
|  | DidDumpToLog () const | 
|  | { | 
|  | return m_dumped_to_log; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | uint32_t | 
|  | GetFirstSavedPacketIndex () const | 
|  | { | 
|  | if (m_total_packet_count < m_packets.size()) | 
|  | return 0; | 
|  | else | 
|  | return m_curr_idx + 1; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | GetNumPacketsInHistory () const | 
|  | { | 
|  | if (m_total_packet_count < m_packets.size()) | 
|  | return m_total_packet_count; | 
|  | else | 
|  | return (uint32_t)m_packets.size(); | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | GetNextIndex() | 
|  | { | 
|  | ++m_total_packet_count; | 
|  | const uint32_t idx = m_curr_idx; | 
|  | m_curr_idx = NormalizeIndex(idx + 1); | 
|  | return idx; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | NormalizeIndex (uint32_t i) const | 
|  | { | 
|  | return i % m_packets.size(); | 
|  | } | 
|  |  | 
|  |  | 
|  | std::vector<Entry> m_packets; | 
|  | uint32_t m_curr_idx; | 
|  | uint32_t m_total_packet_count; | 
|  | mutable bool m_dumped_to_log; | 
|  | }; | 
|  |  | 
|  | PacketResult | 
|  | SendPacket (const char *payload, | 
|  | size_t payload_length); | 
|  |  | 
|  | PacketResult | 
|  | SendPacketNoLock (const char *payload, | 
|  | size_t payload_length); | 
|  |  | 
|  | PacketResult | 
|  | WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response, | 
|  | uint32_t timeout_usec); | 
|  |  | 
|  | bool | 
|  | WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr); | 
|  |  | 
|  | //------------------------------------------------------------------ | 
|  | // Classes that inherit from GDBRemoteCommunication can see and modify these | 
|  | //------------------------------------------------------------------ | 
|  | uint32_t m_packet_timeout; | 
|  | #ifdef ENABLE_MUTEX_ERROR_CHECKING | 
|  | lldb_private::TrackingMutex m_sequence_mutex; | 
|  | #else | 
|  | lldb_private::Mutex m_sequence_mutex;    // Restrict access to sending/receiving packets to a single thread at a time | 
|  | #endif | 
|  | lldb_private::Predicate<bool> m_public_is_running; | 
|  | lldb_private::Predicate<bool> m_private_is_running; | 
|  | History m_history; | 
|  | bool m_send_acks; | 
|  | bool m_is_platform; // Set to true if this class represents a platform, | 
|  | // false if this class represents a debug session for | 
|  | // a single process | 
|  |  | 
|  |  | 
|  | lldb_private::Error | 
|  | StartListenThread (const char *hostname = "127.0.0.1", | 
|  | uint16_t port = 0); | 
|  |  | 
|  | bool | 
|  | JoinListenThread (); | 
|  |  | 
|  | static lldb::thread_result_t | 
|  | ListenThread (lldb::thread_arg_t arg); | 
|  |  | 
|  | private: | 
|  |  | 
|  | lldb::thread_t m_listen_thread; | 
|  | std::string m_listen_url; | 
|  |  | 
|  |  | 
|  | //------------------------------------------------------------------ | 
|  | // For GDBRemoteCommunication only | 
|  | //------------------------------------------------------------------ | 
|  | DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication); | 
|  | }; | 
|  |  | 
|  | #endif  // liblldb_GDBRemoteCommunication_h_ |