diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 80a9954ea9e3b..d73766501e758 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "GDBRemoteCommunication.h" +#include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Host/Config.h" #include "lldb/Host/FileSystem.h" @@ -30,6 +31,7 @@ #include #include #include +#include #include #if HAVE_LIBCOMPRESSION @@ -136,6 +138,10 @@ GDBRemoteCommunication::SendNotificationPacketNoLock( GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendRawPacketNoLock(llvm::StringRef packet, bool skip_ack) { + std::chrono::milliseconds delay = ProcessGDBRemote::GetPacketTestDelay(); + if (delay.count() > 0) + std::this_thread::sleep_for(delay); + if (IsConnected()) { Log *log = GetLog(GDBRLog::Packets); ConnectionStatus status = eConnectionStatusSuccess; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 7c4b5a986940a..42afa9fcaa986 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -177,6 +177,12 @@ class PluginProperties : public Properties { const uint32_t idx = ePropertyUseGPacketForReading; return GetPropertyAtIndexAs(idx, true); } + + uint64_t GetPacketTestDelay() const { + const uint32_t idx = ePropertyPacketTestDelay; + return GetPropertyAtIndexAs( + idx, g_processgdbremote_properties[idx].default_uint_value); + } }; std::chrono::seconds ResumeTimeout() { return std::chrono::seconds(5); } @@ -225,6 +231,11 @@ std::chrono::seconds ProcessGDBRemote::GetPacketTimeout() { return std::chrono::seconds(GetGlobalPluginProperties().GetPacketTimeout()); } +std::chrono::milliseconds ProcessGDBRemote::GetPacketTestDelay() { + return std::chrono::milliseconds( + GetGlobalPluginProperties().GetPacketTestDelay()); +} + ArchSpec ProcessGDBRemote::GetSystemArchitecture() { return m_gdb_comm.GetHostArchitecture(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 63215f3e612c8..921dc065ee560 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -67,6 +67,8 @@ class ProcessGDBRemote : public Process, static std::chrono::seconds GetPacketTimeout(); + static std::chrono::milliseconds GetPacketTestDelay(); + ArchSpec GetSystemArchitecture() override; // Check if a given Process diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td index 08dee3089a094..60188d0286678 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td @@ -21,4 +21,10 @@ let Definition = "processgdbremote", Path = "plugin.process.gdb-remote" in { Global, DefaultFalse, Desc<"Specify if the server should use 'g' packets to read registers.">; + def PacketTestDelay + : Property<"packet-test-delay", "UInt64">, + Global, + DefaultUnsignedValue<0>, + Desc<"Specify an artificial delay in milliseconds inserted before " + "sending each packet, for testing purposes.">; } diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestPacketTestDelay.py b/lldb/test/API/functionalities/gdb_remote_client/TestPacketTestDelay.py new file mode 100644 index 0000000000000..6df42d61e4fa9 --- /dev/null +++ b/lldb/test/API/functionalities/gdb_remote_client/TestPacketTestDelay.py @@ -0,0 +1,39 @@ +import time +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test.gdbclientutils import * +from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase + + +class TestPacketTestDelay(GDBRemoteTestBase): + NO_DEBUG_INFO_TESTCASE = True + + def test_packet_test_delay(self): + """Verify that packet-test-delay inserts a delay before each sent packet.""" + + # 1000ms should be long enough that this test doesn't pass by + # accident even on slow machines, but not too long to waste test + # suite time. + DELAY_MS = 1000 + + class MyResponder(MockGDBServerResponder): + def x(self, addr, length): + return "foobar" + + self.server.responder = MyResponder() + target = self.dbg.CreateTargetWithFileAndTargetTriple("", "x86_64-pc-linux") + process = self.connect(target) + + error = lldb.SBError() + start = time.time() + self.runCmd( + "settings set plugin.process.gdb-remote.packet-test-delay %d" % DELAY_MS + ) + # Send a single dummy packet so we can observe the delay. + process.ReadMemory(0x1000, 10, error) + elapsed_ms = (time.time() - start) * 1000 + + self.assertGreaterEqual( + elapsed_ms, DELAY_MS, "Packet was sent faster than the set test delay?" + )