owenpshaw created this revision. owenpshaw added a reviewer: clayborg. Gdb servers like openocd may send many $O reply packets for the client to output during a qRcmd command sequence. Currently, lldb interprets the first O packet as an unexpected response. Besides generating no output, this causes lldb to get out of sync with future commands because it continues reading O packets from the first command as response to subsequent commands.
This patch handles any O packets during an qRcmd, treating the first non-O packet as the true response. Looking for guidance on how best to write test cases, haven't found anything currently testing qRcmd but may have just missed it. Preliminary discussion at http://lists.llvm.org/pipermail/lldb-dev/2018-January/013078.html https://reviews.llvm.org/D41745 Files: source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -5152,12 +5152,14 @@ packet.PutCString("qRcmd,"); packet.PutBytesAsRawHex8(command, strlen(command)); - bool send_async = true; StringExtractorGDBRemote response; - process->GetGDBRemote().SendPacketAndWaitForResponse( - packet.GetString(), response, send_async); - result.SetStatus(eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); + process->GetGDBRemote().SendPacketHandlingOutput( + packet.GetString(), response, + [&output_strm](llvm::StringRef output) { + output_strm << output; + }); + result.SetStatus(eReturnStatusSuccessFinishResult); output_strm.Printf(" packet: %s\n", packet.GetData()); const std::string &response_str = response.GetStringRef(); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -232,6 +232,10 @@ PacketResult ReadPacket(StringExtractorGDBRemote &response, Timeout<std::micro> timeout, bool sync_on_timeout); + PacketResult ReadPacketHandlingOutput(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, bool sync_on_timeout, + std::function<void(llvm::StringRef)> output_callback); + // Pop a packet from the queue in a thread safe manner PacketResult PopPacketFromQueue(StringExtractorGDBRemote &response, Timeout<std::micro> timeout); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -274,6 +274,24 @@ return result; } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::ReadPacketHandlingOutput( + StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, + bool sync_on_timeout, + std::function<void(llvm::StringRef)> output_callback) { + auto result = ReadPacket(response, timeout, sync_on_timeout); + while (result == PacketResult::Success && response.IsNormalResponse() && + response.PeekChar() == 'O') { + response.GetChar(); + std::string output; + if (response.GetHexByteString(output)) + output_callback(output); + result = ReadPacket(response, timeout, sync_on_timeout); + } + return result; +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, Timeout<std::micro> timeout, Index: source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h +++ source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -48,6 +48,10 @@ StringExtractorGDBRemote &response, bool send_async); + PacketResult SendPacketHandlingOutput(llvm::StringRef payload, + StringExtractorGDBRemote &response, + std::function<void(llvm::StringRef)> output_callback); + bool SendvContPacket(llvm::StringRef payload, StringExtractorGDBRemote &response); Index: source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -176,6 +176,28 @@ return SendPacketAndWaitForResponseNoLock(payload, response); } +GDBRemoteCommunication::PacketResult +GDBRemoteClientBase::SendPacketHandlingOutput(llvm::StringRef payload, + StringExtractorGDBRemote &response, + std::function<void(llvm::StringRef)> output_callback) { + Lock lock(*this, true); + if (!lock) { + if (Log *log = + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) + log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending " + "packet '%.*s' (send_async=true)", + __FUNCTION__, int(payload.size()), payload.data()); + return PacketResult::ErrorSendFailed; + } + + PacketResult packet_result = SendPacketNoLock(payload); + if (packet_result != PacketResult::Success) + return packet_result; + + return ReadPacketHandlingOutput(response, GetPacketTimeout(), true, + output_callback); +} + GDBRemoteCommunication::PacketResult GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock( llvm::StringRef payload, StringExtractorGDBRemote &response) {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits