1 //===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef liblldb_GDBRemoteCommunication_h_ 11 #define liblldb_GDBRemoteCommunication_h_ 12 13 // C Includes 14 // C++ Includes 15 #include <string> 16 #include <queue> 17 #include <vector> 18 19 // Other libraries and framework includes 20 // Project includes 21 #include "lldb/lldb-public.h" 22 #include "lldb/Core/Communication.h" 23 #include "lldb/Core/Listener.h" 24 #include "lldb/Host/HostThread.h" 25 #include "lldb/Host/Mutex.h" 26 #include "lldb/Host/Predicate.h" 27 #include "lldb/Host/TimeValue.h" 28 29 #include "Utility/StringExtractorGDBRemote.h" 30 31 namespace lldb_private { 32 namespace process_gdb_remote { 33 34 typedef enum 35 { 36 eStoppointInvalid = -1, 37 eBreakpointSoftware = 0, 38 eBreakpointHardware, 39 eWatchpointWrite, 40 eWatchpointRead, 41 eWatchpointReadWrite 42 } GDBStoppointType; 43 44 enum class CompressionType 45 { 46 None = 0, // no compression 47 ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's libcompression 48 LZFSE, // an Apple compression scheme, requires Apple's libcompression 49 LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with https://code.google.com/p/lz4/ 50 LZMA, // Lempel–Ziv–Markov chain algorithm 51 }; 52 53 class ProcessGDBRemote; 54 55 class GDBRemoteCommunication : public Communication 56 { 57 public: 58 enum 59 { 60 eBroadcastBitRunPacketSent = kLoUserBroadcastBit, 61 eBroadcastBitGdbReadThreadGotNotify = kLoUserBroadcastBit << 1 // Sent when we received a notify packet. 62 }; 63 64 enum class PacketType 65 { 66 Invalid = 0, 67 Standard, 68 Notify 69 }; 70 71 enum class PacketResult 72 { 73 Success = 0, // Success 74 ErrorSendFailed, // Error sending the packet 75 ErrorSendAck, // Didn't get an ack back after sending a packet 76 ErrorReplyFailed, // Error getting the reply 77 ErrorReplyTimeout, // Timed out waiting for reply 78 ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that was sent 79 ErrorReplyAck, // Sending reply ack failed 80 ErrorDisconnected, // We were disconnected 81 ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request 82 }; 83 84 // Class to change the timeout for a given scope and restore it to the original value when the 85 // created ScopedTimeout object got out of scope 86 class ScopedTimeout 87 { 88 public: 89 ScopedTimeout (GDBRemoteCommunication& gdb_comm, uint32_t timeout); 90 ~ScopedTimeout (); 91 92 private: 93 GDBRemoteCommunication& m_gdb_comm; 94 uint32_t m_saved_timeout; 95 }; 96 97 GDBRemoteCommunication(const char *comm_name, 98 const char *listener_name); 99 100 ~GDBRemoteCommunication() override; 101 102 PacketResult 103 GetAck (); 104 105 size_t 106 SendAck (); 107 108 size_t 109 SendNack (); 110 111 char 112 CalculcateChecksum (const char *payload, 113 size_t payload_length); 114 115 bool 116 GetSequenceMutex(Mutex::Locker& locker, const char *failure_message = nullptr); 117 118 PacketType 119 CheckForPacket (const uint8_t *src, 120 size_t src_len, 121 StringExtractorGDBRemote &packet); 122 123 bool 124 IsRunning() const 125 { 126 return m_public_is_running.GetValue(); 127 } 128 129 bool 130 GetSendAcks () 131 { 132 return m_send_acks; 133 } 134 135 //------------------------------------------------------------------ 136 // Client and server must implement these pure virtual functions 137 //------------------------------------------------------------------ 138 virtual bool 139 GetThreadSuffixSupported () = 0; 140 141 //------------------------------------------------------------------ 142 // Set the global packet timeout. 143 // 144 // For clients, this is the timeout that gets used when sending 145 // packets and waiting for responses. For servers, this might not 146 // get used, and if it doesn't this should be moved to the 147 // GDBRemoteCommunicationClient. 148 //------------------------------------------------------------------ 149 uint32_t 150 SetPacketTimeout (uint32_t packet_timeout) 151 { 152 const uint32_t old_packet_timeout = m_packet_timeout; 153 m_packet_timeout = packet_timeout; 154 return old_packet_timeout; 155 } 156 157 uint32_t 158 GetPacketTimeoutInMicroSeconds () const 159 { 160 return m_packet_timeout * TimeValue::MicroSecPerSec; 161 } 162 163 //------------------------------------------------------------------ 164 // Start a debugserver instance on the current host using the 165 // supplied connection URL. 166 //------------------------------------------------------------------ 167 Error 168 StartDebugserverProcess(const char *url, 169 Platform *platform, // If non nullptr, then check with the platform for the GDB server binary if it can't be located 170 ProcessLaunchInfo &launch_info, 171 uint16_t *port); 172 173 void 174 DumpHistory(Stream &strm); 175 176 protected: 177 class History 178 { 179 public: 180 enum PacketType 181 { 182 ePacketTypeInvalid = 0, 183 ePacketTypeSend, 184 ePacketTypeRecv 185 }; 186 187 struct Entry 188 { 189 Entry() : 190 packet(), 191 type (ePacketTypeInvalid), 192 bytes_transmitted (0), 193 packet_idx (0), 194 tid (LLDB_INVALID_THREAD_ID) 195 { 196 } 197 198 void 199 Clear () 200 { 201 packet.clear(); 202 type = ePacketTypeInvalid; 203 bytes_transmitted = 0; 204 packet_idx = 0; 205 tid = LLDB_INVALID_THREAD_ID; 206 } 207 std::string packet; 208 PacketType type; 209 uint32_t bytes_transmitted; 210 uint32_t packet_idx; 211 lldb::tid_t tid; 212 }; 213 214 History (uint32_t size); 215 216 ~History (); 217 218 // For single char packets for ack, nack and /x03 219 void 220 AddPacket (char packet_char, 221 PacketType type, 222 uint32_t bytes_transmitted); 223 224 void 225 AddPacket (const std::string &src, 226 uint32_t src_len, 227 PacketType type, 228 uint32_t bytes_transmitted); 229 230 void 231 Dump (Stream &strm) const; 232 233 void 234 Dump (Log *log) const; 235 236 bool 237 DidDumpToLog () const 238 { 239 return m_dumped_to_log; 240 } 241 242 protected: 243 uint32_t 244 GetFirstSavedPacketIndex () const 245 { 246 if (m_total_packet_count < m_packets.size()) 247 return 0; 248 else 249 return m_curr_idx + 1; 250 } 251 252 uint32_t 253 GetNumPacketsInHistory () const 254 { 255 if (m_total_packet_count < m_packets.size()) 256 return m_total_packet_count; 257 else 258 return (uint32_t)m_packets.size(); 259 } 260 261 uint32_t 262 GetNextIndex() 263 { 264 ++m_total_packet_count; 265 const uint32_t idx = m_curr_idx; 266 m_curr_idx = NormalizeIndex(idx + 1); 267 return idx; 268 } 269 270 uint32_t 271 NormalizeIndex (uint32_t i) const 272 { 273 return i % m_packets.size(); 274 } 275 276 std::vector<Entry> m_packets; 277 uint32_t m_curr_idx; 278 uint32_t m_total_packet_count; 279 mutable bool m_dumped_to_log; 280 }; 281 282 uint32_t m_packet_timeout; 283 uint32_t m_echo_number; 284 LazyBool m_supports_qEcho; 285 #ifdef ENABLE_MUTEX_ERROR_CHECKING 286 TrackingMutex m_sequence_mutex; 287 #else 288 Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time 289 #endif 290 Predicate<bool> m_public_is_running; 291 Predicate<bool> m_private_is_running; 292 History m_history; 293 bool m_send_acks; 294 bool m_is_platform; // Set to true if this class represents a platform, 295 // false if this class represents a debug session for 296 // a single process 297 298 CompressionType m_compression_type; 299 300 PacketResult 301 SendPacket (const char *payload, 302 size_t payload_length); 303 304 PacketResult 305 SendPacketNoLock (const char *payload, 306 size_t payload_length); 307 308 PacketResult 309 ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout); 310 311 // Pop a packet from the queue in a thread safe manner 312 PacketResult 313 PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec); 314 315 PacketResult 316 WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response, 317 uint32_t timeout_usec, 318 bool sync_on_timeout); 319 320 bool 321 WaitForNotRunningPrivate (const TimeValue *timeout_ptr); 322 323 bool 324 CompressionIsEnabled () 325 { 326 return m_compression_type != CompressionType::None; 327 } 328 329 // If compression is enabled, decompress the packet in m_bytes and update 330 // m_bytes with the uncompressed version. 331 // Returns 'true' packet was decompressed and m_bytes is the now-decompressed text. 332 // Returns 'false' if unable to decompress or if the checksum was invalid. 333 // 334 // NB: Once the packet has been decompressed, checksum cannot be computed based 335 // on m_bytes. The checksum was for the compressed packet. 336 bool 337 DecompressPacket (); 338 339 Error 340 StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); 341 342 bool 343 JoinListenThread (); 344 345 static lldb::thread_result_t 346 ListenThread (lldb::thread_arg_t arg); 347 348 // GDB-Remote read thread 349 // . this thread constantly tries to read from the communication 350 // class and stores all packets received in a queue. The usual 351 // threads read requests simply pop packets off the queue in the 352 // usual order. 353 // This setup allows us to intercept and handle async packets, such 354 // as the notify packet. 355 356 // This method is defined as part of communication.h 357 // when the read thread gets any bytes it will pass them on to this function 358 void AppendBytesToCache(const uint8_t * bytes, 359 size_t len, 360 bool broadcast, 361 lldb::ConnectionStatus status) override; 362 363 private: 364 std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue 365 lldb_private::Mutex m_packet_queue_mutex; // Mutex for accessing queue 366 Condition m_condition_queue_not_empty; // Condition variable to wait for packets 367 368 HostThread m_listen_thread; 369 std::string m_listen_url; 370 371 DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication); 372 }; 373 374 } // namespace process_gdb_remote 375 } // namespace lldb_private 376 377 #endif // liblldb_GDBRemoteCommunication_h_ 378