xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
10b57cec5SDimitry Andric //===-- GDBRemoteClientBase.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 
90b57cec5SDimitry Andric #ifndef liblldb_GDBRemoteClientBase_h_
100b57cec5SDimitry Andric #define liblldb_GDBRemoteClientBase_h_
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "GDBRemoteCommunication.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include <condition_variable>
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric namespace lldb_private {
170b57cec5SDimitry Andric namespace process_gdb_remote {
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric class GDBRemoteClientBase : public GDBRemoteCommunication {
200b57cec5SDimitry Andric public:
210b57cec5SDimitry Andric   struct ContinueDelegate {
220b57cec5SDimitry Andric     virtual ~ContinueDelegate();
230b57cec5SDimitry Andric     virtual void HandleAsyncStdout(llvm::StringRef out) = 0;
240b57cec5SDimitry Andric     virtual void HandleAsyncMisc(llvm::StringRef data) = 0;
250b57cec5SDimitry Andric     virtual void HandleStopReply() = 0;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric     /// Process asynchronously-received structured data.
280b57cec5SDimitry Andric     ///
290b57cec5SDimitry Andric     /// \param[in] data
300b57cec5SDimitry Andric     ///   The complete data packet, expected to start with JSON-async.
310b57cec5SDimitry Andric     virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0;
320b57cec5SDimitry Andric   };
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric   GDBRemoteClientBase(const char *comm_name, const char *listener_name);
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   bool SendAsyncSignal(int signo);
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   bool Interrupt();
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   lldb::StateType SendContinuePacketAndWaitForResponse(
410b57cec5SDimitry Andric       ContinueDelegate &delegate, const UnixSignals &signals,
420b57cec5SDimitry Andric       llvm::StringRef payload, StringExtractorGDBRemote &response);
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload,
450b57cec5SDimitry Andric                                             StringExtractorGDBRemote &response,
460b57cec5SDimitry Andric                                             bool send_async);
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   PacketResult SendPacketAndReceiveResponseWithOutputSupport(
490b57cec5SDimitry Andric       llvm::StringRef payload, StringExtractorGDBRemote &response,
500b57cec5SDimitry Andric       bool send_async,
510b57cec5SDimitry Andric       llvm::function_ref<void(llvm::StringRef)> output_callback);
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   bool SendvContPacket(llvm::StringRef payload,
540b57cec5SDimitry Andric                        StringExtractorGDBRemote &response);
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   class Lock {
570b57cec5SDimitry Andric   public:
580b57cec5SDimitry Andric     Lock(GDBRemoteClientBase &comm, bool interrupt);
590b57cec5SDimitry Andric     ~Lock();
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric     explicit operator bool() { return m_acquired; }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric     // Whether we had to interrupt the continue thread to acquire the
640b57cec5SDimitry Andric     // connection.
650b57cec5SDimitry Andric     bool DidInterrupt() const { return m_did_interrupt; }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   private:
680b57cec5SDimitry Andric     std::unique_lock<std::recursive_mutex> m_async_lock;
690b57cec5SDimitry Andric     GDBRemoteClientBase &m_comm;
700b57cec5SDimitry Andric     bool m_acquired;
710b57cec5SDimitry Andric     bool m_did_interrupt;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric     void SyncWithContinueThread(bool interrupt);
740b57cec5SDimitry Andric   };
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric protected:
770b57cec5SDimitry Andric   PacketResult
780b57cec5SDimitry Andric   SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,
790b57cec5SDimitry Andric                                      StringExtractorGDBRemote &response);
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   virtual void OnRunPacketSent(bool first);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric private:
84*9dba64beSDimitry Andric   /// Variables handling synchronization between the Continue thread and any
85*9dba64beSDimitry Andric   /// other threads wishing to send packets over the connection. Either the
86*9dba64beSDimitry Andric   /// continue thread has control over the connection (m_is_running == true) or
87*9dba64beSDimitry Andric   /// the connection is free for an arbitrary number of other senders to take
88*9dba64beSDimitry Andric   /// which indicate their interest by incrementing m_async_count.
89*9dba64beSDimitry Andric   ///
90*9dba64beSDimitry Andric   /// Semantics of individual states:
91*9dba64beSDimitry Andric   ///
92*9dba64beSDimitry Andric   /// - m_continue_packet == false, m_async_count == 0:
93*9dba64beSDimitry Andric   ///   connection is free
94*9dba64beSDimitry Andric   /// - m_continue_packet == true, m_async_count == 0:
95*9dba64beSDimitry Andric   ///   only continue thread is present
96*9dba64beSDimitry Andric   /// - m_continue_packet == true, m_async_count > 0:
97*9dba64beSDimitry Andric   ///   continue thread has control, async threads should interrupt it and wait
98*9dba64beSDimitry Andric   ///   for it to set m_continue_packet to false
99*9dba64beSDimitry Andric   /// - m_continue_packet == false, m_async_count > 0:
100*9dba64beSDimitry Andric   ///   async threads have control, continue thread needs to wait for them to
101*9dba64beSDimitry Andric   ///   finish (m_async_count goes down to 0).
102*9dba64beSDimitry Andric   /// @{
1030b57cec5SDimitry Andric   std::mutex m_mutex;
1040b57cec5SDimitry Andric   std::condition_variable m_cv;
1050b57cec5SDimitry Andric 
106*9dba64beSDimitry Andric   /// Packet with which to resume after an async interrupt. Can be changed by
107*9dba64beSDimitry Andric   /// an async thread e.g. to inject a signal.
108*9dba64beSDimitry Andric   std::string m_continue_packet;
109*9dba64beSDimitry Andric 
110*9dba64beSDimitry Andric   /// When was the interrupt packet sent. Used to make sure we time out if the
111*9dba64beSDimitry Andric   /// stub does not respond to interrupt requests.
112*9dba64beSDimitry Andric   std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time;
113*9dba64beSDimitry Andric 
114*9dba64beSDimitry Andric   /// Number of threads interested in sending.
115*9dba64beSDimitry Andric   uint32_t m_async_count;
116*9dba64beSDimitry Andric 
117*9dba64beSDimitry Andric   /// Whether the continue thread has control.
118*9dba64beSDimitry Andric   bool m_is_running;
119*9dba64beSDimitry Andric 
120*9dba64beSDimitry Andric   /// Whether we should resume after a stop.
121*9dba64beSDimitry Andric   bool m_should_stop;
122*9dba64beSDimitry Andric   /// @}
123*9dba64beSDimitry Andric 
124*9dba64beSDimitry Andric   /// This handles the synchronization between individual async threads. For
125*9dba64beSDimitry Andric   /// now they just use a simple mutex.
1260b57cec5SDimitry Andric   std::recursive_mutex m_async_mutex;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   bool ShouldStop(const UnixSignals &signals,
1290b57cec5SDimitry Andric                   StringExtractorGDBRemote &response);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   class ContinueLock {
1320b57cec5SDimitry Andric   public:
1330b57cec5SDimitry Andric     enum class LockResult { Success, Cancelled, Failed };
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric     explicit ContinueLock(GDBRemoteClientBase &comm);
1360b57cec5SDimitry Andric     ~ContinueLock();
1370b57cec5SDimitry Andric     explicit operator bool() { return m_acquired; }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     LockResult lock();
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric     void unlock();
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   private:
1440b57cec5SDimitry Andric     GDBRemoteClientBase &m_comm;
1450b57cec5SDimitry Andric     bool m_acquired;
1460b57cec5SDimitry Andric   };
1470b57cec5SDimitry Andric };
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric } // namespace process_gdb_remote
1500b57cec5SDimitry Andric } // namespace lldb_private
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric #endif // liblldb_GDBRemoteCommunicationClient_h_
153