10b57cec5SDimitry Andric //===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 95ffd83dbSDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H 105ffd83dbSDimitry Andric #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "GDBRemoteCommunicationHistory.h" 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include <condition_variable> 15349cc55cSDimitry Andric #include <future> 160b57cec5SDimitry Andric #include <mutex> 170b57cec5SDimitry Andric #include <queue> 180b57cec5SDimitry Andric #include <string> 190b57cec5SDimitry Andric #include <vector> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric #include "lldb/Core/Communication.h" 220b57cec5SDimitry Andric #include "lldb/Host/Config.h" 230b57cec5SDimitry Andric #include "lldb/Host/HostThread.h" 240b57cec5SDimitry Andric #include "lldb/Utility/Args.h" 250b57cec5SDimitry Andric #include "lldb/Utility/Listener.h" 260b57cec5SDimitry Andric #include "lldb/Utility/Predicate.h" 270b57cec5SDimitry Andric #include "lldb/Utility/StringExtractorGDBRemote.h" 280b57cec5SDimitry Andric #include "lldb/lldb-public.h" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric namespace lldb_private { 31480093f4SDimitry Andric namespace repro { 32480093f4SDimitry Andric class PacketRecorder; 33480093f4SDimitry Andric } 340b57cec5SDimitry Andric namespace process_gdb_remote { 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric enum GDBStoppointType { 370b57cec5SDimitry Andric eStoppointInvalid = -1, 380b57cec5SDimitry Andric eBreakpointSoftware = 0, 390b57cec5SDimitry Andric eBreakpointHardware, 400b57cec5SDimitry Andric eWatchpointWrite, 410b57cec5SDimitry Andric eWatchpointRead, 420b57cec5SDimitry Andric eWatchpointReadWrite 430b57cec5SDimitry Andric }; 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric enum class CompressionType { 460b57cec5SDimitry Andric None = 0, // no compression 470b57cec5SDimitry Andric ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's 480b57cec5SDimitry Andric // libcompression 490b57cec5SDimitry Andric LZFSE, // an Apple compression scheme, requires Apple's libcompression 500b57cec5SDimitry Andric LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with 510b57cec5SDimitry Andric // https://code.google.com/p/lz4/ 520b57cec5SDimitry Andric LZMA, // Lempel–Ziv–Markov chain algorithm 530b57cec5SDimitry Andric }; 540b57cec5SDimitry Andric 55349cc55cSDimitry Andric // Data included in the vFile:fstat packet. 56349cc55cSDimitry Andric // https://sourceware.org/gdb/onlinedocs/gdb/struct-stat.html#struct-stat 57349cc55cSDimitry Andric struct GDBRemoteFStatData { 58349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_dev; 59349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_ino; 60349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_mode; 61349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_nlink; 62349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_uid; 63349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_gid; 64349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_rdev; 65349cc55cSDimitry Andric llvm::support::ubig64_t gdb_st_size; 66349cc55cSDimitry Andric llvm::support::ubig64_t gdb_st_blksize; 67349cc55cSDimitry Andric llvm::support::ubig64_t gdb_st_blocks; 68349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_atime; 69349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_mtime; 70349cc55cSDimitry Andric llvm::support::ubig32_t gdb_st_ctime; 71349cc55cSDimitry Andric }; 72349cc55cSDimitry Andric static_assert(sizeof(GDBRemoteFStatData) == 64, 73349cc55cSDimitry Andric "size of GDBRemoteFStatData is not 64"); 74349cc55cSDimitry Andric 75349cc55cSDimitry Andric enum GDBErrno { 76349cc55cSDimitry Andric #define HANDLE_ERRNO(name, value) GDB_##name = value, 77349cc55cSDimitry Andric #include "Plugins/Process/gdb-remote/GDBRemoteErrno.def" 78349cc55cSDimitry Andric GDB_EUNKNOWN = 9999 79349cc55cSDimitry Andric }; 80349cc55cSDimitry Andric 810b57cec5SDimitry Andric class ProcessGDBRemote; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric class GDBRemoteCommunication : public Communication { 840b57cec5SDimitry Andric public: 850b57cec5SDimitry Andric enum class PacketType { Invalid = 0, Standard, Notify }; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric enum class PacketResult { 880b57cec5SDimitry Andric Success = 0, // Success 890b57cec5SDimitry Andric ErrorSendFailed, // Status sending the packet 900b57cec5SDimitry Andric ErrorSendAck, // Didn't get an ack back after sending a packet 910b57cec5SDimitry Andric ErrorReplyFailed, // Status getting the reply 920b57cec5SDimitry Andric ErrorReplyTimeout, // Timed out waiting for reply 930b57cec5SDimitry Andric ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that 940b57cec5SDimitry Andric // was sent 950b57cec5SDimitry Andric ErrorReplyAck, // Sending reply ack failed 960b57cec5SDimitry Andric ErrorDisconnected, // We were disconnected 970b57cec5SDimitry Andric ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet 980b57cec5SDimitry Andric // request 990b57cec5SDimitry Andric }; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric // Class to change the timeout for a given scope and restore it to the 1020b57cec5SDimitry Andric // original value when the 1030b57cec5SDimitry Andric // created ScopedTimeout object got out of scope 1040b57cec5SDimitry Andric class ScopedTimeout { 1050b57cec5SDimitry Andric public: 1060b57cec5SDimitry Andric ScopedTimeout(GDBRemoteCommunication &gdb_comm, 1070b57cec5SDimitry Andric std::chrono::seconds timeout); 1080b57cec5SDimitry Andric ~ScopedTimeout(); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric private: 1110b57cec5SDimitry Andric GDBRemoteCommunication &m_gdb_comm; 1120b57cec5SDimitry Andric std::chrono::seconds m_saved_timeout; 1130b57cec5SDimitry Andric // Don't ever reduce the timeout for a packet, only increase it. If the 1140b57cec5SDimitry Andric // requested timeout if less than the current timeout, we don't set it 1150b57cec5SDimitry Andric // and won't need to restore it. 1160b57cec5SDimitry Andric bool m_timeout_modified; 1170b57cec5SDimitry Andric }; 1180b57cec5SDimitry Andric 119*bdd1243dSDimitry Andric GDBRemoteCommunication(); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric ~GDBRemoteCommunication() override; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric PacketResult GetAck(); 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric size_t SendAck(); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric size_t SendNack(); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric char CalculcateChecksum(llvm::StringRef payload); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric PacketType CheckForPacket(const uint8_t *src, size_t src_len, 1320b57cec5SDimitry Andric StringExtractorGDBRemote &packet); 1330b57cec5SDimitry Andric GetSendAcks()1340b57cec5SDimitry Andric bool GetSendAcks() { return m_send_acks; } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric // Set the global packet timeout. 1370b57cec5SDimitry Andric // 1380b57cec5SDimitry Andric // For clients, this is the timeout that gets used when sending 1390b57cec5SDimitry Andric // packets and waiting for responses. For servers, this is used when waiting 1400b57cec5SDimitry Andric // for ACKs. SetPacketTimeout(std::chrono::seconds packet_timeout)1410b57cec5SDimitry Andric std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) { 1420b57cec5SDimitry Andric const auto old_packet_timeout = m_packet_timeout; 1430b57cec5SDimitry Andric m_packet_timeout = packet_timeout; 1440b57cec5SDimitry Andric return old_packet_timeout; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric GetPacketTimeout()1470b57cec5SDimitry Andric std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // Start a debugserver instance on the current host using the 1500b57cec5SDimitry Andric // supplied connection URL. 1510b57cec5SDimitry Andric Status StartDebugserverProcess( 1520b57cec5SDimitry Andric const char *url, 1530b57cec5SDimitry Andric Platform *platform, // If non nullptr, then check with the platform for 1540b57cec5SDimitry Andric // the GDB server binary if it can't be located 1550b57cec5SDimitry Andric ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args, 1560b57cec5SDimitry Andric int pass_comm_fd); // Communication file descriptor to pass during 1570b57cec5SDimitry Andric // fork/exec to avoid having to connect/accept 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric void DumpHistory(Stream &strm); 160480093f4SDimitry Andric 161480093f4SDimitry Andric void SetPacketRecorder(repro::PacketRecorder *recorder); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric static llvm::Error ConnectLocally(GDBRemoteCommunication &client, 1640b57cec5SDimitry Andric GDBRemoteCommunication &server); 1650b57cec5SDimitry Andric 1665ffd83dbSDimitry Andric /// Expand GDB run-length encoding. 1675ffd83dbSDimitry Andric static std::string ExpandRLE(std::string); 1685ffd83dbSDimitry Andric 1690b57cec5SDimitry Andric protected: 1700b57cec5SDimitry Andric std::chrono::seconds m_packet_timeout; 1710b57cec5SDimitry Andric uint32_t m_echo_number; 1720b57cec5SDimitry Andric LazyBool m_supports_qEcho; 1730b57cec5SDimitry Andric GDBRemoteCommunicationHistory m_history; 1740b57cec5SDimitry Andric bool m_send_acks; 1750b57cec5SDimitry Andric bool m_is_platform; // Set to true if this class represents a platform, 1760b57cec5SDimitry Andric // false if this class represents a debug session for 1770b57cec5SDimitry Andric // a single process 1780b57cec5SDimitry Andric 179*bdd1243dSDimitry Andric std::string m_bytes; 180*bdd1243dSDimitry Andric std::recursive_mutex m_bytes_mutex; 1810b57cec5SDimitry Andric CompressionType m_compression_type; 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric PacketResult SendPacketNoLock(llvm::StringRef payload); 18481ad6265SDimitry Andric PacketResult SendNotificationPacketNoLock(llvm::StringRef notify_type, 18581ad6265SDimitry Andric std::deque<std::string>& queue, 18681ad6265SDimitry Andric llvm::StringRef payload); 1870b57cec5SDimitry Andric PacketResult SendRawPacketNoLock(llvm::StringRef payload, 1880b57cec5SDimitry Andric bool skip_ack = false); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric PacketResult ReadPacket(StringExtractorGDBRemote &response, 1910b57cec5SDimitry Andric Timeout<std::micro> timeout, bool sync_on_timeout); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response, 1940b57cec5SDimitry Andric Timeout<std::micro> timeout, 1950b57cec5SDimitry Andric bool sync_on_timeout); 1960b57cec5SDimitry Andric CompressionIsEnabled()1970b57cec5SDimitry Andric bool CompressionIsEnabled() { 1980b57cec5SDimitry Andric return m_compression_type != CompressionType::None; 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric // If compression is enabled, decompress the packet in m_bytes and update 2020b57cec5SDimitry Andric // m_bytes with the uncompressed version. 2030b57cec5SDimitry Andric // Returns 'true' packet was decompressed and m_bytes is the now-decompressed 2040b57cec5SDimitry Andric // text. 2050b57cec5SDimitry Andric // Returns 'false' if unable to decompress or if the checksum was invalid. 2060b57cec5SDimitry Andric // 2070b57cec5SDimitry Andric // NB: Once the packet has been decompressed, checksum cannot be computed 2080b57cec5SDimitry Andric // based 2090b57cec5SDimitry Andric // on m_bytes. The checksum was for the compressed packet. 2100b57cec5SDimitry Andric bool DecompressPacket(); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric Status StartListenThread(const char *hostname = "127.0.0.1", 2130b57cec5SDimitry Andric uint16_t port = 0); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric bool JoinListenThread(); 2160b57cec5SDimitry Andric 21781ad6265SDimitry Andric lldb::thread_result_t ListenThread(); 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric private: 220349cc55cSDimitry Andric // Promise used to grab the port number from listening thread 221349cc55cSDimitry Andric std::promise<uint16_t> m_port_promise; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric HostThread m_listen_thread; 2240b57cec5SDimitry Andric std::string m_listen_url; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric #if defined(HAVE_LIBCOMPRESSION) 2270b57cec5SDimitry Andric CompressionType m_decompression_scratch_type = CompressionType::None; 2280b57cec5SDimitry Andric void *m_decompression_scratch = nullptr; 2290b57cec5SDimitry Andric #endif 2300b57cec5SDimitry Andric 2315ffd83dbSDimitry Andric GDBRemoteCommunication(const GDBRemoteCommunication &) = delete; 2325ffd83dbSDimitry Andric const GDBRemoteCommunication & 2335ffd83dbSDimitry Andric operator=(const GDBRemoteCommunication &) = delete; 2340b57cec5SDimitry Andric }; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric } // namespace process_gdb_remote 2370b57cec5SDimitry Andric } // namespace lldb_private 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric namespace llvm { 2400b57cec5SDimitry Andric template <> 2410b57cec5SDimitry Andric struct format_provider< 2420b57cec5SDimitry Andric lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult> { 2430b57cec5SDimitry Andric static void format(const lldb_private::process_gdb_remote:: 2440b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult &state, 2450b57cec5SDimitry Andric raw_ostream &Stream, StringRef Style); 2460b57cec5SDimitry Andric }; 2470b57cec5SDimitry Andric } // namespace llvm 2480b57cec5SDimitry Andric 2495ffd83dbSDimitry Andric #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H 250