xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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