Added a packet history object to the GDBRemoteCommunication class that is always remembering the last 512 packets that were sent/received. These packets get dumped if logging gets enabled, or when the new expr lldb::DumpProcessGDBRemotePacketHistory (void *process, const char *log_file_path) global function is called.



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@154354 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 6ea0cd5..5b589dc 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -17,6 +17,7 @@
 // C++ Includes
 // Other libraries and framework includes
 #include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Host/FileSpec.h"
 #include "lldb/Host/Host.h"
@@ -31,6 +32,63 @@
 using namespace lldb;
 using namespace lldb_private;
 
+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::Dump (lldb_private::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] <%4u> %s packet: %s\n",
+                     entry.packet_idx,
+                     entry.bytes_transmitted,
+                     (entry.type == ePacketTypeSend) ? "send" : "read",
+                     entry.packet.c_str());
+    }
+}
+
+void
+GDBRemoteCommunication::History::Dump (lldb_private::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] <%4u> %s packet: %s",
+                         entry.packet_idx,
+                         entry.bytes_transmitted,
+                         (entry.type == ePacketTypeSend) ? "send" : "read",
+                         entry.packet.c_str());
+        }
+    }
+}
+
 //----------------------------------------------------------------------
 // GDBRemoteCommunication constructor
 //----------------------------------------------------------------------
@@ -42,6 +100,7 @@
     m_sequence_mutex (Mutex::eMutexTypeRecursive),
     m_public_is_running (false),
     m_private_is_running (false),
+    m_history (512),
     m_send_acks (true),
     m_is_platform (is_platform)
 {
@@ -76,22 +135,26 @@
 GDBRemoteCommunication::SendAck ()
 {
     LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
-    if (log)
-        log->Printf ("send packet: +");
     ConnectionStatus status = eConnectionStatusSuccess;
-    char ack_char = '+';
-    return Write (&ack_char, 1, status, NULL);
+    char ch = '+';
+    const size_t bytes_written = Write (&ch, 1, status, NULL);
+    if (log)
+        log->Printf ("<%4zu> send packet: %c", bytes_written, ch);
+    m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+    return bytes_written;
 }
 
 size_t
 GDBRemoteCommunication::SendNack ()
 {
     LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
-    if (log)
-        log->Printf ("send packet: -");
     ConnectionStatus status = eConnectionStatusSuccess;
-    char nack_char = '-';
-    return Write (&nack_char, 1, status, NULL);
+    char ch = '-';
+    const size_t bytes_written = Write (&ch, 1, status, NULL);
+    if (log)
+        log->Printf ("<%4zu> send packet: %c", bytes_written, ch);
+    m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+    return bytes_written;
 }
 
 size_t
@@ -129,10 +192,26 @@
         packet.PutHex8(CalculcateChecksum (payload, payload_length));
 
         LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
-        if (log)
-            log->Printf ("send packet: %.*s", (int)packet.GetSize(), packet.GetData());
         ConnectionStatus status = eConnectionStatusSuccess;
         size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
+        if (log)
+        {
+            // If logging was just enabled and we have history, then dump out what
+            // we have to the log so we get the historical context. The Dump() call that
+            // logs all of the packet will set a boolean so that we don't dump this more
+            // than once
+            if (!m_history.DidDumpToLog ())
+            {
+                DumpHistory("/tmp/foo.txt");
+                m_history.Dump (log.get());
+            }
+
+            log->Printf ("<%4zu> send packet: %.*s", bytes_written, (int)packet.GetSize(), packet.GetData());
+        }
+
+        m_history.AddPacket (packet.GetString(), packet.GetSize(), History::ePacketTypeSend, bytes_written);
+
+
         if (bytes_written == packet.GetSize())
         {
             if (GetSendAcks ())
@@ -146,7 +225,6 @@
         }
         else
         {
-            LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
             if (log)
                 log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData());
         }
@@ -353,7 +431,24 @@
             
             bool success = true;
             std::string &packet_str = packet.GetStringRef();
+            
+            
+            if (log)
+            {
+                // If logging was just enabled and we have history, then dump out what
+                // we have to the log so we get the historical context. The Dump() call that
+                // logs all of the packet will set a boolean so that we don't dump this more
+                // than once
+                if (!m_history.DidDumpToLog ())
+                    m_history.Dump (log.get());
+                
+                log->Printf ("<%4zu> read packet: %.*s", total_length, (int)(total_length), m_bytes.c_str());
+            }
+
+            m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length);
+
             packet_str.assign (m_bytes, content_start, content_length);
+            
             if (m_bytes[0] == '$')
             {
                 assert (checksum_idx < m_bytes.size());
@@ -381,11 +476,6 @@
                         else
                             SendAck();
                     }
-                    if (success)
-                    {
-                        if (log)
-                            log->Printf ("read packet: %.*s", (int)(total_length), m_bytes.c_str());
-                    }
                 }
                 else
                 {
@@ -394,6 +484,7 @@
                         log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str());
                 }
             }
+            
             m_bytes.erase(0, total_length);
             packet.SetFilePos(0);
             return success;
@@ -531,3 +622,13 @@
     return error;
 }
 
+void
+GDBRemoteCommunication::DumpHistory(const char *path)
+{
+    StreamFile strm;
+    Error error (strm.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate));
+    if (error.Success())
+        m_history.Dump (strm);
+    else
+        fprintf (stderr, "error: unable to open '%s' -- %s\n", path, error.AsCString());
+}