Skip to content

Commit c941bee

Browse files
authored
[lldb] Fix qEcho message handling. (#145675)
This fixes issues found in e066f35, which was later reverted. The problem was with "k" message which was sent with sync_on_timeout flag set to true, so lldb was waiting for response, which is currently not being sent by lldb-server. Not waiting for response at all seems to be not a solution, because on MAC OS X lldb waits for response from "k" to gracefully kill inferior.
1 parent 97fdc23 commit c941bee

File tree

7 files changed

+98
-9
lines changed

7 files changed

+98
-9
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/GDBRemoteClientBase.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) {
180180
GDBRemoteCommunication::PacketResult
181181
GDBRemoteClientBase::SendPacketAndWaitForResponse(
182182
llvm::StringRef payload, StringExtractorGDBRemote &response,
183-
std::chrono::seconds interrupt_timeout) {
183+
std::chrono::seconds interrupt_timeout, bool sync_on_timeout) {
184184
Lock lock(*this, interrupt_timeout);
185185
if (!lock) {
186186
if (Log *log = GetLog(GDBRLog::Process))
@@ -191,7 +191,7 @@ GDBRemoteClientBase::SendPacketAndWaitForResponse(
191191
return PacketResult::ErrorSendFailed;
192192
}
193193

194-
return SendPacketAndWaitForResponseNoLock(payload, response);
194+
return SendPacketAndWaitForResponseNoLock(payload, response, sync_on_timeout);
195195
}
196196

197197
GDBRemoteCommunication::PacketResult
@@ -236,14 +236,15 @@ GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
236236

237237
GDBRemoteCommunication::PacketResult
238238
GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
239-
llvm::StringRef payload, StringExtractorGDBRemote &response) {
239+
llvm::StringRef payload, StringExtractorGDBRemote &response,
240+
bool sync_on_timeout) {
240241
PacketResult packet_result = SendPacketNoLock(payload);
241242
if (packet_result != PacketResult::Success)
242243
return packet_result;
243244

244245
const size_t max_response_retries = 3;
245246
for (size_t i = 0; i < max_response_retries; ++i) {
246-
packet_result = ReadPacket(response, GetPacketTimeout(), true);
247+
packet_result = ReadPacket(response, GetPacketTimeout(), sync_on_timeout);
247248
// Make sure we received a response
248249
if (packet_result != PacketResult::Success)
249250
return packet_result;

lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ class GDBRemoteClientBase : public GDBRemoteCommunication, public Broadcaster {
6161
// ErrorReplyTimeout.
6262
PacketResult SendPacketAndWaitForResponse(
6363
llvm::StringRef payload, StringExtractorGDBRemote &response,
64-
std::chrono::seconds interrupt_timeout = std::chrono::seconds(0));
64+
std::chrono::seconds interrupt_timeout = std::chrono::seconds(0),
65+
bool sync_on_timeout = true);
6566

6667
PacketResult ReadPacketWithOutputSupport(
6768
StringExtractorGDBRemote &response, Timeout<std::micro> timeout,
@@ -104,7 +105,8 @@ class GDBRemoteClientBase : public GDBRemoteCommunication, public Broadcaster {
104105
protected:
105106
PacketResult
106107
SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,
107-
StringExtractorGDBRemote &response);
108+
StringExtractorGDBRemote &response,
109+
bool sync_on_timeout = true);
108110

109111
virtual void OnRunPacketSent(bool first);
110112

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

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

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

Lines changed: 4 additions & 2 deletions
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;
@@ -4358,7 +4358,9 @@ llvm::Expected<int> GDBRemoteCommunicationClient::KillProcess(lldb::pid_t pid) {
43584358
StringExtractorGDBRemote response;
43594359
GDBRemoteCommunication::ScopedTimeout(*this, seconds(3));
43604360

4361-
if (SendPacketAndWaitForResponse("k", response, GetPacketTimeout()) !=
4361+
// LLDB server typically sends no response for "k", so we shouldn't try
4362+
// to sync on timeout.
4363+
if (SendPacketAndWaitForResponse("k", response, GetPacketTimeout(), false) !=
43624364
PacketResult::Success)
43634365
return llvm::createStringError(llvm::inconvertibleErrorCode(),
43644366
"failed to send k packet");

lldb/test/API/commands/command/script_alias/TestCommandScriptAlias.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class CommandScriptAliasTestCase(TestBase):
1111
NO_DEBUG_INFO_TESTCASE = True
1212

1313
def test_pycmd(self):
14+
self.runCmd("log enable -f /tmp/gdb.log gdb-remote all")
1415
self.runCmd("command script import tcsacmd.py")
1516
self.runCmd("command script add -f tcsacmd.some_command_here attach")
1617

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)