diff options
author | Greg Clayton <gclayton@apple.com> | 2012-04-09 22:46:21 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2012-04-09 22:46:21 +0000 |
commit | c1422c1d314ed9a261e91048ddeac78cb78d98c9 (patch) | |
tree | 404dfd40ddd50c132b5a2251b2cb5aaf304c852d /lldb/source/Plugins/Process/gdb-remote | |
parent | 5c61054742df2714ec669523e54afa332bcad54b (diff) | |
download | bcm5719-llvm-c1422c1d314ed9a261e91048ddeac78cb78d98c9.tar.gz bcm5719-llvm-c1422c1d314ed9a261e91048ddeac78cb78d98c9.zip |
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.
llvm-svn: 154354
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
4 files changed, 267 insertions, 24 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 6ea0cd5cb5f..5b589dce795 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/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 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, 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 @@ size_t 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 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le 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 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le } 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 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri 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 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri else SendAck(); } - if (success) - { - if (log) - log->Printf ("read packet: %.*s", (int)(total_length), m_bytes.c_str()); - } } else { @@ -394,6 +484,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri 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 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, 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()); +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index c50e52ab9e8..0e9ea0dcb1d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -17,7 +17,7 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" +#include "lldb/lldb-public.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Listener.h" #include "lldb/Host/Mutex.h" @@ -128,9 +128,136 @@ public: const char *unix_socket_name, lldb_private::ProcessLaunchInfo &launch_info); + void + DumpHistory(const char *path); protected: - typedef std::list<std::string> packet_collection; + + class History + { + public: + enum PacketType + { + ePacketTypeInvalid = 0, + ePacketTypeSend, + ePacketTypeRecv + }; + + struct Entry + { + Entry() : + packet(), + type (ePacketTypeInvalid), + bytes_transmitted (0), + packet_idx (0) + { + } + + void + Clear () + { + packet.clear(); + type = ePacketTypeInvalid; + bytes_transmitted = 0; + packet_idx = 0; + + } + std::string packet; + PacketType type; + uint32_t bytes_transmitted; + uint32_t packet_idx; + }; + + History (uint32_t size); + + ~History (); + + // For single char packets for ack, nack and /x03 + void + 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; + } + } + + void + 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; + } + } + + void + Dump (lldb_private::Stream &strm) const; + + void + Dump (lldb_private::Log *log) const; + + bool + DidDumpToLog () const + { + return m_dumped_to_log; + } + +protected: + uint32_t + GetFirstSavedPacketIndex () const + { + if (m_total_packet_count < m_packets.size()) + return 0; + else + return m_curr_idx + 1; + } + + uint32_t + GetNumPacketsInHistory () const + { + if (m_total_packet_count < m_packets.size()) + return m_total_packet_count; + else + return (uint32_t)m_packets.size(); + } + + uint32_t + GetNextIndex() + { + ++m_total_packet_count; + const uint32_t idx = m_curr_idx; + m_curr_idx = NormalizeIndex(idx + 1); + return idx; + } + + uint32_t + NormalizeIndex (uint32_t i) const + { + return i % m_packets.size(); + } + + + std::vector<Entry> m_packets; + uint32_t m_curr_idx; + uint32_t m_total_packet_count; + mutable bool m_dumped_to_log; + }; size_t SendPacketNoLock (const char *payload, @@ -150,6 +277,7 @@ protected: lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time lldb_private::Predicate<bool> m_public_is_running; lldb_private::Predicate<bool> m_private_is_running; + History m_history; bool m_send_acks; bool m_is_platform; // Set to true if this class represents a platform, // false if this class represents a debug session for diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 47ebf22a97a..8a1f120f308 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -53,6 +53,20 @@ #include "ThreadGDBRemote.h" #include "StopInfoMachException.h" +namespace lldb +{ + // Provide a function that can easily dump the packet history if we know a + // ProcessGDBRemote * value (which we can get from logs or from debugging). + // We need the function in the lldb namespace so it makes it into the final + // executable since the LLDB shared library only exports stuff in the lldb + // namespace. This allows you to attach with a debugger and call this + // function and get the packet history dumped to a file. + void + DumpProcessGDBRemotePacketHistory (void *p, const char *path) + { + ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (path); + } +}; #define DEBUGSERVER_BASENAME "debugserver" diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 4ecd3a06424..9f3b75874ea 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -210,6 +210,12 @@ public: virtual bool StopNoticingNewThreads(); + GDBRemoteCommunicationClient & + GetGDBRemote() + { + return m_gdb_comm; + } + protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; @@ -275,12 +281,6 @@ protected: void BuildDynamicRegisterInfo (bool force); - GDBRemoteCommunicationClient & - GetGDBRemote() - { - return m_gdb_comm; - } - void SetLastStopPacket (const StringExtractorGDBRemote &response) { |