Add GDB remote packet reproducer.

llvm-svn: 346780
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 23b24ba..0f32d6e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -9,6 +9,7 @@
 
 #include "GDBRemoteCommunication.h"
 
+#include <future>
 #include <limits.h>
 #include <string.h>
 #include <sys/stat.h>
@@ -22,6 +23,8 @@
 #include "lldb/Host/Socket.h"
 #include "lldb/Host/StringConvert.h"
 #include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/FileSpec.h"
@@ -51,78 +54,6 @@
 using namespace lldb_private;
 using namespace lldb_private::process_gdb_remote;
 
-GDBRemoteCommunication::History::History(uint32_t size)
-    : m_packets(), m_curr_idx(0), m_total_packet_count(0),
-      m_dumped_to_log(false) {
-  m_packets.resize(size);
-}
-
-GDBRemoteCommunication::History::~History() {}
-
-void GDBRemoteCommunication::History::AddPacket(char packet_char,
-                                                PacketType type,
-                                                uint32_t bytes_transmitted) {
-  const size_t size = m_packets.size();
-  if (size > 0) {
-    const uint32_t idx = GetNextIndex();
-    m_packets[idx].packet.assign(1, packet_char);
-    m_packets[idx].type = type;
-    m_packets[idx].bytes_transmitted = bytes_transmitted;
-    m_packets[idx].packet_idx = m_total_packet_count;
-    m_packets[idx].tid = llvm::get_threadid();
-  }
-}
-
-void GDBRemoteCommunication::History::AddPacket(const std::string &src,
-                                                uint32_t src_len,
-                                                PacketType type,
-                                                uint32_t bytes_transmitted) {
-  const size_t size = m_packets.size();
-  if (size > 0) {
-    const uint32_t idx = GetNextIndex();
-    m_packets[idx].packet.assign(src, 0, src_len);
-    m_packets[idx].type = type;
-    m_packets[idx].bytes_transmitted = bytes_transmitted;
-    m_packets[idx].packet_idx = m_total_packet_count;
-    m_packets[idx].tid = llvm::get_threadid();
-  }
-}
-
-void GDBRemoteCommunication::History::Dump(Stream &strm) const {
-  const uint32_t size = GetNumPacketsInHistory();
-  const uint32_t first_idx = GetFirstSavedPacketIndex();
-  const uint32_t stop_idx = m_curr_idx + size;
-  for (uint32_t i = first_idx; i < stop_idx; ++i) {
-    const uint32_t idx = NormalizeIndex(i);
-    const Entry &entry = m_packets[idx];
-    if (entry.type == ePacketTypeInvalid || entry.packet.empty())
-      break;
-    strm.Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n",
-                entry.packet_idx, entry.tid, entry.bytes_transmitted,
-                (entry.type == ePacketTypeSend) ? "send" : "read",
-                entry.packet.c_str());
-  }
-}
-
-void GDBRemoteCommunication::History::Dump(Log *log) const {
-  if (log && !m_dumped_to_log) {
-    m_dumped_to_log = true;
-    const uint32_t size = GetNumPacketsInHistory();
-    const uint32_t first_idx = GetFirstSavedPacketIndex();
-    const uint32_t stop_idx = m_curr_idx + size;
-    for (uint32_t i = first_idx; i < stop_idx; ++i) {
-      const uint32_t idx = NormalizeIndex(i);
-      const Entry &entry = m_packets[idx];
-      if (entry.type == ePacketTypeInvalid || entry.packet.empty())
-        break;
-      log->Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s",
-                  entry.packet_idx, entry.tid, entry.bytes_transmitted,
-                  (entry.type == ePacketTypeSend) ? "send" : "read",
-                  entry.packet.c_str());
-    }
-  }
-}
-
 //----------------------------------------------------------------------
 // GDBRemoteCommunication constructor
 //----------------------------------------------------------------------
@@ -169,7 +100,8 @@
   const size_t bytes_written = Write(&ch, 1, status, NULL);
   if (log)
     log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
-  m_history.AddPacket(ch, History::ePacketTypeSend, bytes_written);
+  m_history.AddPacket(ch, GDBRemoteCommunicationHistory::ePacketTypeSend,
+                      bytes_written);
   return bytes_written;
 }
 
@@ -180,26 +112,31 @@
   const size_t bytes_written = Write(&ch, 1, status, NULL);
   if (log)
     log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
-  m_history.AddPacket(ch, History::ePacketTypeSend, bytes_written);
+  m_history.AddPacket(ch, GDBRemoteCommunicationHistory::ePacketTypeSend,
+                      bytes_written);
   return bytes_written;
 }
 
 GDBRemoteCommunication::PacketResult
 GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) {
-  if (IsConnected()) {
     StreamString packet(0, 4, eByteOrderBig);
-
     packet.PutChar('$');
     packet.Write(payload.data(), payload.size());
     packet.PutChar('#');
     packet.PutHex8(CalculcateChecksum(payload));
+    std::string packet_str = packet.GetString();
 
+    return SendRawPacketNoLock(packet_str);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::SendRawPacketNoLock(llvm::StringRef packet,
+                                            bool skip_ack) {
+  if (IsConnected()) {
     Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
     ConnectionStatus status = eConnectionStatusSuccess;
-    // TODO: Don't shimmy through a std::string, just use StringRef.
-    std::string packet_str = packet.GetString();
-    const char *packet_data = packet_str.c_str();
-    const size_t packet_length = packet.GetSize();
+    const char *packet_data = packet.data();
+    const size_t packet_length = packet.size();
     size_t bytes_written = Write(packet_data, packet_length, status, NULL);
     if (log) {
       size_t binary_start_offset = 0;
@@ -238,11 +175,12 @@
                     (int)packet_length, packet_data);
     }
 
-    m_history.AddPacket(packet.GetString(), packet_length,
-                        History::ePacketTypeSend, bytes_written);
+    m_history.AddPacket(packet.str(), packet_length,
+                        GDBRemoteCommunicationHistory::ePacketTypeSend,
+                        bytes_written);
 
     if (bytes_written == packet_length) {
-      if (GetSendAcks())
+      if (!skip_ack && GetSendAcks())
         return GetAck();
       else
         return PacketResult::Success;
@@ -857,7 +795,8 @@
         }
       }
 
-      m_history.AddPacket(m_bytes, total_length, History::ePacketTypeRecv,
+      m_history.AddPacket(m_bytes, total_length,
+                          GDBRemoteCommunicationHistory::ePacketTypeRecv,
                           total_length);
 
       // Clear packet_str in case there is some existing data in it.
@@ -1302,6 +1241,42 @@
 
 void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); }
 
+void GDBRemoteCommunication::SetHistoryStream(llvm::raw_ostream *strm) {
+  m_history.SetStream(strm);
+};
+
+llvm::Error
+GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
+                                       GDBRemoteCommunication &server) {
+  const bool child_processes_inherit = false;
+  const int backlog = 5;
+  TCPSocket listen_socket(true, child_processes_inherit);
+  if (llvm::Error error =
+          listen_socket.Listen("127.0.0.1:0", backlog).ToError())
+    return error;
+
+  Socket *accept_socket;
+  std::future<Status> accept_status = std::async(
+      std::launch::async, [&] { return listen_socket.Accept(accept_socket); });
+
+  llvm::SmallString<32> remote_addr;
+  llvm::raw_svector_ostream(remote_addr)
+      << "connect://localhost:" << listen_socket.GetLocalPortNumber();
+
+  std::unique_ptr<ConnectionFileDescriptor> conn_up(
+      new ConnectionFileDescriptor());
+  if (conn_up->Connect(remote_addr, nullptr) != lldb::eConnectionStatusSuccess)
+    return llvm::make_error<llvm::StringError>("Unable to connect",
+                                               llvm::inconvertibleErrorCode());
+
+  client.SetConnection(conn_up.release());
+  if (llvm::Error error = accept_status.get().ToError())
+    return error;
+
+  server.SetConnection(new ConnectionFileDescriptor(accept_socket));
+  return llvm::Error::success();
+}
+
 GDBRemoteCommunication::ScopedTimeout::ScopedTimeout(
     GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout)
   : m_gdb_comm(gdb_comm), m_timeout_modified(false) {