diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:06:29 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:06:29 +0000 |
commit | 94994d372d014ce4c8758b9605d63fae651bd8aa (patch) | |
tree | 51c0b708bd59f205d6b35cb2a8c24d62f0c33d77 /source/Plugins/Process/gdb-remote | |
parent | 39be7ce23363d12ae3e49aeb1fdb2bfeb892e836 (diff) |
Notes
Diffstat (limited to 'source/Plugins/Process/gdb-remote')
25 files changed, 952 insertions, 377 deletions
diff --git a/source/Plugins/Process/gdb-remote/CMakeLists.txt b/source/Plugins/Process/gdb-remote/CMakeLists.txt index 7ae25f83c5f8a..4eb5291d54d5a 100644 --- a/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -15,6 +15,8 @@ add_lldb_library(lldbPluginProcessGDBRemote PLUGIN GDBRemoteClientBase.cpp GDBRemoteCommunication.cpp GDBRemoteCommunicationClient.cpp + GDBRemoteCommunicationHistory.cpp + GDBRemoteCommunicationReplayServer.cpp GDBRemoteCommunicationServer.cpp GDBRemoteCommunicationServerCommon.cpp GDBRemoteCommunicationServerLLGS.cpp diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp index 4e20b56fb111b..a3a4aa053261b 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -379,7 +379,7 @@ void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) { log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03"); m_comm.m_interrupt_time = steady_clock::now(); } - m_comm.m_cv.wait(lock, [this] { return m_comm.m_is_running == false; }); + m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; }); m_did_interrupt = true; } m_acquired = true; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index c335b60028619..72c1314a7c943 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -9,21 +9,22 @@ #include "GDBRemoteCommunication.h" -// C Includes +#include <future> #include <limits.h> #include <string.h> #include <sys/stat.h> -// C++ Includes -// Other libraries and framework includes #include "lldb/Core/StreamFile.h" #include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Pipe.h" #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" @@ -33,7 +34,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/ScopedPrinter.h" -// Project includes #include "ProcessGDBRemoteLog.h" #if defined(__APPLE__) @@ -42,7 +42,8 @@ #define DEBUGSERVER_BASENAME "lldb-server" #endif -#if defined(HAVE_LIBCOMPRESSION) +#if defined(__APPLE__) +#define HAVE_LIBCOMPRESSION #include <compression.h> #endif @@ -54,78 +55,6 @@ using namespace lldb; 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 //---------------------------------------------------------------------- @@ -139,7 +68,10 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, #endif m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512), m_send_acks(true), m_compression_type(CompressionType::None), - m_listen_url() { + m_listen_url(), m_decompression_scratch_type(CompressionType::None), + m_decompression_scratch(nullptr) { + // Unused unless HAVE_LIBCOMPRESSION is defined. + (void)m_decompression_scratch_type; } //---------------------------------------------------------------------- @@ -150,6 +82,9 @@ GDBRemoteCommunication::~GDBRemoteCommunication() { Disconnect(); } + if (m_decompression_scratch) + free (m_decompression_scratch); + // Stop the communications read thread which is used to parse all incoming // packets. This function will block until the read thread returns. if (m_read_thread_enabled) @@ -172,7 +107,8 @@ size_t GDBRemoteCommunication::SendAck() { 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; } @@ -183,26 +119,31 @@ size_t GDBRemoteCommunication::SendNack() { 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; @@ -241,11 +182,12 @@ GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { (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; @@ -597,7 +539,7 @@ bool GDBRemoteCommunication::DecompressPacket() { size_t decompressed_bytes = 0; if (decompressed_bufsize != ULONG_MAX) { - decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize + 1); + decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize); if (decompressed_buffer == nullptr) { m_bytes.erase(0, size_of_first_packet); return false; @@ -605,11 +547,10 @@ bool GDBRemoteCommunication::DecompressPacket() { } #if defined(HAVE_LIBCOMPRESSION) - // libcompression is weak linked so check that compression_decode_buffer() is - // available if (m_compression_type == CompressionType::ZlibDeflate || m_compression_type == CompressionType::LZFSE || - m_compression_type == CompressionType::LZ4) { + m_compression_type == CompressionType::LZ4 || + m_compression_type == CompressionType::LZMA) { compression_algorithm compression_type; if (m_compression_type == CompressionType::LZFSE) compression_type = COMPRESSION_LZFSE; @@ -620,16 +561,33 @@ bool GDBRemoteCommunication::DecompressPacket() { else if (m_compression_type == CompressionType::LZMA) compression_type = COMPRESSION_LZMA; - // If we have the expected size of the decompressed payload, we can - // allocate the right-sized buffer and do it. If we don't have that - // information, we'll need to try decoding into a big buffer and if the - // buffer wasn't big enough, increase it and try again. + if (m_decompression_scratch_type != m_compression_type) { + if (m_decompression_scratch) { + free (m_decompression_scratch); + m_decompression_scratch = nullptr; + } + size_t scratchbuf_size = 0; + if (m_compression_type == CompressionType::LZFSE) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE); + else if (m_compression_type == CompressionType::LZ4) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZ4_RAW); + else if (m_compression_type == CompressionType::ZlibDeflate) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB); + else if (m_compression_type == CompressionType::LZMA) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZMA); + else if (m_compression_type == CompressionType::LZFSE) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE); + if (scratchbuf_size > 0) { + m_decompression_scratch = (void*) malloc (scratchbuf_size); + m_decompression_scratch_type = m_compression_type; + } + } if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) { decompressed_bytes = compression_decode_buffer( - decompressed_buffer, decompressed_bufsize + 10, - (uint8_t *)unescaped_content.data(), unescaped_content.size(), NULL, - compression_type); + decompressed_buffer, decompressed_bufsize, + (uint8_t *)unescaped_content.data(), unescaped_content.size(), + m_decompression_scratch, compression_type); } } #endif @@ -721,7 +679,7 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Size of packet before it is decompressed, for logging purposes size_t original_packet_size = m_bytes.size(); if (CompressionIsEnabled()) { - if (DecompressPacket() == false) { + if (!DecompressPacket()) { packet.Clear(); return GDBRemoteCommunication::PacketType::Standard; } @@ -860,7 +818,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, } } - 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. @@ -997,7 +956,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( // debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) { - debugserver_file_spec.SetFile(env_debugserver_path, false, + debugserver_file_spec.SetFile(env_debugserver_path, FileSpec::Style::native); if (log) log->Printf("GDBRemoteCommunication::%s() gdb-remote stub exe path set " @@ -1005,13 +964,14 @@ Status GDBRemoteCommunication::StartDebugserverProcess( __FUNCTION__, env_debugserver_path); } else debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = debugserver_file_spec.Exists(); + bool debugserver_exists = + FileSystem::Instance().Exists(debugserver_file_spec); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources directory. debugserver_file_spec = HostInfo::GetSupportExeDir(); if (debugserver_file_spec) { debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME); - debugserver_exists = debugserver_file_spec.Exists(); + debugserver_exists = FileSystem::Instance().Exists(debugserver_file_spec); if (debugserver_exists) { if (log) log->Printf( @@ -1074,7 +1034,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( debugserver_args.AppendArgument(llvm::StringRef("--setsid")); } - llvm::SmallString<PATH_MAX> named_pipe_path; + llvm::SmallString<128> named_pipe_path; // socket_pipe is used by debug server to communicate back either // TCP port or domain socket name which it listens on. // The second purpose of the pipe to serve as a synchronization point - @@ -1114,9 +1074,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess( __FUNCTION__, error.AsCString()); return error; } - int write_fd = socket_pipe.GetWriteFileDescriptor(); + pipe_t write = socket_pipe.GetWritePipe(); debugserver_args.AppendArgument(llvm::StringRef("--pipe")); - debugserver_args.AppendArgument(llvm::to_string(write_fd)); + debugserver_args.AppendArgument(llvm::to_string(write)); launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); #endif } else { @@ -1304,6 +1264,42 @@ Status GDBRemoteCommunication::StartDebugserverProcess( 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) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 67796e4c61ef2..369eb25b1dfac 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -10,24 +10,21 @@ #ifndef liblldb_GDBRemoteCommunication_h_ #define liblldb_GDBRemoteCommunication_h_ -// C Includes -// C++ Includes +#include "GDBRemoteCommunicationHistory.h" + #include <condition_variable> #include <mutex> #include <queue> #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Core/Communication.h" -#include "lldb/Core/Listener.h" #include "lldb/Host/HostThread.h" -#include "lldb/Host/Predicate.h" #include "lldb/Utility/Args.h" -#include "lldb/lldb-public.h" - +#include "lldb/Utility/Listener.h" +#include "lldb/Utility/Predicate.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#include "lldb/lldb-public.h" namespace lldb_private { namespace process_gdb_remote { @@ -140,86 +137,16 @@ public: // fork/exec to avoid having to connect/accept void DumpHistory(Stream &strm); + void SetHistoryStream(llvm::raw_ostream *strm); -protected: - class History { - public: - enum PacketType { - ePacketTypeInvalid = 0, - ePacketTypeSend, - ePacketTypeRecv - }; - - struct Entry { - Entry() - : packet(), type(ePacketTypeInvalid), bytes_transmitted(0), - packet_idx(0), tid(LLDB_INVALID_THREAD_ID) {} - - void Clear() { - packet.clear(); - type = ePacketTypeInvalid; - bytes_transmitted = 0; - packet_idx = 0; - tid = LLDB_INVALID_THREAD_ID; - } - std::string packet; - PacketType type; - uint32_t bytes_transmitted; - uint32_t packet_idx; - lldb::tid_t tid; - }; - - 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); - - void AddPacket(const std::string &src, uint32_t src_len, PacketType type, - uint32_t bytes_transmitted); - - void Dump(Stream &strm) const; - - void Dump(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; - }; + static llvm::Error ConnectLocally(GDBRemoteCommunication &client, + GDBRemoteCommunication &server); +protected: std::chrono::seconds m_packet_timeout; uint32_t m_echo_number; LazyBool m_supports_qEcho; - History m_history; + GDBRemoteCommunicationHistory 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 @@ -228,6 +155,8 @@ protected: CompressionType m_compression_type; PacketResult SendPacketNoLock(llvm::StringRef payload); + PacketResult SendRawPacketNoLock(llvm::StringRef payload, + bool skip_ack = false); PacketResult ReadPacket(StringExtractorGDBRemote &response, Timeout<std::micro> timeout, bool sync_on_timeout); @@ -289,6 +218,9 @@ private: HostThread m_listen_thread; std::string m_listen_url; + CompressionType m_decompression_scratch_type; + void *m_decompression_scratch; + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication); }; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index c8b59d5d236b9..1e12ea6b2d566 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -9,17 +9,13 @@ #include "GDBRemoteCommunicationClient.h" -// C Includes #include <math.h> #include <sys/stat.h> -// C++ Includes #include <numeric> #include <sstream> -// Other libraries and framework includes #include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/XML.h" #include "lldb/Symbol/Symbol.h" @@ -31,9 +27,9 @@ #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" -// Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Host/Config.h" @@ -41,7 +37,8 @@ #include "llvm/ADT/StringSwitch.h" -#if defined(HAVE_LIBCOMPRESSION) +#if defined(__APPLE__) +#define HAVE_LIBCOMPRESSION #include <compression.h> #endif @@ -256,10 +253,7 @@ bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported() { m_attach_or_wait_reply = eLazyBoolYes; } } - if (m_attach_or_wait_reply == eLazyBoolYes) - return true; - else - return false; + return m_attach_or_wait_reply == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { @@ -273,14 +267,11 @@ bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { m_prepare_for_reg_writing_reply = eLazyBoolYes; } } - if (m_prepare_for_reg_writing_reply == eLazyBoolYes) - return true; - else - return false; + return m_prepare_for_reg_writing_reply == eLazyBoolYes; } void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { - if (did_exec == false) { + if (!did_exec) { // Hard reset everything, this is when we first connect to a GDB server m_supports_not_sending_acks = eLazyBoolCalculate; m_supports_thread_suffix = eLazyBoolCalculate; @@ -749,7 +740,7 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { bool sequence_mutex_unavailable; size_t size; size = GetCurrentThreadIDs(thread_ids, sequence_mutex_unavailable); - if (size && sequence_mutex_unavailable == false) { + if (size && !sequence_mutex_unavailable) { m_curr_pid = thread_ids.front(); m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; @@ -843,8 +834,8 @@ int GDBRemoteCommunicationClient::SendEnvironmentPacket( if (name_equal_value && name_equal_value[0]) { StreamString packet; bool send_hex_encoding = false; - for (const char *p = name_equal_value; - *p != '\0' && send_hex_encoding == false; ++p) { + for (const char *p = name_equal_value; *p != '\0' && !send_hex_encoding; + ++p) { if (isprint(*p)) { switch (*p) { case '$': @@ -1134,6 +1125,9 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { + // host info computation can require DNS traffic and shelling out to external processes. + // Increase the timeout to account for that. + ScopedTimeout timeout(*this, seconds(10)); m_qHostInfo_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qHostInfo", response, false) == @@ -1686,12 +1680,17 @@ Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) { m_supports_watchpoint_support_info = eLazyBoolYes; llvm::StringRef name; llvm::StringRef value; + bool found_num_field = false; while (response.GetNameColonValue(name, value)) { if (name.equals("num")) { value.getAsInteger(0, m_num_supported_hardware_watchpoints); num = m_num_supported_hardware_watchpoints; + found_num_field = true; } } + if (!found_num_field) { + m_supports_watchpoint_support_info = eLazyBoolNo; + } } else { m_supports_watchpoint_support_info = eLazyBoolNo; } @@ -1724,12 +1723,10 @@ GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction( // On targets like MIPS and ppc64le, watchpoint exceptions are always // generated before the instruction is executed. The connected target may // not support qHostInfo or qWatchpointSupportInfo packets. - if (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || - atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el || - atype == llvm::Triple::ppc64le) - after = false; - else - after = true; + after = + !(atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || + atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el || + atype == llvm::Triple::ppc64le); } else { // For MIPS and ppc64le, set m_watchpoints_trigger_after_instruction to // eLazyBoolNo if it is not calculated before. @@ -1815,7 +1812,7 @@ bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { return false; std::string cwd; response.GetHexByteString(cwd); - working_dir.SetFile(cwd, false, GetHostArchitecture().GetTriple()); + working_dir.SetFile(cwd, GetHostArchitecture().GetTriple()); return !cwd.empty(); } return false; @@ -1925,8 +1922,7 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( // characters in a process name std::string name; extractor.GetHexByteString(name); - process_info.GetExecutableFile().SetFile(name, false, - FileSpec::Style::native); + process_info.GetExecutableFile().SetFile(name, FileSpec::Style::native); } else if (name.equals("cputype")) { value.getAsInteger(0, cpu); } else if (name.equals("cpusubtype")) { @@ -3559,7 +3555,7 @@ bool GDBRemoteCommunicationClient::GetModuleInfo( StringExtractor extractor(value); std::string path; extractor.GetHexByteString(path); - module_spec.GetFileSpec() = FileSpec(path, false, arch_spec.GetTriple()); + module_spec.GetFileSpec() = FileSpec(path, arch_spec.GetTriple()); } } @@ -3595,8 +3591,7 @@ ParseModuleSpec(StructuredData::Dictionary *dict) { if (!dict->GetValueForKeyAsString("file_path", string)) return llvm::None; - result.GetFileSpec() = - FileSpec(string, false, result.GetArchitecture().GetTriple()); + result.GetFileSpec() = FileSpec(string, result.GetArchitecture().GetTriple()); return result; } @@ -3774,7 +3769,7 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups( // Is this the initial qSymbol:: packet? bool first_qsymbol_query = true; - if (m_supports_qSymbol && m_qSymbol_requests_done == false) { + if (m_supports_qSymbol && !m_qSymbol_requests_done) { Lock lock(*this, false); if (lock) { StreamString packet; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index cf1d249768d7a..37d53ab425f59 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -12,8 +12,6 @@ #include "GDBRemoteClientBase.h" -// C Includes -// C++ Includes #include <chrono> #include <map> #include <mutex> diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp new file mode 100644 index 0000000000000..69b13f2a3acb6 --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp @@ -0,0 +1,143 @@ +//===-- GDBRemoteCommunicationHistory.cpp -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GDBRemoteCommunicationHistory.h" + +// Other libraries and framework includes +#include "lldb/Core/StreamFile.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Log.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; + +void GDBRemoteCommunicationHistory::Entry::Serialize(raw_ostream &strm) const { + yaml::Output yout(strm); + yout << const_cast<GDBRemoteCommunicationHistory::Entry &>(*this); + strm.flush(); +} + +GDBRemoteCommunicationHistory::GDBRemoteCommunicationHistory(uint32_t size) + : m_packets(), m_curr_idx(0), m_total_packet_count(0), + m_dumped_to_log(false) { + if (size) + m_packets.resize(size); +} + +GDBRemoteCommunicationHistory::~GDBRemoteCommunicationHistory() {} + +void GDBRemoteCommunicationHistory::AddPacket(char packet_char, PacketType type, + uint32_t bytes_transmitted) { + const size_t size = m_packets.size(); + if (size == 0) + return; + + const uint32_t idx = GetNextIndex(); + m_packets[idx].packet.data.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(); + if (m_stream && type == ePacketTypeRecv) + m_packets[idx].Serialize(*m_stream); +} + +void GDBRemoteCommunicationHistory::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) + return; + + const uint32_t idx = GetNextIndex(); + m_packets[idx].packet.data.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(); + if (m_stream && type == ePacketTypeRecv) + m_packets[idx].Serialize(*m_stream); +} + +void GDBRemoteCommunicationHistory::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.data.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.data.c_str()); + } +} + +void GDBRemoteCommunicationHistory::Dump(Log *log) const { + if (!log || m_dumped_to_log) + return; + + 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.data.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.data.c_str()); + } +} + +void yaml::ScalarEnumerationTraits<GDBRemoteCommunicationHistory::PacketType>:: + enumeration(IO &io, GDBRemoteCommunicationHistory::PacketType &value) { + io.enumCase(value, "Invalid", + GDBRemoteCommunicationHistory::ePacketTypeInvalid); + io.enumCase(value, "Send", GDBRemoteCommunicationHistory::ePacketTypeSend); + io.enumCase(value, "Recv", GDBRemoteCommunicationHistory::ePacketTypeRecv); +} + +void yaml::ScalarTraits<GDBRemoteCommunicationHistory::Entry::BinaryData>:: + output(const GDBRemoteCommunicationHistory::Entry::BinaryData &Val, void *, + raw_ostream &Out) { + Out << toHex(Val.data); +} + +StringRef +yaml::ScalarTraits<GDBRemoteCommunicationHistory::Entry::BinaryData>::input( + StringRef Scalar, void *, + GDBRemoteCommunicationHistory::Entry::BinaryData &Val) { + Val.data = fromHex(Scalar); + return {}; +} + +void yaml::MappingTraits<GDBRemoteCommunicationHistory::Entry>::mapping( + IO &io, GDBRemoteCommunicationHistory::Entry &Entry) { + io.mapRequired("packet", Entry.packet); + io.mapRequired("type", Entry.type); + io.mapRequired("bytes", Entry.bytes_transmitted); + io.mapRequired("index", Entry.packet_idx); + io.mapRequired("tid", Entry.tid); +} + +StringRef yaml::MappingTraits<GDBRemoteCommunicationHistory::Entry>::validate( + IO &io, GDBRemoteCommunicationHistory::Entry &Entry) { + if (Entry.bytes_transmitted != Entry.packet.data.size()) + return "BinaryData size doesn't match bytes transmitted"; + + return {}; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h new file mode 100644 index 0000000000000..d0ca6a0235c9b --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h @@ -0,0 +1,156 @@ +//===-- GDBRemoteCommunicationHistory.h--------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteCommunicationHistory_h_ +#define liblldb_GDBRemoteCommunicationHistory_h_ + +#include <string> +#include <vector> + +#include "lldb/lldb-public.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +namespace lldb_private { +namespace process_gdb_remote { + +/// The history keeps a circular buffer of GDB remote packets. The history is +/// used for logging and replaying GDB remote packets. +class GDBRemoteCommunicationHistory { +public: + friend llvm::yaml::MappingTraits<GDBRemoteCommunicationHistory>; + + enum PacketType { ePacketTypeInvalid = 0, ePacketTypeSend, ePacketTypeRecv }; + + /// Entry in the ring buffer containing the packet data, its type, size and + /// index. Entries can be serialized to file. + struct Entry { + Entry() + : packet(), type(ePacketTypeInvalid), bytes_transmitted(0), + packet_idx(0), tid(LLDB_INVALID_THREAD_ID) {} + + void Clear() { + packet.data.clear(); + type = ePacketTypeInvalid; + bytes_transmitted = 0; + packet_idx = 0; + tid = LLDB_INVALID_THREAD_ID; + } + + struct BinaryData { + std::string data; + }; + + void Serialize(llvm::raw_ostream &strm) const; + + BinaryData packet; + PacketType type; + uint32_t bytes_transmitted; + uint32_t packet_idx; + lldb::tid_t tid; + }; + + GDBRemoteCommunicationHistory(uint32_t size = 0); + + ~GDBRemoteCommunicationHistory(); + + // For single char packets for ack, nack and /x03 + void AddPacket(char packet_char, PacketType type, uint32_t bytes_transmitted); + + void AddPacket(const std::string &src, uint32_t src_len, PacketType type, + uint32_t bytes_transmitted); + + void Dump(Stream &strm) const; + void Dump(Log *log) const; + bool DidDumpToLog() const { return m_dumped_to_log; } + + void SetStream(llvm::raw_ostream *strm) { m_stream = strm; } + +private: + 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 m_packets.empty() ? 0 : 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; + llvm::raw_ostream *m_stream = nullptr; +}; + +} // namespace process_gdb_remote +} // namespace lldb_private + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR( + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry) + +namespace llvm { +namespace yaml { + +template <> +struct ScalarEnumerationTraits<lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::PacketType> { + static void enumeration(IO &io, + lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::PacketType &value); +}; + +template <> +struct ScalarTraits<lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::Entry::BinaryData> { + static void output(const lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::Entry::BinaryData &, + void *, raw_ostream &); + + static StringRef + input(StringRef, void *, + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry:: + BinaryData &); + + static QuotingType mustQuote(StringRef S) { return QuotingType::None; } +}; + +template <> +struct MappingTraits< + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry> { + static void + mapping(IO &io, + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry + &Entry); + + static StringRef validate( + IO &io, + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry &); +}; + +} // namespace yaml +} // namespace llvm + +#endif // liblldb_GDBRemoteCommunicationHistory_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp new file mode 100644 index 0000000000000..6a78eb20992e0 --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -0,0 +1,204 @@ +//===-- GDBRemoteCommunicationReplayServer.cpp ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <errno.h> + +#include "lldb/Host/Config.h" + +#include "GDBRemoteCommunicationReplayServer.h" +#include "ProcessGDBRemoteLog.h" + +// C Includes +// C++ Includes +#include <cstring> + +// Project includes +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Event.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; + +GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer() + : GDBRemoteCommunication("gdb-remote.server", + "gdb-remote.server.rx_packet"), + m_async_broadcaster(nullptr, "lldb.gdb-remote.server.async-broadcaster"), + m_async_listener_sp( + Listener::MakeListener("lldb.gdb-remote.server.async-listener")), + m_async_thread_state_mutex(), m_skip_acks(false) { + m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, + "async thread continue"); + m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, + "async thread should exit"); + + const uint32_t async_event_mask = + eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; + m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, + async_event_mask); +} + +GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() { + StopAsyncThread(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( + Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) { + StringExtractorGDBRemote packet; + PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); + + if (packet_result != PacketResult::Success) { + if (!IsConnected()) { + error.SetErrorString("lost connection"); + quit = true; + } else { + error.SetErrorString("timeout"); + } + return packet_result; + } + + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); + + if (m_skip_acks) { + const StringExtractorGDBRemote::ServerPacketType packet_type = + packet.GetServerPacketType(); + switch (packet_type) { + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + return PacketResult::Success; + default: + break; + } + } else if (packet.GetStringRef() == "QStartNoAckMode") { + m_skip_acks = true; + m_send_acks = false; + } + + while (!m_packet_history.empty()) { + // Pop last packet from the history. + GDBRemoteCommunicationHistory::Entry entry = m_packet_history.back(); + m_packet_history.pop_back(); + + // We only care about what we received from the server. Skip everything + // the client sent. + if (entry.type != GDBRemoteCommunicationHistory::ePacketTypeRecv) + continue; + + return SendRawPacketNoLock(entry.packet.data, true); + } + + quit = true; + + return packet_result; +} + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR( + std::vector< + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry>) + +llvm::Error +GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) { + auto error_or_file = MemoryBuffer::getFile(path.GetPath()); + if (auto err = error_or_file.getError()) + return errorCodeToError(err); + + yaml::Input yin((*error_or_file)->getBuffer()); + yin >> m_packet_history; + + if (auto err = yin.error()) + return errorCodeToError(err); + + // We want to manipulate the vector like a stack so we need to reverse the + // order of the packets to have the oldest on at the back. + std::reverse(m_packet_history.begin(), m_packet_history.end()); + + return Error::success(); +} + +bool GDBRemoteCommunicationReplayServer::StartAsyncThread() { + std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); + if (!m_async_thread.IsJoinable()) { + // Create a thread that watches our internal state and controls which + // events make it to clients (into the DCProcess event queue). + m_async_thread = ThreadLauncher::LaunchThread( + "<lldb.gdb-remote.server.async>", + GDBRemoteCommunicationReplayServer::AsyncThread, this, nullptr); + } + + // Wait for handshake. + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); + + return m_async_thread.IsJoinable(); +} + +void GDBRemoteCommunicationReplayServer::StopAsyncThread() { + std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); + + if (!m_async_thread.IsJoinable()) + return; + + // Request thread to stop. + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); + + // Disconnect client. + Disconnect(); + + // Stop the thread. + m_async_thread.Join(nullptr); + m_async_thread.Reset(); +} + +void GDBRemoteCommunicationReplayServer::ReceivePacket( + GDBRemoteCommunicationReplayServer &server, bool &done) { + Status error; + bool interrupt; + auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1), + error, interrupt, done); + if (packet_result != GDBRemoteCommunication::PacketResult::Success && + packet_result != + GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) { + done = true; + } else { + server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); + } +} + +thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) { + GDBRemoteCommunicationReplayServer *server = + (GDBRemoteCommunicationReplayServer *)arg; + + EventSP event_sp; + bool done = false; + + while (true) { + if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { + const uint32_t event_type = event_sp->GetType(); + if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) { + switch (event_type) { + case eBroadcastBitAsyncContinue: + ReceivePacket(*server, done); + if (done) + return {}; + break; + case eBroadcastBitAsyncThreadShouldExit: + default: + return {}; + } + } + } + } + + return {}; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h new file mode 100644 index 0000000000000..5b840c8459b71 --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h @@ -0,0 +1,83 @@ +//===-- GDBRemoteCommunicationReplayServer.h --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteCommunicationReplayServer_h_ +#define liblldb_GDBRemoteCommunicationReplayServer_h_ + +// Other libraries and framework includes +#include "GDBRemoteCommunication.h" +#include "GDBRemoteCommunicationHistory.h" + +// Project includes +#include "lldb/Host/HostThread.h" +#include "lldb/Utility/Broadcaster.h" +#include "lldb/lldb-private-forward.h" +#include "llvm/Support/Error.h" + +// C Includes +// C++ Includes +#include <functional> +#include <map> +#include <thread> + +class StringExtractorGDBRemote; + +namespace lldb_private { +namespace process_gdb_remote { + +class ProcessGDBRemote; + +/// Dummy GDB server that replays packets from the GDB Remote Communication +/// history. This is used to replay GDB packets. +class GDBRemoteCommunicationReplayServer : public GDBRemoteCommunication { +public: + GDBRemoteCommunicationReplayServer(); + + ~GDBRemoteCommunicationReplayServer() override; + + PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout, + Status &error, bool &interrupt, + bool &quit); + + bool HandshakeWithClient() { return GetAck() == PacketResult::Success; } + + llvm::Error LoadReplayHistory(const FileSpec &path); + + bool StartAsyncThread(); + void StopAsyncThread(); + +protected: + enum { + eBroadcastBitAsyncContinue = (1 << 0), + eBroadcastBitAsyncThreadShouldExit = (1 << 1), + }; + + static void ReceivePacket(GDBRemoteCommunicationReplayServer &server, + bool &done); + static lldb::thread_result_t AsyncThread(void *arg); + + /// Replay history with the oldest packet at the end. + std::vector<GDBRemoteCommunicationHistory::Entry> m_packet_history; + + /// Server thread. + Broadcaster m_async_broadcaster; + lldb::ListenerSP m_async_listener_sp; + HostThread m_async_thread; + std::recursive_mutex m_async_thread_state_mutex; + + bool m_skip_acks; + +private: + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationReplayServer); +}; + +} // namespace process_gdb_remote +} // namespace lldb_private + +#endif // liblldb_GDBRemoteCommunicationReplayServer_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 4fc1fc7a1964e..026f78117a0c4 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -13,11 +13,8 @@ #include "GDBRemoteCommunicationServer.h" -// C Includes -// C++ Includes #include <cstring> -// Project includes #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringExtractorGDBRemote.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 880caacd64149..082fb0d854243 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -10,13 +10,9 @@ #ifndef liblldb_GDBRemoteCommunicationServer_h_ #define liblldb_GDBRemoteCommunicationServer_h_ -// C Includes -// C++ Includes #include <functional> #include <map> -// Other libraries and framework includes -// Project includes #include "GDBRemoteCommunication.h" #include "lldb/lldb-private-forward.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index c5b478378faa4..f11ef4f1bbf84 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -11,23 +11,21 @@ #include <errno.h> -// C Includes #ifdef __APPLE__ #include <TargetConditionals.h> #endif -// C++ Includes #include <chrono> #include <cstring> -// Other libraries and framework includes #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/Config.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/SafeMachO.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/FileAction.h" @@ -36,12 +34,10 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/SafeMachO.h" #include "lldb/Utility/StreamGDBRemote.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/Triple.h" -// Project includes #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" @@ -353,7 +349,7 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( std::string file; extractor.GetHexByteString(file); match_info.GetProcessInfo().GetExecutableFile().SetFile( - file, false, FileSpec::Style::native); + file, FileSpec::Style::native); } else if (key.equals("name_match")) { NameMatch name_match = llvm::StringSwitch<NameMatch>(value) .Case("equals", NameMatch::Equals) @@ -520,7 +516,8 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Open( if (packet.GetChar() == ',') { mode_t mode = packet.GetHexMaxU32(false, 0600); Status error; - const FileSpec path_spec{path, true}; + FileSpec path_spec(path); + FileSystem::Instance().Resolve(path_spec); int fd = ::open(path_spec.GetCString(), flags, mode); const int save_errno = fd == -1 ? errno : 0; StreamString response; @@ -659,12 +656,14 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Mode( std::string path; packet.GetHexByteString(path); if (!path.empty()) { - Status error; - const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error); + FileSpec file_spec(path); + FileSystem::Instance().Resolve(file_spec); + std::error_code ec; + const uint32_t mode = FileSystem::Instance().GetPermissions(file_spec, ec); StreamString response; response.Printf("F%u", mode); - if (mode == 0 || error.Fail()) - response.Printf(",%i", (int)error.GetError()); + if (mode == 0 || ec) + response.Printf(",%i", (int)Status(ec).GetError()); return SendPacketNoLock(response.GetString()); } return SendErrorResponse(23); @@ -698,7 +697,11 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_symlink( packet.GetHexByteStringTerminatedBy(dst, ','); packet.GetChar(); // Skip ',' char packet.GetHexByteString(src); - Status error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); + + FileSpec src_spec(src); + FileSystem::Instance().Resolve(src_spec); + Status error = FileSystem::Instance().Symlink(src_spec, FileSpec(dst)); + StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetString()); @@ -731,9 +734,11 @@ GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell( packet.GetHexByteString(working_dir); int status, signo; std::string output; - Status err = Host::RunShellCommand( - path.c_str(), FileSpec{working_dir, true}, &status, &signo, &output, - std::chrono::seconds(10)); + FileSpec working_spec(working_dir); + FileSystem::Instance().Resolve(working_spec); + Status err = + Host::RunShellCommand(path.c_str(), working_spec, &status, &signo, + &output, std::chrono::seconds(10)); StreamGDBRemote response; if (err.Fail()) { response.PutCString("F,"); @@ -884,7 +889,7 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN( packet.GetHexByteString(path); const bool read = true; const bool write = false; - if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) { + if (file_action.Open(STDIN_FILENO, FileSpec(path), read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse(); } @@ -900,7 +905,7 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT( packet.GetHexByteString(path); const bool read = false; const bool write = true; - if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) { + if (file_action.Open(STDOUT_FILENO, FileSpec(path), read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse(); } @@ -916,7 +921,7 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR( packet.GetHexByteString(path); const bool read = false; const bool write = true; - if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) { + if (file_action.Open(STDERR_FILENO, FileSpec(path), read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse(); } @@ -1024,7 +1029,7 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { if (success) { if (arg_idx == 0) m_process_launch_info.GetExecutableFile().SetFile( - arg, false, FileSpec::Style::native); + arg, FileSpec::Style::native); m_process_launch_info.GetArguments().AppendArgument(arg); if (log) log->Printf("LLGSPacketHandler::%s added arg %d: \"%s\"", @@ -1263,7 +1268,9 @@ FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile( #ifdef __ANDROID__ return HostInfoAndroid::ResolveLibraryPath(module_path, arch); #else - return FileSpec(module_path, true); + FileSpec file_spec(module_path); + FileSystem::Instance().Resolve(file_spec); + return file_spec; #endif } @@ -1272,7 +1279,9 @@ GDBRemoteCommunicationServerCommon::GetModuleInfo(llvm::StringRef module_path, llvm::StringRef triple) { ArchSpec arch(triple); - const FileSpec req_module_path_spec(module_path, true); + FileSpec req_module_path_spec(module_path); + FileSystem::Instance().Resolve(req_module_path_spec); + const FileSpec module_path_spec = FindModuleFile(req_module_path_spec.GetPath(), arch); const ModuleSpec module_spec(module_path_spec, arch); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index e9ab8f1a11deb..f3825bb367917 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -10,12 +10,8 @@ #ifndef liblldb_GDBRemoteCommunicationServerCommon_h_ #define liblldb_GDBRemoteCommunicationServerCommon_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Process.h" #include "lldb/lldb-private-forward.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 50392fa389562..cdb63e72f6bdb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -14,15 +14,10 @@ #include "GDBRemoteCommunicationServerLLGS.h" #include "lldb/Utility/StreamGDBRemote.h" -// C Includes -// C++ Includes #include <chrono> #include <cstring> #include <thread> -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/State.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Debug.h" #include "lldb/Host/File.h" @@ -41,12 +36,13 @@ #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/UriParser.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ScopedPrinter.h" -// Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" @@ -222,8 +218,10 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { m_process_launch_info.SetLaunchInSeparateProcessGroup(true); m_process_launch_info.GetFlags().Set(eLaunchFlagDebug); - const bool default_to_use_pty = true; - m_process_launch_info.FinalizeFileActions(nullptr, default_to_use_pty); + if (should_forward_stdio) { + if (llvm::Error Err = m_process_launch_info.SetUpPtyRedirection()) + return Status(std::move(Err)); + } { std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); @@ -1333,7 +1331,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir( packet.SetFilePos(::strlen("QSetWorkingDir:")); std::string path; packet.GetHexByteString(path); - m_process_launch_info.SetWorkingDirectory(FileSpec{path, true}); + m_process_launch_info.SetWorkingDirectory(FileSpec(path)); return SendOKResponse(); } @@ -3220,7 +3218,7 @@ GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path, if (m_debugged_process_up ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec) .Success()) { - if (file_spec.Exists()) + if (FileSystem::Instance().Exists(file_spec)) return file_spec; } } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 5a74d1acaa237..a085a3cc17dd1 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -10,18 +10,14 @@ #ifndef liblldb_GDBRemoteCommunicationServerLLGS_h_ #define liblldb_GDBRemoteCommunicationServerLLGS_h_ -// C Includes -// C++ Includes #include <mutex> #include <unordered_map> -// Other libraries and framework includes #include "lldb/Core/Communication.h" #include "lldb/Host/MainLoop.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/lldb-private-forward.h" -// Project includes #include "GDBRemoteCommunicationServerCommon.h" class StringExtractorGDBRemote; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 26e28a900320a..3521ddafbb166 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -11,15 +11,12 @@ #include <errno.h> -// C Includes -// C++ Includes #include <chrono> #include <csignal> #include <cstring> #include <mutex> #include <sstream> -// Other libraries and framework includes #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" @@ -38,7 +35,6 @@ #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UriParser.h" -// Project includes #include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; @@ -168,9 +164,6 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( StringExtractorGDBRemote &packet) { -#ifdef _WIN32 - return SendErrorResponse(9); -#else // Spawn a local debugserver as a platform so we can then attach or launch a // process... @@ -221,10 +214,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( PacketResult packet_result = SendPacketNoLock(response.GetString()); if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill(debugserver_pid, SIGINT); + Host::Kill(debugserver_pid, SIGINT); } return packet_result; -#endif } GDBRemoteCommunication::PacketResult @@ -532,7 +524,7 @@ const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { const char *domainsocket_dir_env = ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); if (domainsocket_dir_env != nullptr) - g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); + g_domainsocket_dir = FileSpec(domainsocket_dir_env); else g_domainsocket_dir = HostInfo::GetProcessTempDir(); }); @@ -542,15 +534,15 @@ const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { FileSpec GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) { - llvm::SmallString<PATH_MAX> socket_path; - llvm::SmallString<PATH_MAX> socket_name( + llvm::SmallString<128> socket_path; + llvm::SmallString<128> socket_name( (llvm::StringRef(prefix) + ".%%%%%%").str()); FileSpec socket_path_spec(GetDomainSocketDir()); socket_path_spec.AppendPathComponent(socket_name.c_str()); llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); - return FileSpec(socket_path.c_str(), false); + return FileSpec(socket_path.c_str()); } void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index aed5106272d1b..df51e0367d1d2 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -10,14 +10,10 @@ #ifndef liblldb_GDBRemoteCommunicationServerPlatform_h_ #define liblldb_GDBRemoteCommunicationServerPlatform_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <set> -// Other libraries and framework includes -// Project includes #include "GDBRemoteCommunicationServerCommon.h" #include "lldb/Host/Socket.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 07dab751f4b90..e58f47f4befef 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -9,17 +9,13 @@ #include "GDBRemoteRegisterContext.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/StreamString.h" -// Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" @@ -462,7 +458,7 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues( ((ProcessGDBRemote *)process)->GetGDBRemote()); const bool use_g_packet = - gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; + !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process); GDBRemoteClientBase::Lock lock(gdb_comm, false); if (lock) { @@ -525,7 +521,7 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( ((ProcessGDBRemote *)process)->GetGDBRemote()); const bool use_g_packet = - gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; + !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process); GDBRemoteClientBase::Lock lock(gdb_comm, false); if (lock) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 8ef91af55e0f8..6e8f3306669f3 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -10,12 +10,8 @@ #ifndef lldb_GDBRemoteRegisterContext_h_ #define lldb_GDBRemoteRegisterContext_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/DynamicRegisterInfo.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/ConstString.h" diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index b3d33b19bd666..797f63d537a17 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -9,12 +9,11 @@ #include "lldb/Host/Config.h" -// C Includes #include <errno.h> #include <stdlib.h> #ifndef LLDB_DISABLE_POSIX #include <netinet/in.h> -#include <sys/mman.h> // for mmap +#include <sys/mman.h> #include <sys/socket.h> #include <unistd.h> #endif @@ -22,7 +21,6 @@ #include <sys/types.h> #include <time.h> -// C++ Includes #include <algorithm> #include <csignal> #include <map> @@ -34,7 +32,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" #include "lldb/DataFormatters/FormatManager.h" @@ -68,10 +65,11 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/CleanUp.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" -// Project includes #include "GDBRemoteRegisterContext.h" #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" @@ -88,6 +86,7 @@ #include "llvm/Support/raw_ostream.h" #define DEBUGSERVER_BASENAME "debugserver" +using namespace llvm; using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; @@ -101,21 +100,21 @@ namespace lldb { // and get the packet history dumped to a file. void DumpProcessGDBRemotePacketHistory(void *p, const char *path) { StreamFile strm; - Status error(strm.GetFile().Open(path, File::eOpenOptionWrite | - File::eOpenOptionCanCreate)); + Status error = FileSystem::Instance().Open(strm.GetFile(), FileSpec(path), + File::eOpenOptionWrite | + File::eOpenOptionCanCreate); if (error.Success()) ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(strm); } -} +} // namespace lldb namespace { -static PropertyDefinition g_properties[] = { - {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, NULL, +static constexpr PropertyDefinition g_properties[] = { + {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, {}, "Specify the default packet timeout in seconds."}, - {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, NULL, - "The file that provides the description for remote target registers."}, - {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; + {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, {}, + "The file that provides the description for remote target registers."}}; enum { ePropertyPacketTimeout, ePropertyTargetDefinitionFile }; @@ -158,7 +157,42 @@ static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { return g_settings_sp; } -} // anonymous namespace end +class ProcessGDBRemoteProvider + : public repro::Provider<ProcessGDBRemoteProvider> { +public: + ProcessGDBRemoteProvider(const FileSpec &directory) : Provider(directory) { + m_info.name = "gdb-remote"; + m_info.files.push_back("gdb-remote.yaml"); + } + + raw_ostream *GetHistoryStream() { + FileSpec history_file = + GetRoot().CopyByAppendingPathComponent("gdb-remote.yaml"); + + std::error_code EC; + m_stream_up = llvm::make_unique<raw_fd_ostream>(history_file.GetPath(), EC, + sys::fs::OpenFlags::F_None); + return m_stream_up.get(); + } + + void SetCallback(std::function<void()> callback) { + m_callback = std::move(callback); + } + + void Keep() override { m_callback(); } + + void Discard() override { m_callback(); } + + static char ID; + +private: + std::function<void()> m_callback; + std::unique_ptr<raw_fd_ostream> m_stream_up; +}; + +char ProcessGDBRemoteProvider::ID = 0; + +} // namespace // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing it @@ -234,7 +268,7 @@ bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, case ObjectFile::eTypeUnknown: break; } - return exe_module->GetFileSpec().Exists(); + return FileSystem::Instance().Exists(exe_module->GetFileSpec()); } // However, if there is no executable module, we return true since we might // be preparing to attach. @@ -259,8 +293,8 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_addr_to_mmap_size(), m_thread_create_bp_sp(), m_waiting_for_attach(false), m_destroy_tried_resuming(false), m_command_sp(), m_breakpoint_pc_offset(0), - m_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false), - m_erased_flash_ranges() { + m_initial_tid(LLDB_INVALID_THREAD_ID), m_replay_mode(false), + m_allow_flash_writes(false), m_erased_flash_ranges() { m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, @@ -268,6 +302,15 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, "async thread did exit"); + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + ProcessGDBRemoteProvider &provider = + g->GetOrCreate<ProcessGDBRemoteProvider>(); + // Set the history stream to the stream owned by the provider. + m_gdb_comm.SetHistoryStream(provider.GetHistoryStream()); + // Make sure to clear the stream again when we're finished. + provider.SetCallback([&]() { m_gdb_comm.SetHistoryStream(nullptr); }); + } + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); const uint32_t async_event_mask = @@ -440,10 +483,10 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile(); - if (!target_definition_fspec.Exists()) { + if (!FileSystem::Instance().Exists(target_definition_fspec)) { // If the filename doesn't exist, it may be a ~ not having been expanded - // try to resolve it. - target_definition_fspec.ResolvePath(); + FileSystem::Instance().Resolve(target_definition_fspec); } if (target_definition_fspec) { // See if we can get register definitions from a python file @@ -640,7 +683,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { m_register_info.Finalize(GetTarget().GetArchitecture()); } -Status ProcessGDBRemote::WillLaunch(Module *module) { +Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) { return WillLaunchOrAttach(); } @@ -689,7 +732,9 @@ Status ProcessGDBRemote::DoConnectRemote(Stream *strm, if (m_gdb_comm.GetProcessArchitecture().IsValid()) { target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); } else { - target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + if (m_gdb_comm.GetHostArchitecture().IsValid()) { + target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } } } @@ -754,7 +799,7 @@ Status ProcessGDBRemote::WillLaunchOrAttach() { //---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- -Status ProcessGDBRemote::DoLaunch(Module *exe_module, +Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, ProcessLaunchInfo &launch_info) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); Status error; @@ -824,13 +869,13 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module, if (disable_stdio) { // set to /dev/null unless redirected to a file above if (!stdin_file_spec) - stdin_file_spec.SetFile(FileSystem::DEV_NULL, false, + stdin_file_spec.SetFile(FileSystem::DEV_NULL, FileSpec::Style::native); if (!stdout_file_spec) - stdout_file_spec.SetFile(FileSystem::DEV_NULL, false, + stdout_file_spec.SetFile(FileSystem::DEV_NULL, FileSpec::Style::native); if (!stderr_file_spec) - stderr_file_spec.SetFile(FileSystem::DEV_NULL, false, + stderr_file_spec.SetFile(FileSystem::DEV_NULL, FileSpec::Style::native); } else if (platform_sp && platform_sp->IsHost()) { // If the debugserver is local and we aren't disabling STDIO, lets use @@ -839,7 +884,7 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module, // does a lot of output. if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, NULL, 0)) { - FileSpec slave_name{pty.GetSlaveName(NULL, 0), false}; + FileSpec slave_name{pty.GetSlaveName(NULL, 0)}; if (!stdin_file_spec) stdin_file_spec = slave_name; @@ -1058,9 +1103,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s gdb-remote had process architecture, " "using %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1069,9 +1115,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s gdb-remote did not have process " "architecture, using gdb-remote host architecture %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1083,9 +1130,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf( "ProcessGDBRemote::%s analyzing target arch, currently %s %s", - __FUNCTION__, target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "<null>", target_arch.GetTriple().getTriple().c_str() ? target_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1105,9 +1153,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s remote process is ARM/Apple, " "setting target arch to %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1135,9 +1184,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s final target arch after " "adjustments for remote architecture: %s %s", - __FUNCTION__, target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "<null>", target_arch.GetTriple().getTriple().c_str() ? target_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1478,7 +1528,7 @@ Status ProcessGDBRemote::DoResume() { new EventDataBytes(continue_packet.GetString().data(), continue_packet.GetSize())); - if (listener_sp->GetEvent(event_sp, std::chrono::seconds(5)) == false) { + if (!listener_sp->GetEvent(event_sp, std::chrono::seconds(5))) { error.SetErrorString("Resume timed out."); if (log) log->Printf("ProcessGDBRemote::DoResume: Resume timed out."); @@ -1832,7 +1882,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( bool handled = false; bool did_exec = false; if (!reason.empty()) { - if (reason.compare("trace") == 0) { + if (reason == "trace") { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() ->GetBreakpointSiteList() @@ -1850,7 +1900,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo( StopInfo::CreateStopReasonToTrace(*thread_sp)); handled = true; - } else if (reason.compare("breakpoint") == 0) { + } else if (reason == "breakpoint") { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() ->GetBreakpointSiteList() @@ -1871,9 +1921,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo(invalid_stop_info_sp); } } - } else if (reason.compare("trap") == 0) { + } else if (reason == "trap") { // Let the trap just use the standard signal stop reason below... - } else if (reason.compare("watchpoint") == 0) { + } else if (reason == "watchpoint") { StringExtractor desc_extractor(description.c_str()); addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); @@ -1905,11 +1955,11 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( *thread_sp, watch_id, wp_hit_addr)); handled = true; - } else if (reason.compare("exception") == 0) { + } else if (reason == "exception") { thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( *thread_sp, description.c_str())); handled = true; - } else if (reason.compare("exec") == 0) { + } else if (reason == "exec") { did_exec = true; thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithExec(*thread_sp)); @@ -1934,7 +1984,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( } } - if (!handled && signo && did_exec == false) { + if (!handled && signo && !did_exec) { if (signo == SIGTRAP) { // Currently we are going to assume SIGTRAP means we are either // hitting a breakpoint or hardware single stepping. @@ -2648,7 +2698,7 @@ void ProcessGDBRemote::SetLastStopPacket( // We are are not using non-stop mode, there can only be one last stop // reply packet, so clear the list. - if (GetTarget().GetNonStopModeEnabled() == false) + if (!GetTarget().GetNonStopModeEnabled()) m_stop_packet_stack.clear(); // Add this stop packet to the stop packet stack This stack will get popped @@ -3378,6 +3428,43 @@ Status ProcessGDBRemote::DoSignal(int signo) { return error; } +Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { + if (!loader) + return Status("No loader provided."); + + auto provider_info = loader->GetProviderInfo("gdb-remote"); + if (!provider_info) + return Status("No provider for gdb-remote."); + + if (provider_info->files.empty()) + return Status("Provider for gdb-remote contains no files."); + + // Construct replay history path. + FileSpec history_file = loader->GetRoot().CopyByAppendingPathComponent( + provider_info->files.front()); + + // Enable replay mode. + m_replay_mode = true; + + // Load replay history. + if (auto error = m_gdb_replay_server.LoadReplayHistory(history_file)) + return Status("Unable to load replay history"); + + // Make a local connection. + if (auto error = GDBRemoteCommunication::ConnectLocally(m_gdb_comm, + m_gdb_replay_server)) + return Status("Unable to connect to replay server"); + + // Start server thread. + m_gdb_replay_server.StartAsyncThread(); + + // Start client thread. + StartAsyncThread(); + + // Do the usual setup. + return ConnectToDebugserver(""); +} + Status ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) { // Make sure we aren't already connected? @@ -3388,6 +3475,9 @@ ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) { if (platform_sp && !platform_sp->IsHost()) return Status("Lost debug server connection"); + if (repro::Loader *loader = repro::Reproducer::Instance().GetLoader()) + return ConnectToReplayServer(loader); + auto error = LaunchAndConnectToDebugserver(process_info); if (error.Fail()) { const char *error_string = error.AsCString(); @@ -3497,7 +3587,7 @@ bool ProcessGDBRemote::MonitorDebugserverProcess( bool exited, // True if the process did exit int signo, // Zero for no signal int exit_status // Exit value of process if signal is zero - ) { +) { // "debugserver_pid" argument passed in is the process ID for debugserver // that we are tracking... Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); @@ -4269,8 +4359,9 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, return false; feature_node.ForEachChildElementWithName( - "reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, - &abi_sp](const XMLNode ®_node) -> bool { + "reg", + [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, + &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; @@ -4432,7 +4523,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, return true; } -} // namespace {} +} // namespace // query the target of gdb-remote for extended target information return: // 'true' on success @@ -4509,12 +4600,19 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { // <architecture>arm</architecture> (seen from Segger JLink on unspecified arm board) // use that if we don't have anything better. if (!arch_to_use.IsValid() && !target_info.arch.empty()) { - if (target_info.arch == "i386:x86-64") - { + if (target_info.arch == "i386:x86-64") { // We don't have any information about vendor or OS. arch_to_use.SetTriple("x86_64--"); GetTarget().MergeArchitecture(arch_to_use); } + + // SEGGER J-Link jtag boards send this very-generic arch name, + // we'll need to use this if we have absolutely nothing better + // to work with or the register definitions won't be accepted. + if (target_info.arch == "arm") { + arch_to_use.SetTriple("arm--"); + GetTarget().MergeArchitecture(arch_to_use); + } } // Initialize these outside of ParseRegisters, since they should not be @@ -4760,7 +4858,8 @@ size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) { if (!modInfo.get_link_map(link_map)) link_map = LLDB_INVALID_ADDRESS; - FileSpec file(mod_name, true); + FileSpec file(mod_name); + FileSystem::Instance().Resolve(file); lldb::ModuleSP module_sp = LoadModuleAtAddress(file, link_map, mod_base, mod_base_is_offset); @@ -4802,7 +4901,7 @@ size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) { return true; lldb::ModuleSP module_copy_sp = module_sp; - target.SetExecutableModule(module_copy_sp, false); + target.SetExecutableModule(module_copy_sp, eLoadDependentsNo); return false; }); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 45bb2d4c28e71..14a5237e43451 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -10,15 +10,12 @@ #ifndef liblldb_ProcessGDBRemote_h_ #define liblldb_ProcessGDBRemote_h_ -// C Includes -// C++ Includes #include <atomic> #include <map> #include <mutex> #include <string> #include <vector> -#include "lldb/Core/Broadcaster.h" #include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ThreadSafeValue.h" @@ -26,6 +23,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamGDBRemote.h" @@ -36,11 +34,15 @@ #include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationClient.h" +#include "GDBRemoteCommunicationReplayServer.h" #include "GDBRemoteRegisterContext.h" #include "llvm/ADT/DenseMap.h" namespace lldb_private { +namespace repro { +class Loader; +} namespace process_gdb_remote { class ThreadGDBRemote; @@ -264,6 +266,7 @@ protected: }; GDBRemoteCommunicationClient m_gdb_comm; + GDBRemoteCommunicationReplayServer m_gdb_replay_server; std::atomic<lldb::pid_t> m_debugserver_pid; std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet // stack replaces @@ -304,6 +307,7 @@ protected: int64_t m_breakpoint_pc_offset; lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach + bool m_replay_mode; bool m_allow_flash_writes; using FlashRangeVector = lldb_private::RangeVector<lldb::addr_t, size_t>; using FlashRange = FlashRangeVector::Entry; @@ -331,6 +335,8 @@ protected: bool UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) override; + Status ConnectToReplayServer(repro::Loader *loader); + Status EstablishConnectionIfNeeded(const ProcessInfo &process_info); Status LaunchAndConnectToDebugserver(const ProcessInfo &process_info); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index 3c58011766908..d4981df88d8da 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -10,11 +10,7 @@ #ifndef liblldb_ProcessGDBRemoteLog_h_ #define liblldb_ProcessGDBRemoteLog_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Utility/Log.h" #define GDBR_LOG_PROCESS (1u << 1) diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index a525c16b9f135..db7dc3eae0ba4 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -10,7 +10,6 @@ #include "ThreadGDBRemote.h" #include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Core/State.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -20,6 +19,7 @@ #include "lldb/Target/UnixSignals.h" #include "lldb/Target/Unwind.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "ProcessGDBRemote.h" @@ -197,13 +197,10 @@ void ThreadGDBRemote::SetQueueLibdispatchQueueAddress( } bool ThreadGDBRemote::ThreadHasQueueInformation() const { - if (m_thread_dispatch_qaddr != 0 && - m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS && - m_dispatch_queue_t != LLDB_INVALID_ADDRESS && - m_queue_kind != eQueueKindUnknown && m_queue_serial_number != 0) { - return true; - } - return false; + return m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS && + m_dispatch_queue_t != LLDB_INVALID_ADDRESS && + m_queue_kind != eQueueKindUnknown && m_queue_serial_number != 0; } LazyBool ThreadGDBRemote::GetAssociatedWithLibdispatchQueue() { diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 1a5b60aea2887..4485a9cdc4c36 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -10,12 +10,8 @@ #ifndef liblldb_ThreadGDBRemote_h_ #define liblldb_ThreadGDBRemote_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/StructuredData.h" |