217 lines · c
1//===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H10#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H11 12#include "GDBRemoteCommunicationHistory.h"13#include "lldb/Core/Communication.h"14#include "lldb/Host/Config.h"15#include "lldb/Host/Socket.h"16#include "lldb/Utility/Args.h"17#include "lldb/Utility/StringExtractorGDBRemote.h"18#include <mutex>19#include <string>20 21namespace lldb_private {22namespace process_gdb_remote {23 24enum GDBStoppointType {25 eStoppointInvalid = -1,26 eBreakpointSoftware = 0,27 eBreakpointHardware,28 eWatchpointWrite,29 eWatchpointRead,30 eWatchpointReadWrite31};32 33enum class CompressionType {34 None = 0, // no compression35 ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's36 // libcompression37 LZFSE, // an Apple compression scheme, requires Apple's libcompression38 LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with39 // https://code.google.com/p/lz4/40 LZMA, // Lempel–Ziv–Markov chain algorithm41};42 43// Data included in the vFile:fstat packet.44// https://sourceware.org/gdb/onlinedocs/gdb/struct-stat.html#struct-stat45struct GDBRemoteFStatData {46 llvm::support::ubig32_t gdb_st_dev;47 llvm::support::ubig32_t gdb_st_ino;48 llvm::support::ubig32_t gdb_st_mode;49 llvm::support::ubig32_t gdb_st_nlink;50 llvm::support::ubig32_t gdb_st_uid;51 llvm::support::ubig32_t gdb_st_gid;52 llvm::support::ubig32_t gdb_st_rdev;53 llvm::support::ubig64_t gdb_st_size;54 llvm::support::ubig64_t gdb_st_blksize;55 llvm::support::ubig64_t gdb_st_blocks;56 llvm::support::ubig32_t gdb_st_atime;57 llvm::support::ubig32_t gdb_st_mtime;58 llvm::support::ubig32_t gdb_st_ctime;59};60static_assert(sizeof(GDBRemoteFStatData) == 64,61 "size of GDBRemoteFStatData is not 64");62 63enum GDBErrno {64#define HANDLE_ERRNO(name, value) GDB_##name = value,65#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def"66 GDB_EUNKNOWN = 999967};68 69class ProcessGDBRemote;70 71class GDBRemoteCommunication : public Communication {72public:73 enum class PacketType { Invalid = 0, Standard, Notify };74 75 enum class PacketResult {76 Success = 0, // Success77 ErrorSendFailed, // Status sending the packet78 ErrorSendAck, // Didn't get an ack back after sending a packet79 ErrorReplyFailed, // Status getting the reply80 ErrorReplyTimeout, // Timed out waiting for reply81 ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that82 // was sent83 ErrorReplyAck, // Sending reply ack failed84 ErrorDisconnected, // We were disconnected85 ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet86 // request87 };88 89 // Class to change the timeout for a given scope and restore it to the90 // original value when the91 // created ScopedTimeout object got out of scope92 class ScopedTimeout {93 public:94 ScopedTimeout(GDBRemoteCommunication &gdb_comm,95 std::chrono::seconds timeout);96 ~ScopedTimeout();97 98 private:99 GDBRemoteCommunication &m_gdb_comm;100 std::chrono::seconds m_saved_timeout;101 // Don't ever reduce the timeout for a packet, only increase it. If the102 // requested timeout if less than the current timeout, we don't set it103 // and won't need to restore it.104 bool m_timeout_modified;105 };106 107 GDBRemoteCommunication();108 109 ~GDBRemoteCommunication() override;110 111 PacketResult GetAck();112 113 size_t SendAck();114 115 size_t SendNack();116 117 char CalculcateChecksum(llvm::StringRef payload);118 119 PacketType CheckForPacket(const uint8_t *src, size_t src_len,120 StringExtractorGDBRemote &packet);121 122 bool GetSendAcks() { return m_send_acks; }123 124 // Set the global packet timeout.125 //126 // For clients, this is the timeout that gets used when sending127 // packets and waiting for responses. For servers, this is used when waiting128 // for ACKs.129 std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) {130 const auto old_packet_timeout = m_packet_timeout;131 m_packet_timeout = packet_timeout;132 return old_packet_timeout;133 }134 135 std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; }136 137 // Start a debugserver instance on the current host using the138 // supplied connection URL.139 static Status140 StartDebugserverProcess(std::variant<llvm::StringRef, shared_fd_t> comm,141 ProcessLaunchInfo &launch_info,142 const Args *inferior_args);143 144 void DumpHistory(Stream &strm);145 146 /// Expand GDB run-length encoding.147 static std::optional<std::string> ExpandRLE(std::string);148 149protected:150 std::chrono::seconds m_packet_timeout;151 uint32_t m_echo_number;152 LazyBool m_supports_qEcho;153 GDBRemoteCommunicationHistory m_history;154 bool m_send_acks;155 bool m_is_platform; // Set to true if this class represents a platform,156 // false if this class represents a debug session for157 // a single process158 159 std::string m_bytes;160 std::recursive_mutex m_bytes_mutex;161 CompressionType m_compression_type;162 163 PacketResult SendPacketNoLock(llvm::StringRef payload);164 PacketResult SendNotificationPacketNoLock(llvm::StringRef notify_type,165 std::deque<std::string>& queue,166 llvm::StringRef payload);167 PacketResult SendRawPacketNoLock(llvm::StringRef payload,168 bool skip_ack = false);169 170 PacketResult ReadPacket(StringExtractorGDBRemote &response,171 Timeout<std::micro> timeout, bool sync_on_timeout);172 173 PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response,174 Timeout<std::micro> timeout,175 bool sync_on_timeout);176 177 bool CompressionIsEnabled() {178 return m_compression_type != CompressionType::None;179 }180 181 // If compression is enabled, decompress the packet in m_bytes and update182 // m_bytes with the uncompressed version.183 // Returns 'true' packet was decompressed and m_bytes is the now-decompressed184 // text.185 // Returns 'false' if unable to decompress or if the checksum was invalid.186 //187 // NB: Once the packet has been decompressed, checksum cannot be computed188 // based189 // on m_bytes. The checksum was for the compressed packet.190 bool DecompressPacket();191 192private:193#if HAVE_LIBCOMPRESSION194 CompressionType m_decompression_scratch_type = CompressionType::None;195 void *m_decompression_scratch = nullptr;196#endif197 198 GDBRemoteCommunication(const GDBRemoteCommunication &) = delete;199 const GDBRemoteCommunication &200 operator=(const GDBRemoteCommunication &) = delete;201};202 203} // namespace process_gdb_remote204} // namespace lldb_private205 206namespace llvm {207template <>208struct format_provider<209 lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult> {210 static void format(const lldb_private::process_gdb_remote::211 GDBRemoteCommunication::PacketResult &state,212 raw_ostream &Stream, StringRef Style);213};214} // namespace llvm215 216#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H217