diff --git a/lldb/include/lldb/Core/Communication.h b/lldb/include/lldb/Core/Communication.h --- a/lldb/include/lldb/Core/Communication.h +++ b/lldb/include/lldb/Core/Communication.h @@ -188,8 +188,9 @@ /// The number of bytes actually read. /// /// \see size_t Connection::Read (void *, size_t); - size_t Read(void *dst, size_t dst_len, const Timeout &timeout, - lldb::ConnectionStatus &status, Status *error_ptr); + virtual size_t Read(void *dst, size_t dst_len, + const Timeout &timeout, + lldb::ConnectionStatus &status, Status *error_ptr); /// The actual write function that attempts to write to the communications /// protocol. @@ -206,8 +207,8 @@ /// /// \return /// The number of bytes actually Written. - size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, - Status *error_ptr); + virtual size_t Write(const void *src, size_t src_len, + lldb::ConnectionStatus &status, Status *error_ptr); /// Sets the connection that it to be used by this class. /// diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -31,7 +31,9 @@ virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; }; - GDBRemoteClientBase(const char *comm_name, const char *listener_name); + GDBRemoteClientBase(const char *comm_name, const char *listener_name, + std::chrono::nanoseconds delay_multiplier = + std::chrono::nanoseconds::zero()); bool SendAsyncSignal(int signo); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -28,10 +28,11 @@ GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default; -GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name, - const char *listener_name) - : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0), - m_is_running(false), m_should_stop(false) {} +GDBRemoteClientBase::GDBRemoteClientBase( + const char *comm_name, const char *listener_name, + std::chrono::nanoseconds delay_multiplier) + : GDBRemoteCommunication(comm_name, listener_name, delay_multiplier), + m_async_count(0), m_is_running(false), m_should_stop(false) {} StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( ContinueDelegate &delegate, const UnixSignals &signals, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -95,7 +95,9 @@ bool m_timeout_modified; }; - GDBRemoteCommunication(const char *comm_name, const char *listener_name); + GDBRemoteCommunication(const char *comm_name, const char *listener_name, + std::chrono::nanoseconds delay_multiplier = + std::chrono::nanoseconds::zero()); ~GDBRemoteCommunication() override; @@ -156,6 +158,13 @@ // a single process CompressionType m_compression_type; + std::chrono::nanoseconds m_delay_multiplier; + + size_t Read(void *dst, size_t dst_len, const Timeout &timeout, + lldb::ConnectionStatus &status, Status *error_ptr) override; + + size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, + Status *error_ptr) override; PacketResult SendPacketNoLock(llvm::StringRef payload); PacketResult SendRawPacketNoLock(llvm::StringRef payload, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -60,7 +60,8 @@ // GDBRemoteCommunication constructor GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, - const char *listener_name) + const char *listener_name, + std::chrono::nanoseconds delay_multiplier) : Communication(comm_name), #ifdef LLDB_CONFIGURATION_DEBUG m_packet_timeout(1000), @@ -69,7 +70,7 @@ #endif m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512), m_send_acks(true), m_compression_type(CompressionType::None), - m_listen_url() { + m_delay_multiplier(delay_multiplier), m_listen_url() { } // Destructor @@ -98,6 +99,22 @@ return checksum & 255; } +size_t GDBRemoteCommunication::Read(void *dst, size_t dst_len, + const Timeout &timeout, + lldb::ConnectionStatus &status, + Status *error_ptr) { + size_t size = Communication::Read(dst, dst_len, timeout, status, error_ptr); + std::this_thread::sleep_for(m_delay_multiplier * size); + return size; +} + +size_t GDBRemoteCommunication::Write(const void *src, size_t src_len, + ConnectionStatus &status, Status *error_ptr) { + size_t size = Communication::Write(src, src_len, status, error_ptr); + std::this_thread::sleep_for(m_delay_multiplier * size); + return size; + +} size_t GDBRemoteCommunication::SendAck() { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); ConnectionStatus status = eConnectionStatusSuccess; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -51,7 +51,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { public: - GDBRemoteCommunicationClient(); + GDBRemoteCommunicationClient(std::chrono::nanoseconds delay_multiplier = + std::chrono::nanoseconds::zero()); ~GDBRemoteCommunicationClient() override; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -53,8 +53,10 @@ } // GDBRemoteCommunicationClient constructor -GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() - : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet"), +GDBRemoteCommunicationClient::GDBRemoteCommunicationClient( + std::chrono::nanoseconds delay_multiplier) + : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet", + delay_multiplier), m_supports_not_sending_acks(eLazyBoolCalculate), m_supports_thread_suffix(eLazyBoolCalculate), m_supports_threads_in_stop_reply(eLazyBoolCalculate), diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -164,6 +164,12 @@ const uint32_t idx = ePropertyUseGPacketForReading; return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } + + uint64_t GetPacketDelayMultiplier() const { + const uint32_t idx = ePropertyPacketDelayMultiplier; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_processgdbremote_properties[idx].default_uint_value); + } }; typedef std::shared_ptr ProcessKDPPropertiesSP; @@ -252,6 +258,8 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, ListenerSP listener_sp) : Process(target_sp, listener_sp), + m_gdb_comm(std::chrono::nanoseconds( + GetGlobalPluginProperties()->GetPacketDelayMultiplier())), m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(), m_register_info_sp(nullptr), m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"), diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td @@ -17,4 +17,8 @@ Global, DefaultFalse, Desc<"Specify if the server should use 'g' packets to read registers.">; + def PacketDelayMultiplier: Property<"packet-delay-multiplier", "UInt64">, + Global, + DefaultUnsignedValue<0>, + Desc<"If greater than 0, sleep for packet-delay-multiplier * packet size nanoseconds for every packet sent or received.">; }