[lldb] Fix qEcho message handling (#145072)

Patch fixes the sync-on-timeout logic in lldb and switches to qEcho
based ping, instead of qC. This fixes vRun message case, when there is
no process yet and qC returns an error.
This commit is contained in:
eleviant
2025-06-21 22:48:08 +02:00
committed by GitHub
parent 056b52df34
commit e066f35c69
4 changed files with 85 additions and 2 deletions

View File

@@ -92,6 +92,9 @@ class MockGDBServerResponder:
class RESPONSE_DISCONNECT:
pass
class RESPONSE_NONE:
pass
def __init__(self):
self.packetLog = []
@@ -181,6 +184,8 @@ class MockGDBServerResponder:
return self.qQueryGDBServer()
if packet == "qHostInfo":
return self.qHostInfo()
if packet.startswith("qEcho"):
return self.qEcho(int(packet.split(":")[1]))
if packet == "qGetWorkingDir":
return self.qGetWorkingDir()
if packet == "qOffsets":
@@ -237,6 +242,9 @@ class MockGDBServerResponder:
def qHostInfo(self):
return "ptrsize:8;endian:little;"
def qEcho(self):
return "E04"
def qQueryGDBServer(self):
return "E04"
@@ -655,6 +663,8 @@ class MockGDBServer:
if not isinstance(response, list):
response = [response]
for part in response:
if part is MockGDBServerResponder.RESPONSE_NONE:
continue
if part is MockGDBServerResponder.RESPONSE_DISCONNECT:
raise self.TerminateConnectionException()
self._sendPacket(part)

View File

@@ -354,8 +354,9 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
disconnected = true;
Disconnect();
}
} else {
timed_out = true;
}
timed_out = true;
break;
case eConnectionStatusSuccess:
// printf ("status = success but error = %s\n",

View File

@@ -406,7 +406,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_qXfer_memory_map_read = eLazyBoolYes;
else if (x == "qXfer:siginfo:read+")
m_supports_qXfer_siginfo_read = eLazyBoolYes;
else if (x == "qEcho")
else if (x == "qEcho+")
m_supports_qEcho = eLazyBoolYes;
else if (x == "QPassSignals+")
m_supports_QPassSignals = eLazyBoolYes;

View File

@@ -356,6 +356,78 @@ class TestGDBRemoteClient(GDBRemoteTestBase):
["vRun;%s;61726731;61726732;61726733" % (exe_hex,)]
)
def test_launch_lengthy_vRun(self):
class MyResponder(MockGDBServerResponder):
def __init__(self, *args, **kwargs):
self.started = False
return super().__init__(*args, **kwargs)
def qC(self):
if self.started:
return "QCp10.10"
else:
return "E42"
def qfThreadInfo(self):
if self.started:
return "mp10.10"
else:
return "E42"
def qsThreadInfo(self):
return "l"
def qEcho(self, num):
resp = "qEcho:" + str(num)
if num >= 2:
# We have launched our program
self.started = True
return [resp, "T13"]
return resp
def qSupported(self, client_supported):
return "PacketSize=3fff;QStartNoAckMode+;qEcho+;"
def qHostInfo(self):
return "default_packet_timeout:1;"
def vRun(self, packet):
return [self.RESPONSE_NONE]
def A(self, packet):
return "E28"
self.server.responder = MyResponder()
target = self.createTarget("a.yaml")
# NB: apparently GDB packets are using "/" on Windows too
exe_path = self.getBuildArtifact("a").replace(os.path.sep, "/")
exe_hex = binascii.b2a_hex(exe_path.encode()).decode()
process = self.connect(target)
lldbutil.expect_state_changes(
self, self.dbg.GetListener(), process, [lldb.eStateConnected]
)
process = target.Launch(
lldb.SBListener(),
["arg1", "arg2", "arg3"], # argv
[], # envp
None, # stdin_path
None, # stdout_path
None, # stderr_path
None, # working_directory
0, # launch_flags
True, # stop_at_entry
lldb.SBError(),
) # error
self.assertTrue(process, PROCESS_IS_VALID)
self.assertEqual(process.GetProcessID(), 16)
self.assertPacketLogContains(
["vRun;%s;61726731;61726732;61726733" % (exe_hex,)]
)
def test_launch_QEnvironment(self):
class MyResponder(MockGDBServerResponder):
def qC(self):