https://github.com/dlgus8648 updated https://github.com/llvm/llvm-project/pull/202556
>From 3fc3e8f91128ad4f907e7f53ff41a50076c8c48e Mon Sep 17 00:00:00 2001 From: KIMRIHYEON <[email protected]> Date: Tue, 9 Jun 2026 18:07:43 +0900 Subject: [PATCH] [lldb] Ignore async notification packets while waiting for a response OpenOCD's gdbserver sends an async notification packet ("%oocd_keepalive:XX#cc") roughly every 500ms while a long memory read/write is in progress. WaitForPacketNoLock() treated any non-invalid packet returned by CheckForPacket() -- including a PacketType::Notify -- as the response to the pending request, so a keepalive arriving during a memory write produced: unexpected response to GDB server memory write packet 'M2ffff8,4:54430000': 'oocd_keepalive:00' GDB has silently dropped unknown notifications received while waiting for a packet since 7.0 (2009). Match that behaviour: drop notification packets and keep waiting for the actual response. The LLDB client does not otherwise consume '%' notifications, so this is safe. Adds a unit test covering single and multiple notifications preceding the response. Fixes #197944. Assisted-by: Claude Code (Anthropic) --- .../gdb-remote/GDBRemoteCommunication.cpp | 24 +++++++++++++++++-- .../gdb-remote/GDBRemoteCommunicationTest.cpp | 19 +++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 04f486882e2c2..56d1d8bc09fb1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -242,7 +242,17 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, Log *log = GetLog(GDBRLog::Packets); // Check for a packet from our cache first without trying any reading... - if (CheckForPacket(nullptr, 0, packet) != PacketType::Invalid) + // Async notification packets (e.g. OpenOCD's "oocd_keepalive", sent during + // long memory operations) are not responses to our request. GDB silently + // drops such notifications while waiting for a packet; do the same and keep + // looking for the actual response. + PacketType packet_type = CheckForPacket(nullptr, 0, packet); + while (packet_type == PacketType::Notify) { + LLDB_LOGF(log, "GDBRemoteCommunication::%s ignoring notification packet", + __FUNCTION__); + packet_type = CheckForPacket(nullptr, 0, packet); + } + if (packet_type != PacketType::Invalid) return PacketResult::Success; bool timed_out = false; @@ -258,7 +268,17 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, error, bytes_read); if (bytes_read > 0) { - if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) + // Drop any async notification packets (see above) and keep waiting for + // the actual response. Once the freshly-read bytes have been consumed, + // re-check the cache for any further buffered packets. + packet_type = CheckForPacket(buffer, bytes_read, packet); + while (packet_type == PacketType::Notify) { + LLDB_LOGF(log, + "GDBRemoteCommunication::%s ignoring notification packet", + __FUNCTION__); + packet_type = CheckForPacket(nullptr, 0, packet); + } + if (packet_type != PacketType::Invalid) return PacketResult::Success; } else { switch (status) { diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp index e96d587b10e25..2491ace98565b 100644 --- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp +++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp @@ -75,6 +75,25 @@ TEST_F(GDBRemoteCommunicationTest, ReadPacket) { } } +// Test that async notification packets received while waiting for a response +// are silently dropped and that we keep looking for the actual response. +// OpenOCD sends a "%oocd_keepalive:XX#cc" notification during long memory +// operations; like GDB (since 7.0), LLDB must ignore it rather than mistake it +// for the response. See https://github.com/llvm/llvm-project/issues/197944. +TEST_F(GDBRemoteCommunicationTest, ReadPacketIgnoresNotifications) { + StringExtractorGDBRemote response; + + // A single notification ahead of the response. + ASSERT_TRUE(Write("%oocd_keepalive:00#54$OK#9a")); + ASSERT_EQ(PacketResult::Success, client.ReadPacket(response)); + EXPECT_EQ("OK", response.GetStringRef()); + + // Several notifications ahead of the response. + ASSERT_TRUE(Write("%oocd_keepalive:01#55%oocd_keepalive:02#56$OK#9a")); + ASSERT_EQ(PacketResult::Success, client.ReadPacket(response)); + EXPECT_EQ("OK", response.GetStringRef()); +} + // Test that packets with incorrect RLE sequences do not cause a crash and // reported as invalid. TEST_F(GDBRemoteCommunicationTest, CheckForPacket) { _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
