Skip to content

Commit e066f35

Browse files
authored
[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.
1 parent 056b52d commit e066f35

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

lldb/packages/Python/lldbsuite/test/gdbclientutils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class MockGDBServerResponder:
9292
class RESPONSE_DISCONNECT:
9393
pass
9494

95+
class RESPONSE_NONE:
96+
pass
97+
9598
def __init__(self):
9699
self.packetLog = []
97100

@@ -181,6 +184,8 @@ def respond(self, packet):
181184
return self.qQueryGDBServer()
182185
if packet == "qHostInfo":
183186
return self.qHostInfo()
187+
if packet.startswith("qEcho"):
188+
return self.qEcho(int(packet.split(":")[1]))
184189
if packet == "qGetWorkingDir":
185190
return self.qGetWorkingDir()
186191
if packet == "qOffsets":
@@ -237,6 +242,9 @@ def qProcessInfo(self):
237242
def qHostInfo(self):
238243
return "ptrsize:8;endian:little;"
239244

245+
def qEcho(self):
246+
return "E04"
247+
240248
def qQueryGDBServer(self):
241249
return "E04"
242250

@@ -655,6 +663,8 @@ def _handlePacket(self, packet):
655663
if not isinstance(response, list):
656664
response = [response]
657665
for part in response:
666+
if part is MockGDBServerResponder.RESPONSE_NONE:
667+
continue
658668
if part is MockGDBServerResponder.RESPONSE_DISCONNECT:
659669
raise self.TerminateConnectionException()
660670
self._sendPacket(part)

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,9 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
354354
disconnected = true;
355355
Disconnect();
356356
}
357+
} else {
358+
timed_out = true;
357359
}
358-
timed_out = true;
359360
break;
360361
case eConnectionStatusSuccess:
361362
// printf ("status = success but error = %s\n",

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
406406
m_supports_qXfer_memory_map_read = eLazyBoolYes;
407407
else if (x == "qXfer:siginfo:read+")
408408
m_supports_qXfer_siginfo_read = eLazyBoolYes;
409-
else if (x == "qEcho")
409+
else if (x == "qEcho+")
410410
m_supports_qEcho = eLazyBoolYes;
411411
else if (x == "QPassSignals+")
412412
m_supports_QPassSignals = eLazyBoolYes;

lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,78 @@ def A(self, packet):
356356
["vRun;%s;61726731;61726732;61726733" % (exe_hex,)]
357357
)
358358

359+
def test_launch_lengthy_vRun(self):
360+
class MyResponder(MockGDBServerResponder):
361+
def __init__(self, *args, **kwargs):
362+
self.started = False
363+
return super().__init__(*args, **kwargs)
364+
365+
def qC(self):
366+
if self.started:
367+
return "QCp10.10"
368+
else:
369+
return "E42"
370+
371+
def qfThreadInfo(self):
372+
if self.started:
373+
return "mp10.10"
374+
else:
375+
return "E42"
376+
377+
def qsThreadInfo(self):
378+
return "l"
379+
380+
def qEcho(self, num):
381+
resp = "qEcho:" + str(num)
382+
if num >= 2:
383+
# We have launched our program
384+
self.started = True
385+
return [resp, "T13"]
386+
387+
return resp
388+
389+
def qSupported(self, client_supported):
390+
return "PacketSize=3fff;QStartNoAckMode+;qEcho+;"
391+
392+
def qHostInfo(self):
393+
return "default_packet_timeout:1;"
394+
395+
def vRun(self, packet):
396+
return [self.RESPONSE_NONE]
397+
398+
def A(self, packet):
399+
return "E28"
400+
401+
self.server.responder = MyResponder()
402+
403+
target = self.createTarget("a.yaml")
404+
# NB: apparently GDB packets are using "/" on Windows too
405+
exe_path = self.getBuildArtifact("a").replace(os.path.sep, "/")
406+
exe_hex = binascii.b2a_hex(exe_path.encode()).decode()
407+
process = self.connect(target)
408+
lldbutil.expect_state_changes(
409+
self, self.dbg.GetListener(), process, [lldb.eStateConnected]
410+
)
411+
412+
process = target.Launch(
413+
lldb.SBListener(),
414+
["arg1", "arg2", "arg3"], # argv
415+
[], # envp
416+
None, # stdin_path
417+
None, # stdout_path
418+
None, # stderr_path
419+
None, # working_directory
420+
0, # launch_flags
421+
True, # stop_at_entry
422+
lldb.SBError(),
423+
) # error
424+
self.assertTrue(process, PROCESS_IS_VALID)
425+
self.assertEqual(process.GetProcessID(), 16)
426+
427+
self.assertPacketLogContains(
428+
["vRun;%s;61726731;61726732;61726733" % (exe_hex,)]
429+
)
430+
359431
def test_launch_QEnvironment(self):
360432
class MyResponder(MockGDBServerResponder):
361433
def qC(self):

0 commit comments

Comments
 (0)