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

Reply via email to