Files
Tim Hutt f108671fa4 [lldb] Ignore notification packets (#204788)
The gdb-protocol spec says

> Recipients should silently ignore corrupted notifications and
notifications they do not understand.

This changes `WaitForPacketNoLock` so that it ignores all notifications
(I'm not sure about corrupted ones).

An example of a notification that causes issues without this change is
that OpenOCD sends `%ookeepalive:00` notifications during memory
accesses.

Fixes #197944
2026-06-29 10:12:17 +01:00

72 lines
2.6 KiB
Python

"""
Test that LLDB ignores notification packets (those beginning with '%')
when waiting for a response to a '$' packet.
OpenOCD is one debug server that uses notification packets to reset
the connection timeout if a memory read takes too long. So that's what
we test here, but it should apply to any exchange.
"""
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test.gdbclientutils import *
from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
class NotifyingServerResponder(MockGDBServerResponder):
def readMemory(self, addr, length):
return "01" * length
class NotifyingServer(MockGDBServer):
def __init__(self, socket):
self._socket = socket
self.responder = NotifyingServerResponder()
self.sent_notification = False
def _sendPacket(self, packet: str, prefix="$"):
# In theory we could add notifies before all packets, but it always
# goes through the same code and just makes the test take longer.
if packet == "01010101":
# Send more than one to make sure we clear them all to find
# the real response.
super()._sendPacket("this_is_a_notification", prefix="%")
super()._sendPacket("this_is_a_2nd_notification", prefix="%")
self.sent_notification = True
super()._sendPacket(packet)
if packet == "01010101":
super()._sendPacket("this_is_a_3rd_notification", prefix="%")
class TestIgnoringNotifications(GDBRemoteTestBase):
def setUp(self):
TestBase.setUp(self)
self.server = NotifyingServer(self.server_socket_class())
self.server.start()
@skipIfLLVMTargetMissing("AArch64")
def test(self):
target = self.createTarget("basic_eh_frame-aarch64.yaml")
if self.TraceOn():
self.runCmd("log enable gdb-remote packets")
self.runCmd("log enable gdb-remote comm")
self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets"))
process = self.connect(target)
lldbutil.expect_state_changes(
self, self.dbg.GetListener(), process, [lldb.eStateStopped]
)
# Disabling cache is not required but makes debugging this test easier.
self.runCmd("settings set target.process.disable-memory-cache true")
# Should succeed despite getting a notification before the real result.
self.expect("memory read --format hex 0x1234 0x1238", substrs=["0x01010101"])
# Check we didn't succeed because lldb got memory in some other way.
self.assertTrue(self.server.sent_notification)